这个反汇编如何对应于给定的C代码?
环境:arm Cortex m4f的GCC 4.7.3(arm无eabi GCC)。裸机(实际上是MQX RTO,但这与此无关)。CPU处于拇指状态 下面是我正在查看的一些代码的反汇编程序列表:这个反汇编如何对应于给定的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:
//.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;