【问题标题】:Passing parameters when compile C and nasm编译 C 和 nasm 时传递参数
【发布时间】:2014-06-26 03:53:52
【问题描述】:

在 Mac OS X 上编译 C 和 nasm 时,我发现它在传递参数和进行系统调用时与 Linux 不同。我的代码有效,但我真的很困惑。
我在 nasm 中编写了一个函数 myprint 来打印从 C 传递的字符串。

这里是C代码main.c

#include <stdio.h>

void myprint(char* msg, int len);

int main(void){
     myprint("hello\n",6);
     return 0;
}

这是 nasm 代码myprint.asm

section .text

global _myprint

_syscall:
    int 0x80
    ret

_myprint:
    push dword [esp+8]    ;after push, esp-4
    push dword [esp+8]
    push dword 1
    mov eax,4
    call _syscall
    add esp,12
    ret

编译并链接它们:

nasm -f macho -o myprint.o myprint.asm
gcc -m32 -o main main.c myprint.o

它正确打印“你好”。

如您所见,OS X(FreeBSD) 使用 push 将参数传递给 sys 调用,但参数 char*int 已经被压入堆栈,它们的地址是 esp+4esp+8。但是,我必须从堆栈中读取它们并将它们再次推入堆栈以使其工作。
如果我删除

push dword [esp+8]    ;after push, esp-4
push dword [esp+8]

它会打印很多错误代码和Bus error: 10,像这样:

???]?̀?j????????
               ?hello
`44?4
     __mh_execute_headerm"ain1yprint6???;??
                                           <??
                                              (
                                               libSystem.B?
                                                           `%?. _syscall__mh_execute_header_main_myprintdyld_stub_binder ??z0&?z?&?z?&?z۽??۽????N?R?N?o?N???N??N?e?N?h?N?0?zR?N???N???t??N?N???N?????@?`@b?`?`?a@c aaU??]N?zBus error: 10

为什么需要再次将参数压入堆栈?如何在不再次推送的情况下将堆栈中的这些参数传递给系统调用?

【问题讨论】:

  • 你怎么知道这是因为操作系统而不是因为不同的处理器或编译器?您使用的是同一台计算机和相同的编译器吗?
  • Linux 使用寄存器将参数传递给系统调用。它不同于 Mac OS X(FreeBSD)。

标签: c macos assembly nasm


【解决方案1】:

即使是普通的 C 函数调用,这也是正常的。问题是返回地址仍然在参数之前的堆栈上。如果您不再次将它们推送到返回地址下方,那么您将在参数之前的堆栈上有 2 个返回地址(第一个到 main,第二个到 myprint)但系统调用只需要 1。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-13
    • 2010-09-21
    • 2016-02-23
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多