到目前為止,我一直在 Linux 上用 GAS 語法撰寫匯編代碼,所以我想試試它在 Windows 上的表現。第一個目標是將單個字符列印到標準輸出上 - 這不起作用
這是我的代碼:
.intel_syntax noprefix
.extern GetStdHandle
.extern GetLastError
.extern WriteFile
.extern ExitProcess
.section .rodata
.Lchar: .ascii "F"
.section .data
.Lbytes_written: .long 0
.section .text
.global main
main:
mov rcx, -11 //-11 = stdout
call GetStdHandle
mov rcx, rax
lea rdx, [rip .Lchar]
mov r8, 1
lea r9, [rip .Lbytes_written]
push 0
call WriteFile
call GetLastError //After this call, rax=0x6
xor rcx, rcx
call ExitProcess
使用(我使用 mingw64)編譯后gcc -g -o example.exe ./example.S,沒有列印任何內容。使用除錯器單步執行代碼時,我注意到 GetStdHandle 沒有失敗(在回傳 0 后直接呼叫 GetLastError),但 WriteFile 失敗并回傳 0x6,即 ERROR_INVALID_HANDLE。
所以我的問題是:這可能是什么問題?這個問題對某些人來說可能很愚蠢,所以我提前道歉。謝謝!
編輯:這比我想象的更奇怪。拿這兩個代碼塊
.section .rodata
.Lchar: .ascii "F"
.section .data
.Lbytes_written: .long 0
.section .text
.global main
main:
sub rsp, 8
mov rcx, -11
call GetStdHandle
mov rcx, rax
lea rdx, [rip .Lchar]
mov r8, 1
lea r9, [rip .Lbytes_written]
push 0
push 0
call WriteFile
call GetLastError
add rsp, 16
add rsp, 8
ret
.section .rodata
.Lchar: .ascii "F"
.section .data
.Lbytes_written: .long 0
.section .text
.global main
main:
sub rsp, 24
mov rcx, -11
call GetStdHandle
mov rcx, rax
lea rdx, [rip .Lchar]
mov r8, 1
lea r9, [rip .Lbytes_written]
push 0
push 0
call WriteFile
call GetLastError
add rsp, 16
add rsp, 24
ret
The only difference is that the second code block allocates 16B more on the Stack, which shouldn't be a problem, as all calls are still 16B-aligned. Yet for the second code block, the call to WriteFile does not work. Funnily enough, both function calls to GetStdHandle succeed and return the same value (which is 84 in my case) What could be the source of that?
uj5u.com熱心網友回復:
我的代碼的主要問題是我違反了 Windows 的 ABI,其中包括
- 在函式呼叫之前沒有正確對齊堆疊
- 未在堆疊中添加 32B 填充(陰影空間),這意味著錯誤地提供了第 5 個引數
這是此代碼的作業版本:
.intel_syntax noprefix
.extern GetStdHandle
.extern GetLastError
.extern WriteFile
.section .rodata
.Lchar: .ascii "F"
.section .data
.Lbytes_written: .long 0 # surprisingly just needs to be a dword, not qword in win64
.section .text
.global main
main:
sub rsp, 40 # allocate shadow space re-align the stack to RSP == 0
mov rcx, -11 # Magic number for stdout
call GetStdHandle
mov rcx, rax # hFile = return value
lea rdx, [rip .Lchar] # lpBuffer
mov r8, 1 # 1 byte to write
lea r9, [rip .Lbytes_written] # output arg pointer
mov QWORD PTR [rsp 32], 0 # lpOverlapped=NULL in the stack space that was padding for the first call
call WriteFile
add rsp, 40
ret
感謝 Peter Cordes、Joshua 和 RbMm 在這方面的幫助!
uj5u.com熱心網友回復:
main:
sub rsp, 8
mov rcx, -11
call GetStdHandle
記憶在這一刻被破壞了。堆疊中的前四個插槽(32 位元組)需要空閑。正確的線似乎是
sub rsp, 40
繼續前進:
call WriteFile
call GetLastError
這里的錯誤。檢查rax錯誤代碼。如果沒有錯誤,GetLastError則回傳先前的錯誤,無論它是什么。
如果某些東西看起來很瘋狂,請進一步檢查代碼。據我可以通過嘗試使這些東西正常作業來確定,Windows 在某些地方會反匯編您的代碼,如果堆疊未對齊,未到達的代碼仍然會崩潰。我有一個案例,崩潰是由于不注釋代碼和無條件跳轉的注釋代碼之間的差異造成的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/415420.html
標籤:
上一篇:COBOL是否將一行的前6個字符強制為數字,因為它更容易編譯為二進制可執行檔案?
下一篇:如何在匯編x86中使用變數
