12

Global Offset Table (GOT): Is used for relocation of ELF symbols (implemented GCC), It helps in sharing of same binary without any specific linking for each process. Thus reduces copies of same binary image in the memory.

My question is, is there any way to disable R_386_GOT32,R_386_GOTOFF type relocation entries in relocatable ELF image? I mean, can I force GCC to use R_386_PC32 or R_386_32 type relocation instead of GOT type relocation?

If not, could you explain the way of implementing GOT? I am writing a dynamic linking and loading library for ELF.

Edit:
Reference Links
https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-74186.html
http://man7.org/linux/man-pages/man8/ld.so.8.html
http://wiki.osdev.org/ELF

sorush-r
  • 10,490
  • 17
  • 89
  • 173
amaneureka
  • 1,150
  • 11
  • 26
  • 1
    This is a valid question. However, if you're writing your own dynamic linker, you should better read the whole ELF specification and implement proper GOT relocation. – 3442 Jun 19 '16 at 00:57
  • @KemyLand I agree, But for now I want to make a limited implementation because of time constraint. – amaneureka Jun 19 '16 at 05:28
  • Neat, this is exactly what I need for my toy OS – minexew Apr 09 '17 at 09:24
  • 1
    @minexew I made it open source. You can look at full source code for ELF loading from here https://github.com/amaneureka/AtomOS/blob/master/src/Kernel/Atomix.Kernel_H/Exec/ELF.cs – amaneureka Apr 09 '17 at 10:08

3 Answers3

7

Finally I cracked it!
No, It is not possible to restrict GCC to output with non-GOT type relocation.
Now how to resolve GOT type relocation?
GOT is of fixed 128KB memory chunk (It works on principle of copy on write) allocated by dynamic linker which contains entries for relocation.
Dynamic Linker allocates GOT only if any type of (listed below) GOT relocation exist in ELF binary.

R_386_GOTOFF (== 0x9)
This relocation type computes the difference between a symbol's value and the address of the global offset table. It also instructs the link-editor to create the global offset table.

R_386_GOTPC (== 0xA)
This relocation type resembles R_386_PC32, except it uses the address of the global offset table in its calculation.

How to implement them?
Note: Following code-snippet belongs to Atom OS source code which protected by closed source license. But I (Atom Developer) hereby declare this code snippet free to use :)

    uint GOT = Heap.kmalloc(1024 * 128); // 128 KB
    ...
    private static void Relocate(Elf_Header* aHeader, Elf_Shdr* aShdr, uint GOT)
    {
        uint BaseAddress = (uint)aHeader;
        Elf32_Rel* Reloc = (Elf32_Rel*)aShdr->sh_addr;
        Elf_Shdr* TargetSection = (Elf_Shdr*)(BaseAddress + aHeader->e_shoff) + aShdr->sh_info;

        uint RelocCount = aShdr->sh_size / aShdr->sh_entsize;

        uint SymIdx, SymVal, RelocType;
        for (int i = 0; i < RelocCount; i++, Reloc++)
        {
            SymVal = 0;
            SymIdx = (Reloc->r_info >> 8);
            RelocType = Reloc->r_info & 0xFF;

            if (SymIdx != SHN_UNDEF)
            {
                if (RelocType == R_386_GOTPC)
                    SymVal = GOT;
                else
                    SymVal = GetSymValue(aHeader, TargetSection->sh_link, SymIdx);
            }

            uint* add_ref = (uint*)(TargetSection->sh_addr + Reloc->r_offset);
            switch(RelocType)
            {
                case R_386_32:
                    *add_ref = SymVal + *add_ref; // S + A
                    break;
                case R_386_GOTOFF:
                    *add_ref = SymVal + *add_ref - GOT; // S + A - GOT
                    break;
                case R_386_PLT32:   // L + A - P
                case R_386_PC32:    // S + A - P
                case R_386_GOTPC:   // GOT + A - P
                    *add_ref = SymVal + *add_ref - (uint)add_ref;
                    break;
                default:
                    throw new Exception("[ELF]: Unsupported Relocation type");
            }
        }
    }
amaneureka
  • 1,150
  • 11
  • 26
2

gcc -fno-plt -fno-pic will limit relocation types to R_386_PC32 and R_386_32 (or at least it worked in my case). Accepted answer is misleading in claiming it's not possible.

Uprooted
  • 941
  • 8
  • 21
0

You can try to use gcc option: -fPIE or -fpie which could disable the GOT.