TURBO PASCAL HEAP MANAGEMENT W. BRIMHALL 13DEC87 ZNODE 52 (602)996-8739 OVERVIEW This file contains information to supplement the Dynamic Storage section of the CP/M 80 Turbo Pascal vers 3.0 reference manual which does not adequately cover these topics: 1) Changing the address of the heap. 2) Preserving the heap during a program chain. A call to Borland technical support did not improve the situation so the following information was obtained from several hours of disassembly and debugging. First of all a COM file produced by Turbo Pascal follows this general memory map: HIGH MEMORY --------------------------------- bdos --------------------------------- variable area --------------------------------- program stack (growing down) --------------------------------- recursion stack (growing down) heap (growing up) --------------------------------- program code --------------------------------- runtime library --------------------------------- page 0 vectors & pointers LOW MEMORY --------------------------------- Turbo maintains these 2 heap pointers in page 0: 00C4 HEAPPTR: dw 0 ;pointer to start of free memory at top of heap 00D4 HEAPFRE: dw 0 ;pointer to 1st block of free memory in heap HeapPtr is predefined and can be accessed like any integer variable. HeapFre is not even mentioned in the Turbo Reference manual. It must be declared as an absolute variable before it can be accessed: Var HeapFre : integer absolute $00de; When a Turbo program runs or executes HeapPtr & HeapFre are both set to the first byte past the end of the program code. This is where the heap begins. The first 4 bytes of the heap are then cleared to zero. When memory is first allocated on the heap with the NEW procedure it will be placed at the location addressed by HeapPtr. There is a 4 byte overhead for each block that is allocated, so bytes, chars, & integers will all use up 4 bytes of storage on the heap. The 4 bytes following the newly allocated block will always be zeroed to mark the top of the heap. When storage is reclaimed with the DISPOSE procedure a linked list is created starting with the lowest free block in the heap. The address of this block is placed in HeapFre. The first 4 bytes of each free block in the heap contain link pointers in this format: dw next ;address of next free block dw size ;size of this free block The top of the heap always contains 4 bytes of 0 which mark the end of the link list. The actual pointer variables are stored as integers. If they are declared globally they will be placed in the variable area which is not affected by chains or executes as long as the chained programs don't overwrite that section of memory. TO CHANGE THE HEAP ADDRESS The Turbo Reference manual gives the impression that the heap address can be changed simply by assigning a new value to HeapPtr. This is not correct! To change the heap address to the value i you must: 1) Declare following variables: Var i : integer; HeapFre : integer absolute $00de; 2) Reset HeapPtr, HeapFre & first 4 bytes of heap: HeapPtr:=i; { Set heap pointer to address new heap } HeapFre:=i; { Set free mem ptr to address new heap} for i:=0 to 3 do mem[HeapPtr+i]:=0; { Zero 1st 4 bytes of new heap } RecurPtr is another predefined variable that addresses the recursion stack. Make sure HeapPtr is never greater than RecurPtr and that HeapPtr is always addressing a free memory area! TO PRESERVE THE HEAP DURING A CHAIN The Turbo loader overwrites up to 128 bytes of ram above the program code with a COM file when it is loaded from disk with the execute command. This overwritten memory is the first 128 bytes of the heap. To preserve the heap during a chain this block must be saved along with the heap pointers. These values can then be restored as follows after the chain or execute is performed: 1) Declare following global variables and make sure all pointer variables are global: Var heap,heap_ptr,heap_fre : integer; HeapFre : integer absolute $00de; heap_bytes : array[0..127] of byte; 2) Save heap address when program starts. heap:=HeapPtr; 3) Save 1st 128 bytes of heap, HeapPtr & HeapFre just before chaining. heap_fre:=HeapFre; heap_ptr:=HeapPtr; for i:=0 to 127 do heap_bytes[i]:=mem[heap+i]); 4) Chain to other program and execute back to main program. Make sure the chained program does not overwrite any other areas of the heap or variable area! 5) Restore saved values before accessing heap: HeapPtr:=heap_ptr; HeapFre:=heap_fre; for i:= 0 to 127 do mem[heap+i]:=heap_bytes[i]; 6) The heap is now completely restored and can now be accessed as though the chain never took place.