函数readWord
应返回:
以下示例是否遵循AAPCS? 考虑到AAPCS,还有更好的方法吗?
// OUT:
// R0 (status code): 0 if valid, else > 0
// R1 (data):
// if the R0 represents a successful read: data, which was read,
// else: undetermined
read32:
PUSH {LR}
LDR R0, =memoryMappedAddressOfDataSource
LDR R4, [R0]
BL checkValidRead
// If the read was invalid, directly return the error
// code set by checkValidRead in R0 and do not change R1.
CBNZ R0, read32_return
// R0 is 0, so the read was valid and the the data is returned in R1.
MOV R1, R4
read32_return:
POP {PC}
// IN: none
// Checks a special status register to determine,
// whether the last read was successful.
// OUT:
// R0: 0 if valid, else > 0
checkValidRead:
...
来自AAPCS(第18页):
在r0和r1中返回双字大小的基本数据类型(例如,长长,双和64位容器化向量)。
大于4个字节的复合类型,或者调用者和调用者无法静态确定其大小 callee,在调用函数时作为额外参数传递的地址存储在内存中(§5.5, 规则A.4)。在函数调用期间的任何时候都可以修改用于结果的内存。
然而,我不知道它是否是一个容器化的64位向量或聚合复合类型甚至是......否则:
容器化载体的内容对大多数程序调用标准是不透明的:唯一定义的方面 它的布局是内存格式(基本类型存储在内存中的方式)和 过程调用接口上的不同类别的寄存器。
复合类型是一个或多个基本数据类型的集合,作为单个实体处理 程序调用级别。复合类型可以是以下任何一种: 聚合,其中成员按顺序排列在内存中[...]
答案 0 :(得分:2)
您引用的文档说,任何不适合单个寄存器的复合类型都是通过隐藏指针返回的。这将包括一个C结构。
只有可以在寄存器对中返回单个宽整数或FP类型。
寄存器对比通过隐藏指针存储/重新加载更有效,所以不幸的是你必须破解调用约定而不是只返回struct { uint32_t flag, value; }
要描述您想要C编译器的调用约定,请告诉它您返回uint64_t
,并将其拆分为两个32位整数变量。这将免费发生,因为编译器已将它们放在不同的寄存器中。
例如(source + asm on the Godbolt compiler explorer)。我使用了一个联盟,但你可以同样使用一个班次。
#include <stdint.h>
uint64_t read32(void);
union unpack32 {
uint64_t u64;
uint32_t u32[2];
};
void ext(uint32_t); // something to do with a return value
unsigned read32_wrapper() {
union unpack32 ret = { read32() };
if (ret.u32[0]) {
ext(ret.u32[1]);
}
return ret.u32[0];
}
编译如下:
push {r4, lr}
bl read32
subs r4, r0, #0 @ set flags and copy the flag to r4
movne r0, r1
blne ext @ the if() body.
mov r0, r4 @ always return the status flag
pop {r4, lr}
bx lr