2016-06-07 2 views
-1

Я только начинаю с программирования fasm/x86, и я начал с 64-битных образцов в качестве моей цели для моего проекта, в котором мне понадобится сборка - 64 бит Xeons.push/pop eax дает мне «незаконную инструкцию» во время компиляции

Я начал с PE64DEMO и модифицировал его, чтобы добавить цикл, однако после первой итерации он завершился неудачно (из того, что я мог бы собирать в Интернете), функции api Windows могут изменять регистры и не восстанавливать их. Я также читал, что должен сохранить то, что мне нужно, чтобы выталкивать и выталкивать из стека, я прокомментировал push и pop, если я раскомментирую их, я получаю ошибку времени компиляции с сообщением «Ошибка: незаконная инструкция 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 Я бы не сказал, что это дубликат (это полезно для кого-то другого, ищущего сумасшествие и незаконное обучение с помощью pop или push, googling ничего не дает). Однако похоже, что это может быть одно и то же решение, я проверю его и вернусь сюда. –

+0

В 64-битном режиме вы действительно можете только нажимать и записывать 64-битные регистры, поэтому это должны быть «push rax» и «pop rax», не 'eax'. –

ответ

1

Были множественные проблемы с моим кодом.

Начнем с того, как Rudy Velthuis прокомментировал мой код был незаконно и по праву отвергнут FASM, push eax и pop eax никогда не действует в X64, как EAX является 32-битный регистр и X64 не позволяет толкая 32-битные значения в стек. Переключение на 64-битный регистр исправил эту проблему.

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

При том, что теперь он компилирует и позволяет мне сохранить свой регистр accross вызова однако Теперь код ошибки сегментации внутри Windows API. Как отметил Майкл Пётч, это связано с тем, что, как только я нажимаю на стек, я нарушаю ранее выполненное выравнивание, а Windows 64 требует, чтобы стек был равен 16 байтам, однако вместо того, чтобы фиксировать выравнивание, решение проще использовать нелетучий регистр среди те, которые описаны в ABI Windows X64, и отказаться от использования стека для этой операции.

Окончательный код с изменениями:

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' вашего вызывающего абонента. Поскольку вам это не нужно, лучше не тратить время на инструкции, но эта инструкция заслуживает комментария, говоря, почему это безопасно в этом случае. –

Смежные вопросы