嵌入式Linux ARM汇编(六)——GNU ARM汇编编程

嵌入式Linux ARM汇编(六)——GNU ARM汇编编程

不同的汇编器对汇编语言的语法要求不一样。目前常用的ARM汇编环境有以下两种:

A、ARM ASM:ARM公司的汇编器,适合在Windows平台下使用

B、GNU ARM ASM:GNU交叉编译工具链中的汇编器,适合于Linux开发平台。

GNU汇编器是GNU工具集的一部分,用于将汇编语言文件转化为二进制obj文件。GNU汇编器针对的是多种处理器架构,这意味着GNU汇编器的语法不同于ARM工具链的汇编器。

一、GUN ARM汇编指令格式

1、GNU ARM汇编指令格式

GNUARM汇编指令的格式如下:

[<label>:][<instruction or directive or pseudo-instruction>} @comment

<label>: 为标号, GNU汇编中,任何以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。

Instruction:指令

Directive:伪操作

pseudo-instruction:伪指令

@comment:注释语句

2、标号label的解析

GNU ARM汇编指令中的标号只能由a~z,A~Z,0~9,“.”,_等(由点、字母、数字、下划线等组成,除局部标号外,不能以数字开头)字符组成。

标号label本质上代表它所在行的地址,因此也可以当作变量或者函数来使用。段内标号的地址值在汇编时确定,段外标号的地址值在连接时确定。

标号label依据生成方式分为三类:

A、基于PC的标号。基于PC的标号是位于目标指令前的标号或者程序中数据定义伪操作前的标号。这种标号在汇编时将被处理成PC值加上(或减去)一个数字常量,常用于表示跳转指令”b”等的目标地址,或者代码段中所嵌入的少量数据。

B、基于寄存器的标号。基于寄存器的标号常用MAP和FIELD来定义,也可以用EQU来定义。这种标号在汇编时将被处理成寄存器的值加上(或减去)一个数字常量,常用于访问数据段中的数据。

C、绝对地址。绝对地址是一个32位数据。它可以寻址的范围为[0x00000000,0xFFFFFFFF],即可以直接寻址整个内存空间。

局部标号的使用说明:

局部标号主要在局部范围内使用,而且局部标号可以重复出现。它由两部组成:开头是一个0-99直接的数字,后面紧接一个通常表示该局部变量作用范围的符号。局部变量的作用范围通常为当前段,也可以用ROUT来定义局部变量的作用范围。

局部变量定义的语法格式:N{routname}

A、N:为0~99之间的数字。

B、routname:当前局部范围的名称(为符号),通常为该变量作用范围的名称(用ROUT伪操作定义的)。

局部变量引用的语法格式:%{F|B}{A|T}N{routname}

A、%:表示引用操作

B、N:为局部变量的数字号

C、routname:为当前作用范围的名称(用ROUT伪操作定义的)

D、F:指示编译器只向前搜索

E、B:指示编译器只向后搜索

F、A:指示编译器搜索宏的所有嵌套层次

G、T:指示编译器搜索宏的当前层次

例:使用局部符号的例子,一段循环程序

1:

subs r0, r0, #1 @每次循环使r0=r0-1

bne 1F      @跳转到1标号去执行

如果F和B都没有指定,编译器先向前搜索,再向后搜索;

如果A和T都没有指定,编译器搜索所有从当前层次到宏的最高层次,比当前层次低的层次不再搜索。

如果指定了routname,编译器向前搜索最近的ROUT伪操作,若routname与该ROUT伪操作定义的名称不匹配,编译器报告错误,汇编失败。

二、GNU ARM汇编程序的分段

1、GNU ARM汇编中段的定义

GNU ARM汇编中通过.section伪操作来自定义一个段,格式如下:

.section section_name [, "flags"[, %type[,flag_specific_arguments]]]

Section_name:段名

Flags: ELF格式允许的段标志: a:可分配 w:可写段 x:执行段

Type:段类型

flag_specific_arguments:指定参数内容

定义一个段,每一个段以段名为开始,以下一个段名或者文件结尾为结束。

2、GNU ARM汇编系统预定义的段

.text    @代码段

.data    @初始化数据段 .data Read-write initialized long data.

.bss     @未初始化数据段

.sdata   @ .sdata Read-write initialized short data.

.sbss    @

注意:源程序中.bss段应该在.text段之前。

