访问位置无关代码中的 .data 部分

Gui*_*TeK 3 linux assembly x86-64 nasm elf

我正在用 NASM 构建一个共享库。在那个库中,在某些函数中,我需要我们称之为C 中的静态变量。基本上,我认为它是 .data 部分中的一些空间:

    SECTION .data
last_tok:       dq 0 ; Define a QWORD
Run Code Online (Sandbox Code Playgroud)

当我尝试在我的函数中访问 last_tok时出现问题。

我阅读了NASM 手册:8.2 编写 Linux/ELF 共享库,其中解释了问题并提供了解决方案。

    SECTION .data
last_tok:              dq 0     ; Define a QWORD

    SECTION .text
    EXTERN _GLOBAL_OFFSET_TABLE_
    GLOBAL strtok:function
strtok:
    enter    0, 0
    push     rbx
    call     .get_GOT
.get_GOT:
    pop      rbx
    add      rbx, _GLOBAL_OFFSET_TABLE_ + $$ - .get_GOT wrt ..gotpc

    mov      [rbx + last_tok wrt ..gotoff], rdi ; Store the contents of RDI at last_tok

    mov      rbx, [rbp - 8]
    leave
    ret
Run Code Online (Sandbox Code Playgroud)

它可能适用于 ELF32,但使用 ELF64 时出现以下错误:

nasm -f elf64  -o strtok.o strtok.s
strtok:15: error: ELF64 requires ..gotoff references to be qword
<builtin>: recipe for target 'strtok.o' failed
make: *** [strtok.o] Error 1
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Jes*_*ter 6

有效地址格式仅允许符号扩展为 64 位的 32 位位移。根据错误消息,您需要完整的 64 位。您可以通过寄存器添加它,例如:

mov      rax,  last_tok wrt ..gotoff
mov      [rbx + rax], rdi 
Run Code Online (Sandbox Code Playgroud)

此外,这call .get_GOT是一个 32 位解决方案,在 64 位模式下,您可以在那里使用 rip 相对寻址。虽然上面可以编译,但我不确定它会起作用。幸运的是,简单的解决方案是使用提到的 rip 相对寻址来访问您的变量,因此:

    SECTION .data
    GLOBAL last_tok
last_tok:              dq 0     ; Define a QWORD

    SECTION .text
    GLOBAL strtok:function
strtok:
    mov      rcx, [rel last_tok wrt ..gotpc]    ; load the address from the GOT
    mov      rax, [rcx]                         ; load the old dq value from there
    ; and/or
    mov      [rcx], rdi                         ; store arg at that address
    ret
Run Code Online (Sandbox Code Playgroud)

请注意,对于私有(静态)变量,您可以直接使用,[rel last_tok]而不必弄乱 got 。

在 PIE 可执行文件中,编译器使用(相当于)[rel symbol]访问全局变量,前提是主可执行文件不需要或不希望为自己的符号插入符号。

(符号插入,或在其他共享库中定义的符号,是从 x86-64 上的 GOT 加载符号地址的唯一原因。但mov rdx, [rel stdin]在 PIE 可执行文件中,即使是类似的东西也是安全的:https : //godbolt.org/z/eTf87e - 链接器在可执行文件中创建变量的定义,因此它在 RIP 相对寻址的范围内和链接时间常数偏移量处。)