r0-r3:就是保存子程序的操作数。子程序返回时需要恢复这些寄存器值么?不!
r2在子程序中使用了,无需保存; r4是计数器,统计复制字符的个数,程序一开始就入栈了,结束时弹出,统计值通过r0返回。
若找不到动态链接库,只需要使用一个:
如果参数多于4个,就需要用栈来保存了。r12就是用来保存栈指针的,子程序返回时也不需要恢复r12.
r0经常被用做子程序返回值
r4-r11:这8个寄存器用来保存子程序的局部变量,返回时需要恢复。
r13: sp,堆栈指针,sp在进入子程序和退出子程序时要相等。
r14:链接寄存器 lr。保存子程序的返回地址,如果子程序中保存了返回地址,可以用做其它用途,但子程序返回时需要恢复。
r15: pc 程序寄存器。
在中断中,所有寄存器都必须保护,编译器会自动保护r4-r11
举个例子:
#include <stdio.h>
extern int strcopy(char *dst, const char *src);
int main()
{
int ret=0;
const char *src = "Hello world!";
char dst[] = "World Hello!";
printf("dst string is %s and src string is %s\n", dst, src);
ret = strcopy(dst, src);
printf("After copying %d chars and now dst string is %s\n", ret, dst);
return 0;
}
strcopy 子程序是汇编,要用extern修饰,.就是 .global, strcopy.S是通过寄存器r0和r1引用它们的。
strcopy.S 的内容
.setction .text
.align 2
.global strcopy
strcopy:
/*let r4 as a counter and return*/
push {r4}
mov r4, #0
1:
ldrb r2, [r1], #1 @load 完,地址自增1
strb r2, [r0], #1
cmp r2, #0
add r4, r4, #1
bne 1b
mov r0, r4 @as a return value
pop {r4}
mov pc, lr @continue to exec next instruction
r2在子程序中使用了,无需保存; r4是计数器,统计复制字符的个数,程序一开始就入栈了,结束时弹出,统计值通过r0返回。
r0, r1是子程序的参数
lr 是c函数调用子程序时,保存的函数需要执行的下一个地址,子函数返回时要赋给pc
这个函数的编译:
#arm-linux-gcc -c hello.c -o hello.o
#arm-linux-as -c strcopy.S strcopy.o
#arm-linux-ld hello.o strcpy.o -o hello
若找不到动态链接库,只需要使用一个:
arm-linux-gcc hello.o strcpy.o -o hello -v