代码之家  ›  专栏  ›  技术社区  ›  jbcreix

返回寄存器中的结构-gcc中的arm abi

  •  4
  • jbcreix  · 技术社区  · 14 年前

    在ARMABI文档中,我遇到了定义如下的函数:

    __value_in_regs struct bar foo(int a, int b) {
        ...
    }
    

    但是海湾合作委员会( 4.3.3 )不允许,我只能找到一些 真实视图 编译程序。 海湾合作委员会有办法做到这一点吗?

    我试过-freg struct return,但没什么区别。因为它是一个ABI,所以我不能更改原始程序,返回一个常规结构会管理堆栈。

    如果可以避免的话,我宁愿不使用汇编,因为它在其他方面是不必要的。

    谢谢!

    4 回复  |  直到 9 年前
        1
  •  5
  •   Carl Norum    14 年前

    按请求作为答复发布:

    如果必须生成一个与编译器不支持的ABI一起工作的二进制文件,那么就有麻烦了。在C语言中你什么都做不了。在这种情况下,你需要回到汇编语言编程上,然后对必要的调用进行thunk。有两种可能性:

    1. 从二进制文件调用另一个二进制文件的ABI。
    2. 从另一个二进制文件调用二进制文件的ABI。

    这两个问题都得到了类似的解决。要从代码中调用,您需要使程序集中的填充函数围绕调用约定旋转以匹配外部ABI,然后从那里调用外部函数。与C代码不同的是,现在要进行外部调用,需要调用内部程序集例程,并且它执行外部调用所需的任何操作,然后将返回值放回C代码能够理解的格式,然后返回。

    支持外部二进制文件的调用 进入之内 你的代码,你做了同样的事情,但是反过来。您的二进制文件的入口点是一些小的汇编例程,它们将外部ABI转换成C代码可以理解的格式,调用内部函数,然后将返回值转换成外部代码可以理解的格式,然后返回。

    恐怕有时候没有好的解决办法。

        2
  •  2
  •   calandoa    9 年前

    您可以使用“long long”对两个寄存器执行此操作,如本页“ARM架构的过程调用标准”链接中所述。

    long long test(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
    {
        long long ret;
        ret = a+b;
        ret <<= 32;
        ret |= c + d;
        return ret;
    }
    

    将简单地编译为:

    0002dbb8 <test>:
    2dbb8:       1841            adds    r1, r0, r1
    2dbba:       18d0            adds    r0, r2, r3
    2dbbc:       4770            bx      lr
    

    以及 ret & 0xFFFFFFFF ret >> 32 在您的调用函数中,R0和R1将无缝替换。

    甚至可以使用“集装箱化”对寄存器r0到r3执行此操作。 向量“:

    typedef uint32_t uint32x4_t __attribute__ ((vector_size (16)));
    
    uint32x4_t test2(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
    {
        uint32x4_t ret = { a + 1, b + 2, c + 3, d + 4};
        // to access elements: ret[0], ret[1], ...
        return ret;
    }
    

    编译为:

    0002dbb8 <test2>:
    2dbb8:       3001            adds    r0, #1
    2dbba:       3102            adds    r1, #2
    2dbbc:       3203            adds    r2, #3
    2dbbe:       3304            adds    r3, #4
    2dbc0:       4770            bx      lr
    

    注意,在上面的文档中,它被引用为simd/neon特性,但是我只是在一个皮质m0上以拇指模式实现了它,没有neon支持。

        3
  •  0
  •   David Cary    13 年前

    这个 "Procedure Call Standard for the ARM Architecture" 具体来说(第5.4节:结果返回):

    “r0中返回的复合类型不超过4个字节。”

    “大于4字节的复合类型…存储在内存中,地址在调用函数时作为额外参数传递…."

    我知道有些CPU有几个不同的“标准”ABI。 但我的印象是几乎所有ARM的编译器都使用相同的ABI。

    你有证据证明GCC 使用此标准ABI?

    您是否介意发布一个链接,指向ARM的ABI上与此标准ABI(呼叫者使用的ABI)或被呼叫者使用的ABI或两者都不同的任何信息?

        4
  •  -1
  •   Adam Rosenfield    14 年前

    我不确定这是否有效,但您可以尝试使用 pcs function attribute :

    struct bar foo(int a, int b) __attribute__((pcs("aapcs")));
    struct bar foo(int a, int b) {
        ...
    }