【问题标题】:Disable GOT in GCC在 GCC 中禁用 GOT
【发布时间】:2023-03-30 18:40:01
【问题描述】:

全局偏移表 (GOT):用于 ELF 符号的重定位(实施 GCC),它有助于共享相同的二进制文件,而无需为每个进程进行任何特定链接。从而减少内存中相同二进制图像的副本。

我的问题是,有没有办法在可重定位的 ELF 映像中禁用 R_386_GOT32,R_386_GOTOFF 类型的重定位条目?我的意思是,我可以强制 GCC 使用 R_386_PC32R_386_32 类型重定位而不是 GOT 类型重定位吗?

如果没有,你能解释一下 GOT 的实现方式吗?我正在为 ELF 编写一个动态链接和加载库。

编辑:
参考链接
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

【问题讨论】:

  • 这是一个有效的问题。但是,如果您正在编写自己的动态链接器,则最好阅读整个 ELF 规范并实现正确的 GOT 重定位。
  • @KemyLand 我同意,但是由于时间限制,现在我想做一个有限的实现。
  • 整洁,这正是我的玩具操作系统所需要的
  • @minexew 我把它开源了。您可以从这里查看 ELF 加载的完整源代码 github.com/amaneureka/AtomOS/blob/master/src/Kernel/…

标签: gcc operating-system elf relocation


【解决方案1】:

我终于破解了!
不,不可能通过非 GOT 类型重定位来限制 GCC 输出。
现在如何解决 GOT 类型重定位?
GOT 是由动态链接器分配的固定 128KB 内存块(它的工作原理是写入时复制),其中包含用于重定位的条目。
仅当 ELF 二进制文件中存在任何类型的(如下所列)GOT 重定位时,动态链接器才会分配 GOT。

R_386_GOTOFF (== 0x9)
这种重定位类型计算符号值和全局偏移表地址之间的差异。它还指示链接编辑器创建全局偏移表。

R_386_GOTPC (== 0xA)
这种重定位类型类似于 R_386_PC32,不同之处在于它在计算中使用了全局偏移表的地址。

如何实现它们?
注意:以下 code-sn-p 属于 Atom OS 源代码,受闭源许可证保护。但我(Atom 开发人员)特此声明此代码 sn-p 可供免费使用:)

    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");
            }
        }
    }

【讨论】:

    【解决方案2】:

    gcc -fno-plt -fno-pic 会将重定位类型限制为 R_386_PC32 和 R_386_32(或者至少在我的情况下有效)。接受的答案声称不可能。

    【讨论】:

      【解决方案3】:

      您可以尝试使用 gcc 选项:-fPIE 或 -fpie 可以禁用 GOT。

      【讨论】:

      • 这将禁用所有类型的重定位。我最终会得到静态二进制文件,我无法将其移动到内存中的其他位置。
      • 是的。我的意思是我最终会得到不可重定位的二进制文件。
      猜你喜欢
      • 2010-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      相关资源
      最近更新 更多