程序执行代码放于.text段,需要读写的数据放于.data段,只读数据放于.rodata段,未初始化数据放于.bss段

三、GNU ARM汇编程序的入口点

汇编程序的缺省入口是_start标号,用户也可以在连接脚本文件xxx.lds中用ENTRY标志指明其它入口点。

例:定义入口点

.section .data

< initialized data here>

.section .bss

< uninitialized data here>

.section .text

.globl  _start

_start:

<instruction code goes here>

四、GNU ARM汇编的宏定义

宏定义的格式如下:

.macro 宏名 参数名列表       @伪操作.macro定义一个宏

宏体

.endm @.endm表示宏结束

如果宏使用参数,那么在宏体中使用该参数时添加前缀“\”。宏定义时的参数还可以使用默认值。可以使用.exitm伪指令来退出宏。

五、GNU ARM汇编中的常数

A、十进制数以非0数字开头,如:123和9876;
B、二进制数以0b开头,其中字母也可以为大写;
C、八进制数以0开始,如:0456,0123;
D、十六进制数以0x开头,如:0xabcd,0X123f;
E、字符串常量需要用引号括起来,中间也可以使用转义字符,如: “You are welcome!\n”;
F、当前地址以“.”表示,在汇编程序中可以使用这个符号代表当前指令的地址;
G、表达式:在汇编程序中的表达式可以使用常数或者数值, “-”表示取负数, “~”表示取补,“<>”表示不相等,其他的符号如:+、-、*、 /、%、<、<<、>、>>、|、&、^、!、==、>=、<=、&&、|| 跟C语言中的用法相似。

六、GNU ARM汇编的伪操作

1、数据定义伪操作

A、.byte:单字节定义,如:.byte 1,2,0b01,0x34,072,‘s‘ ;
B、.short:定义双字节数据,如:.short 0x1234,60000 ;
C、.long:定义4字节数据,如:.long 0x12345678,23876565
D、.quad:定义8字节,如:.quad 0x1234567890abcd
E、.float:定义浮点数,如:
  .float 0f-314159265358979323846264338327\
  95028841971.693993751E-40 @ - pi
F、.string/.asciz/.ascii:定义多个字符串,如:
  .string "abcd", "efgh", "hello!"
  .asciz "qwer", "sun", "world!"
  .ascii "welcome\0"
需要注意的是:.ascii伪操作定义的字符串需要自行添加结尾字符‘\0‘。
G、.rept:重复定义伪操作, 格式如下:
  .rept 重复次数
  数据定义
  .endr @结束重复定义
  例如:
  .rept 3
  .byte 0x23
  .endr
H、.equ/.set: 赋值语句, 格式如下:
  .equ(.set) 变量名,表达式
  例如:
  .equ abc 3 @让abc=3

I、.int:定义一个整型

语法格式:.int expressions

2、.if伪操作

根据一个表达式的值来决定是否要编译下面的代码, 用.endif伪操作来表示条件判断的结束, 中间可以使用.else来决定.if的条件不满足的情况下应该编译哪一部分代码。

A、.ifdef label @判断label是否定义
B、.ifc string1,string2 @字符串string1和string2是否相等,字符串可以用单引号括起来
C、.ifeq expression_r @判断expression_r的值是否为0
E、.ifeqs string1,string2 @判断string1和string2是否相等,字符串必须用双引号括起来
F、.ifge expression_r @判断expression_r的值是否大于等于0
G、.ifgt absolute expression_r @判断expression_r的值是否大于0
H、.ifle expression_r @判断expression_r的值是否小于等于0
I、.iflt absolute expression_r @判断expression_r的值是否小于0
J、.ifnc string1,string2 @判断string1和string2是否不相等, 其用法跟.ifc恰好相反。
K、.ifndef symbol, .ifnotdef symbol @判断是否没有定义symbol, 跟.ifdef恰好相反
L、.ifne expression_r @如果expression_r的值不是0, 那么编译器将编译下面的代码
M、.ifnes string1,string2 @如果字符串string1和string2不相 等, 那么编译器将编译下面的代码.

3、操作码

A、NOP
       nop
       空操作, 相当于MOV r0, r0
B、LDR
          ldr <register> , = <expression>
       相当于PC寄存器或其它寄存器的长转移.
C、ADR
          adr <register> <label>
       相于PC寄存器或其它寄存器的小范围转移.

D、ADRL
          adrl <register> <label>
       相于PC寄存器或其寄存器的中范围转移。


