x86程序集:通过堆栈将参数传递给函数

ser*_*ncu 7 x86 assembly cpu-registers x86-16

我正在尝试在程序集中创建一个子程序,它将在屏幕上绘制一个正方形.我不认为我可以像在C++中那样将参数传递给子程序,所以我想我可以使用堆栈来存储和访问参数(我不能使用公共数据寄存器,因为有太多变量到通过).

问题是(我记得在某处阅读)当我使用call命令到当前"程序"的地址时,它被保存在堆栈中,因此当它使用"ret"命令时它将知道返回的位置.但是,如果我存储在堆栈上的东西,然后调用函数,我必须保存在某个地方的地址(也就是在堆栈的顶部),然后安全地弹出的参数.然后在代码完成之后并且在调用"ret"之前,我将不得不推回地址.

我对吗?并且,如果是,我在哪里可以存储地址(我不认为地址只有1个字节长,因此它适合AX或BX或任何其他数据寄存器).我可以使用IP来执行此操作(虽然我知道这用于其他事情)?

这就是我的想象:

[BITS 16]
....
main:
  mov ax,100b
  push ax
  call rectangle ;??--pushes on the stack the current address?

jml $

rectangle:
  pop ax ;??--this is the addres of main right(where the call was made)?
  pop bx ;??--this is the real 100b, right?
  ....
  push ax
ret ;-uses the address saved in stack
Run Code Online (Sandbox Code Playgroud)

Mat*_*lia 11

通常,您使用基指针(bp在16位,ebp在32位上)来引用参数和本地.

基本思想是每次进入函数时都将堆栈指针保存在基本指针内部,以便在函数执行期间将函数作为"固定参考点"调用时使用堆栈指针.在这个模式中,[ebp-something]通常是本地的,[ebp+something]是一个参数.

转置典型的32位,被调用者清理调用约定,你可以这样做:

呼叫者:

push param1
push param2
call subroutine
Run Code Online (Sandbox Code Playgroud)

子程序:

push bp       ; save old base pointer
mov bp,sp     ; use the current stack pointer as new base pointer
; now the situation of the stack is
; bp+0 => old base pointer
; bp+2 => return address
; bp+4 => param2
; bp+6 => param1
mov ax,[bp+4] ; that's param2
mov bx,[bp+6] ; that's param1
; ... do your stuff, use the stack all you want,
; just make sure that by when we get here push/pop have balanced out
pop bp        ; restore old base pointer
ret 4         ; return, popping the extra 4 bytes of the arguments in the process
Run Code Online (Sandbox Code Playgroud)

  • 请注意,对于带有 caller-pops 的简单函数,OP 的想法实际上几乎不起作用。我添加了一个答案来指出这一点。当一个新手发现一种非标准的方式来做一些事实证明确实有效的事情时,这很有趣,即使它很糟糕。:P (2认同)