微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm汇编编程(示例)

arm汇编编程(示例)

时间:11-09 来源:互联网 点击:

包括:

子程序调用过程中寄存器的使用规则、数据栈的使用规则和参数的传递规则。

1.寄存器使用规则

寄存器:R4-R11用来保存局部变量

R0-R3(a1-a4)用于保存参数/返回结果/scratch(临时寄存器)

R4-R11(v1-v8)用于保存ARM状态局部变量

R12(IP)子程序内部调用的scratch

R13(SP)数据栈指针

R14(LR)连接寄存器

R15(PC)程序计数器

R7又可称为wr用于Thumb状态工作寄存器

R9又可称为sb在支持RWPI的ATPCS中为静态基址寄存器

R10又可称为sl在支持PWPI的ATPCS中为数据栈限制指针

R11又可称为fp用于帧指针

2.数据栈使用规则

ATPCS标准规定,数据栈为FD(满递减类型),并且对数据栈的操作是8字节对齐。在进行出栈和入栈操作,则

必须使用ldmfd和strnfd指令(或ldmia和stmdb)

3.参数的传递规则

参数:参数小于等于4,用R0-R3保存参数,参数多于4,剩余的传入堆栈

函数返回:结果为32位整数,通过R0返回

结果为64位整数,通过R0,R1返回

对于位数更多的结果,通过内存传递

例:参数传递及结果返回(r0-r3做参数,r0做返回值)

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序入口

Start

MOVR3,#4;设置实参,将参数写入R0-R3

MOVR2,#3

MOVR1,#2

MOVR0,#1

BLfunc1;调用子程序ADD_SUM

BOVER;跳转到OVER标号处,进入结尾

func1

ADDR0,R0,R1;实现两数相加

ADDR0,R0,R2

ADDR0,R0,R3

MOVPC,LR;子程序返回,R0内为返回的结果

OVER

END

相当于如下C语言

intfunc1(inta,intb,intc,intd){

returna+b+c+d;

}

intmain(){

func1(1,2,3,4);

}

例:多于4个参数,前4个通过寄存器R0-R3传递,其它参数通过数据栈传递

AREAExample,CODE,READONLY;声明代码段Example

ENTRY;程序入口

Start

STMFDSP!,{R1-R4,LR};先将R1-R4,及LR内原有数据压入栈,需要使用这五个寄存器

MOVR0,#1;准备好7个寄存嚣存入7个数据LR,IP,R4作临时寄存器使用

MOVIP,#2

MOVLR,#3

MOVR4,#4

MOVR1,#5

MOVR2,#6

MOVR3,#7

STMFDSP!,{R1-R3};先将R1-R3数据从前向后入栈,然后将IP,LR,R4内的数据装入R1-R3

MOVR3,R4;其中IP,LR,R4是临时使用的寄存器

MOVR2,LR

MOVR1,IP

BLfunc1;调用子程序funclR0是返回结果

LDMFDSP!,{R1-R4,PC};从栈中取出最初的数据,恢复原始值

BOVER;跳转到OVER标号处,进入结尾

func1

STMFDSP!,{R4,LR};当调用函数时,LR和R4都已发生了变化,其中LR是指令地址所以也压入栈

LDRR4,[SP,#0x10];目前共压入5个数据,每一个数据占两个字节,当前栈顶偏移10为前5个数据7

ADDLR,SP,#8;将前第4个数据的地址(栈项+偏移)赋给LR

LDMIALR,{IP,LR};连续将LR地址处的两个数据取出写入IP和LR内,从右向左写,LDMIA即出栈指令

ADDR0,R0,R1;从此行开始相当于returna+b+c+d+e+f+g;

ADDR0,R0,R2

ADDR0,R0,R3

ADDR0,R0,IP

ADDR0,R0,LR

ADDR0,R0,R4

LDMFDSP!,{R4,PC};从栈内取数据加载入R4和PC,PC跳转回主函数

OVER

END

下面是栈顶

相当于如下C语言

intfunc1(inta,intb,intc,intd,inte,intf,intg){

returna+b+c+d+e+f+g;

}

intmain(){

inta=1,b=2,c=3,d=4,e=5,f=6,g=7;

func1(a,b,c,d,e,f,g);

}

(二)、C和ARM汇编程序间的相互调用

1.汇编程序调用C子程序

为保证程序调用时参数正确传递,必须遵守ATPCS。

在C程序中函数不能定义为static函数。在汇编程序中需要在汇编语言中使用IMPORT伪操作来声明C子函数

//C代码

intsum5(inta,intb,intc,intd)

{

return(a+b+c+d);

}

//汇编代码

AREAExample,CODE,READONLY;声明代码段Example

IMPORTsum5;

ENTRY;程序入口

Start

MOVR3,#4;设置实参,将参数写入R0-R3

MOVR2,#3

MOVR1,#2

MOVR0,#1

BLsum5;调用子程序sum5

BOVER;跳转到OVER标号处,进入结尾

OVER

END

2.汇编程序访问全局C变量

汇编程序中可以通过C全局变量的地址来间接访问C语言中定义的全局变量

在编编程序中用IMPORT引入C全局变量,该C全局变量的名称在汇编程序中被认为是一个标号。通过ldr和str指令访问该编号所代表的地址

//C代码

inti=3;

intsum5(inta,intb,intc,intd)

{

return(a+b+c+d+i);

}

//汇编代码

AREAExample,CODE,READONLY;声明代码段Example

IMPORTsum5

IMPORTi

ENTRY;程序入口

Start

LDRR1,i;将i读入R1内

MOVR0,#2

ADDR0,R0,R1

STRR0,i;将寄存器值写入i内

MOVR3,#4;设置实参,将参数写入R0-R3

MOVR2,#3

MOVR1,#2

MOVR0,#1

BLsum5;调用子程序ADD_SUM

BOVER;跳转到OVER标号处,进入结尾

OVER

END

3.在C语言中调用汇编子程序

为保证程序调用时参数的正确传递,在汇编程序中需要使用EXPORT伪操作来声明汇编子程序,同时在C语言中使用extern扩展声明汇编子程序。

//汇编代码

EXPORTfunc1;func1为子函数名

AREAExample,CODE,READONLY;声明代码段Example

func1

ADDR0,R0,R

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top