首先介绍一个重要的寄存器——寄存器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