【问题标题】:How can I get the _GLOBAL_OFFSET_TABLE_ address in my program?如何在我的程序中获取 _GLOBAL_OFFSET_TABLE_ 地址?
【发布时间】:2012-03-13 15:11:15
【问题描述】:

我想在我的程序中获取 _GLOBAL_OFFSET_TABLE_ 的地址。一种方法是在 Linux 中使用 nm 命令,可能会将输出重定向到文件并解析该文件以获取 _GLOBAL_OFFSET_TABLE_ 的地址。但是,这种方法似乎效率很低。有哪些更有效的方法?

【问题讨论】:

    标签: c linux gcc x86-64


    【解决方案1】:

    这似乎有效:

    // test.c
    #include <stdio.h>
    
    extern void *_GLOBAL_OFFSET_TABLE_;
    
    int main()
    {
        printf("_GLOBAL_OFFSET_TABLE = %p\n", &_GLOBAL_OFFSET_TABLE_);
        return 0;
    }
    

    为了获得_GLOBAL_OFFSET_TABLE_ 的一致地址,匹配nm 的结果,您需要使用-fPIE 编译您的代码以进行代码生成,就像链接到与位置无关的可执行文件一样。 (否则你会得到一个像0x2ed6-fno-pie -no-pie 这样的小整数)。大多数现代 Linux 发行版的 GCC 默认值为 -fPIE -pie,这将使 nm 地址只是相对于映像库的偏移量,并且运行时地址是 ASLRed。 (这通常有利于安全,但您可能不想要它。)

    $: gcc -fPIE -no-pie test.c -o test
    

    它给出:

    $ ./test
    _GLOBAL_OFFSET_TABLE = 0x6006d0
    

    但是,nm 的想法不同:

    $ nm test | fgrep GLOBAL
    0000000000600868 d _GLOBAL_OFFSET_TABLE_
    

    或者如果 GCC 太老了,根本不知道 PIE,更不用说将 -fPIE -pie 作为默认值,-fpic 可以工作。

    【讨论】:

    • @MetallicPriest 也许你可以告诉为什么nm给出不同的值?
    • 好的,等我检查了再告诉你:)。
    • 这段代码肯定不对。您正在打印 GOT 的第一个条目,它可能是指向 DYNAMIC 的指针,而不是 GOT 的地址。要打印 GOT 的地址,您应该使用 &amp;_GLOBAL_OFFSET_TABLE_
    • @trojanfoe 只需将 & 符号添加为 R.. 所示,我相信这会解决它。
    • @ZeZNiQ 感谢您对这个旧答案的编辑,但通常(在现代 Linux 上)-fPIE -pie 已经是默认设置,所以我想我应该调整一些。我可以用-fno-pie -no-pie 确认奇怪之处,比如打印出0x2ed6 用于64 位模式,或者0x2e76 用于-m32。我不完全理解,所以你能看看我的编辑,确保我没有破坏你提出的任何重要观点吗?
    【解决方案2】:

    如果你使用汇编语言,你可以得到_GLOBAL_OFFSET_TABLE_地址而不用get_pc_thunk
    这是一种棘手的方式。 :)


    这是示例代码:

    $ cat test.s
    
    .global main
    main:
     lea HEREIS, %eax   # Now %eax holds address of _GLOBAL_OFFSET_TABLE_      
    
    .section .got
    HEREIS:
    
    $ gcc -o test test.s
    

    这是可用的,因为.got 部分与&lt;.got.plt&gt; 相邻
    因此符号HEREIS_GLOBAL_OFFSET_TABLE_ 位于同一地址。


    PS。您可以使用 objdump 检查它是否有效。

    Disassembly of section .got:
    
    080495e8 <HEREIS-0x4>:
     80495e8:   00 00                   add    %al,(%eax)
        ...
    
    Disassembly of section .got.plt:
    
    080495ec <_GLOBAL_OFFSET_TABLE_>:
     80495ec:   00 95 04 08 00 00       add    %dl,0x804(%ebp)
     80495f2:   00 00                   add    %al,(%eax)
     80495f4:   00 00                   add    %al,(%eax)
    

    【讨论】:

    • 问题标记为 x86-64,因此您可以使用 RIP 相对寻址,例如 lea HEREIS(%rip), %rsi / ... / 调用 printf@plt。或者只是_GLOBAL_OFFSET_TABLE_(%rip)。但是,如果您打算使用 32 位绝对地址,则始终首选 mov $HEREIS, %eax。 LEA 对静态地址没有意义,除了 RIP-relative。 (更大的代码大小可以用 [disp32] 寻址模式做同样的事情)
    猜你喜欢
    • 2021-01-10
    • 2023-04-09
    • 2015-08-05
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多