X.86 X64汇编程序

时间:2018-06-01 03:53:49

标签: assembly stack x86-64

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

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

从C调用汇编程序函数。反过来,汇编程序调用C函数。

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

以下代码演示了:

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字节区域允许做什么!是给我还是保留。但是没有这个,我的代码甚至都没有运行!!!

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

中间代码我在调用名为MemRead8_s的C函数(由我提供)之前保存/推送ax寄存器。但是,当我调用该函数时,现在存储在堆栈中的ax的值被覆盖了,所以当我尝试将其恢复一些指令后,它就错了!这个调用之前和之后的rsp值看起来是一样的,所以调用这个函数对堆栈做了什么呢?

任何人都可以了解正确的堆栈设置协议是什么,并可能解释为什么我的堆栈保存会被破坏?

1 个答案:

答案 0 :(得分:1)

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

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

在Linux和其他非Windows上,x86-64 System V ABI表示您的功能比当前RSP(红色区域)低128个字节。显然push或函数调用将踩到该空间,因此它在叶函数中最常用,以避免RSP的子/添加。但是不受信号处理程序的破坏是安全的。

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

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