- 第一章 CPU 简介
- 第二章 Hello,world!
- 第三章 函数开始和结束
- 第四章 栈
- Chapter 5 printf() 与参数处理
- Chapter 6 scanf()
- CHAPER7 访问传递参数
- Chapter 8 一个或者多个字的返回值
- Chapter 9 指针
- Chapter 10 条件跳转
- 第 11 章 选择结构 switch()/case/default
- 第 12 章 循环结构
- 第 13 章 strlen()
- Chapter 14 Division by 9
- chapter 15 用 FPU 工作
- Chapter 16 数组
- Chapter 17 位域
- 第 18 章 结构体
- 19 章 联合体
- 第二十章 函数指针
- 第 21 章 在 32 位环境中的 64 位值
- 第二十二章 SIMD
- 23 章 64 位化
- 24 章 使用 x64 下的 SIMD 来处理浮点数
- 25 章 温度转换
- 26 章 C99 的限制
- 27 章 内联函数
- 第 28 章 得到不正确反汇编结果
- 第 29 章 花指令
- 第 30 章 16 位 Windows
- 第 31 章 类
- 三十二 ostream
- 34.2.2 MSVC
- 34.2.3 C++ 11 std::forward_list
- 34.3 std::vector
- 34.4 std::map and std::set
10.2 ARM
10.2.1 Keil + ARM mode 优化后
Listing 10.6: Optimizing Keil + ARM mode
#!bash
.text:000000B8 EXPORT f_signed
.text:000000B8 f_signed ; CODE XREF: main+C
.text:000000B8 70 40 2D E9 STMFD SP!, {R4-R6,LR}
.text:000000BC 01 40 A0 E1 MOV R4, R1
.text:000000C0 04 00 50 E1 CMP R0, R4
.text:000000C4 00 50 A0 E1 MOV R5, R0
.text:000000C8 1A 0E 8F C2 ADRGT R0, aAB ; "a>b
"
.text:000000CC A1 18 00 CB BLGT __2printf
.text:000000D0 04 00 55 E1 CMP R5, R4
.text:000000D4 67 0F 8F 02 ADREQ R0, aAB_0 ; "a==b
"
.text:000000D8 9E 18 00 0B BLEQ __2printf
.text:000000DC 04 00 55 E1 CMP R5, R4
.text:000000E0 70 80 BD A8 LDMGEFD SP!, {R4-R6,PC}
.text:000000E4 70 40 BD E8 LDMFD SP!, {R4-R6,LR}
.text:000000E8 19 0E 8F E2 ADR R0, aAB_1 ; "a<b
"
.text:000000EC 99 18 00 EA B __2printf
.text:000000EC ; End of function f_signed
ARM 下很多指令只有某些标志位被设置时才会被执行。比如做数值比较时。
举个例子,ADD 实施上是 ADDAL,这里的 AL 是 Always,即总被执行。判定谓词是 32 位 ARM 指令的高 4 位(条件域)。无条件跳转的 B 指令其实是有条件的,就行其它任何条件跳转一样,只是条件域为 AL,这意味着总是被执行,忽略标志位。
ADRGT 指令就像和 ADR 一样,只是该指令前面为 CMP 指令,并且只有前面数值大于另一个数值时(Greater Than)时才被执行。
接下来的 BLGT 行为和 BL 一样,只有比较结果符合条件才能出发(Greater Than)。ADRGT 把字符串“a>b ”的地址写入 R0,然后 BLGT 调用 printf()。因此,这些指令都带有 GT 后缀,只有当 R0(a 值)大于 R4(b 值)时指令才会被执行。
然后我们看 ADREQ 和 BLEQ,这些指令动作和 ADR 及 BL 一样,只有当两个操作数对比后相等时才会被执行。这些指令前面是 CMP(因为 printf() 调用可能会修改状态标识)。 然后我们看 LDMGEFD,该指令行为和 LDMFD 指令一样 1,仅仅当第一个值大于等于另一个值时(Greater Than),指令才会被执行。
“LDMGEFD SP!, {R4-R6,PC}”恢复寄存器并返回,只是当 a>=b 时才被触发,这样之后函数才执行完成。但是如果 a<b,触发条件不成立是将执行下一条指令 LDMFD SP!, {R4-R6,LR},该指令保存 R4-R6 寄存器,使用 LR 而不是 PC,函数并不返回。最后两条指令是执行 printf()(5.3.2)。
f_unsigned 与此一样只是使用对应的指令为 ADRHI, BLHI 及 LDMCSFD,判断谓词(HI = Unsigned higher, CS = Carry Set (greater than or equal))请类比之前的说明,另外就是函数内部使用无符号数值。
我们来看一下 main() 函数:
Listing 10.7: main()
#!bash
.text:00000128 EXPORT main
.text:00000128 main
.text:00000128 10 40 2D E9 STMFD SP!, {R4,LR}
.text:0000012C 02 10 A0 E3 MOV R1, #2
.text:00000130 01 00 A0 E3 MOV R0, #1
.text:00000134 DF FF FF EB BL f_signed
.text:00000138 02 10 A0 E3 MOV R1, #2
.text:0000013C 01 00 A0 E3 MOV R0, #1
.text:00000140 EA FF FF EB BL f_unsigned
.text:00000144 00 00 A0 E3 MOV R0, #0
.text:00000148 10 80 BD E8 LDMFD SP!, {R4,PC}
.text:00000148 ; End of function main
这就是 ARM 模式如何避免使用条件跳转。
这样做有什么好处呢?因为 ARM 使用精简指令集(RISC)。简言之,处理器流水线技术受到跳转的影响,这也是分支预测重要的原因。程序使用的条件或者无条件跳转越少越好,使用断言指令可以减少条件跳转的使用次数。
x86 没有这也的功能,通过使用 CMP 设置相应的标志位来触发指令。
10.2.2 Optimizing Keil + thumb mode
Listing 10.8: Optimizing Keil + thumb mode
#!bash
.text:00000072 f_signed ; CODE XREF: main+6
.text:00000072 70 B5 PUSH {R4-R6,LR}
.text:00000074 0C 00 MOVS R4, R1
.text:00000076 05 00 MOVS R5, R0
.text:00000078 A0 42 CMP R0, R4
.text:0000007A 02 DD BLE loc_82
.text:0000007C A4 A0 ADR R0, aAB ; "a>b
"
.text:0000007E 06 F0 B7 F8 BL __2printf
.text:00000082
.text:00000082 loc_82 ; CODE XREF: f_signed+8
.text:00000082 A5 42 CMP R5, R4
.text:00000084 02 D1 BNE loc_8C
.text:00000086 A4 A0 ADR R0, aAB_0 ; "a==b
"
.text:00000088 06 F0 B2 F8 BL __2printf
.text:0000008C
.text:0000008C loc_8C ; CODE XREF: f_signed+12
.text:0000008C A5 42 CMP R5, R4
.text:0000008E 02 DA BGE locret_96
.text:00000090 A3 A0 ADR R0, aAB_1 ; "a<b
"
.text:00000092 06 F0 AD F8 BL __2printf
.text:00000096
.text:00000096 locret_96 ; CODE XREF: f_signed+1C
.text:00000096 70 BD POP {R4-R6,PC}
.text:00000096 ; End of function f_signed
仅仅 Thumb 模式下的 B 指令可能需要条件代码辅助,所以 thumb 代码看起来更普通一些。
BLE 通常是条件跳转小于或等于(Less than or Equal),BNE—不等于(Not Equal),BGE—大于或等于(Greater than or Equal)。
f_unsigned 函数是同样的,只是使用的指令用来处理无符号数值:BLS (Unsigned lower or same) 和 BCS (Carry Set (Greater than or equal)).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论