arm基础汇编指令小结

来源:互联网 发布:windows阻止此软件 编辑:程序博客网 时间:2024/05/16 15:31

arm汇编指令:

1、算术和逻辑指令 2、比较指令3、跳转指令 4、移位指令5、程序状态字访问指令 6、存储器访问指令

1、算术和逻辑指令

MOV : 传送

(Move)

  MOV{条件}{S}  <dest>, <op 1>                dest = op_1
MOV 从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器。你可以指定相同的寄存器来实现 NOP 指令的效果,你还可以专门移位一个寄存器:
  MOV     R0, R0                  ; R0 = R0... NOP 指令  MOV     R0, R0, LSL#3           ; R0 = R0 * 8
如果 R15 是目的寄存器,将修改程序计数器或标志。这用于返回到调用代码,方法是把连接寄存器的内容传送到 R15:
  MOV     PC, R14                 ; 退出到调用者  MOVS    PC, R14                 ; 退出到调用者并恢复标志位                                    (不遵从 32-bit 体系)
 

MVN : 传送取反的值

(Move Negative)

  MVN{条件}{S}  <dest>, <op 1>                dest = !op_1
MVN 从另一个寄存器、被移位的寄存器、或一个立即值装载一个值到目的寄存器。不同之处是在传送之前位被反转了,所以把一个被取反的值传送到一个寄存器中。这是逻辑非操作而不是算术操作,这个取反的值加 1 才是它的取负的值:
  MVN     R0, #4                  ; R0 = -5  MVN     R0, #0                  ; R0 = -1

SUB : 减法

(Subtraction)

  SUB{条件}{S}  <dest>, <op 1>, <op 2>                dest = op_1 - op_2
SUB 用操作数 one 减去操作数 two,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
  SUB     R0, R1, R2              ; R0 = R1 - R2  SUB     R0, R1, #256            ; R0 = R1 - 256  SUB     R0, R2, R3,LSL#1        ; R0 = R2 - (R3 << 1)
减法可以在有符号和无符号数上进行。 


ADD : 加法

(Addition)

  ADD{条件}{S}  <dest>, <op 1>, <op 2>                dest = op_1 + op_2
ADD 将把两个操作数加起来,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
  ADD     R0, R1, R2              ; R0 = R1 + R2  ADD     R0, R1, #256            ; R0 = R1 + 256  ADD     R0, R2, R3,LSL#1        ; R0 = R2 + (R3 << 1)
加法可以在有符号和无符号数上进行。 


AND : 逻辑与

(logical AND)

  AND{条件}{S}  <dest>, <op 1>, <op 2>                dest = op_1 AND op_2
AND 将在两个操作数上进行逻辑与,把结果放置到目的寄存器中;对屏蔽你要在上面工作的位很有用。 操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
  AND     R0, R0, #3              ; R0 = 保持 R0 的位 0 和 1,丢弃其余的位。
AND 的真值表(二者都是 1 则结果为 1):
  Op_1   Op_2   结果  0      0      0  0      1      0  1      0      0  1      1      1

BIC : 位清除

(Bit Clear)

  BIC{条件}{S}  <dest>, <op 1>, <op 2>                dest = op_1 AND (!op_2)
BIC 是在一个字中清除位的一种方法,与 OR 位设置是相反的操作。操作数 2 是一个 32 位位掩码(mask)。如果如果在掩码中设置了某一位,则清除这一位。未设置的掩码位指示此位保持不变。
  BIC     R0, R0, #%1011          ; 清除 R0 中的位 0、1、和 3。保持其余的不变。
BIC 真值表 :
  Op_1   Op_2   结果  0      0      0  0      1      0  1      0      1  1      1      0


2、比较指令

CMP : 比较

(Compare)

 CMP{条件}{P}  <op 1>, <op 2>                status = op_1 - op_2
CMP 允许把一个寄存器的内容如另一个寄存器的内容或立即值进行比较,更改状态标志来允许进行条件执行。它进行一次减法,但不存储结果,而是正确的更改标志。标志表示的是操作数 1 比操作数 2 如何(大小等)。如果操作数 1 大于操作操作数 2,则此后的有 GT 后缀的指令将可以执行。
明显的,你不需要显式的指定 S 后缀来更改状态标志... 如果你指定了它则被忽略。

  

TST : 测试位

(Test bits)

  TST{条件}{P}  <op 1>, <op 2>                Status = op_1 AND op_2
TST 类似于 CMP,不产生放置到目的寄存器中的结果。而是在给出的两个操作数上进行操作并把结果反映到状态标志上。使用TST 来检查是否设置了特定的位。操作数 1 是要测试的数据字而操作数 2 是一个位掩码。经过测试后,如果匹配则设置 Zero 标志,否则清除它。象CMP 那样,你不需要指定 S 后缀。
  TST     R0, #%1                 ; 测试在 R0 中是否设置了位 0。 


3、跳转指令

B : 分支

(Branch)

  B{条件}  <地址>
B 是最简单的分支。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的 R15 的值的一个偏移量;而不是一个绝对地址。它的值由汇编器来计算,它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(+/- 32 M)。

在其他处理器上,你可能经常见到这样的指令:

  OPT 1  LDA &70  CMP #0  BEQ Zero  STA &72 .Zero RTS
(取自 Acorn Electron User Guide issue 1 page 213)

在 ARM 处理器上,它们将变成下面这些东西:

  OPT     1  ADR     R1, #&70  LDR     R0, [R1]  CMP     #0  BEQ     Zero  STR     R0, [R1, #2] .Zero  MOV     PC, R14
