ARM汇编常用伪操作总结

发布者:陈熙琼最新更新时间:2016-11-27 来源: eefocus关键字:ARM汇编  伪操作 手机看文章 扫描二维码
随时随地手机看文章

在分析 2410 工程中启动代码的过程中,除了一些常用的汇编如 ldr,str,bic 等,还有一些很陌生的符号让我们很困惑,到网上一查资料,噢,原来是 ARM 的一些伪操作。为了在阅读启动代码的过程中不会出现很大的阅读与理解障碍,就总结了启动代码中用到的伪操作以供熟悉和查阅

PS: 这里说一下自己对汇编指令的看法,感觉就如英语单词似的,在进行阅读之前必须具备一些词汇量,但不需要精记,因为精记的话量太大太杂,不容易掌握,效果也不好。最好的方法是一些单词有一些大概的印象,也就是粗记,然后在阅读中不断的加强印象,最终牢固掌握它。

所以在这里不需要对所有的伪操作都记牢,配合着小例子先对其有个印象,然后在看启动代码的过程中不断的复习查阅,就能很快掌握之~~

 

 

全局操作

GET (或 INCLUDE )   

语法格式:   

    GET 文件名   

    GET 伪操作用于将一个源文件包含到当前的源文件中 ,并将被包含的源文件在当前位置进行汇编处理。可以使用 INCLUDE 代替 GET 。可以使用路径信息(路径信息中可以包含空格)。   

    汇编程序中常用的方法是在某源文件中定义一些宏指令,用 EQU 定义常量的符号名称,用 MAP 和 FIELD 定义结构化的数据类型,这样的源文件类似于 C 语言中的 .H 文件。然后用 GET 伪操作将这个源文件包含到其他的源文件中。使用方法与 C 语言中的 include   “*.h” 相似。   

    GET 伪操作只能用于包含源文件,包含目标文件需要使用 INCBIN 伪操作   

使用示例:   

    AREA Init , CODE , READONLY  

    GET a1.s ;通知编译器当前源文件包含源文件 a1.s  

    GET C:\project\file2.s ;通知编译器当前源文件包含源文件 C:\project\file2.s

END  

 

AREA

语法格式:   

AREA 段名 属性 1 ,属性 2 , ……  

    AREA 伪指令用于定义一个代码段或数据段 。其中,段名若以数字开头,则该段名需用 “ | ” 括起来,如 |1_test| 。还有一些代码段具有约定的名称,如 |.text| 表示 C 语言编译器产生的代码段或者是与 C 语言库相关的代码段。

    属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:   

    — CODE 属性:用于定义代码段,默认为 READONLY 。   

    — DATA 属性:用于定义数据段,默认为 READWRITE 。   

— NOINIT 属性:指定本数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各内存单元初始化为 0.

    — READONLY 属性:指定本段为只读,代码段默认为 READONLY 。   

    — READWRITE 属性:指定本段为可读可写,数据段的默认属性为 READWRITE 。       使用示例:   

    AREA Init , CODE , READONLY  

    该伪操作定义了一个代码段,段名为 Init ,属性为只读   

 

ENTRY  

语法格式:   

    ENTRY  

    ENTRY 伪操作用于指定汇编程序的入口点 。在一个完整的汇编程序中至少要有一个 ENTRY (也可以有多个,当有多个 ENTRY 时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个 ENTRY (可以没有)。   

使用示例:   

    AREA Init , CODE , READONLY  

    ENTRY ;指定应用程序的入口点   

    ……  

 

END  

语法格式:

     END

     END 伪操作用于通知编译器已经到了源程序的结尾 。   

使用示例:

    AREA Init , CODE , READONLY  

    ……  

END ;指定应用程序的结尾  

 

符号操作

ALIGN

语法格式:   

    ALIGN { 表达式 { ,偏移量 }}  

    ALIGN 伪指令可通过添加填充字节的方式,使当前位置满足一定的对其方式 。其中,表达式的值用于指定对齐方式,可能的取值为 2 的幂,如 1 、 2 、 4 、 8 、 16 等。若未指定表达式,则将当前位置对齐到下一个字的位置。偏移量也为一个数字表达式,若使用该字段,则当前位置的对齐方式为: 2 的表达式次幂+偏移量。   

下面的情况中,需要特定的地址对齐方式:

1 ) Thumb 的宏指令 ADR 要求地址是字对齐的,而 Thumb 代码中地址标号可能不是字对齐的。这时就要使用伪操作 ALIGN 4 使 Thumb 代码中的地址标号字对齐。