4、其他伪操作

A、.end:表明源文件的结束

B、.extern:用于声明一个外部标号

语法格式:.extern label

C、.global/.globl:用来声明一个全局标号

语法格式:.global/.globl label

D、.zero、.space、.skip

分配number_of_bytes字节的数据空间,.zero伪操作用0填充内存,.space/.skip用值为fill_byte填充内存,若未指定该值,缺省填充0

语法格式:

.zero <number_of_bytes>
.space/.skip <number_of_bytes> {,<fill_byte>}

E、.reg、.unreq

.reg: 用来给寄存器赋予别名,格式如下:

别名 .req 寄存器名

.unreq: 用来取消一个寄存器的别名,格式如下:

.unreq 寄存器别名

注意被取消的别名必须事先定义过,否则编译器就会报错,这个伪操作也可以用来取消系统预制的别名,

F、.include:

语法格式:.include "filename"

在当前源文件中展开filename的内容。

G、.align

用来指定数据的对齐方式

语法格式:

.align [absexpr1, absexpr2]
  以某种对齐方式,在未使用的存储区域填充值. 第一个值表示对齐方式,

表示2^n字节对齐,第二个表达式值表示填充的值。

.balignl 4 0xdeadbeef   4字节对齐,l表示以四字节单位填充,填充0xdeadbeef

H、.incbin

.incbin伪操作可以将原封不动的一个二进制文件编译到当前文件中,语法格式:
  .incbin "file"[,skip[,count]]
 skip表明是从文件开始跳过skip个字节开始读取文件,count是读取的字数。

七、GUN ARM汇编中的寄存器

寄存器命名规范:

通用寄存器:R0--R15

栈指针寄存器:SP(R13)

帧指针寄存器:FP(R11)

链接寄存器:LR(R14)

程序计数器:PC(R15)

程序状态寄存器:xPSR, xPSR_all, xPSR_f, xPSR_x, xPSR_ctl, xPSR_fs,
xPSR_fx, xPSR_f, xPSR_cs, xPSR_cf, xPSR_cx

编程过程中对所有寄存器的赋值必须遵循AAPCS(The ARM Architecture Procedure Call Standard)。

八、GNU ARM汇编与ARM ASM汇编语法比较

GNU汇编器与ARM汇编器语法比较:


GNU Assembler


ARM ASM


备注


@


;


注释


#&


#0x


十六进制立即数


.if


IFDEF,IF


不完全相同


.else


ELSE


.elseif


ELSEIF


.endif


ENDIF


.ltorg


LTORG


|


:OR:


OR


&


:AND:


AND


<<


:SHL:


Shift left


>>


:SHR:


Shift right


.macro


MACRO


开始宏


.end


ENDM


结束宏


.include


INCLUDE


.word


DCB


A data word


.short


DCW


.long


DCD


.byte


DCB


.req


RN


.global


IMPORT


EXPORT


.equ


EQU

时间: 2024-08-24 07:56:40

嵌入式Linux ARM汇编(六)——GNU ARM汇编编程的相关文章

嵌入式 Linux进程间通信(六)——管道

嵌入式 Linux进程间通信(六)--管道 一.管道 管道是单向的.先进先出的.无结构的.固定大小的字节流.写进程在管道的尾端写入数据,读进程在管道的首端读出数据.数据读出后将从管道中移走,其它读进程都不能再读到这些数据.管道提供了简单的流控制机制.进程试图读空管道时,在有数据写入管道前,进程将一直阻塞:管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞.管道存在于系统内核之中,管道只能用于具有亲缘关系进程间的通信.管道是半双工的,数据只能向一个方向流动:需要双方通

嵌入式linux 项目开发(一)——HTML编程

嵌入式linux 项目开发(一)--HTML编程 本文主要讲解HTML的基础知识,主要是涉及嵌入式web服务器中数据交互HTML页面表单制作部分. 一.HTML简介 HTML是Hypertext Marked Language的简称,即超文本标记语言,是一种用来制作超文本文档的简单标记语言.HTML是由WEB的发明者Tim Berners-Lee和同事Daniel W.Connolly于1990年创立的一种标记式语言,是标准通用化标记语言SGML的应用. 用HTML编写的超文本文档称为HTML文

嵌入式linux 项目开发(一)——CGIC编程