这不是一个很好的例子,但你可以构想如何更好的去条件执行而不是分支。另一方面,如果你有大段的代码或者你的代码使用状态标志,那么你可以使用条件执行来实现各类分支: 这样一个单一的简单条件执行指令可以替代在其他处理器中存在的所有这些分支和跳转指令。
  OPT     1  ADR     R1, #&70  LDR     R0, [R1]  CMP     R0, #0  STRNE   R0, [R1, #2]  MOV     PC, R14

BL : 带连接的分支

(Branch with Link)

  BL{条件}  <地址>
BL 是另一个分支指令。就在分支之前,在寄存器 14 中装载上 R15 的内容。你可以重新装载 R14 到 R15 中来返回到在这个分支之后的那个指令,它是子例程的一个基本但强力的实现。它的作用在屏幕装载器 2 (例子 4)中得以很好的展现...
    .load_new_format      BL     switch_screen_mode      BL     get_screen_info      BL     load_palette    .new_loop      MOV    R1, R5      BL     read_byte      CMP    R0, #255      BLEQ   read_loop      STRB   R0, [R2, #1]!
...在这里我们见到在装载器循环之前调用了三个子例程。接着,一旦满足了条件执行就在循环中调用了 read_byte 子例程。 


4、移位指令

逻辑或算术左移

(Logical or ArithmeticShift Left)

  Rx, LSL #n    or  Rx, ASL #n    or  Rx, LSL Rn    or  Rx, ASL Rn
接受 Rx 的内容并按用‘n’或在寄存器 Rn 中指定的数量向高有效位方向移位。最低有效位用零来填充。除了概念上的第 33 位(就是被移出的最小的那位)之外丢弃移出最左端的高位,如果逻辑类指令中 S 位被设置了,则此位将成为从桶式移位器退出时进位标志的值。

考虑下列:

  MOV    R1, #12  MOV    R0, R1, LSL#2
在退出时,R0 是 48。 这些指令形成的总和是 R0 = #12, LSL#2 等同于 BASIC 的 R0 = 12 << 2


循环右移

(Rotate Right)

  Rx, ROR #n    or  Rx, ROR Rn
循环右移类似于逻辑右移,但是把从右侧移出去的位放置到左侧,如果逻辑类指令中 S 位被设置了,则同时放置到进位标志中,这就是位的‘循环’。一个移位量为 32 的操作将导致输出与输入完全一致,因为所有位都被移位了 32 个位置,又回到了开始时的位置! 

5、程序状态字访问指令

操纵 32 位 PSR 的指令

你不能在 32 位模式中使用 MOVS PC, R14LDMFD R13!, {registers, PC}^。也不能使用ORRS PC, R14, #1<<28 来设置 V 标志。现在需要使用 MRSMSR

复制一个寄存器到 PSR 中  MSR     CPSR, R0                ; 复制 R0 到 CPSR 中  MSR     SPSR, R0                ; 复制 R0 到 SPSR 中  MSR     CPSR_flg, R0            ; 复制 R0 的标志位到 CPSR 中  MSR     CPSR_flg, #1<<28        ; 复制(立即值)标志位到 CPSR 中
复制 PSR 到一个寄存器中  MRS     R0, CPSR                ; 复制 CPSR 到 R0 中  MRS     R0, SPSR                ; 复制 SPSR 到 R0 中
指令格式

你有两个 PSR - CPSR 是当前的程序状态寄存器(Current Program Status Register),而 SPSR 是保存的程序状态寄存器(Saved Program Status Register)(前面的处理器模式的 PSR)。每个有特权的模式都有自己的 SPSR,可获得的 PSR 有:

  • CPSR_all - 当前的
  • SPSR_svc - 保存的,SVC(32) 模式
  • SPSR_irq - 保存的,IRQ(32) 模式
  • SPSR_abt - 保存的,ABT(32) 模式
  • SPSR_und - 保存的,UND(32) 模式
  • SPSR_fiq - 保存的,FIQ(32) 模式
你不能显式的指定把 CPSR 保存到哪个 SPSR 中,比如 SPSR_fiq。而是必须变更到 FIQ 模式并接着保存到 SPSR。换句话说,你只能在你所在的模式中改变这个模式的 SPSR。使用_flg 后缀允许你改变标志位而不影响控制位。

在 user(32) 模式中,保护 CPSR 的控制位,你只能改变条件标志。在其他模式中,可获得整个 CPSR。你不应该指定 R15 为一个源寄存器或一个目标寄存器。最后,在 user(32) 模式中,你不能尝试访问 SPSR,因为它不存在!

要设置 V 标志:

  MSR     CPSR_flg, #&10000000
这将设置 V 标志但不影响控制位。

要改变模式:

  MRS     R0, CPSR_all            ; 复制 PSR  BIC     R0, R0, #&1F            ; 清除模式位  ORR     R0, R0, #new_mode       ; 把模式位设置为新模式  MSR     CPSR_all, R0            ; 写回 PSR,变更模式

现在我们要做的是进入 SVC32 模式并设置 Z 标志。接着我们返回 SVC26 模式并‘测试’是否设置了 Z。
RISC OS 不希望发现自己处在 32 位模式中,所以我们要禁止所有中断并保持它们这样(keep them that way)。尽管这些代码应该执行的非常快,但我们不应当冒任何风险...

0 0
原创粉丝点击