Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does libgcc use global offset table?

Tags:

c

I'm trying to build gcc 4.6 for i386-elf target.

My problem is as follows. When compiling libgcc I get the output-file _fixunsdfdi.o which make use of the global offset table.

The function is used when converting 'double' to 'unsigned long long'. When i look at the assembly it looks like its the Wtype_MAXp1_F, that is placed in the GOT - but why?

I configured with

--target=i386-elf  --enable-languages=c --disable-nls --disable-libssp --disable-libquadmath --enable-shared=no  --enable-static=yes


//Code for fixunsdfdi (from libgcc2.c)
#if defined(L_fixunsdfdi) && LIBGCC2_HAS_DF_MODE
UDWtype __fixunsdfDI (DFtype a)
{
/* Get high part of result.  The division here will just moves the radix
 point and will not cause any rounding.  Then the conversion to integral
 type chops result as desired.  */
const UWtype hi = a / Wtype_MAXp1_F;

/* Get low part of result.  Convert `hi' to floating type and scale it back,
 then subtract this from the number being converted.  This leaves the low
 part.  Convert that to integral type.  */
const UWtype lo = a - (DFtype) hi * Wtype_MAXp1_F;

/* Assemble result from the two parts.  */
return ((UDWtype) hi << W_TYPE_SIZE) | lo;
}
#endif


//Dump of the output
Class:                             32-bit
Data:                              Little Endian
Header version:                    1[Current Version]
OS/ABI:                            0[UNIX System V ABI]
Type:                              1[REL (Relocatable file)]
Machine:                           0003h[Intel Architecture EM_386]
File version:                      1[Current Version]
Entry point address:               00000000h
Start of program headers:          0 (bytes into file)
Start of section headers:          35496 (bytes into file)
Flags:                             0
Size of this header:               52 (bytes)
Size of program headers:           0 (bytes)
Number of program headers:         0
Size of section headers:           40 (bytes)
Number of section headers:         15
Section header string table index: 12

