use*_*392 4 c embedded assembly powerpc endianness
这基本上是在传输消息缓冲区时执行缓冲区的交换.这句话让我感到困惑(因为我不熟悉c中的嵌入式汇编代码).这是一个power pc指令
#define ASMSWAP32(dest_addr,data) __asm__ volatile ("stwbrx %0, 0, %1" : : "r" (data), "r" (dest_addr))
Run Code Online (Sandbox Code Playgroud)
除了因为一个bug而不安全之外,这个宏的效率也低于编译器为你生成的效率.
stwbrx
= 存储字字节反转.x
索引的立场.
在GNU C中你不需要内联asm,你可以使用__builtin_bswap32
并让编译器为你发出这个指令.
void swapstore_asm(int a, int *p) {
ASMSWAP32(p, a);
}
void swapstore_c(int a, int *p) {
*p = __builtin_bswap32(a);
}
Run Code Online (Sandbox Code Playgroud)
使用gcc4.8.5编译-O3 -mregnames
,我们从两个函数(Godbolt编译器资源管理器)获得相同的代码 :
swapstore:
stwbrx %r3, 0, %r4
blr
swapstore_c:
stwbrx %r3,0,%r4
blr
Run Code Online (Sandbox Code Playgroud)
但是对于更复杂的地址(存储到p[off]
,其中off
是整数函数arg),编译器知道如何使用两个寄存器输入,而宏强制编译器将地址放在单个寄存器中:
void swapstore_offset(int a, int *p, int off) {
= __builtin_bswap32(a);
}
swapstore_offset:
slwi %r5,%r5,2 # *4 = sizeof(int)
stwbrx %r3,%r4,%r5 # use an indexed addressing mode, with both registers non-zero
blr
swapstore_offset_asm:
slwi %r5,%r5,2
add %r4,%r4,%r5 # extra instruction forced by using the macro
stwbrx %r3, 0, %r4
blr
Run Code Online (Sandbox Code Playgroud)
顺便说一句,如果您在理解GNU C内联asm模板时遇到问题,查看编译器的asm输出可能是查看替换内容的有用方法.请参阅如何从GCC/clang程序集输出中删除"noise"?有关读取编译器asm输出的更多信息.
还要注意,这个宏是错误的:它缺少"memory"
商店的破坏.是的,你还需要它asm volatile
.*dest_addr
除非你告诉它,否则编译器不会假设它被修改,所以它可以*dest_addr
在此insn之前提升非易失性负载,或者更可能是一个真正的问题,在它之后接收存储.(例如,如果在使用此存储器将存储器归零之前,编译器可能在此指令之后实际为零.)
您可以告诉编译器您使用操作数修改哪个内存位置,或者使用操作数作为伪操作数,或者在寻址模式下使用约束,而不是使用"memory"
clobber(也可以省略volatile
),这样您就可以使用它.(IDK PPC足以知道通常会扩展到什么.)=m" (*dest_addr)
reg+reg
"=m"
在大多数情况下,这个bug不会咬你,但它仍然是一个bug.升级您的编译器版本或使用链接时优化可能会使您的程序错误,没有源级别的更改.
这种事情是为什么https://gcc.gnu.org/wiki/DontUseInlineAsm
另请参见https://stackoverflow.com/tags/inline-assembly/info.
#define ASMSWAP32(dest_addr,data)
...
这部分应该清楚
__asm__ volatile (
...: : "r" (data), "r" (dest_addr))
这是实际的内联汇编:
两个值传递给汇编代码; 汇编代码中没有返回任何值(这是实际汇编代码之后的冒号).
两个参数都在寄存器("r"
)中传递.该表达式%0
将被包含值的寄存器替换,data
而表达式%1
将被包含值的寄存器替换dest_addr
(在这种情况下将是指针).
这volatile
意味着汇编代码必须在此时执行,不能移动到其他地方.
因此,如果您在C源代码中使用以下代码:
ASMSWAP(&a, b);
Run Code Online (Sandbox Code Playgroud)
...将生成以下汇编代码:
# write the address of a to register 5 (for example)
...
# write the value of b to register 6
...
stwbrx 6, 0, 5
Run Code Online (Sandbox Code Playgroud)
所以stwbrx
指令的第一个参数是值,b
最后一个参数是地址a
.
stwbrx x, 0, y
该指令将寄存器中的值写入寄存器x
中存储的地址y
; 但是它将值写入"反向端"(在大端CPU上它写入值"little endian").
以下代码:
uint32 a;
ASMSWAP32(&a, 0x12345678);
Run Code Online (Sandbox Code Playgroud)
......因此应该导致a = 0x78563412
.
归档时间: |
|
查看次数: |
575 次 |
最近记录: |