【问题标题】:How to pass variables to a external assembly function如何将变量传递给外部汇编函数
【发布时间】:2020-02-14 21:57:15
【问题描述】:

如何将变量从 C 程序传递到汇编函数。

例子:

main.c:

void main() {
  unsigned int passthis = 42
  extern asm_function();
  asm_function(passthis)
}

main.asm:

bits 32
global start
section .text
asm_function:
  ...

如何在asm_function 中访问passthis

编辑:可能应该提到我没有使用操作系统,我正在使用 i686-elf 交叉编译器进行编译,并将其用作内核。

【问题讨论】:

    标签: c assembly memory x86 calling-convention


    【解决方案1】:

    如果您使用默认的 GCC 选项(而不是像 Linux 内核使用的 -mregparm=3)将 C 编译成 32 位代码,那么在函数入口处,第一个参数位于返回地址上方的堆栈上(@987654322 @),但是在你 push 任何东西或移动 ESP 之后,偏移量会发生变化。

    您可以在设置传统堆栈指针后使用[ebp+8](即使 ESP 会在函数期间更改)。

    例如,int asm_function(int) 可以实现为:

    ;bits 32              ; unneeded, nasm -felf32 implies this.
    global asm_function   ; include asm_function in ELF .o symbol table for linking
    section .text
    asm_function:
        push ebp
        mov ebp, esp
        mov eax, [ebp+8]  ; return the first argument
        mov esp, ebp
        pop ebp
        ret
    

    对于之后的每个参数,只需简单地添加另一个4(即,对于第二个参数,使用[ebp+12])。如您所见,将 EBP 设置为帧指针会为小函数增加很多开销。

    一些非 ELF 系统/ABI 在 C 符号名称前加上前导下划线,因此您应该声明 asm_function_asm_function 以使您的代码在这些 ABI 中大致等效,如下所示:

    global _asm_function
    global asm_function  ; make both names of the function global
    section .text
    _asm_function:
    asm_function:        ; make both symbols point to the same place
        push ebp
        mov ebp, esp
        mov eax, [ebp+8]
        mov esp, ebp
        pop ebp
        ret
    

    【讨论】:

    • 这个操作系统是特定的吗?
    • @charliehogger31 据我所知,没有。
    • 第一个参数是@ESP+8,但更常见的约定是通过 EBP 寻址参数。 EBP+0 = 函数调用时EBP的值,EBP+4返回给调用者的地址。
    • 我建议反对在你的 NASM 源文件中包含 bits 32。这会让你意外地使用nasm -felf64 构建,然后将 32 位机器代码链接到 64 位二进制文​​件中。 (对于 GAS .s 文件来说这是一个更大的问题,它可以使用 gcc -c foo.s 构建,在普通系统上默认为 -m64,所以 .code32 是一个糟糕的主意。NASM 的默认值是 16 位平面二进制文件,所以你总是需要-f 选项除外。)
    【解决方案2】:

    x86 可能有一些不同的调用约定。这取决于很多因素,例如 windows 与 linux,以及您使用的编译器环境、32 位与 64 位等。

    最好查看您正在使用的编译器的输出,以了解参数是如何传递的,并采取相应的适当方式在程序集中接受参数。因此,如果它被压入堆栈,则期待它在那里,如果它被传入一个寄存器,期待它在那里......

    您可以使用反汇编程序或调试器查看输出。

    【讨论】:

    • 它可能不是 64 位 x86,正如 asm 代码中的 bits 32 所证明的那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多