一、ARM汇编介绍
1、框架
Start.S
.section .data @数据段(可省略),.section可省略
<初始化的数据>
.section .bss @bss段(可省略),.section可省略
<未初始化的数据>
.section .text @代码段,.section可省略
.golbal _start
_start: @程序入口
<汇编代码>
2、链接器(ld/arm-linux-ld)
(1)选项
-T 指定链接脚本
-o 输出最终可执行二进制文件
-Ttext 指定代码段的起始地址
-Tdata 指定数据段的起始地址
-Tbss 指定未初始化数据段的起始地址
Makefile:
all:start.o
arm-linux-ld -Text 0x30000000 -o start_elf $^
# arm-linux-ld -Tleds.lds -o start_elf $^
%.0:%.S
arm-linux-gcc -g -o $@ $^ -c
clean:
rm *.o *.elf
(2)链接器脚本
SECTIONS{
. = 0x30000000; #指出起始地址
. = ALIGN(4); #指出该地址四字节对其
.text :
{
main.o (.text)
*(.text)
}
. = ALIGN(4);
.data :
{
*(.data)
}
. = ALIGN(4);
bss_start = .;
.bss :
{
*(.bss)
}
bss_end = .;
}
SECTIONS {
firtst 0x00000000 : { head.o init.o }
#0xB0004000为程序执行(虚拟)地址(程序需要被拷贝到该地址才可以被正常执行),2048为存储地址
second 0xB0004000 : AT(2048) { leds.o }
}
3、拷贝工具(objcopy/arm-linux-objcopy)
-O binary //输出格式
-S //不拷贝符号信息
4、反编译(objdump/arm-linux-objcopy)
-D //反汇编,包括所有section
-m arm //指出指令集架构为arm
二、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
(8)ldmia:批量拷贝知道地址到寄存器
stmia r1!, {r3-r10} // 将r1指向的地址开始8个单元(8*4byte) 到r3-r10 寄存器
(9)strmia:批量将指定范围寄存器拷贝到指定地址
stmia r1!, {r3-r10} // 将r3-r10寄存器数据拷贝致 r1指定地址
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:(相对)跳转;相对跳转,位置无关的跳转(PCnew=PC+偏移)
b [条件] addr
(2)bl:(相对)跳转,带返回地址;相对跳转,位置无关的跳转(PCnew=PC+偏移)
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)adr:相对(PC寄存器)赋值
adr r0,_start
(3)str:将寄存器拷贝至内存
str r0, [r1] @[r1]=r2 -> *r1=r2
str r0, [r1], #4
@[r1]=r0; -> *r1=r0
@r1+=4;
三、伪指令
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位以上立即数数据,立即数表现格式不同
ldr r0, [r1], #4 @ r0=[r1]; r1+=4;
(2)nop:空操作,可以用来延时