【问题标题】:Can't pass parameter from C to Assembly code无法将参数从 C 传递到汇编代码
【发布时间】:2014-06-22 13:06:55
【问题描述】:

据我了解,当在 C 中的函数调用中传递参数时,被调用者可以在[ebp+8] 找到第一个参数。
通过eax 返回一个值对我有用,从堆栈中读取正确的参数值不起作用。

现在我只是在尝试编写一个汇编函数,它可以从 C 中调用并返回与传递相同的值。

当我运行以下程序时,它会将number: 1 打印到控制台,无论传递给myFunc 的值是什么。我做错了什么?


assembly.s

section .text
    global _myFunc

    _myFunc:
        mov eax, [ebp+8]
        ret

ma​​in.c

#include <stdio.h>

extern unsigned int myFunc(unsigned int somedata);

int main() {
    unsigned int i = myFunc(6);
    printf("number: %i\n",i);
    return 0;
}

我正在使用 Mac,nasm 来组装代码和 gcc 用于 C 编译。

生成文件

macho32:
    nasm -f macho32 assembly.s
    gcc -m32 -o macho32 assembly.o main.c

【问题讨论】:

  • 有点不合我意,但我认为您必须在汇编函数中使用push ebpmov ebp, esp 设置ebp,然后才能引用函数参数。然后您需要在返回之前pop ebp。见unixwiz.net/techtips/win32-callconv-asm.html

标签: c assembly nasm


【解决方案1】:

您需要先通过保存esp 来设置访问参数。解释如下:

http://www.nasm.us/doc/nasmdoc9.html

在“9.1.2 函数定义和函数调用”部分中

以下对我有用

程序集.s

section .text
    global myFunc:function

    myFunc:
    push ebp
    mov ebp, esp
    mov eax, [ebp+8]
    mov esp, ebp
    pop ebp
        ret

main.c

#include <stdio.h>

extern unsigned int myFunc(unsigned int somedata);

int main() {
    unsigned int i = myFunc(6);
    printf("number: %i\n",i);
    return 0;
}

汇编和编译

ericu@eric-phenom-linux:~$ nasm -f elf32 assembly.s 
ericu@eric-phenom-linux:~$ gcc -m32  assembly.o main.c
ericu@eric-phenom-linux:~$ ./a.out 
number: 6

我在一台 linux 机器上,所以我使用elf32。在您的 Mac 上使用 macho32 是正确的。

【讨论】:

  • mov esp, ebp 只是为了捕捉任何东西,它被推送了,但没有在我的汇编代码中弹出,对吧?否则 esp 无论如何都应该和以前一样在同一个位置。
  • 这样做是因为 ESP 下方的空间通常用于函数局部变量,并通过从 ESP 中减去所需空间量来保留 - 稍后,在函数结束时,ESP 恢复到以前的以这种方式重视
【解决方案2】:

您通过读取 [EBP+offset] 来引用堆栈上的参数 - EBP 是否已设置为实际指向堆栈?如果不是,您可能必须先这样做,通常通过以下方式完成:

push  ebp    
mov   ebp,esp

只有这样才能将 EBP 指向其堆叠的先前内容、堆叠的返回地址下方和传递的参数下方。

【讨论】:

  • 并且在return之前不要忘记pop ebp,不然我觉得leave可以作为替代。
  • 我认为这是由 C 编译器为我完成的。非常感谢。
【解决方案3】:

你的函数应该是这样的,

 _myFunc:

    push    ebp                    ; setup ebp as frame pointer
    mov     ebp, esp

    mov     eax, [ebp + 8] 

    leave                          ; mov esp,ebp / pop ebp

    ret

约定是使用 ebp 来访问参数,为此你需要将 ebp 保存在堆栈中并使其指向新的顶部堆。在函数退出时,您应该恢复 ebpesp,就像 leave 指令所做的那样。

nasm 中有一个宏包,c32.mak,可以帮助支持 C 调用约定,这些宏是 arg、procendproc。 使用这些宏,您的代码应该是这样的,

proc _myfunc
%$i arg

    mov     eax, [ebp + %$i]

endproc

【讨论】:

    猜你喜欢
    • 2016-10-01
    • 2021-07-18
    • 2017-07-01
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多