User-replaceable heap services

The Metal C Runtime Library provides the ability to completely replace the underlying heap services at run time. You can use this function if you want the heap services to use a different storage management mechanism, for instance, one that is already in use elsewhere within an application.

A Metal C application replaces the underlying heap services by providing sets of function entry points in the __csysenv_s structure that is passed to the __cinit() function. To have the function entry point fields available and recognized by the __cinit() function, take the following steps:
The Metal C application can provide at environment initialization time 8 bytes of data that can be accessed by the replacement heap services. To reserve the 8 bytes of data, take the following steps:

During the __cinit() call, field __csetheapuserdata can only be set from __cseheapuserdata if heap services have been replaced; otherwise, field __csetheapuserdata will be set to binary zeroes.

Two sets of heap service function entry points are provided, one set for replacing heap services in the AMODE 31 version of the library, and the other set for replacing heap services in the AMODE 64 version of the library.

AMODE 31 heap services

To replace heap services in the AMODE 31 version of the library, consider the following __csysenv_s fields:
void * (*__cseamode31malloc) (size_t)
When specified, MCRTL AMODE 31 malloc() calls this routine to obtain a piece of below-the-bar heap storage and returns its result to the caller of malloc(). __cseamode31malloc is treated as having the same function prototype as malloc(): void * malloc (size_t);
void (* __cseamode31free) (void *)
When specified, MCRTL AMODE 31 free() calls this routine to free a piece of heap storage. __cseamode31free is treated as having the same function prototype as free(): void free(void *);
void * (*__cseamode31realloc) (void *, size_t)
When specified, MCRTL AMODE 31 realloc() calls this routine to perform a realloc for a piece of heap storage and returns its result to the caller of realloc(). __cseamode31realloc is treated as having the same function prototype as realloc(): void * realloc (void *, size_t);

Providing this routine is optional. If realloc() is called when a __cseamode31malloc routine has been provided but __cseamode31realloc has not, realloc() will return a zero.

Note: __cseamode31malloc and __cseamode31free must be provided together. __cseamode31realloc is optional, but when it is provided, the application must also include the other AMODE 31 heap services in this set.

AMODE 64 heap services

To replace heap services in the AMODE 64 version of the library, consider the following __csysenv_s fields:
void * (* __cseamode64malloc) (size_t)
When specified, MCRTL AMODE 64 malloc() calls this routine to obtain a piece of above-the-bar heap storage and returns to the caller of malloc(). __cseamode64malloc is treated as having the same function prototype as malloc(): void * malloc (size_t);
void * (*__cseamode64malloc31) (size_t)
When specified, MCRTL AMODE 64 __malloc31() calls this routine to obtain a piece of below-the-bar heap storage and returns its result to the caller of __malloc31(). __cseamode64malloc31 is treated as having the same function prototype as __malloc31(): void * __malloc31(size_t);
void (* __cseamode64free) (void *)
When specified, MCRTL AMODE 64 free() calls this routine to free a piece of heap storage. __cseamode64free is treated as having the same function prototype as free(): void free(void *);

Note that MCRTL AMODE 64 free() accepts as input and processes heap storage that is allocated above or below the bar. The user-specified __cseamode64free routine must provide the same capability.

void * (*__cseamode64realloc) (void *, size_t)
When specified, MCRTL AMODE 64 realloc() calls this routine to perform a realloc for a piece of heap storage and returns its result to the caller of realloc(). __cseamode64realloc is treated as having the same function prototype as realloc(): void * realloc (void *, size_t);

Providing this routine is optional. If realloc() is called when a __cseamode64malloc routine has been provided but __cseamode64realloc has not, realloc() will return a zero.

Note that MCRTL AMODE 64 realloc() accepts as input and processes heap storage that is allocated above or below the bar. The user-specified __cseamode64realloc routine must provide the same capability.

Note: __cseamode64malloc, __cseamode64malloc31, and __cseamode64free must all be provided together. __cseamode64realloc is optional, but when it is provided, the application must also include the other AMODE 64 heap services in this set.

Usage notes

  • Each heap service gets control in the AMODE of the calling service. The heap service must return to the calling service in that same AMODE.
  • Each heap service is called using standard Metal C linkage conventions, including:
    • GPR 1 containing the address of the function parameter list (using C style parameter passing)
    • GPR 13 containing the address of a stack frame allocated on a contiguous Metal C stack
    GPR 12 contains the environment token representing the Metal C environment that is currently in use.
  • It is not necessary to provide a replacement for the calloc() function. The calloc() function calls malloc() as part of its processing, so replacing malloc() indirectly alters the behavior of calloc() as well.
  • When user-provided heap services are in use, the Metal C Runtime Library makes no attempt to keep track of any heap storage that has been allocated by the application. The application is entirely responsible for tracking its heap storage, and for freeing it after it calls __cterm() to terminate the Metal C environment.
  • The heap allocation functions should return NULL when they are unable to obtain storage. The application is responsible for capturing its own diagnostic data when necessary.
  • The Metal C Runtime Library expects the following alignment for the storage that is returned by the replacement heap services:
    • Storage returned from the below-the-bar heap (AMODE 64 __malloc31(), and AMODE 31 malloc()) is doubleword aligned.
    • Storage returned from the above-the-bar heap (AMODE 64 malloc()) is quadword aligned.