2 ) 由于有些 ARM 处理器的 CACHE 采用了其他对齐方式,如 16 字节的对齐方式,这时使用 ALIGN 伪操作指定合适的对齐方式可以充分发挥该 CACHE 的性能优势。

3 ) LDRD 以及 STRD 指令要求内存单元是 8 字节对齐的。这样在为 LDRD/STRD 指令分配的内存单元前要使用 ALIGN 8 实现 8 字节对齐方式。

4 ) 地址标号通常自身没有对齐要求。而在 ARM 代码中要求地址标号是字对齐的,在 Thumb 代码中要求字节对齐。这样需要使用合适的 ALIGN 伪操作来调整对齐方式。

使用示例:   

    在 AREA 伪操作中的 ALIGN 与 ALIGN 伪操作中表达式含义是不同的

AREA Init , CODE , READONLY , ALIEN = 3 ;指定后面的指令为 8 字节对齐。

 

CODE16 、 CODE32  

语法格式:

    CODE16 (或 CODE32 )   

    CODE16 伪操作告诉编译器,其后的指令序列为 16 位的 Thumb 指令 。   

    CODE32 伪操作告诉编译器,其后的指令序列为 32 位的 ARM 指令 。   

    若在汇编源程序中同时包含 ARM 指令和 Thumb 指令时,可用 CODE16 伪操作通知编译器其后的指令序列为 16 位的 Thumb 指令, CODE32 伪操作通知编译器其后的指令序列为 32 位的 ARM 指令。因此,在使用 ARM 指令和 Thumb 指令混合编程的代码里,可用这两条伪操作进行切换,但注意他们只是告诉编译器其后指令的类型,本身并不能对处理器进行程序状态的切换。   

使用示例:   

    AREA Init , CODE , READONLY  

    ……  

    CODE32 ;通知编译器其后的指令为 32 位的 ARM 指令   

    LDR R0 ,= NEXT + 1 ;将跳转地址放入寄存器 R0  

    BX R0 ;程序跳转到新的位置执行,并将处理器切换到 Thumb 工作状态    

    ……  

    CODE16 ;通知编译器其后的指令为 16 位的 Thumb 指令   

    NEXT LDR R3 ,= 0x3FF  

    ……  

    END ;程序结束

 

EQU ( “ * ” )

语法格式:   

    名称     EQU     表达式 { ,类型 }  

    EQU 伪操作用于为程序中的常量、基于寄存器的值和程序中的标号定义一个字符名称,其作用类似于 C 语言中的# define 。   

    名称为 EQU 伪操作定义的字符名称,表达式为基于寄存器的地址值、程序中的标号、 32 位的地址常量或者 32 位的常量。当表达式为 32 位的常量时,可以指定表达式的数据类型,可以有以下三种类型:   

    CODE16 、 CODE32 和 DATA  

使用示例:   

    Test EQU 50 ;定义标号 Test 的值为 50  

    Addr EQU 0x55 , CODE32 ;定义 Addr 的值为 0x55 ,且该处为 32 位的 ARM 指令。   

 

EXPORT (或 GLOBAL )   

语法格式:   

    EXPORT           符号       {[WEAK]}  

    EXPORT 伪操作声明一个符号可以被其他文件引用,相当于声明了一个全局变量 。 EXPORT 可用 GLOBAL 代替。符号在程序中区分大小写, [WEAK] 选项声明其他的同名符号优先于该符号被引用。   

使用示例:   

    AREA Init , CODE , READONLY  

    EXPORT DoAdd ;下面的函数名称 DoAdd 可以被其他源文件引用

DoAdd ADD r0,r0,r1

    END  

 