嵌入式linux 项目开发(一)--CGIC编程 一.CGIC简介 1.CGI简介 CGI(Common Gateway Interface)是外部应用扩展应用程序与WWW服务器交互的一个标准接口.按照CGI标准编写的外部扩展应用程序可以处理客户端浏览器输入的数据,从而完成客户端与服务器的交互操作.而CGI规范就定义了Web服务器如何向扩展应用程序发送消息,在收到扩展应用程序的信息后又如何进行处理等内容.通 过CGI可以提供许多静态的HTML网页无法实现的功能,比如搜索引擎.基于Web的数据库访

外网访问ARM嵌入式Linux系统

外网访问ARM嵌入式Linux系统 实验室里的ARM嵌入式Linux系统,只能在局域网内访问,怎样从外网也能访问ARM嵌入式Linux系统? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动ARM嵌入式Linux系统 ARM嵌入式Linux系统默认的sshd端口是22. 2. 实现步骤 2.1 下载并解压holer软件包 Holer软件包:holer-linux-arm.tar.gz Holer支持多种ARM版本,请选择跟自己ARM版本匹配的holer程序上传至系统上. 2.2 获

简单翻译和补充:1. GNU ARM Eclipse

原文链接: GNU ARM Eclipse GNU 介绍: GNU 计划,又称革奴计划,是由RichardStallman在1983年9月27日公开发起的.它的目标是创建一套完全自由的操作系统.RichardStallman最早是在net.unix-wizards新闻组上公布该消息,并附带一份<GNU宣言>等解释为何发起该计划的文章,其中一个理由就是要"重现当年软件界合作互助的团结精神".为保证GNU软件可以自由地"使用.复制.修改和发布",所有GNU软

嵌入式Linux下S3C2410的调色板彩色显示

对于一个显示设备,数据的更新率正比于画面的像素数和色彩深度的乘积.在嵌入式Linux系统中,受处理器资源配置和运算能力的制约,当使用大分辨率显示时(如在一些屏幕尺寸较大的终端上,往往需要640×480以上),需要降低显示的色彩深度.否则,由于数据处理负担过重会造成画面的抖动和不连贯.这时,调色板技术将发挥重要作用.ARM9内核的S3C2410在国内的嵌入式领域有着广泛的应用,芯片中带有LCD控制器,可支持多种分辨率.多种颜色深度的LCD显示输出.在此,将S3C2410的调色板技术,以及嵌入式Li

嵌入式linux系统移植开发视频教程

深入浅出嵌入式linux系统移植开发(环境搭建.uboot的移植.嵌入式内核的配置与编译) 课程讲师:韩老师 课程分类:Linux 适合人群:中级 课时数量:56课时 用到技术:嵌入式Linux开发模式 涉及项目:基于tftp烧写系统 咨询qq:1840215592 课程介绍: 本课程重点是给大家讲解嵌入式linux系统移植的开发方法,采用理论与实践,硬件与软件相结合的方法. 1.在每节开始之前先简单回顾上一节所讲的主要内容,并对本节所讲的内容先进行概述,讲解概念.技术要点,设计实现思路等内容,

【课程分享】深入浅出嵌入式linux系统移植开发 (环境搭建、uboot的移植、嵌入式内核的配置与编译)

深入浅出嵌入式linux系统移植开发 (环境搭建.uboot的移植.嵌入式内核的配置与编译) 亲爱的网友,我这里有套课程想和大家分享,如果对这个课程有兴趣的,可以加我的QQ2059055336和我联系. 课程内容简介 本课程重点是给大家讲解嵌入式linux系统移植的开发方法,采用理论与实践,硬件与软件相结合的方法. 1.在每节开始之前先简单回顾上一节所讲的主要内容,并对本节所讲的内容先进行概述,讲解概念.技术要点,设计实现思路等内容,最后总结本次课程的要掌握的要点. 2.在讲课的过程中对关键技术

嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程

嵌入式Linux ARM汇编(七)--C语言与ARM汇编混合编程 在嵌入式系统开发中,目前使用的主要编程语言是C和汇编.在大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较好,便于人的理解,而且有大量的支持库.但是很多地方还是要用到汇编语言,例如开机时硬件系统的初始化,包括CPU状态的设定,中断的使能,主频的设定,以及RAM的控制参数及初始化,一些中断处理方面也可能涉及汇编.另外一个使用汇编的地方就是一些对性能非常敏感的代码块,这是不能依靠C编译器的生成代