IBM®
Skip to main content
    United States [change]      Terms of use
 
 
   
     Home      Products      Services & solutions      Support & downloads      My account     
     
  TPF : Library : Presentations

Differences between TARGET(TPF) and ISO-C Memory


by Bill Ashby, IBM TPF Development

When we designed TPF ISO-C support, we spent a lot of effort making it as compatible as possible with TARGET(TPF) without compromising our basic goal of delivering support for a standard C language implementation. One of the areas that we redesigned for ISO-C is the function call stack. This redesign removed the restriction of less than 4 K (4 KB) of automatic data per function and allowed us to implement more efficient stack overflow handling than TARGET(TPF) allows. Writable static storage (or RENT static in ISO-C terms), works about the same way in ISO-C as in TARGET(TPF), but some changes were required to remove the TARGET(TPF) 4 K size restriction on static data for a single program segment.

This redesign introduced some subtle changes in the behavior of the stack and static, which can only show themselves in interfaces to routines that run in 24-bit addressing mode, in system virtual memory (SVM), or that use real addresses. However, these incompatibilities have required some code changes in a couple of migration efforts recently, so it appears that raising awareness about the differences between the two implementations may help users recognize the kinds of problems that they might run into if they are working with code that handles these kinds of interfaces.

Stack Implementations TARGET(TPF) gets memory for its function call stack by allocating 4 K working storage blocks. The first few bytes of each block are used to link the stack together. This has several consequences:

  1. TARGET(TPF) stack frames are not always adjacent in memory, and there is no particular ordering to their addresses except that stack frames in the same 4 K block are allocated from lower addresses first.
  2. Each TARGET(TPF) stack frame must fit within a single 4 K block minus the chaining overhead.
  3. Every TARGET(TPF) stack frame is below the 16-MB boundary
  4. Every TARGET(TPF) stack frame is contained in a single 4 K hardware page.
The ISO-C stack is in a reserved area of virtual memory above the end of usable real memory. Its virtual address space and segment tables are allocated during CTIN, but no real frames are allocated for it until an ISO-C run-time environment is initialized, when the initial stack allocation (two pages, or 8 K, by default) is allocated. Additional frames are added as needed; pages that back the ISO-C function call stack are not deallocated until the ECB exits, so the amount of real storage allocated to the ISO-C function call stack can only increase. In contrast to the TARGET(TPF) stack:
  1. The entire ISO-C stack is contiguous in its ECB virtual address (EVA), the addresses of the active stack frames are all in ascending order, and there is no space between adjacent stack frames.
  2. The size of an ISO-C stack frame is limited only by the remaining virtual address space for the entire stack and the availability of real pages.
  3. Every ISO-C stack frame is above the 16-MB boundary.
  4. ISO-C stack frames may span two or more hardware pages.
Therefore, they are not necessarily contiguous either in real or in system virtual memory.

Static Storage Implementations TARGET(TPF) and ISO-C both implement static storage by allocating and initializing a static block the first time they enter a program segment that defines writable static storage. TARGET(TPF) uses working storage blocks for its static blocks and ISO-C uses hardware pages mapped into the heap virtual address space. Therefore, the differences between TARGET(TPF) and ISO-C static are similar to the differences between their function call stacks:

  1. Each TARGET(TPF) static block must fit within a single 4 K block minus some overhead. The size of an ISO-C stack block is limited only by the remaining virtual address space for the heap and the availability of real pages.
  2. Every TARGET(TPF) static block is below the 16-MB boundary. Every ISO-C static block is above the 16-MB boundary.
  3. Every TARGET(TPF) static block is contained in a single 4 K hardware page. ISO-C static blocks may span more than one hardware page and be noncontiguous in SVM or real memory.
In addition to writable static, ISO-C allows you to define nonwritable static storage (or NORENT static). Because nonwritable static is defined in the program machine code, and ISO-C programs are stored above the 16-MB line (unless the 31-bit core resident program area (CRPA) overflows; a core resident ISO-C program can then be loaded into the 24-bit CRPA) and may be larger than 4 K, nonwritable ISO-C static behaves (for the purpose of this discussion) in the same way as ISO-C writable static except that it is key protected.

Problem Scenario 1: Interfacing with Routines That Run in 24-Bit Mode All C programs that run on TPF 4.1, regardless of whether they are TARGET(TPF) or ISO-C, must be allocated as running in 31-bit mode. However, because the TARGET(TPF) stack and static blocks reside below the 16-MB line, pointers to data contained in them can be passed to routines that require 24-bit addressing.