IMPORT  

语法格式:   

    IMPORT           符号     {[WEAK]}  

    IMPORT 伪操作告诉编译器当前的符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号 ,而且不论本源文件是否实际引用该符号,该符号均会被加入到本源文件的符号表中

    符号在程序中区分大小写, [WEAK] 指定这个选项后,如果符号在所有的源文件中都没有定义,编译器也不会产生任何错误信息,同时编译器也不会到当前没有被 INCLUDE 进来的库中去查找该符号。

使用 IMPORT 伪操作声明一个符号是在其他源文件中定义的。如果连接器在连接处理时不能解析该符号,而 IMPORT 伪操作中没有指定 [WEAK] 选项,则连接器会报告错误。如果连接器在连接处理时不能解析该符号,而 IMPORT 伪操作中指定了 [WEAK] 选项,则连接器将不会报告错误,而是进行下面的操作:

1 ) 如果该符号被 B 或者 BL 指令引用,则该符号被设置成下一条指令的地址,该 B 或者 BL 指令相当于一条 NOP 指令

2 ) 其他情况下该符号被设置为 0.

使用示例:   

    AREA Init , CODE , READONLY  

    IMPORT Main ;通知编译器当前文件要引用标号 Main ,但 Main 在其他源文件中定义 ……  

    END  

 

EXTERN  

语法格式:   

    EXTERN     符号     {[WEAK]}  

    EXTERN 伪操作告诉编译器当前的符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号。如果本源文件没有实际引用该符号,该符号将不会被加入到本源文件的符号表中。

注:与 IMPORT 的不同之处

使用示例:   

    AREA Init , CODE , READONLY  

    EXTERN Main ;通知编译器当前文件要引用标号 Main ,但 Main 在其他源文件中定义 ……  

END  

 

控制操作

MACRO  MEND  

语法格式:   

MACRO

          [$ label] macroname{ $ parameter1 , $ parameter ,……     }

          指令序列

    MEND   

    MACRO 伪操作标识宏定义的开始, MEND 标识宏定义的结束。用 MACRO 及 MEND 定义一段代码,称为宏定义体,这样在程序中就可以通过宏指令多次调用该代码段。

其中, $ label 在宏指令被展开时, label 会被替换成相应的符号,通常是一个标号。在一个符号前使用 $ 表示程序被汇编时将使用相应的值来替代 $ 后的符号。

macroname 为所定义的宏的名称。

$parameter 为宏指令的参数。当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数,可以在宏定义时为参数指定相应的默认值。   

    宏指令的使用方式和功能与子程序有些相似,子程序可以提供模块化的程序设计、节省存储空间并提高运行速度。但在使用子程序结构时需要保护现场,从而增加了系统的开销,因此,在代码较短且需要传递的参数较多时,可以使用宏汇编技术。   

    首先使用 MACRO 和 MEND 等伪操作定义宏。包含在 MACRO 和 MEND 之间的代码段称为宏定义体,在 MACRO 伪操作之后的一行声明宏的原型(包含宏名、所需的参数),然后就可以在汇编程序中通过宏名来调用它。在源程序被汇编时,汇编器将宏调用展开,用宏定义体代替源程序中的宏定义的名称,并用实际参数值代替宏定义时的形式参数。  

宏定义中的 $label 是一个可选参数。当宏定义体中用到多个标号时,可以使用类似 $label.$internallabel 的标号命名规则使程序易读。

    MACRO 、 MEND 伪操作可以嵌套使用。  

使用示例:

MACRO

$HandlerLabel   HANDLER   $HandleLabel         ; 宏的名称为 HANDLER ,有 1 个参数 $HandleLabel

 

$HandlerLabel

sub sp,sp,#4                    ;decrement sp(to store jump address)

stmfd sp!,{r0}                       ;PUSH the work register to stack(lr does not push because it return to original address)

ldr     r0,=$HandleLabel   ;load the address of HandleXXX to r0

ldr     r0,[r0]                   ;load the contents(service routine start address) of HandleXXX

