問題
我目前正在閱讀這本書以及關于動態鏈接的章節,其中包含以下代碼:
link_example.s
.globl main
.section .data
output:
.ascii "Yeet\n\0"
.section .text
main:
enter $0, $0
movq stdout, %rdi
movq $output, %rsi
call fprintf
movq $0, %rax
leave
ret
現在根據書,我需要編譯如下動態鏈接C庫:
gcc -rdynamic link_example.s -o link_example
但我收到以下錯誤訊息:
/usr/bin/ld: /tmp/cchUlvqS.o: relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
我究竟做錯了什么?
你試過什么?
添加-fPIE標志
-fPIE我通過添加標志嘗試了編譯器的建議:
gcc -rdynamic -fPIE link_example.s -o link_example
但我仍然再次遇到同樣的錯誤。
搜索類似帖子
我發現一個類似的帖子說,我只需要使用-shared標志:
gcc -shared link_example.s -o link_example
但這給了我:
/usr/bin/ld: /tmp/ccxktZan.o: relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
如果我添加-fPIC標志:
gcc -shared -fPIC link_example.s -o link_example
然后我得到這個:
/usr/bin/ld: /tmp/ccKIQ9sl.o: relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
uj5u.com熱心網友回復:
讓我向您展示如何修復您書中的匯編語言,使其與您的編譯器的默認設定一起使用。
正如對問題的評論所說,問題在于您的編譯器默認生成與位置無關的可執行檔案。這意味著 、 和 的地址stdout在fprintf鏈接output時是未知的,因此聯結器無法“重新定位”參考它們的指令。
然而,在鏈接時已知的是這些東西的地址與程式計數器之間的偏移量。這意味著,如果您只是稍微不同地撰寫程式集,它就會起作用。像這樣:
.globl main
.section .data
output:
.ascii "Yeet\n\0"
.section .text
main:
enter $0, $0
movq stdout(%rip), %rdi
leaq output(%rip), %rsi
call fprintf@PLT
movq $0, %rax
leave
ret
請注意,這三者的變化略有不同。mov stdout, %rdi變成mov stdout(%rip), %rdi——只是同一條指令的不同尋址模式。從固定地址的記憶體加載變成從 RIP 暫存器(也稱為程式計數器)stdout的固定位移的記憶體加載。 另一方面,用stdout加載固定地址 變成。我建議您將此視為始終是加載有效地址的操作,但是可執行檔案位于固定地址的舊代碼能夠使用立即移動而不是實際的 lea 指令來表達該操作。最后,變成。這告訴聯結器呼叫需要通過outputmov $output, %rsilea output(%rip), %rsicall fprintfcall fprintf@PLT程序鏈接表——你的書應該解釋這是什么以及為什么需要它。
順便說一句,我發現這種匯編語言還有其他幾個問題,其中最重要的是:
- 該字串
"Yeet\n\0"屬于只讀資料部分。 - x86-64 ABI 表示,
fprintf需要通過適當設定來告知可變引數函式它們接收的浮點引數的數量eax。 enter并且leave在 x86-64 上是不必要的。(此外,enter這是一個非常緩慢的微編碼指令,根本不應該使用。)
我會寫這樣的東西:
.section .rodata, "a", @progbits
.output:
.string "Yeet\n"
.section .text, "ax", @progbits
.globl main
.type main, @function
main:
sub $8, %rsp
mov stdout(%rip), %rdi
lea .output(%rip), %rsi
xor
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/445118.html
