我正在瀏覽exercism.org 上的 x86-64 教程。我在 Linux 上使用 NASM,生成 ELF 二進制檔案。只有一小段 C 代碼可以在測驗工具中呼叫我的匯編代碼。他們的構建系統-pie在 LDFLAGS 和-fPIECFLAGS 中指定(除其他外,但我認為這些是最相關的)。因此,我需要(并且想了解)一個使用 PIC 的解決方案,它需要 RIP 相對尋址。
我有一個索引 (in rdi) 到一個 8 位元組 (qword) 值陣列中,稱為values. 我只想獲取偏移量處的地址,以便將mov它指向的值放入暫存器。或者我會mov直接接受這個值。
我試過這個:
lea rbx, [rel values rdi * 8]
我的理解是,這將查看該部分中的地址(相對于)rip,然后將添加正確的偏移量()并將其放入。valuesdatardi * 8rbx
但這會產生下一個錯誤:
/usr/bin/ld: space_age.o: relocation R_X86_64_32S against `.data' can not be used when making a PIE object; recompile with -fPIE
我知道這recompile with -fPIE是聯結器認為代碼是編譯而不是從手寫程式集中組裝的結果。所以看起來 NASM 正在產生一種重定位型別,它與它所鏈接的內容不一致,并且聯結器認為它不是 PIE,對吧?
所以我然后嘗試了這個:
lea rbx, [rdi * 8] ; first compute the offset: index * sizeof(qword value)
lea r8, [rel values] ; then find the address of the values
add rbx, r8 ; rbx = offset of the array address of base of the array
對我來說,這與第一條指令完全相同。我不明白這些有何不同,但關于第一個重定位的事實R_X86_64_32S似乎表明第一條指令只有一個帶符號的 32 位偏移量,并且可能lea r8, [rel values]會創建一個不同的 64 位重定位型別,但我我只是在那里猜測。
這可以在一條指令中完成嗎?
編輯:這不是這個關于尋址模式的問題的重復,因為它沒有解釋為什么 NASM 接受我的代碼但它無法鏈接。多虧了公認的答案,我現在明白了這種尋址模式不存在,但 NASM 默默地忽略了這一rel部分。
uj5u.com熱心網友回復:
沒有這樣的指令lea rbx, [rel values rdi * 8],或者換句話說lea rbx, [values rip rdi * 8]。rip-relative 尋址模式不能與變址暫存器組合(有或沒有縮放)。請參閱參考記憶體位置的內容。(x86 尋址模式)
不幸的是,看起來 nasm 只是通過忽略rel和 assemble來處理這個lea rbx, [values rdi * 8]問題,這需要有問題的重定位。的地址values必須放在指令記憶體運算元的 32 位位移欄位中,但這是不可能的,因為values不需要位于最低或最高 2 GB 記憶體中;因此令人困惑的錯誤訊息。
但正確的解決方案是你只需要寫更多的指令。您可以通過兩條指令獲得所需的效果
lea rbx, [rel values]
lea rbx, [rbx rdi * 8]
或者,如果您想實際執行負載:
lea rbx, [rel values]
mov rcx, [rbx rdi * 8]
(暫存器的選擇是任意的。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/459712.html