str     r0,[sp,#4]           ;store the contents(ISR) of HandleXXX to stack

ldmfd  sp!,{r0,pc}          ;POP the work register and pc(jump to ISR)

MEND

 

;在程序中调用该宏

HandlerFIQ          HANDLER     HandleFIQ ;通过宏的名称 HANDLER 调用宏,其中宏的标号为 HandlerFIQ ,参数为 HandleFIQ

HandlerIRQ         HANDLER      HandleIRQ

HandlerUndef       HANDLER     HandleUndef

HandlerSWI                 HANDLER     HandleSWI

HandlerDabort      HANDLER     HandleDabort

HandlerPabort       HANDLER    HandlePabort

;程序被汇编后,宏展开的结果

HandlerFIQ

sub sp,sp,#4

stmfd sp!,{r0}

ldr     r0,=HandleFIQ

ldr     r0,[r0]

str     r0,[sp,#4]

ldmfd   sp!,{r0,pc}

 

IF 、 ELSE 、 ENDIF

语法格式:   

    IF 逻辑表达式   

    指令序列 1  

    ELSE  

    指令序列 2  

ENDIF  

    IF 、 ELSE 、 ENDIF 伪操作能根据条件把一段源代码包括在汇编程序内或者将其排除在程序之外。 [ 是 IF 伪操作的同义词, | 是 ELSE 伪操作的同义词, ] 是 ENDIF 伪操作的同义词。

    IF 、 ELSE 、 ENDIF 伪指令可以嵌套使用。   

使用示例:   

MACRO

MOV_PC_LR

[ THUMBCODE

bx lr

|

mov pc,lr

]

 

内存操作

DCD “ & ”(或 DCDU )   

语法格式:   

标号       DCD ( 或 DCDU)           表达式   

用于分配一段字内存单元并用伪操作中指定的表达式初始化 。其中,表达式可以为程序中的标号或数字表达式。

用 DCD 分配的字存储单元是字对齐 的,而用 DCDU 分配的字存储单元并不严格字对齐。   

使用示例:   

DataTest DCD   4,5,6              ; 其值分别为 4 , 5 和 6 。

data2     DCD   memaddr+4     ; 分配一个字单元,其值为程序中标号 memaddr 加 4 个字节

 

MAP ( “ ^ ” )

语法格式:   

     MAP     表达式   { ,基址寄存器 }  

    用于定义一个结构化的内存表的首地址 。

    表达式可以为程序中的标号或数字表达式,基址寄存器为可选项,当基址寄存器选项不存在时,表达式的值即为内存表的首地址,当该选项存在时,内存表的首地址为表达式的值与基址寄存器的和。   

    MAP 伪操作通常与 FIELD 伪操作配合使用来定义结构化的内存表。   

使用示例:   

    MAP 0x100 , R9   ; 定义结构化内存表首地址的值为 0x100 + R9 。

 

FILED   ( “ # ” )

语法格式:   

    标号       FIELD   表达式   

    用于定义一个结构化内存表中的数据域 。

    表达式的值为当前数据域在内存表中所占的字节数。   

    FIELD 伪操作常与 MAP 伪操作配合使用来定义结构化的内存表结构。 MAP 伪操作定义内存表的首地址, FIELD 伪操作定义内存表中的各数据域的字节长度,并可以为每个数据域指定一个标号供其他的指令引用。   

    注意 MAP 和 FIELD 伪操作仅用于定义数据结构,并不实际分配存储单元。   

示例 1 :   

    下面的伪操作序列定义一个内存表,其首地址为固定地址 4096 ,该内存表中包括 5 个数据域: consta 长度为 4 个字节; constb 长度为 4 个字节; x 长度为 8 个字节; y 长度为 8 个字节; string 长度为 256 个字节。这种内存表称为基于绝对地址的内存表。

 

   MAP 4096               ;内存表的首地址为 4096 ( 0x1000 )

 

   consta FIELD 4        ; consta 长度为 4 个字节,相对位置为 0

 

   constb FIELD 4        ; constb 长度为 4 个字节,相对位置为 5000

 

   x      FIELD 8        ; x 长度为 4 个字节,相对位置为 5004

 

   y      FIELD 8        ; y 长度为 4 个字节,相对位置为 5012

 

   string FIELD 256      ; string 长度为 256 字节,相对位置为 5020

 

; 在指令中可以这样引用内存表中的数据域:

LDR R6 , consta

 

上面的指令仅仅可以访问 LDR 指令前面(或后面) 4KB 地址范围的数据域

 

示例 2 :

下面的伪操作序列定义一个内存表,其首地址为 0 ,该内存表中包括 5 个数据域: consta 长度为 4 个字节; constb 长度为 4 个字节; x 长度为 8 个字节; y 长度为 8 个字节; string 长度为 256 个字节。这种内存表称为基于相对地址的内存表。

 

   MAP 4096               ;内存表的首地址为 0

 

   consta FIELD 4        ; consta 长度为 4 个字节,相对位置为 0

 

   constb FIELD 4        ; constb 长度为 4 个字节,相对位置为 4

 

   x      FIELD 8        ; x 长度为 4 个字节,相对位置为 8

 

   y      FIELD 8        ; y 长度为 4 个字节,相对位置为 16

 

   string FIELD 256      ; string 长度为 256 字节,相对位置为 24

 

; 可以通过下面的指令方便地访问地址范围超过 4KB 的数据

MOV R9 , #4096

LDR R5 , [R9,constb] ;将内存表中数据域 constb 读取到 R5 中

 

在这里,内存表中各数据域的实际内存地址不是基于一个固定地址,而是基于 LDR 指令执行时 R9 寄存器中的内容。这样通过上面方法定义的内存表结构可以在程序中有多个实例(通过在 LDR 指令中指定不同的基址寄存器值来实现)。通常用 R9 作为静态基址寄存器。


关键字:ARM汇编  伪操作 引用地址:ARM汇编常用伪操作总结

上一篇:移植u-boot到s3c2410开发板
下一篇:S3C2410 bootloader ----VIVI阅读笔记

推荐阅读最新更新时间:2024-03-16 15:22

ARM汇编编程基础之二-流水线对PC值的影响
CPU模型图,源自 http://teach.jwc.bupt.cn:4213/jsjzcyl/resource/cai/素材库/fig/Flash/5.1.swf 从上图中我们看到CPU内部有3个主要组成部分:指令寄存器,指令译码器,指令执行单元(包括ALU和通用寄存器组)。 CPU在执行1条指令的时候,主要有3个步骤:取指(将指令从内存或指令cache中取入指令寄存器);译码(指令译码器对指令寄存器中的指令进行译码操作,从而辨识出该指令是要执行add,或是sub,或是其它操作,从而产生各种时序控制信号);执行(指令执行单元根据译码的结果进行运算并保存结果) 现在我们假设一下:CPU串行执行程序(即:
[单片机]
ARM编程进阶之一-ARM汇编伪指令
到目前为止,我们已经具备编写较为复杂的ARM汇编程序的能力,但要编写较为复杂且实用的程序,我们就不得不掌握ARM汇编的伪指令(pseudo-instruction)。千万别把汇编伪操作(directive)与汇编伪指令(pseudo-instruction)弄混了,directive不会被编译器编译为机器指令,但pseudo-instruction会。而pseudo-instruction与指令(instruction)的区别在于,1条instruction与1条机器指令对应,而编译器会把1条pseudo-instruction编译为1条或多条机器指令。 ARM汇编伪指令共4条:ldr、adr、adrl、nop 1、ldr 首先
[单片机]
嵌入式工程师到底要不要学习ARM汇编指令?
嵌入式工程师到底要不要学习ARM汇编指令? 网上搜索这个问题,答案很多,大部分的建议是不要学汇编,只要学C语言。 而一口君作为一个十几年经验的驱动工程师,个人认为,汇编语言还是需要掌握的,想要搞精、搞深,汇编和计算机系统知识是必须的。 我们来列举一些问题 系统是如何启动的? 链接C语言的函数是如何调用的,参数是如何传递的? 如何使能关闭中断? 多核处理器是如何分配进程到某个核上运行的? MMU是如何实现的? 中断产生之后,cpu是如何处理的? 系统调用是如何实现的? 这些问题要想搞懂清楚就必须要搞懂汇编代码,搞懂arm架构。 系统启动、上电代码都是汇编,汇编不掌握,你如何知道系统是如何启动的? 想了解指针的
[单片机]
基于Android的ARM汇编语言系列之五:ARM指令集与Thumb指令集
章节列表 之一:ARM汇编语言开篇 之二:C/C++程序生成ARM汇编程序的过程分析 之三:ARM汇编语言程序结构 之四:ARM处理器的寻址方式 之五:ARM指令集与Thumb指令集 之六:NEON指令集与VFP指令集 写在前面:本篇文章旨在大致介绍下ARM指令集的相关内容,这里也同时提供一个有详细解释和用例的待书签的PDF版本,方便大家查阅。 ARM指令集详解 指令集是处理器的核心,ARM指令的基本格式如下所示: opcode {cond}{S}{.W\.N}Rd, Rn{.operand2} S:指定是否影响CPSR寄存器的值,如ADDS,SUBS等。 .W.N:指令宽度说明符。 Rd:目的寄存器。
[单片机]
基于Android的<font color='red'>ARM汇编</font>语言系列之五:ARM指令集与Thumb指令集
ARM汇编学习的总结
ARM汇编指令的一些总结 ARM汇编指令很多,但是真正常用的不是很多,而且需要认真琢磨的又更少了。 比较有用的是MOV B BL LDR STR 还是通过具体汇编代码来学习吧。 @ disable watch dog timer mov r1, #0x53000000 //立即数寻址方式 mov r2, #0x0 str r2, MOV没有什么好说的,只要掌握几个寻址方式就可以了,而且ARM的寻址方式比386的简单很多。立即数寻址方式,立即数要求以“#”作前缀,对于十六进制的数,还要求在#后面加上0x或者&。0x大家很好理解。有一次我碰到了&ff这个数,现在才明白跟0xff是一
[单片机]
【s3c2440】第二课:arm汇编指令
s3c2440 arm汇编指令以及使用示例 首先需要了解s3c2440CPU内部的寄存器有哪些: CPSR/SPSR寄存器格式: arm指令 (1)运算指令 (2)跳转指令 (3)协处理器相关指令 (4)数据转移指令 tips: db(Decrement Before):先减后存 ib(Increment Before):先增后存 da(Decrement After):先存后减 ia(Increment After):先存后增 (5)异常处理指令
[单片机]
【s3c2440】第二课:<font color='red'>arm汇编</font>指令
ARM汇编中^、!、cxsf符号和movs等指令使用
.macro restore_user_regs ldr r1, ldr lr, ! @ !用来控制基址变址寻址的最终新地址是否进行回写操作, @ 执行ldr之后sp被回写成sp+#S_PC基址变址寻址的新地址 msrspsr,r1 @ 把cpsr的值保存到spsr中 ldmdb sp,{r0 - lr}^ @lr= ,r13= ,r12= ,......,r0= @ 因为没对pc赋值,所以^的表示将数据恢复到User模式的 寄存器组中 mov r0,r0 add sp,sp,#S_FRAME_SIZE - S_PC movs pc,lr
[单片机]
<font color='red'>ARM汇编</font>中^、!、cxsf符号和movs等指令使用
ARM汇编调试
最近在学习ARM的汇编,但是ARM不像x86,可以很方便的调试。不过还好有虚拟机,而且还有GDB这样万能的调试器。Google了很久,又结合自己的实践,终于成功的调试了ARM的汇编,在此向对ARM嵌入式感兴趣的同学分享一下。 首先说明需要的工具 1. QEMU 这个模拟器不仅可以模拟x86,还可以模拟ARM和MIPS,可谓强大 2. GDB(源代码) 不用说了,万能调试器,但是需要从源代码编译 3. arm-linux交叉工具链 我用的是自己开发板配套的3.4版本,不过去 www.uclinux.org 随便下载一个就可以(不过貌似uclinux被GFW了 ) 先编译GDB,设置target为ARM平台: $ ./configu
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved