The University of Queensland Homepage
School of ITEE ITEE Main Website

 Some Notes on ELF Binary File Format

Global Offset Table

The exact mechanism of the Global Offset Table is not clear from the ELF documentation. The purpose of the GOT is to define a place where position independent code can access global data. There is an ELF section named .got, but it can be all zeroes apart from perhaps the first entry. Special relocation types, such as the Sparc R_SPARC_GLOB_DAT actually set the values of the GOT to the address of particular symbols. Thus, the GOT can actually be set up as part of the relocation process.

Various instructions reference the global offset table, possibly with the aid of other relocation types such as R_SPARC_GOT22 (but I have not seen these). Here is an example of Sparc code, from the second function in libelf.so.1:

_elf_armem:
00002A4C:  9DE3BFA0     save %sp, -96, %sp
00002A50:  40000002     call 0x00002a58          ; PC -> %o7
00002A54:  2F000066     sethi %hi(0x19800), %l7	 ; Set %l7 to...
...
00002A5C:  AE15E07C     or %l7, 0x7C, %l7        ; 0x1987C
00002A60:  AE05C00F     add %l7, %o7, %l7        ; Base+0x1C2CC->%l7
...
00002A74:  D605E138     ld [%l7+312], %o3        ; Ref the GOT
Note that the gcc linker just initialises the GOT. (Use either -fpic or -fPIC to generate Position Independent Code). For example, consider this simple function:
extern char* name;
 
void func2()
{
        printf("Me too! <%s>\n", name);
}

The format string as well as the external global will have to be made position independent. Here is the resultant object (.o) code, using gcc -fpic:
00000000:  9DE3BF90     save %sp, -112, %sp
00000004:  40000002     call 0x0000000c
00000008:  01000000     nop
0000000C:  2F000000     sethi %hi(0x0), %l7
00000010:  AE15E000     or %l7, 0, %l7        ; See below
00000014:  AE05C00F     add %l7, %o7, %l7     ; %l7 now points to GOT
00000018:  D205E000     ld [%l7+0], %o1       ; Some GOT entry (format str)
0000001C:  D405E000     ld [%l7+0], %o2       ; Another GOT entry (name)
00000020:  9010000A     mov %o2, %o0          ; first arg (format string)
00000024:  D2024000     ld [%o1], %o1 	      ; name
00000028:  40000000     call 0x00000028       ; printf
0000002C:  01000000     nop
00000030:  81C7E008     ret
00000034:  81E80000     restore
The instructions at offsets 0C, 10, 18, and 1C have relocation entries:
        Relocation Section Table .rela.text
        Address = 0000000C
                Info = 00000911 Addend = 00000008
                Sym = 9 Type = R_SPARC_PC22
        Address = 00000010
                Info = 00000910 Addend = 0000000C
                Sym = 9 Type = R_SPARC_PC10
        Address = 00000018
                Info = 0000080E Addend = 00000000
                Sym = 8 Type = R_SPARC_GOT13
        Address = 0000001C
                Info = 0000020E Addend = 00000000
                Sym = 2 Type = R_SPARC_GOT13
The first two are complex relocations that have the effect of setting %l7 to be the address of symbol 9 (_GLOBAL_OFFSET_TABLE) relative to the instruction at offset 4. Note how gcc has not even allocated any offsets in the GOT; in fact, the object file does not even have a .got section at all! The GOT is created by the link editor, and all offsets within it are managed by the GOT. Presumably, the Sun compiler uses different relocation types which result in the different GOT organisation, or more likely, the Sun linker chooses to initialise the GOT differently.