[file offset:00008AA8h]Section Headers:
[Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
[0]                    NULL            00000000 000000 000000 00     0  0   0
[1]  .text             PROGBITS        00000000 000034 000067 00 AX  0  0   4
[2]  .rel.text         REL             00000000 008E18 000018 08     13 1   4
[3]  .data             PROGBITS        00000000 00009C 000000 00 WA  0  0   4
[4]  .bss              NOBITS          00000000 00009C 000000 00 WA  0  0   4
[5]  .stab             PROGBITS        00000000 00009C 0004D4 0C     7  0   4
[6]  .rel.stab         REL             00000000 008E30 000030 08     13 5   4
[7]  .stabstr          STRTAB          00000000 000570 00844A 00     0  0   1
[8]  .rodata.cst4      PROGBITS        00000000 0089BC 000008 04 A   0  0   4
[9]  .comment          PROGBITS        00000000 0089C4 000028 01     0  0   1
[10] .eh_frame         PROGBITS        00000000 0089EC 000054 00 A   0  0   4
[11] .rel.eh_frame     REL             00000000 008E60 000008 08     13 10  4
[12] .shstrtab         STRTAB          00000000 008A40 000067 00     0  0   1
[13] .symtab           SYMTAB          00000000 008D00 0000E0 10     14 12  4
[14] .strtab           STRTAB          00000000 008DE0 000038 00     0  0   1

[file offset:00008E18h]Relocation section '.rel.text' contains 3 entries:
Type: REL
   Num:   Offset     Info    Type            Sym.Value Addend   To->Sym. Name
0:       0000000E  00000D0A R_386_GOTPC      00000000  00000003 _GLOBAL_OFFSET_TABLE_
1:       0000001A  00000709 R_386_GOTOFF     00000000  00000000 .LC0
2:       0000004A  00000809 R_386_GOTOFF     00000004  00000000 .LC1

[file offset:00008E30h]Relocation section '.rel.stab' contains 6 entries:
Type: REL
Num:   Offset     Info    Type            Sym.Value Addend   To->Sym. Name
0:       00000014  00000201 R_386_32         00000000  00000000 .text
1:       00000020  00000201 R_386_32         00000000  00000000 .text
2:       00000434  00000C01 R_386_32         00000000  00000000 __fixunsdfdi
3:       0000044C  00000201 R_386_32         00000000  00000000 .text
4:       000004C4  00000201 R_386_32         00000000  00000067 .text
5:       000004D0  00000201 R_386_32         00000000  00000067 .text

[file offset:00008E60h]Relocation section '.rel.eh_frame' contains 1 entries:
Type: REL
Num:   Offset     Info    Type            Sym.Value Addend   To->Sym. Name
0:       00000020  00000202 R_386_PC32       00000000  00000000 .text

[file offset:00008D00h]Symbol table '.symtab' contains 14 entries:
Num[h]:    Value  Size Type    Bind   Vis      Ndx Name
000000: 00000000 0000  NOTYPE  LOCAL           UND 
000001: 00000000 0000  FILE    LOCAL           ABS libgcc2.c
000002: 00000000 0000  SECTION LOCAL           1   .text
000003: 00000000 0000  SECTION LOCAL           3   .data
000004: 00000000 0000  SECTION LOCAL           4   .bss
000005: 00000000 0000  SECTION LOCAL           8   .rodata.cst4
000006: 00000000 0000  SECTION LOCAL           10  .eh_frame
000007: 00000000 0000  NOTYPE  LOCAL           8   .LC0
000008: 00000004 0000  NOTYPE  LOCAL           8   .LC1
000009: 00000000 0000  SECTION LOCAL           5   .stab
00000A: 00000000 0000  SECTION LOCAL           7   .stabstr
00000B: 00000000 0000  SECTION LOCAL           9   .comment
00000C: 00000000 0067  FUNC    GLOBAL          1   __fixunsdfdi
00000D: 00000000 0000  NOTYPE  GLOBAL          UND _GLOBAL_OFFSET_TABLE_

I would prefer not to create the global offset table as I has no need for it elsewhere, and it is currently not supported in the linker in the project im working on.

Q1: Why does it use symbols in the global offset table?

Q2: Is there anyway to avoid using global offset table? Any help out there?

like image 466
Skriver Avatar asked Nov 19 '13 10:11

Skriver


1 Answers

Ok, I am not sure if I understood completely, but here it goes...

Q1: Why does it use symbols in the global offset table (GOT)?

GOT is used because by the way compiler, linker and loader works, it is impossible to tell where each object will end up in memory at runtime. The compiler proper step sees one module at a time, so it cannot tell from where each (external) function and global var will be referred. Instead, for each one it creates a symbol to be resolved at link time. For static functions/variables, it generates code that access those directly (it is platform dependent: in Linux/x86_64 is uses an offset from the program counter). For externals, it generates indirect access code through a runtime data structure: GOT.

At link time, you can tell which modules call what symbols, so it is the linker job to make sure that all symbols (either those in your program or in its external dependencies) are resolved, meaning they are defined elsewhere in the multiple modules that compose your program. For objects defined in your own code (or linked statically) it is possible to tell its location inside your binary (ELF/COFF/PE/etc), but you do not know where are they going to be in memory until load time. Linker also writes into the binary what are the required shared libraries and (optionally) their likely location at runtime.

When you run your program, the loader! will try to find all dependencies (shared libs), and then as part of process start up will build GOT structure. It will load your program code from binary's text section into memory and for each symbol it will create an entry in the GOT with the actual memory address where to find it. Then it will do the same for each shared library. It is also worth noting that some libraries may keep internal offset tables independent of GOT. This way you can have the same symbol defined multiple times. This is by example what happens with Window SxS! (Microsoft's answer to DLL hell problem).

From the point of view of your program, each access to external symbol requires 2 memory accesses (indirect). If the symbol represents a function, there is another structure PLT, that is a jump table with GOTO instructions to each place.

Q2: Is there anyway to avoid using global offset table? Any help out there?

Yes, the easiest way is to figure out what functions/globals you do not need access outside the module they are defined and declare those as static. In this way, compiler will know that it can generate direct access code to find them (offset from program counter is the way it is done in Linux/x86_64, but it is platform dependent).

I have read that in large projects there is a specialized build teams that identify tightly coupled sets of modules and integrate them in a single big C file in order to minimize the number of exposed symbols into the general product, but I have never seen it first hand.

There are also linker options that help you avoid exposing symbols, but for what I know they are just syntactic sugar. The GOT and PLT is still being used, just you make its contents opaque.

A great resource for this subject is Ulrich Drepper's How to Write Shared Libraries!

like image 151
Carlos Patiño Avatar answered Nov 12 '22 04:11

Carlos Patiño