使用GCC修复与位置无关的可执行文件中的全局变量的重定位

时间:2017-12-16 14:26:15

标签: gcc relocation position-independent-code

我正在寻找gcc命令行标记或其他设置,以便为我的静态链接,与位置无关的i386可执行文件生成GOTOFF重定位而不是GOT重定位。关于我在下面尝试的更多细节。

我的源文件g1.s如下所示:

extern int answer;
int get_answer1() { return answer; }

我的其他源文件g2.s如下所示:

extern int answer;
int get_answer2() { return answer; }

我使用gcc -m32 -fPIE -Os -static -S -ffreestanding -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables g1.c为i386编译它们。

我得到以下程序集输出:

    .file   "g1.c"
    .text
    .globl  get_answer1
    .type   get_answer1, @function
get_answer1:
    call    __x86.get_pc_thunk.cx
    addl    $_GLOBAL_OFFSET_TABLE_, %ecx
    movl    answer@GOT(%ecx), %eax
    movl    (%eax), %eax
    ret
    .size   get_answer1, .-get_answer1
    .section        .text.__x86.get_pc_thunk.cx,"axG",@progbits,__x86.get_pc_thunk.cx,comdat
    .globl  __x86.get_pc_thunk.cx
    .hidden __x86.get_pc_thunk.cx
    .type   __x86.get_pc_thunk.cx, @function
__x86.get_pc_thunk.cx:
    movl    (%esp), %ecx
    ret
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
    .section        .note.GNU-stack,"",@progbits

以下是使用GCC 7.2在线重现此行为的方法:https://godbolt.org/g/XXkxJh

而不是上面的GOT,我想要GOTOFF,而movl %(eax), %eax应该会消失,所以函数的汇编代码应如下所示:

get_answer1:
    call    __x86.get_pc_thunk.cx
    addl    $_GLOBAL_OFFSET_TABLE_, %ecx
    movl    answer@GOTOFF(%ecx), %eax
    ret

我已经确认此GOTOFF程序集版本有效,而GOT版本不起作用(因为它有一个额外的指针间接)。

如何说服gcc生成GOTOFF版本?我尝试过-fPIC-fpic-fPIE-fpie-pie-fno-plt的各种组合。它们都没有奏效,所有这些都使gcc生成GOT版本。

我无法在https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html上找到任何特定于i386的标记或此处的任何通用标记:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

事实上,我正在为GOTOFF字符串文字进行"..."重定位,而且我还想为extern变量获取它们。

最终输出是自定义二进制格式的静态链接可执行文件(我已经编写了GNU ld链接器脚本)。没有动态链接,也没有共享库。地址随机化由自定义加载程序执行,自定义加载程序可以将可执行文件加载到任何地址。所以我确实需要与位置无关的代码。没有每段内存映射:整个可执行文件按原样连续加载。

我在网上找到的所有文档都谈到了与动态关联的位置无关的可执行文件,而且我无法在那里找到任何有用的文件。

1 个答案:

答案 0 :(得分:0)

我无法用gcc -fPIE来解决这个问题,所以我通过处理输出文件手动解决了这个问题。

我使用gcc -Wl,-q和包含重定位的输出ELF可执行文件。我对这个ELF可执行文件进行了后处理,并在开头添加了以下汇编指令:

call next
next:
pop ebx
add [ebx + R0 + (after_add - next)], ebx
add [ebx + R1 + (after_add - next)], ebx
add [ebx + R2 + (after_add - next)], ebx
...
after_add:

,其中R0,R1,R2 ...是ELF可执行文件中R_386_32重定位的地址。 In use objdump -O binary prog.elf prog.bin', and now prog.bin'包含与位置无关的代码,因为它以`add [ebx + ...],ebx'指令开头,它们在代码开始运行时对代码进行必要的重定位

根据执行环境,需要gcc标志-Wl,-N,以使.text部分可写(`add [ebx + ...],ebx'指令需要这一点)。