Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable GOT in GCC

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

like image 298
amaneureka Avatar asked Jun 19 '16 00:06

amaneureka


2 Answers

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");
            }
        }
    }
like image 125
amaneureka Avatar answered Sep 23 '22 21:09

amaneureka


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.

like image 20
Uprooted Avatar answered Sep 23 '22 21:09

Uprooted