首先介绍一个重要的寄存器——寄存器R14:子程序连接寄存器(Subroutine Link Register)或链接寄存器LR;
当使用BL指令调用子程序时,返回地址将自动存入R14中;
当发生异常时,将R14设置为异常返回地址(有些异常有一个小的固定偏移量)。
ARM指令可选后缀:
1、.s后缀
指令中使用s后缀时,指令执行后程序状态寄存器的条件标志位将被刷新,不使用s后缀时,指令执行后程序状态寄存器的条件标志位将不会发生变化。
s后缀通常用于对条件进行测试,例如是否有溢出,是否进位等,根据这些变化,就可以进行一些判断,如是否大于,是否相等,从而可能影响指令的执行顺序。
2、.!后缀
如果指令地址表达式中不含!后缀,则基址寄存器中的地址值不会发生变化。指令中的地址表达式中含有!后缀时,指令执行后,基址寄存器中的地址值将发生变化,变化的结果如下:基址寄存器中的值(指令执行后)=指令执行前的值+地址偏移量;
程序间的相互调用(注意空格和顶格的地方)
1、.s文件程序调用.s文件程序
asm1.s文件:
addr equ 0x80000100
IMPORT exp2 ;引入exp2,空一格
AREA ex1,code,readonly ;空一格
entry
code32
st ldr r0, =addr ;顶格
mov r1, #10
mov r2, #20
add r1, r1, r2
str r1, [r0]
mov r14,pc ;子程序连接寄存器
ldr pc,=exp2 ;程序计数器
b st
end
asm2.s文件:
EXPORT exp2 ;可以给外部程序引用,空一格
AREA exp2,CODE,READONLY ;空一格
CODE32
START LDR R4,=0x00090010 ;存储器访问地址
LDR R13,=0x00090200 ;堆栈初始地址
MOV R0,#0x0F100 ;立即数寻址
MOV R2,#10
MOV R1,R0 ;寄存器寻址
ADD R0,R1,R2
STR R0,[R4] ;寄存器间接
LDR R3,[R4]
MOV R0,R1, LSL#1 ;寄存器移位
STR R0,[R4,#4] ;基址变址
LDR R3,[R4,#4]!
STMIA R4!,{R0-R3} ;多寄存器寻址
LDMIA R4!,{R5,R6,R7,R8}
STMFD R13!,{R5,R6,R7,R8} ;堆栈寻址
LDMFD R13!,{R1-R4}
;B START ;相对寻址
mov pc,r14 ;程序计数器
END
2、.s调用.c文件程序
testqq.s文件:
import add
area asm,code,readonly
entry
st ldr r0,=0x1
ldr r1,=0x2
ldr r2,=0x3
bl add;
b st
end
add.c文件:
int add(int a,int b,int c)
{
return a+b+c;
}
3、.c调用.s文件程序
exadd.c文件:
extern int add(int x,int y);
int main()
{
int a=1,b=2,c;
c=add(a,b);
}
testadd.s文件:
export add
area add,code,readonly
st add r0,r0,r1
mov pc,lr
b st
end
4、.c调用.s文件(多参数)
main.c文件:
#define UINT unsigned int
extern UINT add_six(UINT a,UINT b,UINT c,UINT d,UINT e,UINT f);
int main(void)
{
add_six(1,2,3,4,5,6);
return 0;
}
mainadd.s文件:
export add_six
area add_six,code,readonly
code32
st
stmfd r13,{r4,r5}
ldr r4,[r13]
ldr r5,[r13,#4]
add r0,r0,r1
add r0,r0,r2
add r0,r0,r3
add r0,r0,r4
add r0,r0,r5
sub r3,r13,#8
ldmfd r3,{r4,r5}
mov r15,r14
b st
end