【问题标题】:How to pass functions parameters in a register with gcc asm keyword如何使用 gcc asm 关键字在寄存器中传递函数参数
【发布时间】:2013-02-19 01:24:36
【问题描述】:

在 gcc 中,您可以使用以下语法声明应将局部变量放入寄存器中。

register int arg asm("eax");

在我在互联网上找到的一些旧代码中,此语法用于声明函数的参数应在寄存器中传递:

void foo(register int arg asm("eax"))

但是当我尝试这个例子时:

/*
   Program to demonstrate usage of asm keyword to allocate register for a variable.
*/
#include <stdio.h>

/* Function with argument passed in register */
void foo(register int arg asm("eax") )
{
    register int loc asm("ebx");
    loc = arg;
    printf("foo() local var: %d\n", loc);
}

int main(void)
{
    foo(42);
    return 0;
}

然后用 gcc 编译我得到一个错误:

gcc main.c -o test-asm.exe
main.c:7:27: error: expected ';', ',' or ')' before 'asm'

现在我的问题是:
上面的 asm 语法是否正确,在 gcc 中,即对于函数的形式参数?
gcc 曾经支持过这个吗?
如果这不是正确的语法,那么如何实现呢?

谢谢,
//jk

【问题讨论】:

    标签: c gcc assembly parameter-passing calling-convention


    【解决方案1】:

    我知道的唯一方法是使用 fastcall 属性:

    (GCC 手册第 6.30 节)http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html#Function-Attributes

    快速调用

    在 Intel 386 上,fastcall 属性使编译器在寄存器 ECX 中传递第一个参数(如果是整数类型),然后 寄存器 EDX 中的第二个参数(如果是整数类型)。 随后的和其他类型的参数在堆栈上传递。这 被调用的函数会将参数从堆栈中弹出。如果数 arguments 是可变的,所有参数都被压入堆栈。

    在以下示例代码中使用它:

    __attribute__((fastcall,noinline)) int add (int a, int b)
    {
      return a + b;
    }
    
    int main () {
      return add (1, 2);
    }
    

    将导致:

        .file   "main.c"
        .text
    .globl add
        .type   add, @function
    add:
        pushl   %ebp
        movl    %esp, %ebp
        leal    (%edx,%ecx), %eax
        popl    %ebp
        ret
        .size   add, .-add
    .globl main
        .type   main, @function
    main:
        pushl   %ebp
        movl    %esp, %ebp
        movl    $2, %edx
        movl    $1, %ecx
        call    add
        popl    %ebp
        ret
        .size   main, .-main
    

    别忘了在其他翻译单元的任何声明中提到 fastcall 属性,否则可能会发生相当奇怪的事情。

    【讨论】:

    • 感谢您的建议。但我认为 gcc 可能支持或曾经支持更通用的语法。
    • 哇,生成的函数有一半以上是无用的序言/尾声废话真是太难看了……是-O0还是……?
    • 不 - 使用 -O0 会变得更有趣,因为无论出于何种原因,通过 ecx 和 edx 传递的参数都会首先存储在堆栈中。这是(没有开玩笑的)gcc 对 -O0 的作用:add: pushl %ebp movl %esp, %ebp subl $8, %esp movl %ecx, -4(%ebp) movl %edx, -8(%ebp) movl -8(%ebp), %eax movl -4(%ebp), %edx leal (%edx,%eax), %eax leave ret
    • 还有gcc -mregparm=3,或者作为每个函数的属性。
    猜你喜欢
    • 2014-08-19
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 2010-11-01
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多