- 第一章 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
14.2 ARM
ARM 处理器,就像其他的“纯”RISC 处理器一样,缺少除法指令,缺少 32 位常数乘法的单条指令。利用一个技巧,通过加法,减法,移位是可以实现除法的。 这里有一个 32 位数被 10(20,3.3 常量除法)除的例子,输出商和余数。
#!bash
; takes argument in a1
; returns quotient in a1, remainder in a2
; cycles could be saved if only divide or remainder is required
SUB a2, a1, #10 ; keep (x-10) for later
SUB a1, a1, a1, lsr #2
ADD a1, a1, a1, lsr #4
ADD a1, a1, a1, lsr #8
ADD a1, a1, a1, lsr #16
MOV a1, a1, lsr #3
ADD a3, a1, a1, asl #2
SUBS a2, a2, a3, asl #1 ; calc (x-10) - (x/10)*10
ADDPL a1, a1, #1 ; fix-up quotient
ADDMI a2, a2, #10 ; fix-up remainder
MOV pc, lr
14.2.1 Xcode 优化模式(LLVM)+ARM 模式
#!bash
__text:00002C58 39 1E 08 E3 E3 18 43 E3 MOV R1, 0x38E38E39
__text:00002C60 10 F1 50 E7 SMMUL R0, R0, R1
__text:00002C64 C0 10 A0 E1 MOV R1, R0,ASR#1
__text:00002C68 A0 0F 81 E0 ADD R0, R1, R0,LSR#31
__text:00002C6C 1E FF 2F E1 BX LR
运行原理
这里的代码和优化模式的 MSVC 和 GCC 生成的基本相同。显然,LLVM 在产生常量上使用相同的算法。
善于观察的读者可能会问,MOV 指令是如何将 32 位数值写入寄存器中的,因为这在 ARM 模式下是不可能的。实际上是可能的,但是,就像我们看到的,与标准指令每条有四个字节不同的是,这里的每条指令有 8 个字节,其实这是两条指令。第一条指令将值 0x8E39 装入寄存器的低十六位,第二条指令是 MOVT,它将 0x383E 装入寄存器的高 16 位。IDA 知道这些顺序,并且为了精简紧凑,将它精简转换成一条伪代码。
SMMUL (Signed Most Significant Word Multiply) 实现两个 32 位有符号数的乘法,并且将高 32 位的部分放在 r0 中,弃掉结果的低 32 位部分。
“MOV R1,R0,ASR#1“指令算数右移一位。
“ADD R0,R1,LSR#31” R0=R1+R0>>32
事实上,在 ARM 模式下,并没有单独的移位指令。相反,像(MOV,ADD,SUB,RSB)3 这样的数据处理指令,第二个操作数需要被移位。ASR 表示算数右移,LSR 表示逻辑右移。
14.2.2 优化 Xcode(LLVM)+thumb-2 模式
#!bash
MOV R1, 0x38E38E39
SMMUL.W R0, R0, R1
ASRS R1, R0, #1
ADD.W R0, R1, R0,LSR#31
BX LR
在 thumb 模式下有些单独的移位指令,这个例子中使用了 ASRS(算数右移)
14.2.3 Xcode 非优化模式(LLVM) keil 模式
非优化模式 LLVM 不生成我们之前看到的那样的代码,它插入了一个调用库函数的 call __divsi3
关于 keil:通常插入一个调用库函数的 call __aeabi_idivmod
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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