followed by small-malloc() space
The kernel has a preferred location for mmap data objects, at 0x4000.0000.Since the libraries are loaded by mmap, they end up here.
The library that most of us are using for malloc (GLIBC) handles smallmallocs by calling sys_brk(), which extends the data area after the app,at 0x0800.0000+sizeof(app). Large mallocs are realized by creating a mmap,so these end up in the pool at 0x4000.0000.
As the mmap pool grows upward, the stack grows downward. Between them,they share 2G bytes.
The shared library design usually has the app loading first, then theloader notices that it need support, and loads the dyn-loader library (usually/lib/ld-linux.so.2) at 0x4000.0000. Other libraries are loaded after ld.so.1.You can see where libraries will load by using the utility ldd
ldd foo_app
Notice that the small malloc space is much smaller in this case, butthis is supposed to be for load-testing and diagnostics, so it's not toobad.
Please, if you need more text, let me know: patb@corel.ca
Here is some analysis of the i386 design:
Intel
in .o files; these are the old relocs......R_386_PC32 | determine the destinance from this memory location to the 'symbol',then add it to the value currently at this dword; deposit the result backinto the dword |
R_386_PLT32 | create a new entry in the PLT[] and GOT[] determine the distance from here to the PLT[] entry and store thatdistance as a dword at this location at final link, rename the reloc to a R_386_JMP_SLOT, keeping the same'symbol' and point it at the GOT[] entry |
Executable files that are built 'static' have no relocs in them. Theyrun standalone.
In executable files which are intended to run with shared libraries......R_386_COPY | read a string of bytes from the 'symbol' address and deposit a copyinto this location; the 'symbol' object has an intrinsic length i.e. move initialized data from a library down into the app data space |
this reloc is, in a sense, the complement of the R_386_COPY above | |
R_386_RELATIVE | at dynamic link time, read the dword at this location, add it to therun-time start address of this module; deposit the result back into thisdword |
Note that R_386_32 relocs can appear in libraries as well. These mustbe executed carefully!
R_386_COPY and R_386_GLOB_DATA can be considered complements ofeach other. Suppose you have a global data object defined in a dynamiclibrary. The library will have the binary version of the object in its.data space. When the application is built, the linker puts a R_386_COPYreloc in there to copy the data down to the application's .bss space. Inturn, the library never references the original global object; it referencesthe copy that is in the application data space, through a correspondingR_386_GLOB_DATA. Wierd, huh? After loading and copying, the original data(from the library) is never used; only the copy (in the app data space).
To make the whole dynamic linking operation happen, the linker introducesseveral 'synthetic' constructs into the target when you build an app ora library: R_386_COPY=5, R_386_GLOB_DAT=6, Jump Solutions IncR_386_JUMP_SLOT=7, Cars Slow Motion Jump Slot CarR_386_RELATIVE=8,Jump Clothes OffR_386_GOTOFF=9,R_386_GOTPC=10 }; Here is an excerpt from the reloc list for my version of /usr/bin/dir Some architectures, like the M68k use a different reloc, called Rela,which has one extra parameter, called an addend. This makes the relocs12 bytes each, instead of 8. The Rel is just as flexible (in my opinion:) Example code This appendix will show C code which triggers the new relocs. Line 5 publishes a function foo() as a public symbol. Since it can becalled from outside, and it needs to be position independent (-fpic),it needs to generate a local reference to the GOT. Early in the prologin foo(), the compiler will generate something like: Line 6 will trigger a R_386_PLT32 reloc, using the symbol 'fPub'. Line7 also generates the same reloc, against the symbol 'fLocal'. (This relocwill disappear at the final link.) Line 8 requires the address of a public object. This object locationhas to be flexible at run time, so a R_386_GOT32 reloc is used. Later,at link time, this will create an address slot in the GOT[]. Line 9 requires the 'contents of' the same object. The object contentsare fetched by using the address contained in the GOT[] entry. [Note thatcompiler is smart enough to use a single reloc to realize both line 8 andline 9] Lines 10 & 11 require the address and contents of a local object.We don't know exactly where this object is going to be a run time, butwe do know that it is local, and we can state its position relative tothe &GOT[0]. So a pair of R_386_GOTOFF relocs are generated. [Again,the compiler may merge lines 10 and 11 into a single reloc, but it didn'twhen I built this example.] [Because of the structure of the linker, full name resolution isn'tchecked until a link is made with an executable. In other words, if yourlibrary has unresolved references, you won't find out about it until youtry to make an app using your library.] To summarize, the .o file contains the following relocs: Lines 3 & 4 remain as R_386_32 relocs, and will ask the dyn-linkerfor the full 32 bit absolute address to be deposited into the reloc target. The reloc triggered by line 5 is fixed up fully, and does not appearin the library. Jackpot Inferno Jump Slot WinnersThe reloc in line 6 will cause the linker to add a PLT entry, and acorresponding GOT entry. The latter gets a R_386_JUMP_SLOT reloc, usingthe symbol 'fPub'. [The code generated at line 6 appears to be a subroutinecall into the PLT entry.] The reloc at line 7 can be fully resolved by the final linker stage,so it is transformed into a direct call to fLocal(). The reloc at line 8 and 9 will cause the linker to add a GOT entry,which will hold &cPub. The GOT entry gets marked with a R_386_GLOB_DATreloc, asking the dyn-linker for the full 32 bit abolute address. The relocs at line 10 & 11 can be fully resolved at final link time.They turn into 'find the data at &GOT[0] plus this offset', sono relocis required. As you can see, the 10 relocs in the .o file turn into 4 in the library.Also, the PLT gets a new entry, and the GOT gets two new entries. Now suppose we have an executable which references the library:When the .o file is created, there is a R_386_PC32 generated for 'fPub'and a R_386_32 generated for the 'cPub'. When the executable is created, the R_386_PC32 from line 1 will causean entry in the PLT, and the code will call into the PLT. At the same time,the linker will create an entry in the GOT, which the PLT will jump through.The GOT entry will get a R_386_JUMP_SLOT reloc, using the symbol 'fPub'. The data reference in line 2 will cause a local copy of the global cPubto be created in the data space of the app. The data reference at line2 is changed to point to this new global data, and the reloc is resolved.This new global gets a R_386_COPY reloc, using the symbol 'cPub'. The symbolhas certain properties, including the fact that references data, and thatit has a length of 1 byte. At run time, the dyn-linker will find the symbolcPub in one of the libraries and copy the 1 byte down from the libraryinto the app data space. The dyn-linker will then publish that latter addressas the address of 'cPub'. Request for commentsJackpot Jump Slot MachineI think the above is exhaustive for the i386. Please let me know if I missedsomething, or if the presentation should be changed. PatBeirne |