【问题标题】:Access .data section in Position Independent Code访问位置无关代码中的 .data 部分
【发布时间】:2016-07-13 09:37:16
【问题描述】:

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

    SECTION .data
last_tok:       dq 0 ; Define a QWORD

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

我阅读了NASM Manual: 8.2 Writing Linux/ELF Shared Libraries,它解释了问题并给出了解决方案。

    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

它可能适用于 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

我做错了什么?

【问题讨论】:

    标签: linux assembly nasm x86-64 elf


    【解决方案1】:

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

    mov      rax,  last_tok wrt ..gotoff
    mov      [rbx + rax], rdi 
    

    另外,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
    

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

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

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

    【讨论】:

    • 谢谢!我不知道 64 位模式下的 RIP 相对寻址。它使事情比 32 位模式简单得多!另外,我刚刚在手册中读到,如果在文件顶部指定了“DEFAULT REL”,则甚至不需要“rel”前缀。
    • [rel last_tok wrt ..gotpc] 保存 GOT 条目 的地址。您需要类似 mov rax, [rel last_tok wrt ..gotpc] / mov [rax], rdi 的东西来从 GOT 加载该指针并取消引用它。如果您使用 [rel last_tok] 绕过 GOT(例如 static 变量或没有符号插入),则只能在 1 个存储指令中执行此操作。
    猜你喜欢
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多