环境:用于ARM Cortex m4f的GCC 4.7.3(arm-none-eabi-gcc).裸金属(实际上是MQX RTOS,但这里无关紧要).CPU处于Thumb状态.
这是我正在查看的一些代码的反汇编列表:
//.label flash_command // ... while(!(FTFE_FSTAT & FTFE_FSTAT_CCIF_MASK)) {} // Compiles to: 12: bf00 nop 14: f04f 0300 mov.w r3, #0 18: f2c4 0302 movt r3, #16386 ; 0x4002 1c: 781b ldrb r3, [r3, #0] 1e: b2db uxtb r3, r3 20: b2db uxtb r3, r3 22: b25b sxtb r3, r3 24: 2b00 cmp r3, #0 26: daf5 bge.n 14
常量(在扩展宏之后等)是:
address of FTFE_FSTAT is 0x40020000u FTFE_FSTAT_CCIF_MASK is 0x80u
这是使用NO优化(-O0)编译的,因此GCC不应该做任何花哨的事情......然而,我没有得到这个代码.回答后编辑:永远不要假设这一点.我的问题是因为关闭优化而产生了一种错误的安全感.
我读过"uxtb r3,r3"是截断32位值的常用方法.你为什么要截断它然后签名扩展?世界上的这个如何等同于C代码中的位掩码操作?
我在这里错过了什么?
编辑:涉及的事物的类型:因此FTFE_FSTAT的实际宏扩展归结为
((((FTFE_MemMapPtr)0x40020000u))->FSTAT)
结构定义为的位置
/** FTFE - Peripheral register structure */ typedef struct FTFE_MemMap { uint8_t FSTAT; /**< Flash Status Register, offset: 0x0 */ uint8_t FCNFG; /**< Flash Configuration Register, offset: 0x1 */ //... a bunch of other uint_8 } volatile *FTFE_MemMapPtr;
user3386109.. 6
这两个uxtb
指令是编译器是愚蠢的,如果你打开优化它们应该被优化.该sxtb
是编译器是辉煌,使用,你会不会在未经优化的代码想到了一招.
第一个uxtb
原因是你从内存中加载了一个字节.编译器将寄存器r3的其他24位归零,以便字节值填满整个寄存器.
第二个uxtb
原因是你使用8位值进行AND运算.编译器意识到结果的高24位始终为零,因此它uxtb
用于清除高24位.
这两个uxtb
指令都没有任何用处,因为sxtb
指令会覆盖反之的高24位r3
.优化器应该实现并在启用优化的情况下进行编译时删除它们.
该sxtb
指令采用您关心的一位0x80
,并将其移入寄存器的符号位r3
.这样,如果0x80
设置了位,则r3
变为负数.所以现在编译器可以比较0
以确定该位是否已设置.如果未设置该位,则bge
指令分支回到while
循环的顶部.
这两个uxtb
指令是编译器是愚蠢的,如果你打开优化它们应该被优化.该sxtb
是编译器是辉煌,使用,你会不会在未经优化的代码想到了一招.
第一个uxtb
原因是你从内存中加载了一个字节.编译器将寄存器r3的其他24位归零,以便字节值填满整个寄存器.
第二个uxtb
原因是你使用8位值进行AND运算.编译器意识到结果的高24位始终为零,因此它uxtb
用于清除高24位.
这两个uxtb
指令都没有任何用处,因为sxtb
指令会覆盖反之的高24位r3
.优化器应该实现并在启用优化的情况下进行编译时删除它们.
该sxtb
指令采用您关心的一位0x80
,并将其移入寄存器的符号位r3
.这样,如果0x80
设置了位,则r3
变为负数.所以现在编译器可以比较0
以确定该位是否已设置.如果未设置该位,则bge
指令分支回到while
循环的顶部.