2016-06-07 4 views
-1

저는 fasm/x86 프로그래밍으로 시작했고 64 비트 샘플을 프로젝트의 타겟으로 시작했는데 일부 어셈블리는 64 비트입니다. 제온.push/pop eax는 컴파일 타임에 "불법 명령어"를 제공합니다

PE64DEMO에서 시작하여 루프를 추가하기 위해 수정했지만 Windows API 함수가 레지스터를 변경하고 복원하지 못하도록 첫 번째 반복 이후에 실패합니다. 나는 또한 내가 pushing하고 스택에서 poping 할 필요가있는 것을 읽어야한다. push와 pop에 주석을 달았다면, "Error : 불법적 인 명령 pop 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

가능한 중복 [푸시 및 AMD64에 팝업] (http://stackoverflow.com/questions/5050186/push-and-pop-on-amd64) – Ari0nhh

+0

@ Ari0nhh 나는 그것이 중복이라고 말하지 않을 것이다 (이것은 다른 사람이 팝이나 푸시와 관련된 불경기와 불법적 인 지시를 찾는 데 유용하며, 인터넷 검색으로는 아무것도 산출하지 못했다). 그러나 그것은 똑같은 해결책이 될 것 같은데, 나는 그것을 시험해보고 다시 올 것이다. –

+0

64 비트에서 64 비트 레지스터를 밀어 넣을 수 있기 때문에 push rax와 pop rax이어야한다. 'eax'가 아닙니다. –

답변

1

내 코드에 여러 문제가 있었다. EAX는 32 비트 레지스터이고, X64는 스택에 32 개 비트 값을 밀어 허용하지 않는 루디 Velthuis 내 코드를 주석으로 시작하려면

불법이고 정당 FASM에 의해 거부, push eaxpop eax는 X64에서 유효 적이 없습니다. 64 비트 레지스터로 전환하면이 문제가 해결되었습니다.

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

이제는 컴파일되어서 내 등록 정보를 유지할 수 있지만 코드는 이제 Windows API 내부에서 분류됩니다. Michael Petch가 언급했듯이 스택에 푸시하면 이전에 수행 된 정렬을 중단하고 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'를 clobbering하는 대신'rbx'를 저장/복원해야합니다. 그렇게 할 필요가 없으므로 지침을 낭비하지 않는 것이 좋지만이 지침은 왜이 경우 안전한지에 대한 설명이 필요합니다. –

관련 문제