我正在尝试为 AVR 编写一个自定义内存复制函数作为内联程序集,因为 avr-gcc 将始终使用循环进行 memcpy 和结构分配,这在时间方面效率低下。我想使用内存操作数来避免添加“内存”破坏者。我目前有这个:
void copy_2_bytes (char *restrict dst, char *restrict src)
{
struct S {
char x[2];
};
__asm__(
" ld __tmp_reg__,%[src]+\n"
" st %[dst]+,__tmp_reg__\n"
" ld __tmp_reg__,%[src]+\n"
" st %[dst]+,__tmp_reg__\n"
: [dst] "=m" ( *(struct S *)dst )
: [src] "m" ( *(struct S *)src )
);
}
这可以编译,但通常是不正确的,因为它修改了与内存操作数对应的指针寄存器对。很容易看出 gcc 假定寄存器保持不变,例如通过添加“*dst = 0;” 组装后。
另一方面,Y 和 Z 寄存器支持“ldd”和“std”指令,它们也采用立即偏移量,因此它们可以用于访问多个字节而无需修改。但是似乎没有办法强制 gcc 不选择不支持的 X 寄存器。
更新
实际上,如果 gcc 确定内存操作数的地址是常量,它会将常量地址传递给程序集,而不是寄存器对。所以现在,我完全不知道如何处理这个问题。是否有一些魔术指令或汇编宏可以同时处理指针寄存器和常量地址?