汇编文件一般为.S结尾(S大写,小写的s一般不会有预处理的过程和语句。大写的S一般有预处理等等)
首先编写一个main.S
main:
mov r0,#1
mov r1,#2
ldr r2,add_func_l
bl r2
die:
b die
add_func:
add r0,r0,r1
bx lr
.align 4
add_func_l:.word add_func
执行一个r0=r0+r1的操作。随后死循环
对这个文件执行编译
./arm-linux-gnueabihf-as -o main.o main.S
产生了.o文件
查看反汇编代码
./arm-linux-gnueabihf-objdump -d main.o
得到如下结果
main.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <main>:
0: e3a00001 mov r0, #1
4: e3a01002 mov r1, #2
8: e59f2010 ldr r2, [pc, #16] ; 20 <add_func_l>
c: ebfffffe bl 0 <r2>
00000010 <die>:
10: eafffffe b 10 <die>
00000014 <add_func>:
14: e0800001 add r0, r0, r1
18: e12fff1e bx lr
1c: e1a00000 nop ; (mov r0, r0)
00000020 <add_func_l>:
20: 00000014 .word 0x00000014
24: e1a00000 nop ; (mov r0, r0)
28: e1a00000 nop ; (mov r0, r0)
2c: e1a00000 nop ; (mov r0, r0)
看ldr r2,[pc,#16]这一句,将PC+16地址里面的值赋值给了r2。
随后bl r2就是跳转到r2这里执行。
计算过程如下。
由于arm采用流水式的执行方式,读取-解析-执行,这个是执行的流水线。PC永远比正在执行的语句快两条指令。
1
执行=NULL
解析=NULL
PC= mov r0, #1
2
执行=NULL
解析= mov r0, #1
PC=mov r1, #2
3
执行= mov r0, #1
解析=mov r1, #2
PC=ldr r2, [pc, #16]
4
执行= mov r1, #2
解析=ldr r2, [pc, #16]
PC=bl 0 <r2>
5
执行= ldr r2, [pc, #16]
解析=bl 0 <r2>
PC=b 10 <die>
这里开始执行 ldr r2,[PC,#16]
此时的PC指向b die也就是0x10的位置。所以 r2=[0x10+16]=[32]=[0x20]。此时0x20里面的值是0x14。因此r2=0x14
6
执行=bl 0 <r2>
解析=b 10 <die>
PC=add r0, r0, r1
执行bl的时候 会将PC-4放到lr里面。也就是b die的地址。同时流水线被清空。 PC也变化了
执行完整个函数
接下来执行b die 进入死循环