返回介绍

10.2 ARM

发布于 2025-02-22 14:00:44 字数 4685 浏览 0 评论 0 收藏 0

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文