这个反汇编如何对应于给定的C代码?

这个反汇编如何对应于给定的C代码?,c,gcc,assembly,arm,C,Gcc,Assembly,Arm,环境:arm Cortex m4f的GCC 4.7.3(arm无eabi GCC)。裸机(实际上是MQX RTO,但这与此无关)。CPU处于拇指状态 下面是我正在查看的一些代码的反汇编程序列表: //.label flash_command // ... while(!(FTFE_FSTAT & FTFE_FSTAT_CCIF_MASK)) {} // Compiles to: 12: bf00 nop 14: f04f 0300 mov.w r3, #0 18:

环境:arm Cortex m4f的GCC 4.7.3(arm无eabi GCC)。裸机(实际上是MQX RTO,但这与此无关)。CPU处于拇指状态

下面是我正在查看的一些代码的反汇编程序列表:

//.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 <flash_command+0x14>
这是在没有优化(-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;
/**FTFE-外围寄存器结构*/
类型定义结构FTFE_MemMap{
uint8_t FSTAT;/**<闪存状态寄存器,偏移量:0x0*/
uint8\u t FCNFG;/**<闪存配置寄存器,偏移量:0x1*/
//…一堆其他的uint_8
}挥发性*FTFE_MemMapPtr;

这两条
uxtb
指令是编译器的愚蠢之处,如果启用优化,它们应该被优化掉。
sxtb
是一款出色的编译器,它使用了一种在未优化的代码中无法预料的技巧

第一个
uxtb
是因为您从内存加载了一个字节。编译器将寄存器r3的其他24位归零,以便字节值填充整个寄存器

第二个
uxtb
是由于您使用的是8位值。编译器意识到结果的上24位始终为零,因此它使用
uxtb
清除上24位

这两条
uxtb
指令都没有任何用处,因为
sxtb
指令无论如何都会覆盖
r3
的上24位。优化器应该意识到这一点,并在启用优化的情况下编译时删除它们


sxtb
指令获取您关心的一位
0x80
,并将其移动到寄存器
r3
的符号位。这样,如果设置了位
0x80
,则
r3
变为负数。因此,现在编译器可以与
0
进行比较,以确定是否设置了位。如果未设置位,则
bge
指令分支回到
while
循环的顶部。

不要反汇编代码,只需使用
-S
直接生成汇编程序即可。如果幸运的话,它甚至可能更全面。要么不是实际的
while
语句,要么不是实际的
#define
s。所涉及的事物类型是什么?这些未知宏中是否隐藏了其他表达式?如果没有编译器当时拥有的相同信息,就很难对代码生成进行推理……您所注意到的行为是预期的。如果不启用优化,GCC将生成执行许多不必要操作的坏代码。装配代码是正确的。只要未设置0x40020000处字节的8位(从1开始计数),它就会循环。即使使用-O0,编译器也不需要对任何事情都很直接。2.用-O0生成的代码比我想象的要糟糕得多。啊!因此,当条件为真时,r3中的数字为负,因此小于零!真是天才!谢谢你,我今晚可以睡觉了!也许值得注意的是,加载的
uxtb
是愚蠢的三倍,因为
ldrb
已经为零扩展了该值,并且当您知道
ge
(“大于或等于”)是标志的有符号解释时(与
hs
相反,后者是无符号的“较高或相同”).gcc几乎所有的优化都是在代码的中间表示上进行的,而不是在目标机器指令序列上(本例中为ARM)。如上所述,解析后从其内部表示生成可执行文件需要对内部表示进行一些转换。gcc没有一种模式可以尝试将C翻译成ARM。因此,即使在
-O0
,您也会得到一些“聪明”的东西,因为这是gcc知道如何做一些事情的唯一方法。它没有那种愚蠢的编程方式。
/** 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;