normally you can do most of the job with program header, even for handling the whole lot of relocation, the only thing i need from the sections is the size of the whole symbol table, because with program header you are just supposed to access the symbol table via an id contained in the relocation table, and the size of the whole symbol table shouldn't matter at all, but i still need to parse the whole symbol table to find the list of exported symbols, which is all symbols of the table for which st_value is set, other are unresolved symbols that need to be imported, and i didn't find a way to find the list of exported symbols using only the informations in program headers, but normally they contain everything you need to load, relocate, resolve and run the elf image
in the document yes they refer to relocatable files as 'non executable files', during the process of linking, the linker must make in sort that all the symbols used by all part of the program are assigned a location, and that all reference to a symbols are resolved and that the operand of any opcode involing an address, either jmps/calls or memory access, are set to a value that is meaningfull at runtime, if you compile a single file, the linking process should be pretty simple, but once you use several files, and extern reference, the linker must make sure any symbol used in any part of the program to be linked is assigned a location
if you don't want to bother at all with relocation, you can just set up the memory as it's suggested by elf program headers, and all the memory location in the binary machine code will point at the right place , and you just have to resolve imported symbols, which are entry in the relocation table who make reference to a symbol of which the value is not set
but if you want to load the sections in another place, then you need to parse the relocation table and edit the machine code to change the address it contain to point at the actual location the symbol is loaded at runtime, it's what relocations table are for, technically you can do at least part of the job of the linker at runtime as well with relocation information, and you could change the location of any symbol at runtime, or replace the address of any symbol to anything
normally, at least with some options, any memory access in a binary file either for jmp/calls or access to any symbol should have an entry in the relocation table, in sort that you can relocate the whole executable to any place you want
the elf format can be rather tricky with relocation, it's why i made the choice to rather use my internal binary object format, at least for the most critical module that can be hard to debug, like this i know what to expect from it, and i don't depend on compilation/linking options or fancy format that elf can support, because there are several way relocation can be handled
elf can support the use of GOT table, which is table that contain an ofset used to compute the actual symbol address at runtime, and the loader is supposed to fill/edit the got table at runtime, the whole system look rather complex to handle, but i didn't met any elf that make use of the got table, i think it's only used if gcc is used with 'position independant code' (-fpic) related flags
-fpic
Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. Such code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC; it is part of the operating system). If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no such limit.)
Position-independent code requires special support, and therefore works only on certain machines. For the 386, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always position-independent.
R_386_NONE 0 none none
R_386_32 1 word32 S + A
R_386_PC32 2 word32 S + A - P
R_386_GOT32 3 word32 G + A - P
R_386_PLT32 4 word32 L + A - P
R_386_COPY 5 none none
R_386_GLOB_DAT 6 word32 S
R_386_JMP_SLOT 7 word32 S
R_386_RELATIVE 8 word32 B + A
R_386_GOTOFF 9 word32 S + A - GOT
R_386_GOTPC 10 word32 GOT + A - P
the only relocation i encoutered for now are R_386_32/R_386_PC32 and R_386_RELATIVE , the two first are similar except the second one is relative to the address of the code using the address, it is a relative relocation, the first is absolute relocation and the address is to be replaced with the absolute address of the symbol, with the second type, the address must be replaced with the absolute address of the symbol minus the location at which the relocation take place, the address stored is relative to the instruction, like for relative call/jmps, the last one is not supposed to be related to symbol reference, but rather must point at specific location relative to the place the object was loaded , not sure what they are exactly used for, but there are a few of them in most elf images
the others (R_386_GOT32,R_386_PLT32,R_386_GLOB_DAT,R_386_JMP_SLOT,R_386_GOTOFF,R_386_GOTPC) are related to the got, i don't handle at all the got/plt related things, but again there are many way elf objects can be linked, and many options that can impact what you should be doing when loading an elf file, which is again why i prefer to use my own binary object file, and even editing name mangling for exported symbol to have a cross plateform way to do dynamic linking that is independant of the compiler/linker, and i can debug all the elf parsing involved to make up my own binary format from visual studio or gcc,if you want to load elf file directly, you should make sure they are compiled/linked in a way that fit what you expect, because elf format allow for lot of possibility regarding how the image is organised and how you should load it, specially if it's compiled with position independant code, you have to set up the value in the GOT
normally i think to have 'true relocatable shared object', one should compile with gcc '-fPIC' and use the got table, but even without using the GOT the regular relocation table already contain all the infos you need to relocate the whole image and any reference to any symbol anywhere you want, it just make it more tricky to handle as all relocation address must be translated from virtual address space in order to find the address it has within the memory area the section has be loaded in, or something simpler could probably be done like just compute the ofset between the actual base image, and the virtual address at which the base image should be loaded, and just adding this ofset to the relocation, but it will probably not work if the relative address from a section to another change and that there are cross section relocation