Dynamic Loading is the ability of the simulator to take code with dynamic dependencies and satisfy those dependencies at execution. This allows code to be compiled with the "-non_shared" flag. Details can be found here: Dynamic Linking Info
Any executable with the "DYNAMIC" flag set requires dynamic loading to occur. In that case, Tru64 does the following:
./a.out param1 param2.... Becomes: /sbin/loader ./a.out param1 param2....
At this time.arg files should have /sbin/loader prefacing the desired executable in the same manner (ultimately, we will detect DYNAMIC and handle it ourselves).
/sbin/loader handles detecting dependencies and loading the program into memory in such a manner that the program need not be aware of the situation.
/sbin/loader uses memory mapping extensively. The desired executable is forcibly placed into its program space (generally at 0x120000000) and the shared libraries are placed in the 0x3ff00000000 region. /sbin/loader also wipes pages clean and attempts to unmap pages.
In the context of M-sim, we now allow placement hints for memory mapping as well as wipe pages clean when they are no longer needed. However, we don't remove pages from memory and we assume the hints are an absolute requirement (furthermore, there is no error checking of page allocation - the pages are given without any concern of conflict).
/sbin/loader is very particular about the positioning of data on the program stack. We have not spent a significant time studying this and instead have found values that match Tru64's behavior (for reasonable numbers of command line arguments and environmental variables). First, we move the stack base (loader.c):
From: mem->ld_stack_base = mem->ld_text_base - (409600+4096); To: mem->ld_stack_base = mem->ld_text_base - (-16) - 8192;
The space provided for argv and envp data (pointers only) is strictly set to 8192 bytes:
From: sp = mem->ld_stack_base - MD_MAX_ENVIRON; To: sp = mem->ld_stack_base - 8192;
The actual argv and envp data is placed at mem->ld_stack_base (which is 8192-16 bytes). Originally, this actual data was placed right after the pointers. Tru64 does not expect this.
After all pointers are written:
sp = mem->ld_stack_base - 8;
Then we copy the argv and envp data to sp. The first argument is copied to sp twice. Only the second copy is pointed to by argv.
Previously, all strings were copied with only a NULL between them (unaligned strings). Tru64 aligns all of these strings on quad_word boundaries. This is now done.
After the last pointer in the argv and envp pointer list, there is a NULL. However, after envp and after the NULL there are two additional values. The first is 0x3e9, the second is a pointer to the duplicate copy of the first argument that we now have.
After "//terminate the envp array with a NULL" //These are values that appear in an alpha debugger at runtime. md_addr_t other_name = mem->ld_stack_base - 8; md_addr_t bizarre_val = 0x3e9; mem->mem_access(Write, envp_addr + (i+1)*sizeof(md_addr_t), &bizarre_val, sizeof(md_addr_t)); mem->mem_access(Write, envp_addr + (i+2)*sizeof(md_addr_t), &other_name, sizeof(md_addr_t));
Finally, we adjust the check on sp that checks if we "tromp"ed off the top of the stack:
From: if(sp > mem->ld_stack_base) To: if(sp > mem->ld_text_base)