X.86 X64 汇编器中正确的堆栈操作 [英] Correct Stack Manipulation in X.86 X64 assembler

查看:40
本文介绍了X.86 X64 汇编器中正确的堆栈操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,在阅读了 x64 架构快速入门指南后,我编写了一些汇编程序.

So having read the x64 architecture quick start guide I wrote some assembler.

https://software.intel.com/en-us/articles/introduction-to-x64-assembly

汇编器函数是从 C 调用的.反过来汇编器调用 C 函数.

The assembler function is called from C. In turn the assembler calls C functions.

我不确定堆栈机制是如何工作的,因为我似乎多次破坏堆栈.

I am unsure as to how the stack mechanics work as I seem to be corrupting the stack on several occasions.

以下代码演示:

PUBLIC Lbra_R_A ; Op 16 - Long Branch Always
Lbra_R_A PROC
    sub rsp, 28h
    push rbx ; must preserve rbx
    ; Calc destination branch address by Adding the two Bytes at [PC+1] (high byte) and [PC+2] (low byte) with PC+2 reg
    ; Get first byte high byte
    movzx rcx, word ptr [pc_s]
    mov rbx, rcx ; save pc_s into temp
    inc bx ; inc temp pc_s
    call MemRead8_s ; returns byte in ax (al)
    push ax ; save high byte
    ; Get second byte low byte @ pc_s
    mov rcx, rbx
    inc bx ; inc temp pc_s
    call MemRead8_s ; returns byte in ax (al) - this call destroys saved high byte???
    ; combine low and high bytes to make 16 bit 2 complements offset
    pop dx ; get saved high byte - wrong value
    mov ah, dl ; move the high byte to high position ; ax now contains 16 bit offset
    add bx, ax ; bx now contains pc_s(+2) + offset
    mov word ptr [pc_s], bx
    pop rbx ; must restore rbx - wrong value???
    add rsp, 28h
    ret
Lbra_R_A ENDP

我使用 sub rsp, 28h 设置堆栈,但我不知道为什么,我也不知道我可以在那个 28h 字节区域中做什么!!!是给我的还是保留的.但是没有这个我的代码甚至无法运行!!!

I setup the stack with sub rsp, 28h but I'm not sure why and I have no idea what I am allowed to do in that 28h byte area!!! Is it for me or is it reserved. However without this my code doesn't even run!!!

接下来我保留 rbx 寄存器,因为它被认为是非易失性的.但是最后当我恢复 rbx 时,它与我保存的不一样???

Next I preserve the rbx register because it is considered non volatile. However at the end when I restore rbx it isn't the same as what I saved???

中间代码我在调用名为 MemRead8_s 的 C 函数(由我提供)之前保存/推送 ax 寄存器.然而,当我调用该函数时,现在存储在堆栈中的 ax 值被覆盖,所以当我尝试在几条指令之后恢复它时,它是错误的!!!这个调用前后的 rsp 值好像是一样的,那么调用这个函数对栈有什么影响?

Mid code I save/push the ax register before calling a C function called MemRead8_s (supplied by me). However the moment I call that function the value of ax now stored on the stack is over written so when i attempt to restore it a few instruction later it is wrong!!! The rsp value before and after this call seems to be the same so what did calling this function do to the stack?

谁能解释一下正确的堆栈设置协议是什么,并可能解释为什么我的堆栈保存被破坏了?

Can anyone shed some light on what the correct stack setup protocol is and possibly explain why my stack saves are getting corrupted?

推荐答案

你的函数拥有低于 RSP 初始值(在函数入口)和高于 RSP 当前值的堆栈空间.

Your function owns the stack space below the initial value of RSP (on function entry) and above the current value of RSP.

在 Windows 上,您的函数还拥有返回地址(影子空间)上方的 32 个字节.确保在调用另一个函数之前保留这个空间,除非它是一个不使用影子空间的私有帮助函数.

On Windows, your function also own 32 bytes above the return address (the shadow space). Make sure to reserve this space before calling another function, unless it's a private helper function that doesn't use the shadow space.

在 Linux 和其他非 Windows 上,x86-64 System V ABI 表示您的函数拥有比当前 RSP(红色区域)低 128 个字节.显然 push 或函数调用会踩到那个空间,所以它在叶函数中最有用,以避免 RSP 的 sub/add.但它不会被信号处理程序破坏.

On Linux and other non-Windows, the x86-64 System V ABI says your function owns 128 bytes below the current RSP (the red zone). Obviously push or function calls will step on that space, so it's mostly useful in leaf functions to avoid the sub/add of RSP. But it is safe from being clobbered by signal handlers.

所以 sub rsp, 28h 分配了 0x28 字节的堆栈空间(并将堆栈对齐 16 字节,因为它在 call 在你的调用者中推送了一个返回地址.(你用 16 位(2 字节)推送打破了这种对齐,这很糟糕.ret 基本上是 pop rip,这就是为什么您必须在运行 ret 之前将堆栈恢复到其原始值.

So sub rsp, 28h allocates 0x28 bytes of stack space (and aligns the stack by 16 bytes, because it was 16-byte aligned before call in your caller pushed a return address. (You break that alignment with a 16-bit (2-byte) push, this is bad). ret is basically pop rip, which is why you have to restoring the stack to its original value before you can run ret.

不要使用 16 位推送/弹出;保存/恢复完整的 64 位寄存器.MemRead8_s 允许假设 RSP 在为其推送返回地址的调用之前是 16 字节对齐的,你很幸运,它碰巧不依赖堆栈对齐.)

Don't use 16-bit push/pop; save/restore the full 64-bit register. MemRead8_s is allowed to assume that RSP was 16-byte aligned before the call that pushed a return address for it, you got lucky that it happens not to rely on stack alignment.)

这篇关于X.86 X64 汇编器中正确的堆栈操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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