ARM 汇编指令:LSL(逻辑左移) 和 LSR(逻辑右移)
本文来自于我关于 ARM 汇编指令系列文章。欢迎阅读、点评与交流~
1、汇编指令在不同架构中的联系与区别
2、ARM 汇编指令:MOV
3、ARM 汇编指令:LDR
4、ARM 汇编指令:STR
5、ARM 汇编指令:MRS 和 MSR
6、ARM 汇编指令:ORRS
7、ARM 汇编指令:BEQ
8、ARM 汇编指令:TST
9、ARM 汇编指令:B
10、ARM 汇编指令:BX
11、ARM 汇编指令:ERET
12、ARM 汇编指令:STP\LDP
13、ARM 汇编指令:UBFX
14、ARM 汇编指令:STM
15、ARM 汇编指令:LDM
16、ARM 汇编指令:LSL(逻辑左移) 和 LSR(逻辑右移)
17、ARM 汇编指令:ROR(循环右移)
LSL 和 LSR 是 ARM 汇编中两个最基础且重要的移位指令。
核心概念:移位操作
在了解具体指令前,首先要明白移位 是什么。想象一个二进制数,比如 8 的 8 位二进制表示是 00001000。
- 左移 就是将所有位向左移动,空出的低位补 0。
00001000左移 1 位变成00010000(即 16)。左移一位通常相当于乘以 2。 - 逻辑右移 就是将所有位向右移动,空出的高位补 0。
00001000右移 1 位变成00000100(即 4)。逻辑右移一位通常相当于除以 2(向零取整)。
在 ARM 中,移位操作不仅可以单独使用,还能与大多数数据处理指令(如 ADD, MOV, CMP 等)免费结合 ,这是 ARM 指令集一个非常强大和灵活的特性。但我们先看作为独立指令的 LSL 和 LSR。
1. LSL - 逻辑左移
功能 :将寄存器中的二进制位向左移动指定的位数,右侧空出的低位用 0 填充。
本质:相当于无符号乘法(乘以 2^n)。
语法:
armasm
LSL{S} <Rd>, <Rm>, <Rs> ; 用寄存器 Rs 的值指定移位位数
LSL{S} <Rd>, <Rm>, #<imm5> ; 用立即数 imm5 (0-31) 指定移位位数
{S}:可选的条件标志更新后缀。如果加上S,则根据移位结果更新CPSR中的N(负标志)和Z(零标志)。移位操作也会影响C(进位标志)。<Rd>:目标寄存器。<Rm>:源操作数寄存器。<Rs>:存放移位位数的寄存器(通常只使用低 8 位)。#<imm5>:5 位立即数移位量(0-31)。
工作原理:
Before: Rm = [b31 b30 ... b1 b0]
After: Rd = [b31-n ... b0 0 ... 0] <-- n 个 0 填入低位
\___________/
向左移动 n 位
最后移出的那一位(原 b31-n+1 位)会进入 CPSR 的 C(进位)标志。
示例:
armasm
MOV R1, #5 ; R1 = 5 (二进制 00000101)
LSL R0, R1, #2 ; R0 = R1 << 2
; 计算过程: 00000101 << 2 = 00010100
; 结果: R0 = 20 (5 * 4)
armasm
MOVS R2, #0x80000001 ; R2 = 0x80000001,设置标志
LSLS R3, R2, #1 ; R3 = R2 << 1,并更新标志
; 计算过程: 1000...0001 << 1 = 0000...0010
; 结果: R3 = 0x00000002
; 标志变化:最后移出的 '1' 进入 C 标志,所以 C = 1。结果非零,所以 Z = 0。
2. LSR - 逻辑右移
功能 :将寄存器中的二进制位向右移动指定的位数,左侧空出的高位用 0 填充。
本质:相当于无符号除法(除以 2^n)。
语法:
armasm
LSR{S} <Rd>, <Rm>, <Rs> ; 用寄存器 Rs 的值指定移位位数
LSR{S} <Rd>, <Rm>, #<imm5> ; 用立即数 imm5 (1-32) 指定移位位数
注意 :立即数移位范围是 1-32 。当 #imm5 为 32 时,结果为 0,且最后移出的位进入 C 标志。
工作原理:
Before: Rm = [b31 b30 ... b1 b0]
After: Rd = [0 ... 0 b31 ... bn] <-- n 个 0 填入高位
\___________/
向右移动 n 位
最后移出的那一位(原 bn-1 位)会进入 CPSR 的 C(进位)标志。
示例:
armasm
MOV R1, #20 ; R1 = 20 (二进制 00010100)
LSR R0, R1, #2 ; R0 = R1 >> 2
; 计算过程: 00010100 >> 2 = 00000101
; 结果: R0 = 5 (20 / 4)
armasm
MOV R2, #0x80000001 ; R2 = 0x80000001
LSRS R3, R2, #1 ; R3 = R2 >> 1,并更新标志
; 计算过程: 1000...0001 >> 1 = 0100...0000
; 结果: R3 = 0x40000000
; 标志变化:最后移出的 '1' 进入 C 标志,所以 C = 1。结果非负非零,所以 N=0, Z=0。
关键点与进阶用法
-
移位量为 0 :对于
LSL #0,操作数不变,但可能影响C标志(C标志会被设置为ALU的进位输出,在移位量为0的特定情况下,其行为有详细规定,通常编程时可忽略此边界情况)。对于LSR #0,在 ARM 中实际表示LSR #32,这是一个特例。 -
桶形移位器 :ARM 处理器有一个称为"桶形移位器"的硬件单元,这使得移位操作可以在一个时钟周期内完成 ,并且可以与其他指令结合而无额外开销。这是 ARM 指令集高效的关键之一。
-
与其他指令结合(灵活的第二操作数) :
这是 ARM 汇编最常用的特性之一。几乎所有的数据处理指令(
ADD,SUB,MOV,CMP,AND,ORR等)的第二个操作数都可以先进行移位,然后再参与运算。armasmADD R0, R1, R2, LSL #2 ; R0 = R1 + (R2 * 4) CMP R3, R4, LSR #3 ; 比较 R3 和 (R4 / 8) MOV R5, R6, ROR #4 ; R5 = 将 R6 循环右移 4 位后的值 (ROR是另一种移位)这种结合极大地增强了指令的表达能力,一条指令完成了"移位+运算"。
-
与算术右移 ASR 的区别:
LSR是逻辑右移,高位补 0 。用于处理无符号数。ASR(算术右移)高位用原最高位(符号位)填充 。用于保持有符号数的符号,相当于有符号除法。
总结
| 指令 | 全称 | 方向 | 填充值 | 主要数学意义 | 典型用途 |
|---|---|---|---|---|---|
| LSL | Logical Shift Left | 向左 | 低位补 0 | 乘以 2^n | 快速乘法、位组装、掩码生成 |
| LSR | Logical Shift Right | 向右 | 高位补 0 | 无符号除以 2^n | 快速无符号除法、位提取、无符号数处理 |
掌握 LSL 和 LSR 是理解 ARM 高效编程和位操作的基础。务必通过实践来熟悉它们的行为,尤其是与条件标志和与其他指令结合使用的方式。