ARM(GNU)指令集
一、ARM汇编介绍
1、框架
Start.S
.section .data @数据段(可省略),.section可省略
<初始化的数据>
.section .bss @bss段(可省略),.section可省略
<未初始化的数据>
.section .text @代码段,.section可省略
.golbal _start
_start: @程序入口
<汇编代码>
2、链接器(ld/arm-linux-ld)
-T 指定链接脚本
-o 输出最终可执行二进制文件
-Ttext 指定代码段的起始地址
-Tdata 指定数据段的起始地址
-Tbss 指定未初始化数据段的起始地址
Makefile:
all:start.o
arm-linux-ld -Text 0x30000000 -o start.elf $^
%.0:%.S
arm-linux-gcc -g -o $@ $^ -c
clean:
rm *.o *.elf
3、链接器脚本
SECTIONS{
. = 0x30000000; #指出起始地址
. = ALIGN(4); #指出该地址四字节对其
.text :
{
main.o (.text)
*(.text)
}
. = ALIGN(4);
.data :
{
*(.data)
}
. = ALIGN(4);
bss_start = .;
.bss :
{
*(.bss)
}
bss_end = .;
}
二、ARM指令集
1、算数和逻辑指令
(1)mov:赋值
mov R0, R1 @R0=R1
(2)mvn:赋取反值
mvn R0, #4 @R0=~4 -> R0=-5
(3)sub:减法
sub R0, R1, R2 @R0=R1-R2
(4)add:加法
add R0, R1, R2 @R0=R1+R2
(5)and:逻辑与
and R0, R0, #3 @R0=R0&&3
(6)orr:逻辑或
orr R0, R0, #3 @R0=R0||3
(7)bic:位清除
bic R0, R0, #%1011 @1111 -> 0100
2、比较指令
(1)cmp:比较
cmp R0, R1
@ R0>R1 CPSR B=0 Z=0
@ R0=R1 CPSR B=1 Z=0
@ R0<R1 CPSR B=0 Z=1
(2)tst:按位与
tst R0, #%1001
@ (R0 & %1001)=0 -> CPSR Z=1
@ (R0 & %1001)!=0 -> CPSR Z=0
3、跳转指令
(1)b:跳转
b [条件] addr
(2)bl:跳转,带返回地址
bl fun @将返回地址存于lr
使用场景:
fun:
...
mov pc, lr @lr赋值给pc,实现函数返回
4、移位指令
(1)lsl:逻辑左移
mov R0, R1, ror#2 @R0=R1<<3
(2)ror:循环右移
mov R0, R1, ror#2 @R0=R1循环右移2位
5、程序状态字访问指令
(1)msr:通过寄存器赋值给程序状态寄存器
msr cpsr, r0 @cpsr=r0
(2)mrs:程序状态寄存器拷贝至通用寄存器
mrs r0, cpsr @r0=cpsr
6、 存储器访问指令
(1)ldr:将内存拷贝至寄存器
ldr r2, [r1] @r2=[r1] -> r2=*r1
(2)str:将寄存器拷贝至内存
str r0, [r1] @[r1]=r2 -> *r1=r2
三、伪指令
1、(32位)机器码组成,一条arm汇编指令的机器码
(1)数据处理机器码(以mov为例)
28-31 (cond)条件
26-27 保留
25 (I)源操作数(0-11位)保存为立即数,则该位为1
31-24 (opcond)指令编码
20 (S)是否影响标志位(CPSR)
16-19 (Rn)第一个源操作数,如果有多个源操作数
12-15 (Rd)目的寄存器
0-11 (shifter_operand)源操作数,mov等指令仅可以赋值8位数据
2、定义类伪指令
(1)global:全局标号
(2)ascii:字符串数据
.data
hello:
.ascii "hello world"
.align 4 @保证bdata地址为4字节对齐
bdata:
.byte 0x1
wdata:
.word 0xff
.golbal _start
_start:
(3)byte:字节数据
(4)word:双字节数据
(5)data:定义数据段
(6)equ:宏定义
3、操作类伪指令
(1)ldr:给寄存器赋值,可以赋值大于8位的数(mov只可以赋值8位以内的数值)
mov r0, #0xff
ldr r0, =x1ff @可以赋值8位以上的数据,立即数格式不同
(2)nop:空操作,可以用来延时