我正在嘗試創建一個最小的 64 位 Windows 可執行檔案,以更好地了解 Windows 可執行檔案格式的作業原理。
我撰寫了非常基本的匯編和 C 代碼,如下所示。
他的
section .text
hi:
db "hi", 0
global sayHi
align 16
sayHi:
lea rax, [rel hi]
ret
開始.c
extern int puts();
extern const char *sayHi();
void start() {
puts(sayHi());
}
編譯,
nasm -fwin64 hi.s
gcc -c -ostart.obj -O3 -fno-optimize-sibling-calls start.c
# I will explain the flag
并與,
golink /fo r.exe /console start.obj hi.obj msvcrt.dll
# create a console application `r.exe`
# the default entry point is `start`
該程式運行良好并可以列印hi,但請注意gcc標志-fno-optimize-sibling-calls。該標志禁用尾呼叫優化,以便程式始終分配堆疊空間和callsa 函式。沒有標志,程式就會崩潰。
這是沒有尾呼叫優化的反匯編結果。不知道為什么gcc放在nop那里,但除此之外它非常簡單并且運行良好。
0000000000401000 <.text>:
401000: 48 83 ec 28 sub rsp,0x28
401004: e8 27 00 00 00 call 0x401030 # sayHi
401009: 48 89 c1 mov rcx,rax
40100c: e8 ff 2f 00 00 call 0x404010 # puts
401011: 90 nop
401012: 48 83 c4 28 add rsp,0x28
401016: c3 ret
...
401020: 68 69 00 90 90 push 0xffffffff90900069 # "hi"
...
401030: 48 8d 05 e9 ff ff ff lea rax,[rip 0xffffffffffffffe9] # 0x401020
401037: c3 ret
這是在啟用尾呼叫選項時,程式崩潰。
0000000000401000 <.text>:
401000: 48 83 ec 28 sub rsp,0x28
401004: e8 27 00 00 00 call 0x401030 # sayHi
401009: 48 89 c1 mov rcx,rax
40100c: 48 83 c4 28 add rsp,0x28
401010: e9 eb 2f 00 00 jmp 0x404000 # puts
...
401020: 68 69 00 90 90 push 0xffffffff90900069 # "hi"
...
401030: 48 8d 05 e9 ff ff ff lea rax,[rip 0xffffffffffffffe9] # 0x401020
401037: c3 ret
Now the program doesn't allocate stack space before puts and simply does a jmp instead of call.
I investigated further to see where exactly it jumps when calling puts.
In the no-tail-call case, the called address 0x404010 in the .idata section has the instruction jmp QWORD PTR [rip 0xffffffffffffffea] # 0x404000, and 0x404000 seems to contain the address to puts.
However in the tail-call case, the called address 0x404000 has 54 40 00 00 which is no meaningful instruction. The debugger says the program segfaults at 0x404003, so I'm pretty sure the program chokes trying to execute a garbage instruction.
I must be doing something wrong, but I'm not sure which, so could you explain why the tail-call case fails and how to get it work?
uj5u.com熱心網友回復:
問題在于golink沒有正確處理尾呼叫。我搜索了一段時間以使 GNUld將程式與提供給golink.
ld您可以使用此命令創建 GNU 的控制臺模式 Windows 可執行檔案。
ld -o... --subsystem=console object-files...
--subsystem console或者-subsystem=console也意味著相同。用于--subsystem=windows創建 GUI 應用程式。
GNUld也處理 Windowsdll檔案,因此在這種情況下,只需從系統檔案夾ld中提供一份副本即可。msvcrt.dll
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/424427.html
