APCS规则简述
- 寄存器使用规则
寄存器r0-r3用于函数调用过程中传递函数形参,各有一个别名 a1—a4,使用前后可以不用恢复原来的值
R4-r11用于保存函数内部局部变量的值,每个函数使用前,必须要保存被调用函数的值,使用完毕,必须恢复原值。各有一个别名叫v1-v8.
//特殊寄存器说明
R10 sl 栈限制
R11 fp 桢指针
R12 ip 内部过程调用寄存器
R13 sp 栈指针
R14 lr 连接寄存器
R15 pc 程序计数器
- 栈的使用规则
//APCS规则规定,AMR的栈采用满减使用指令
Stmfd sp!,{}
Ldmfd sp!{}
Push{}
Pop{}
- 调用函数时参数的传递规则
被调用的函数形参,如果小于等于四个,那么从左向右依次由r0-r3来传递参数
如果被调用函数的形参大于四个,那么从左向右前四个依然由r0-r3传递,其余通过堆栈传递。
函数的返回值被存入r0
汇编调用汇编函数
loop:
mov r0,r1 //将r1的值放入r0
add r1,r2;#32
bl loop //调用后返回现场
汇编调用C语言函数
我们通过反汇编
arm-linux-gcc –g –mapsc arg.c
arm-linux-gcc-objdump –Ds arg
发现在处理函数的时候都都会有这些话,前三行和后两行,他就是对现场的布置,就是函数的跳转和返回
mov ip, sp //IP=SP;保存SP
stmdb sp!, {fp, ip, lr, pc} //先对SP减4,再对fp,ip,lr,pc压栈。
sub fp, ip, #4 ; 0x4 //fp=ip-4;此时fp指向栈里面的“fp”
bl main //跳转到main函数
sub sp, fp, #12 ; 0xc //sp=fp-12;此时sp指向栈里面的lr
ldmia sp, {fp, sp, pc} //弹栈pc=lr,sp=ip,fp=fp。然后地址加4
纯汇编代码的编写
.text 关键字,用于声明代码段
.align 2 定义半字对齐,对齐代码
.global _start 声明全局变量.这个是程序入口声明,与链接脚本有关,链接脚本中将制定程序入口。
_start: 标号,定义程序入口。下面必须保存现场,所以需要使用5条指令
mov ip, sp //IP=SP;保存SP
stmdb sp!, {fp, ip, lr, pc} //先对SP减4,再对fp,ip,lr,pc压栈。
sub fp, ip, #4 ; 0x4 //fp=ip-4;此时fp指向栈里面的“fp”
bl main //跳转到main函数
sub sp, fp, #12 ; 0xc //sp=fp-12;此时sp指向栈里面的lr
ldmia sp, {fp, sp, pc} //弹栈pc=lr,sp=ip,fp=fp。然后地址加4
纯汇编的编译
获取过程 arm-linux-gcc –c demo.S 编译为 .o 目标文件
Arm-linux-ld demo.o –Ttext=0x50000000 –o arm
然后用nm工具看看arm 发现入口地址被指定为50000000
但是此时生成的文件具有头信息,
File arm 查看文件信息。发现很多ASCII码,机器无法识别,需要去头。
Arm-linux-objcopy –O binary arm arm.bin 使用objcopy工具,去头。