2016-06-07 26 views
-1

我剛剛開始使用fasm/x86編程,並開始使用64位樣本作爲我的項目目標,其中我需要一些程序集爲64位Xeon處理器。push/pop eax在編譯時給我「非法指令」

我從PE64DEMO開始並修改它以添加一個循環,但是它在第一次迭代後失敗(從我可以在線收集的內容),Windows API函數可以更改寄存器並且不會恢復它們。我也讀我應該保存我需要自己推動和從堆棧彈出,我評論推和彈出,如果我取消註釋他們我得到一個編譯時錯誤,指出「錯誤:非法指令彈出EAX」。

整個文件的代碼波紋管:

; Example of 64-bit PE program 

format PE64 GUI 
include 'win64a.inc' 
entry start 


section '.text' code readable executable 

    start: 
    sub  rsp,8*5   ; reserve stack for API use and make stack dqword aligned 



    ; Assembly code representing expr1 here (for instance mov [count], 0) 
    mov eax,10 
    .for_loop_check: 
    ; Assembly code representing expr2 that jumps to .exit_for_loop when false (for instance cmp [count], TOP_VALUE/jae .exit_for_loop when expr2 is "count < TOP_VALUE"). Note that if expr2 is absent then so is the jump. 

    cmp eax,0 
    jz .exit_for_loop 

    ;push eax 

    ; body code here 
    mov  r9d,0 
    lea  r8,[_caption] 
    lea  rdx,[_message] 
    mov  rcx,0 
    call [MessageBoxA] 

    ;pop eax 

    ; Assembly code representing expr3 here (for instance inc [count]) 
    dec eax 
    jmp .for_loop_check 

    .exit_for_loop: 

    mov  ecx,eax 
    call [ExitProcess] 

section '.data' data readable writeable 

    _caption db 'Win64 assembly program',0 
    _message db 'Hello World!',0 

section '.idata' import data readable writeable 

    library kernel32,'KERNEL32.DLL',\ 
     user32,'USER32.DLL' 

    include 'api\kernel32.inc' 
    include 'api\user32.inc' 
+2

的可能的複製[PUSH和POP上AMD64](http://stackoverflow.com/questions/5050186/push-and-pop-on-amd64) – Ari0nhh

+0

@ Ari0nhh我不會說這是重複的(這對於其他人搜索fasm和非法指令的流行或推送很有用,Google搜索沒有產生任何結果)。然而,它聽起來像可能是相同的解決方案,我會測試它並回到這裏 –

+0

在64位,你確實可以只推動和彈出64位寄存器,所以它應該是'推rax'和'pop rax',而不是'eax'。 –

回答

1

有我的代碼多個問題。

首先爲魯迪Velthuis評論我的代碼是非法的,由FASM理所當然地拒絕了,push eaxpop eax永遠是無效的X64爲EAX是一個32位寄存器和X64不允許推32個值到堆棧。切換到64位寄存器修復了這個問題。

;change 
push eax 
pop eax 
;to 
push rax; 
pop rax; 

由於它現在編譯並允許我保存我的註冊通過調用,但代碼現在在Windows API中segfaults。正如邁克爾佩奇提到的,這是因爲一旦我推入堆棧,我打破之前完成的對齊,並且Windows 64要求堆棧被分配16字節,但是不是固定對齊方式,而是簡化地使用非易失性寄存器在Windows X64 ABI中描述的那些,並放棄使用此操作的堆棧。

最終代碼變化在於:

format PE64 GUI 
include 'win64a.inc' 
entry start 

section '.text' code readable executable 

    start: 
     sub  rsp,8*5   ; reserve stack for API use and make stack dqword aligned 

     ;use rbx as counter as it is preserved across windows API calls 
     mov rbx,10 

     .for_loop_check: 

     cmp rbx,0 
     je .exit_for_loop 

     mov  r9d,0 
     lea  r8,[_caption] 
     lea  rdx,[_message] 
     mov  rcx,0 
     call [MessageBoxA] 

     ;no more pushing and poping to the stack required, rbx is guaranteed to be unmodified by the windows API 

     dec rbx 
     jmp .for_loop_check 

     .exit_for_loop: 

     mov  ecx,eax 
     call [ExitProcess] 

section '.data' data readable writeable 

    _caption db 'Win64 assembly program',0 
    _message db 'Hello World!',0 

section '.idata' import data readable writeable 

    library kernel32,'KERNEL32.DLL',\ 
      user32,'USER32.DLL' 

    include 'api\kernel32.inc' 
    include 'api\user32.inc' 
+0

請注意,如果您正在編寫返回的函數,而不是調用'ExitProcess',則需要保存/恢復'rbx'而不是僅僅調用您的調用者的'rbx'。既然你不需要,最好不要浪費指令這樣做,但是這條指令值得評論,說明爲什麼它在這種情況下是安全的。 –