If a program that does this migrates to ISO-C, the pointers to data in its stack or static will not be valid in 24-bit mode, causing a CTL-000004 addressing exception or other indeterminate behavior if bits 8_31 of the pointers accidentally point to something. This most likely will happen if a C program enters a BAL segment that is allocated as a 24-bit program.

There are two ways to successfully complete this migration:

  1. Change the called routine so that it runs in 31-bit mode or
  2. Move the data below the 16-MB line before the call.

Problem Scenario 2: Interfacing with Services That Run in SVM or in Real Memory If you pass data in ISO-C stack or static storage to a CP service that runs in SVM or executes hardware instructions that require real addresses, the data may be truncated where it crosses a hardware page boundary. For example, you could write a C function that builds a list of data that is passed to a CP service that runs in SVM, or a function that builds a CCW chain for a hardware level I/O routine. In either case, if you build the data in automatic or static storage, it will probably work in TARGET(TPF) but will fail when the code is migrated to ISO-C if the data crosses a real page boundary. (Note that this type of failure would be rare because of the low probability that small amounts of data will cross a page boundary.)

There are two general approaches to solving this problem:

  1. If the called routine gets control in EVM, change it so that it copies the data passed to it into storage that it knows will be contiguous in SVM or real storage.
  2. Change the caller to build the data it is going to pass in storage that it knows will be contiguous in SVM or real storage, such as a working storage block or 4 K frame.
By the way, it is possible to define C storage that does not cross a real page boundary. The following realauto() macro will allocate up to 2 K of automatic storage that is guaranteed to be contained in a single real page. Note that, although this code is written to compile with C/370 without errors or warnings, it is not portable.

/**********************************************************************/
/* Macro: realauto() */
/* */
/* Purpose: Allocate up to 2K in automatic storage that is */
/* guaranteed not to cross a real hardware page boundary. */
/* */
/* Macro call: realauto(type, identifier, storename); */
/* */
/* type - C data type of storage required. */
/* */
/* identifier - the name of the identifier that will */
/* point to the usable storage */
/* allocation. realauto() declares */
/* this as */
/* */
/* type *identifier; */
/* */
/* storename - name for realauto() to use to */
/* generate a storage definition which */
/* will include the required storage. */
/* This name should not be used except */
/* to call the realauto() macro. */
/* */
/* WARNING: The following includes graphic depictions of explicit, */
/* non-portable hardware- and compiler-specific C code. */
/* Viewer discretion is advised. */
/**********************************************************************/
#define realauto(type, identifier, storename) \
double storename[(sizeof (type) + 7) / 4 - 1] = { 0.0 }; \
type *identifier = \
((int)storename & 0x00000FFF) + sizeof (type) > 0x1000 ? \
(type *)((int)storename + 0x00000FFF & 0xFFFFF000) : \
(type *)(int)&storename
Here is an example of how you could use the realauto() macro:

#include <string.h> /* memset() */
/**********************************************************************/
/* Declare types of data structures that must be contiguous in real */
/* memory. */
/**********************************************************************/
typedef struct {
unsigned long hardware1;
unsigned long hardware2;
unsigned long hardware3;
unsigned long hardware4;
} hardwareList;
typedef char hardwareBlock[0x400];
typedef unsigned short parameterList[7];
/**********************************************************************/
/* Declare routine which requires structures that are contiguous in */
/* real memory. */
/**********************************************************************/
extern void foo(hardwareList *);
/**********************************************************************/
/* The following routine defines 3 structures that are contiguous */
/* in real memory, and calls the routine declared above. */
/**********************************************************************/
void bar(void)
{
realauto(parameterList, plistPtr, noname0);
realauto(hardwareList, listPtr, noname1);
realauto(hardwareBlock, blockPtr, noname2);
memset(plistPtr, 0, sizeof *plistPtr);
(*plistPtr)[0] = 0x0123;
(*plistPtr)[1] = 0x4567;
listPtr->hardware1 = 0x89AB0000 + sizeof *plistPtr;
listPtr->hardware2 = (unsigned long)plistPtr;
listPtr->hardware3 = 0xCDEF0000 + sizeof *blockPtr;
listPtr->hardware4 = (unsigned long)blockPtr;
foo(listPtr);
}
You can use a similar approach with static or heap storage.


 

    About IBM Privacy Contact