ASMbits--常用算术运算指令
- 1 基本运算算术指令--最基础
- 1.1 加法和减法
- 1.2 移位操作
- 1.3 乘法
- 2 practice
- 2.1 编写invert(int n)
- 2.2 编写judge_odd(int n)
- 2.3 计算绝对值abs(int n)
- 2.4 add(int n1, int n2)函数
- 2.4 shift寄存器
- 2.5 sihft ath right
- 2.6 shift left
在ARMv7汇编中,代码片段:
1: b 1b //Done
作用是创建一个无限循环,使程序永远停留在当前位置,不在执行后续命令;
语法解释:
-
1::这是一个局部标签(local label)。在 ARM 汇编中,以数字开头的标签(如 1:)是局部标签,可以通过 b 1b 或 b 1f 引用。
1b:表示向后查找最近的 1: 标签(Backward)。
1f:表示向前查找最近的 1: 标签(Forward)。 -
b 1b:这是一个分支指令(Branch),跳转到最近的 1: 标签(向后查找)。由于标签 1: 就在当前行,这条指令会无限循环跳转到自身。
代码 1: b 1b 的作用是让程序在当前位置无限循环,防止后续未定义代码的执行。这是裸机编程或嵌入式系统中常见的“安全终止”方法。
具体在裸机程序(无操作系统)或嵌入式系统中,这种无限循环常用于:
- 防止程序执行到未定义的内存区域(例如代码结束后未初始化的内存)。
- 保持程序在完成所有任务后“挂起”(例如在调试时观察结果);
1 基本运算算术指令–最基础
1.1 加法和减法
- ADD 加法
语法:ADD{条件}{S} 目标寄存器, 操作数1, 操作数2
功能:将操作数1和操作数2相加,结果存入目标寄存器。
ADD R0, R1, R2 @ R0 = R1 + R2
ADD R3, R4, #10 @ R3 = R4 + 10
- SUB减法
语法:SUB{条件}{S} 目标寄存器, 操作数1, 操作数2
功能:从操作数1中减去操作数2,结果存入目标寄存器。
SUB R0, R1, R2 @ R0 = R1 - R2
SUB R3, R4, #5 @ R3 = R4 - 5
1.2 移位操作
- LSL逻辑左移
语法:LSL{条件}{S} 目标寄存器, 操作数, 移位位数
功能:将操作数左移指定位数,低位补零。
LSL R0, R1, #4 @ R0 = R1 << 4
- LSR逻辑右移
语法:LSR{条件}{S} 目标寄存器, 操作数, 移位位数
功能:将操作数右移指定位数,高位补零。
LSR R0, R1, #3 @ R0 = R1 >> 3(无符号)
- ASR(算术右移)
语法:ASR{条件}{S} 目标寄存器, 操作数, 移位位数
功能:将操作数右移指定位数,高位补符号位(用于有符号数)
ASR R0, R1, #2 @ R0 = R1 >> 2(保留符号)
- ROR循环右移
语法:ROR{条件}{S} 目标寄存器, 操作数, 移位位数
功能:将操作数循环右移指定位数,移出的位补到高位。
ROR R0, R1, #8 @ R0 = R1 循环右移8位
1.3 乘法
- MUL无符号乘法
语法:MUL{条件}{S} 目标寄存器, 操作数1, 操作数2
功能:操作数1 × 操作数2,结果低32位存入目标寄存器。
MUL R0, R1, R2 @ R0 = (R1 × R2) 的低32位
- MIL乘加
语法:MLA{条件}{S} 目标寄存器, 操作数1, 操作数2, 操作数3
功能:操作数1 × 操作数2 + 操作数3。
MLA R0, R1, R2, R3 @ R0 = (R1 × R2) + R3
2 practice
2.1 编写invert(int n)
Write a function that returns the bitwise inversion of its parameter.
int invert (int n);
.global _start
_start:
mov r0, #1
bl invert
1: b 1b // Done
.global invert
invert:
MVN r0,r0 // MVN把R0里面的数取反然后再进行存储
BX lr //return caller
2.2 编写judge_odd(int n)
算法:最低位是0还是1,若是1则odd为1,若是为0,则odd为0;如何获得最低位呢,直接使用n & 1;
Steps:
- 将r0与1进行AND操作,结果存在某个寄存器,比如r0本身。
- 然后比较这个结果是否为0,如果不为0,则返回1,否则返回0。
.global _start
_start:
mov r0, #1
bl odd
1: b 1b // Done
.global odd
odd:
AND r0,r0,#1
BX lr
2.3 计算绝对值abs(int n)
算法:进制补码中,负数的符号位是1,正数或零是0。所以,如果我能得到符号位的掩码,可能可以用异或和减法来计算绝对值。比如,对于n,如果符号位是0,那么绝对值是n本身;如果符号位是1,绝对值是~n + 1。或者用另一种方法:将n与符号位的掩码异或,然后减去掩码。这可能更高效。
步骤:
- 将n算术右移31位,得到mask(0或-1)。
- 异或n和mask,得到n ^ mask。
- 减去mask,即(n ^ mask) - mask。因为mask是0或-1,当mask是-1时,减法相当于加1。
.global _start
_start:
mov r0, #10
bl abs
1: b 1b // Done
.global abs
abs:
ASR r1, r0, #31 // r1 = n>>31 to generate mask
EOR r0, r0, r1 // r0 = n ^ mask
SUB r0, r0, r1 // r0 = r0 - mask
BX lr
2.4 add(int n1, int n2)函数
即第一个参数传递给R0,第二个参数传递给R1;
.global _start
_start:
mov r0, #1 // First function parameter is always passed through r0.
mov r1, #1 // Second function parameter is always passed through r1.
bl add // Return value is always in r0.
1: b 1b // Done
.global add
add:
ADD R0,R0,R1
BX LR
2.4 shift寄存器
即将该参数移位到24位,低8位;
.global _start
_start:
ldr r0, =0x12345678
bl shift
b _start // End of testing code
// Convert one U32 sample to U8 format
shift:
LSR r0,r0,#24 //将输入参数 r0 右移24位,保留高8位到低8位
BX lr
2.5 sihft ath right
// A test case to test your function with
.global _start
_start:
ldr r0, =0x40000
bl shift
b _start // End of testing code
// Return 1/4 amplitude for a S32 sample
shift:
ASR r0,r0,#2 //算数右移
BX lr
2.6 shift left
// A test case to test your function with
.global _start
_start:
ldr r0, =0x1234
bl shift
b _start // End of testing code
// Convert one S16 to S32 format
shift:
LSL R0,R0,#16 // left shift 16
BX lr
以上是ARMv7汇编语言的常见算术指令运算;