GNU ARM汇编
来源:互联网 发布:c语言用数组求回文数 编辑:程序博客网 时间:2024/05/28 16:14
目 录
1 GNU ARM汇编... 3
1.1 基本语法... 3
1.2 GNU ARM汇编伪指令... 3
2 ATPCS约定... 3
2.1 寄存器使用规定... 3
3 汇编与C语言对照... 5
1 GNU ARM汇编
不同的汇编器对汇编语言的语法要求不一样。目前常用的ARM汇编环境有以下两种:
u ARMASM:ARM公司的汇编器,适合在Windows平台下使用
u GNU ARM ASM:GNU交叉编译工具链中的汇编器,适合于Linux开发平台。
本文主要讨论GNU ARM语法
1.1 基本语法
在GNU ARM汇编中,一行语句的基本格式如下:
标签:指令 @注释
解释如下:
u 标签可以代表“标签处的代码”也可以代表“标签处的数据的地址” 。
u 指令包括两种:ARM指令、汇编伪指令。
应用举例:
.text @ 代码段开始
.global add @ 声明add为全局标签,这样它就可以在其它文件中使用
add: @ 标签
add r0, r0, r1 @ 将两个参数相加,结果放在r0中
mov pc, lr @函数调用返回
1.2 GNU ARM汇编伪指令
伪指令均是以小数点开头。
此处略去具体的GNU ARM汇编伪指令,如需参考建议阅读何永琪主编的《嵌入式Linux系统实用开发》4.4节相关内容(原书P158页)。
2 ATPCS约定
在汇编语言与C语言混合编程的情况下,或者是各个源文件不是由同一个编译器进行编译的情况下,所有的汇编代码的生成(或编写)都必须遵循统一调用接口规范,这才能保证链接出来的程序功能是正确(即所写的汇编代码可直接与C语言相互调用)。
2.1 寄存器使用规定
ATPCS对通用寄存器的用途做了一些规定,并且根据不同用途为寄存器定义了别名,如下表2-1-1所示。
表2-1-1 通用寄存器的用途与别名
寄存器
别名
用途
r0
A1
函数参数和返回值
r1
A2
函数参数和返回值
r2
A3
函数参数
r3
A4
函数参数
r4
V1
变量
r5
V2
变量
R6
V3
变量
r7
V4
变量
R8
V5
变量
r9
V6, sb
变量,或静态数据基址
r10
V7, sl
变量,或栈限制
r11
V8, fp
变量,或帧指针
r12
Ip
函数调用中间临时寄存器
r13
Sp
栈指针
r14
Lr
链接寄存器
r15
Pc
程序计数器
r0 - r3 这4个寄存器用来传递函数调用第1到第4个参数,更多的参数则必须需要通过栈来传递。而r0同时用来存放函数调用的返回值。被调用的子程序在返回前无须恢复这些寄存器的内容。
r4 – r11 这8个寄存器可作为一般的临时变量使用(即局部变量),子程序进入时必须保存这些寄存器的值,在返回前必须返回前必须恢复这些寄存器的值【以便恢复上一个局部变量的值】。其中,r11(fp)是函数的帧指针。函数在栈中保存的所有的局部信息,包括返回地址、局部变量等构成了函数的帧。fp指向函数帧的第一个字,在函数执行过程中,fp保存不变。
r12(ip) 在函数调用时,用保存栈指针的临时寄存器。
r13(sp)
r14(lr) 用于保存子程序的返回地址。
r15(pc) 程序计数器,不能用作其它用途。
应用举例,见表2-1-2:
原sp(调用新函数前的栈指针)
Data(有数据)
4
fp(由于调用新的函数,而导致栈延长,这是新延长的栈开始的地方,我们称之为函数帧的指针,所有的信息。变量从这里开始存入)
Pc
0(新函数开始的地方)
Lr(内含子程序返回地址)
-4
ip(原sp)
-8
fp(原fp)
-12
a1
-16
a2
-20
Sp
a3
-24
3 汇编与C语言对照
汇编语言的结构:
① 开头声明
② 数据初始化
④函数(入栈、操作、出栈)
③ 被初始化的数据的地址(文字池)
注意:②和③联系比较大,但为了让③处在不会被执行的地方,所以将③放在④之后。
下面的例子是一个算术运算的汇编与C的对照,首先是C语言
/*文件名:test.c*/
/*说明:算术运算*/
int v1 = 1;
static int v2 = 2;
int main(void)
{
int vr;
int v3 = 3, v4 = 4;
vr = (v1 + v2 ) – ( v3 + v4 )
return vr;
}
以下为汇编语言的内容(请结合表2-1-2理解本程序):
.file “test.c”
.global v1 @声明v1为全局标签
.data @ 数据段开始
.align 2 @地址与4的倍数对齐
.type v1, %object @v1标签代表数据对象
.size v1, 4 @对象v1的长度为4
v1:
.word 1 @存放v1的初始值1
.align 2 @地址与4的倍数对齐
.type v2, %object @v2标签代表数据对象
.size v2, 4 @对象v2的长度为4
v2:
.word 2 @存放v2的初始值2
.text @ 代码段开始
.align 2
.global main @ 声明main为全局标签
.type main, %function @ main标签代表函数
main:
@ args = 0, pretend = 0, frame = 12
@ frame_needed = 1, uses_anonymous_args = 0
@入栈及开辟存放局部变量的空间
mov ip, sp @暂时用ip保存栈指针
stmfd sp!, {fp, ip, lr, pc} @入栈
sub fp, ip, #4 @ fp指向入栈的第一个元素(函数帧的开始)
sub sp, ip, #12 @在栈上开辟3个整形数的空间,用于存放局部变量
@给v3,v4赋初值
mov r3, #3
str r3, [fp, #-20] @将v3赋值为3
mov r3, #4
str r3, [fp, #-24] @将v4赋值为4
@计算表达式v1+v2,将结果放到r1中
ldr r3, .L2 @将变量v1的地址加载到r3
ldr r2, .L2+4 @将变量v2的地址加载到r2
ldr r1, [r3, #0] @将变量v1的值加载到r1
ldr r3, [r2, #0] @将变量v2的值加载到r3
add r1, r1, r3 @ v1+v2的结果放到r1中
@计算表达式(v3+v4),将结果放到r3中
ldr r2, [fp, #-20] @将变量v3的值加载到r2上
ldr r3, [fp, #-24] @将变量v4的值加载到r3上
add r3, r2, r3 @ (v1+v2)+(v3+v4)的结果放到r3中
@将(v1+v2)-(v3+v4)的值放到r3中,保存,返回
rsb r3, r3, r1 @将(v1+v2) - (v3+v4)的值放到r3之中
str r3, [fp, #-16] @将结果保存到vr中
ldr r3, [fp, #-16] @将vr的值加载到r3中
mov r0, r3 @将(v1+v2) - (v3+v4)的值放到r0中返回
@出栈
sub sp, fp, #12 @重设栈指针准备返回
ldmfd sp, {fp, sp, pc} @返回
.L3:
.align 2
.L2
.word v1 @变量v1的地址,即标号v1【使.L2获得v1的指针】
.word v2 @变量v2的地址,即标号v2
.size main, .-main @ main函数的大小,当前位置减去main标号处
.ident “GCC: (GNU) 3.4.4”
这里有点4需要注意的:
① 全局变量都被放在数据段上,数据段中保存的其实是变量的初始值
② 未用static声明的变量会被声明为.global,表示他可以链接到其它文件。
③ 加载全局变量实际上使用的是文字池的方法,即将变量地址放在代码段中某个不会执行到的位置,使用时先加载变量的地址,然后通过变量的地址得到变量的值。
④ 每条汇编指令只能执行一个简单的运算,计算的中间结果使用寄存器保存。如果表达式非常复杂以至于无法用寄存器保存所有的中间结果,则还会在栈上开辟局部变量来保存。【非静态的局部变量都放在栈上,通过帧指针和偏移量的方式来访问。帧指针(fp)在开始时设好,整个函数执行期间不会该变(而期间sp会改变)。】
声明:本博文为我学习《嵌入式Linux系统实用开发》时做的笔记,文中有很多内容摘自此书,当然也有我对一些较难知识点的思考、总结。
- GNU GAS (GNU ARM汇编)
- GNU ARM汇编指令
- arm gnu 汇编语法
- GNU ARM汇编入门
- GNU ARM汇编入门
- GNU ARM汇编入门
- arm gnu 汇编语法
- GNU ARM 汇编指令
- GNU ARM 汇编指令
- GNU ARM汇编入门
- GNU ARM汇编入门
- GNU ARM汇编
- GNU ARM 汇编指令
- GNU ARM 汇编指令
- arm gnu 汇编
- GNU ARM 汇编指令
- GNU ARM 汇编指令
- GNU ARM 汇编指令
- Android安卓手机通过VNC远程连接遥控XP桌面教程
- 用php获取本机的IP
- 在Android应用中使用SQLite数据库(传智播客视频笔记)
- Spring mvc (五) [ControllerClassNameHandlerMapping根据Controller类名匹配,解决了bean的递增配置问题]
- 程序员面试题精选100题(11)-求二元查找树的镜像[数据结构]
- GNU ARM汇编
- [刷提笔记] Codeforces187 A Permutations
- 二元查找树的后序遍历结果[数据结构]
- 堆排序
- Linux双向循环链表的实现
- 学习老盖《深入浅出》笔记之buffer cache(1)
- 黑马程序员_java交通灯系统案例
- 加油
- COUNT STOPKEY的优化