我正面临一个奇怪的问题。我正在将uint64_t
偏移量传递给32位架构(Cortex R52)上的函数。寄存器都是32位的。
这是函数。:对不起,我把函数声明弄乱了。
void read_func(uint8_t* read_buffer_ptr, uint64_t offset, size_t size);
main(){
// read_buffer : memory where something is read.
// read_buffer_ptr : points to read_buffer structure where value should be stored after reading value.
read_func(read_buffer_ptr, 0, sizeof(read_buffer));
}
在这个函数中,存储在offset
中的值不是零,而是我在寄存器(r5, r6
)中也看到的一些随机值。此外,当我使用offset
作为32位值时,它工作得非常好。从r2,r3复制到r5,r6。
你能告诉我为什么会这样吗?登记还不够吗?
发布的原型是无效的,它应该是:
void read_func(uint8_t *read_buffer_ptr, uint64_t offset, size_t size);
同样,main()
的定义也过时了:从c99开始不支持隐式的int
返回类型,函数调用有另一个语法错误,缺少)
…
在32位架构上传递64位参数会发生什么是实现定义的:
- 8字节的堆栈空间用来传递值
- 或2个32位寄存器用于传递最低有效部分和最高有效部分
- 或两者的组合取决于参数的数量
- 或其他适合目标CPU的方案
在你的代码中,你传递0
,它的类型是int
,大概只有32位。如果read_func
的原型是正确的,并且在函数调用之前被解析,这不是问题,否则行为是未定义的,C99编译器甚至不应该编译代码,但可能编译器只会发出警告并生成虚假代码。
在您的情况下(Cortex R52), 64位参数传递给寄存器r2和r3中的read_func
。
- Cortex-R52有32位地址总线,偏移量不能为64位。在计算中,只使用较低的32位,因为较高的32位不会产生任何影响。
例子:
uint64_t foo(void *buff, uint64_t offset, uint64_t size)
{
unsigned char *cbuff = buff;
while(size--)
{
*(cbuff++ + offset) = size & 0xff;
}
return offset + (uint32_t)cbuff;
}
void *z1(void);
uint64_t z2(void);
uint64_t z3(void);
uint64_t bar(void)
{
return foo(z1(), z2(), z3());
}
foo:
push {r4, lr}
ldr lr, [sp, #8] //size
ldr r1, [sp, #12] //size
mov ip, lr
add r4, r0, r2 // cbuff + offset calculation r3 is ignored as not needed - processor has only 32bits address space.
.L2:
subs ip, ip, #1 //size--
sbc r1, r1, #0 //size--
cmn r1, #1
cmneq ip, #1
bne .L3
add r0, r0, lr
adds r0, r0, r2
adc r1, r3, #0
pop {r4, pc}
.L3:
strb ip, [r4], #1
b .L2
bar:
push {r0, r1, r4, r5, r6, lr}
bl z1
mov r4, r0 // buff
bl z2
mov r6, r0 // offset
mov r5, r1 // offset
bl z3
mov r2, r6 // offset
strd r0, [sp] // size passed on the stack
mov r3, r5 // offset
mov r0, r4 // buff
bl foo
add sp, sp, #8
pop {r4, r5, r6, pc}
可以看到电阻r2 &R3包含偏移量,r0 - buff和size在堆栈上。