You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用PIE时如何正确构建.rodata字符串表?

在x86-64 NASM汇编的.rodata段中构建兼容PIE的只读字符串表

我在编程练习平台用x86-64 NASM汇编编写代码,希望将字符串表放在.rodata只读段中,但遇到了与PIE(位置无关可执行文件)机制相关的编译错误。将字符串表移至.data段时代码可正常编译,但我想了解如何在.rodata段中正确实现只读字符串表。

原.rodata段代码片段:

section .rodata
align 8, db 0
table:
    dq .Leucine         ; UUA
    dq .Phenylalanine   ; UUC
    dq .Phenylalanine   ; UUU
    dq .Leucine         ; UUG
    dq 0                ; UGA
    dq .Cysteine        ; UGC
    dq .Cysteine        ; UGU
    dq .Tryptophan      ; UGG

.Leucine:
    db "Leucine", 0
.Phenylalanine:
    db "Phenylalanine", 0
.Cysteine:
    db "Cysteine", 0
.Tryptophan:
    db "Tryptophan", 0

提交时收到的错误信息:

/usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: protein_translation.o: warning: relocation in read-only section `.rodata'
/usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make: *** [Makefile:32: tests] Error 1

我知道在可执行代码中可以使用RIP相对寻址(如lea rsi, [rel .Leucine]),想了解字符串表如何实现类似效果。


问题原因

PIE模式下,程序的加载地址是动态分配的,.rodata段中直接用dq .Leucine这种绝对地址引用会产生TEXTREL(文本段重定位)——链接器需要在运行时修改只读段中的绝对地址,这违背了只读段的设计初衷,也会触发错误。

解决方案:用相对偏移量替代绝对地址

核心思路是:在.rodata中存储字符串相对于表起始位置的偏移量(编译时可确定的常量),然后在代码中通过RIP相对寻址获取表的动态基地址,再加上偏移量得到字符串的实际地址。

1. 修改.rodata段的字符串表

section .rodata
align 8, db 0
table:
    dq .Leucine - table         ; 存储相对于table的偏移量
    dq .Phenylalanine - table
    dq .Phenylalanine - table
    dq .Leucine - table
    dq 0                        ; UGA 对应空指针
    dq .Cysteine - table
    dq .Cysteine - table
    dq .Tryptophan - table

.Leucine:
    db "Leucine", 0
.Phenylalanine:
    db "Phenylalanine", 0
.Cysteine:
    db "Cysteine", 0
.Tryptophan:
    db "Tryptophan", 0

2. 在代码中访问字符串

通过RIP相对寻址获取table的基地址,再加上偏移量计算出字符串地址:

; 示例:获取table中第0项对应的字符串地址
lea rbx, [rel table]       ; 用RIP相对寻址拿到table的动态基地址
mov rax, [rbx]             ; 取出对应的偏移量
add rax, rbx               ; 基地址 + 偏移量 = 字符串实际地址
; 此时rax中存储的就是.Leucine的有效地址

这种方式完全兼容PIE机制:偏移量是编译时确定的常量,可安全存放在只读段中;代码通过RIP相对寻址处理动态加载地址,无需修改只读段,也就不会产生TEXTREL错误。


内容的提问来源于stack exchange,提问作者Venusaur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 23:58:18