push/pop eax 给了我“非法指令"在编译时 [英] push / pop eax gives me "illegal instruction" at compile time

查看:26
本文介绍了push/pop eax 给了我“非法指令"在编译时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始使用 fasm/x86 编程,我从 64 位样本开始作为我项目的目标,在该项目中我需要一些汇编程序是 64 位至强.

I'm just starting with fasm / x86 programming and i started with the 64 bit samples as my target for my project in which i will need some assembly is 64 bit xeons.

我从 PE64DEMO 开始并对其进行了修改以添加一个循环,但是在第一次迭代后它失败了,因为(从我可以在线收集的信息)Windows api 函数可以更改寄存器而不是恢复它们.我还读到我应该保存我需要自己从堆栈中推送和弹出的内容,我评论了推送和弹出,如果我取消注释它们,我会收到一个编译时错误,指出错误:非法指令 pop eax".

I started from the PE64DEMO and modified it to add a loop, however it fails after the first iteration as (from what i could gather online) the Windows api functions can change registers and not restore them. I also read i'm supposed to save what i need myself pushing and poping from the stack, i commented the push and pop, if i uncomment them i get a compile time error stating "Error : illegal instruction 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'

推荐答案

我的代码存在多个问题.

There were multiple issues with my code.

首先,Rudy Velthuis 评论说我的代码是非法的并且被 fasm 理所当然地拒绝了,push eaxpop eax 在 X64 中永远不会有效,因为 eax 是 32 位寄存器和 X64 不允许将 32 位值推送到堆栈.切换到 64 位寄存器修复了这个问题.

To start with as Rudy Velthuis commented my code was illegal and rightfully rejected by fasm, push eax and pop eax are never valid in X64 as eax is a 32 bit register and X64 doesn't allow pushing 32 bit values to the stack. Switching to a 64 bit register fixed this issue.

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

有了它,它现在可以编译并允许我在调用中保留我的寄存器,但是代码现在在 Windows API 中出现段错误.正如 Michael Petch 提到的,这是因为一旦我推送到堆栈,我就会破坏之前完成的对齐方式,并且 Windows 64 要求堆栈对齐 16 个字节,但是解决方案不是修复对齐方式,而是简单地在其中使用非易失性寄存器那些在 Windows X64 ABI 中描述的,并放弃使用堆栈进行此操作.

With that it now compiles and allows me to preserve my register accross the call however the code now segfaults inside the Windows API. As Michael Petch mentioned this is because once i push to the stack i break the alignment that was previously done and Windows 64 requires the stack to be 16 bytes alligned, however instead of fixing the alignment the solution is simplpy to use a non volatile register among those described in the Windows X64 ABI and discard the use of the stack for this operation.

修改后的最终代码:

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'

这篇关于push/pop eax 给了我“非法指令"在编译时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