ubuntu - 汇编通过堆栈传递变量

标签 ubuntu assembly nasm

因此,在为了好玩而涉足了一些组装之后,我现在陷入了调用程序的困境。

...
_start:
    push dword len
    push dword msg

    call print

    mov eax, SYS_EXIT
    mov ebx, 0
    int 80h

print: ; *char (message), int (len) -> push len, then message
    mov eax, SYS_WRITE
    mov ebx, STDOUT
    pop ecx
    pop edx
    int 80h
    ret

当我运行这个程序集时
nasm -f elf program.asm && ld -m elf_i386 -o program program.o && ./program

它打印出程序的所有内容然后出现段错误,而如果我用打印功能的内容替换“调用打印”,它工作正常。

最佳答案

下面的代码是您应该编写它的方式:

_start:
    push dword len
    push dword msg
    call print
    add esp, 8 ; equivalent to 2 32-bit POP instructions
               ; (effectively "undoes" the above PUSH instructions
               ;  to restore the stack to its original state)

    mov eax, SYS_EXIT
    mov ebx, 0
    int 80h

print: ; *char (message), int (len) -> push len, then message
    mov eax, SYS_WRITE
    mov ebx, STDOUT
    mov ecx, [esp+4]  ; load "msg" from stack using an offset from ESP
    mov edx, [esp+8]  ; load "length" from stack using an offset from ESP
    int 80h
    ret

问题是堆栈没有指向它应该指向的位置。您必须记住堆栈的后进先出性质,还要考虑 callret指令影响堆栈指针。当你call一个函数,返回地址被压入堆栈,所以当你执行 pop print 内部, 你实际上是从堆栈中弹出返回值,这不仅给你错误的值,而且还会破坏你的能力 ret稍后瓮。

检索传递给堆栈上函数的参数的正确方法是通过堆栈指针的偏移量(ESP)。第一个参数位于 ESP + 4 (在 call 压入堆栈的 4 字节返回地址之后)。有关其他信息,您可以查找 C 代码常用的 STDCALL 和 CDECL 调用约定。

关于ubuntu - 汇编通过堆栈传递变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43568252/

相关文章:

shell - 使用带有 url 参数的 headless chrome

assembly - 尝试在 asm 中重新编码 memmove

assembly - 为什么我们在16位实模式下只能访问1MB?

assembly - 什么时候需要在汇编中指定操作数的大小?

linux - 如何在 linux 下用 nasm 和 gcc 编译这个 asm 代码?

assembly - 32 位寄存器中非零字符的高效 UTF-8 字符长度解码

ubuntu - 如何向在 docker 上运行的服务器发出请求

c++ - Qt qbs 项目设置与库未找到编译错误

excel - 高效地从 .xlsx 电子表格中提取工作表名称

python - 如何在c或python中将数字的高8位移动7次?