linux - 访问位置独立代码中的 .data 部分

标签 linux assembly nasm x86-64 elf

我正在使用 NASM 构建一个共享库。在那个库中,在某些函数中,我需要我们在 C 中称之为 static 变量 的东西。基本上,我认为它是 .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

我做错了什么?

最佳答案

有效地址格式只允许 32 位位移,符号扩展到 64 位。根据错误消息,您需要完整的 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

请注意,对于私有(private)(静态)变量,您只需使用 [rel last_tok] 即可,而无需弄乱 got。

在 PIE 可执行文件中,编译器使用(等同于)[rel symbol] 来访问全局变量,假设主可执行文件不需要或不需要为其自身插入符号符号。

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

关于linux - 访问位置独立代码中的 .data 部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36223182/

相关文章:

cmake - 为什么 nasm 找不到来自 cmake 的包含语句

linux - NASM 为注册 bug 增加值(value)

node.js - 无法连接错误 - Linux 服务器上的 Node Express 应用程序

linux - 如何执行 x86 计算机的硬件重置?

linux - 设备的内存映射 IO 地址是否映射到进程的内核空间?

c - 遵循简单的内核教程时出现奇怪的链接器错误 gcc

linux - 为什么我无法成功将变量内容压入堆栈?

linux - 内核初始化期间崩溃(模块 insmod)

python - 为什么我不能跟踪我的日志?

php - Ubuntu Server 14.04 LAMP更改php目录