返回寄存器中的结构 – GCC中的ARM ABI

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

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

但是GCC( 4.3.3 )不允许它,我能找到的只是对一些RealView编译器的引用。 从GCC有没有办法做到这一点?

我已经尝试过-freg-struct-return但它并没有什么区别。 因为它是一个ABI我无法改变原始程序,并返回一个常规结构破坏堆栈。

如果可以避免,我宁愿不使用组件,因为它没有必要。

谢谢!

根据要求发布答案:

如果你必须生成一个可以与编译器不支持的ABI一起使用的二进制文件,那么你就会遇到麻烦。 在C中没有什么可以做的。在这种情况下,你需要回到汇编语言编程并打乱必要的调用。 有两种可能性:

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

这两个问题都是类似地解决的。 要从代码中调用,您需要在汇编中调用shim函数,调用约束以匹配外部ABI,然后从那里调用外部函数。 与C代码的不同之处在于,现在要进行外部调用,调用内部汇编例程,并执行外部调用所需的任何操作,然后将返回值放回C代码将理解的格式中,并返回。

要支持从外部二进制文件代码的调用,您可以执行相同的操作,但反之亦然。 二进制文件的入口点是小程序集程序,它们将外部ABI转换为C代码可以理解的格式,调用内部函数,然后将返回值恢复为外部代码理解的格式,然后返回。

我害怕,有时候没有好的解决办法。

您可以使用“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 : 2dbb8: 1841 adds r1, r0, r1 2dbba: 18d0 adds r0, r2, r3 2dbbc: 4770 bx lr 

你的调用函数中的ret & 0xFFFFFFFFret >> 32将被r0和r1无缝替换。

甚至可以通过使用“Containerized vectors”对寄存器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 : 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 / NEONfunction,但我只是在Thumb模式下的Cortex M0上实现它,没有NEON支持。

“ARM体系结构的过程调用标准”具体说明(第5.4节:结果返回):

“在R0中返回不大于4个字节的复合类型。”

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

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

您是否有任何证据表明GCC 使用此标准ABI?

您是否介意发布ARM上ABI的任何信息的链接,该信息与此标准ABI不同 – 呼叫者使用的ABI,或被叫,或两者兼而有之?

我不确定这是否可行,但您可以尝试使用pcs 函数属性 :

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