ARM汇编

 

参考文档:

 

ARM应用系统开发详解.pdf

http://student.csdn.net/link.php?url=http://blogimg.chinaunix.net%2Fblog%2Fupfile2%2F080124235942.pdf

 

GNU-ARM-Assy-Quick-Ref.pdf

http://student.csdn.net/link.php?url=http://blogimg.chinaunix.net%2Fblog%2Fupfile2%2F080125000015.pdf

 

GNU ARM汇编快速入门

 

 

GNU ARM汇编快速入门

前言:

以前用 ARM IDE 工具,使用的是 ARM 标准的汇编语言。现在要使用 GNU 的工具,当然要了解一点 GNU ARM 汇编的不同之处。其实非常的简单,浏览一下文档然后再看看程序就完全可以搞定了,或者你硬着头皮看 GNU ARM 的汇编程序,用不了多少时间你就就可以无师自通了。个人比较健忘,还是把文档翻译了一下,算是给自己一个避免遗忘的理由吧。

ARM
汇编语言源程序语句 , 一般由指令 , 伪操作 , 宏指令和伪指令作成 .ARM 汇编语言的设计基础是汇编伪指令 , 汇编伪操作和宏指令 .

目前常用的 ARM 编译环境有 2 种:
ARMASM: ARM
公司的 IDE 中使用了 CodeWarrior 的编译器,绝大多数 windows 下的开发者都在使用这一环境,完全按照 ARM 的规定;
GNU ARM ASM: GNU
工具的 ARM 版本,与 ARMASM 略有不同;

关于 CodeWarriror ARM 汇编的书和文章很多 , 本文假定你已经完全了解 ARMASM ,这里只说明 GNU ARM 汇编,并针对 ARMASM 给出说明。本文翻译自: GNU ARM Assembler Quick Reference 本人水平有限,错误难免,转载随意 , 请注明出处。英文原文地址不详。


GNU ARM 汇编快速入门


任何汇编行都是如下结构:

 

[<label>:] [<instruction or directive>} @ comment
[<
标签 >:] [< 指令 >} @ 注释

 

GNU ARM 汇编中,任何以冒号结尾的都被认为是一个标签,而不一定非要在一行的开始。下面是一个简单的例子,这段汇编程序定义了一个 "add" 的函数,该函数返回两个参数的和:

 

.section .text, “x”
.global add @ give the symbol add external linkage
add:
ADD r0, r0, r1 @ add input arguments
MOV pc, lr @ return from subroutine
@ end of program

 

 

 

GNU ARM汇编伪指令


下面列出了一些 GNU ARM 汇编伪指令,并给出了相应说明。


.ascii “<string>” 在汇编中定义字符串并为之分配存储空间(与armasm中的DCB功能类似)。
.asciz “<string>” 和 .ascii 类似 , 但不分配存储空间。

 

.balign <power_of_2> {,<fill_value> {,<max_padding>} }
以某种排列方式在内存中填充数值。 (该指令与 armasm 中的 ALIGN 类似 )
power_of_2表示排列方式,其值可为 4 8 16 32 ,单位是 byte
fill_value 是要填充的值;
max_padding 最大的填充界限,请求填充的 bytes 数超过该值,将被忽略。

 

.byte <byte1> {,<byte2>} … 定义一个或多个Byte,并为之分配空间(与armasm的DCB类似)。 

.code <number_of_bits> 设定指令宽度,16表示Thumb,32表示ARM assembly
(和armasm中的CODE16,CODE32相同)。

 

.if 
.else
.endif
预编译宏(与armasm中的IF ELSE ENDIF相同)。

 

.end 汇编文件结束标志,常常省略不用。


.endm 宏结束标志。
.exitm 宏跳出。
.macro <name> {<arg_1} {,<arg_2>} … {,<arg_N>}
定义一段名为name的宏,arg_xxx为参数。
必须有对应的.endm结尾。
可以使用 .exitm 从中间跳出宏。(与 armasm 中的 MACRO, MEND, MEXIT 相同)。
在使用宏参数时必须这样使用: “/<arg>”

例如 :
[CODE].macro SHIFTLEFT a, b
.if /b < 0
MOV /a, /a, ASR #-/b
.exitm
.endif
MOV /a, /a, LSL #/b
.endm


.rept <number_of_times> 循环执行.endr前的代码段number_of_times次。
(与armasm中的WEN相似)


.irp <param> {,<val_1>} {,<val_2>} …
循环执行 .endr 前的代码段, param 依次取后面给出的值。
在循环执行的代码段中必须以 “/<param> ” 表示参数。


.endr 结束循环 ( armasm 中的 WEND 相似 ).

 

.equ <symbol name>, <value> 为一个标号赋值,类似C中的#define。(与armasm中的EQU相同)

 

.err 编译错误报告,将引起编译的终止。

 

.global <symbol> 全局声明标志,这样声明的标号将可以被外部使用。(与armasm中的EXPORT相同)。

 

.hword <short1> {,<short2>} …
插入一个 16-bit 的数据队列。(与 armasm 中的 DCW 相同)

 

.ifdef <symbol> 如果 <symbol>被定义,该快代码将被编译。以 .endif结束。
.ifndef <symbol> 如果 <symbol>未被定义,该快代码将被编译。以 .endif结束。

 

.include “<filename>” 包含文件。(与armasm中的INCLUDE 或者C中的#i nclude一样)

 

<register_name> .req <register_name>
定义一个寄存器,.req的左边是定义的寄存器名,右边是使用的真正使用的寄存器。
(与 armasm 中的 RN 类似)
例如: acc .req r0

 

[CODE].section <section_name> {,”<flags>”}
开始一个新的代码或数据段。 .text, 代码段 ;.data, 初始化数据段 ;.bss, 未初始化数据段。
这些段都有缺省的标志( flags , 联接器可以识别这些标志。 ( armasm 中的 AREA 相同 )


下面是 ELF 格式允许的段标志
<标志 > 含义
a 允许段
w
可写段
x 执行段

 

.set <variable_name>, <variable_value> 变量赋值。(与armasm中的SETA相同)

 

.space <number_of_bytes> {,<fill_byte>}
分配number_of_bytes字节的数据空间,并填充其值为fill_byte,若未指定该值,缺省填充0。
(与 armasm 中的 SPACE 功能相同)

 

.word <word1> {,<word2>} …
插入一个 32-bit 的数据队列。(与 armasm 中的 DCD 功能相同)


GNU ARM汇编特殊字符和语法

 

代码行中的注释符号 : ‘@’
整行注释符号 : ‘#’
语句分离符号 : ‘;’
直接操作数前缀 : ‘#’ ‘$’

 

.arm arm 格式编译,同 code32
.thumb
thumb 格式编译,同 code16
.code16
thumb 格式编译
.code32
arm 格式编译

 

篇后语:


更详细的使用说明请参照: ARM Architecture Reference Manual, Addison-Wesley ISBN 0-201-73719-1

 

 原文地址 http://blog.csdn.net/dzassn/archive/2007/06/05/1638408.aspx

 

http://www.cppblog.com/milkyway/archive/2008/07/23/56916.html

对照Startup.s学习ARM汇编指令

(1)GBLL 伪指令用于定义一个全局的逻辑变量,并初始化为{False}。
GBLL    BOOTLOADER
BOOTLOADER   SETL    {TRUE}

(2)GET(或 INCLUDE)
GET 伪指令用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理。可以使用 INCLUDE 代替 GET。
INCLUDE ..//..//kernel//oal//startup.s

(3)IMPORT 伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中。
    IMPORT      BootloaderMain
IMPORT      MMUSetup
(4)BL  带返回的跳转指令
(5)BEQ表示“相等则跳转”,即当CPSR中的Z标志置位时发生跳转
B   Label    ;程序无条件跳转到标号Label处执行
CMP R1,#0   ;当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行
BEQ Label   

(6)LDR 指令的格式为:
LDR{条件} 目的寄存器,<存储器地址>
LDR 指令用于从存储器中将一个 32 位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取 32 位的字数据到通用寄存器,然后对数据进行处理。当程序计数器 PC 作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
指令示例:
LDR  R0,[R1]           ;将存储器地址为R1的字数据读入寄存器R0。
LDR  R0,[R1,R2]       ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR  R0,[R1,#8]      ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR  R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1
LDR  R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
LDR  R0,[R1],R2   ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR  R0,[R1,R2,LSL#2]!  ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR   R0,[R1],R2,LSL#2   ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。

(7)STR 指令的格式为:
STR{条件} 源寄存器,<存储器地址>
STR 指令用于从源寄存器中将一个 32 位的字数据传送到存储器中。与LDR对应

(8)采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。这种寻址方式可以用一条指令完成传送最多 16 个通用寄存器的值。以下指令:
LDMIA   R0,{R1,R2,R3,R4}   ;R1←[R0]
                                   ;R2←[R0+4]
                                  ;R3←[R0+8]
                                  ;R4←[R0+12]
该指令的后缀 IA表示在每次执行完加载/存储操作后,R0 按字长度增加,因此,指令可将连续存储单元的值传送到 R1~R4。

(9)SBC 指令的格式为:
SBC{条件}{S} 目的寄存器,操作数 1,操作数 2
SBC指令用于把操作数1减去操作数 2,再减去 CPSR 中的C 条件标志位的反码,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志 来表示借位,这样就可以做大于 32 位的减法。注意不要忘记设置 S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。
指令示例:
SUBS  R0,R1,R2     ; R0 = R1 - R2 - !C,并根据结果设置CPSR的进位标志位

(10)BX  带状态切换的跳转指令

(11)MCR 指令的格式为:
MCR{条件} 协处理器编码,协处理器操作码 1,源寄存器,目的寄存器 1,目的寄存器 2,协处理器操作码 2
MCR 指令用于将 ARM 处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1和协处理器操作码2为协处理器将 要执行的操作,源寄存器为 ARM 处理器的寄存器,目的寄存器1和目的寄存器2均为协处理器的寄存器。
指令示例:
MCR   P3,3,R0,C4,C5,6    ;该指令将ARM处理器寄存器R0中的数据传送到协处理器P3的寄存器C4和C5中。 

(12)CMP 指令的格式为:
CMP{条件} 操作数 1,操作数 2
CMP 指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新 CPSR 中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数 1 与操作数 2 的关系(大、小、相等),例如,当操作数 1 大于操作操作数 2,则此后的有 GT 后缀的指令将可以执行。
指令示例:
CMP R1,R0  ;将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位
CMP R1,#100 ;将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位

(13)批量数据加载/存储指令LDM(或 STM)指令的格式为:
LDM(或 STM){条件}{类型} 基址寄存器{!},寄存器列表{∧}
LDM(或 STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈(SDM)或出栈(LDM)。其中,{类型}为以下几种情况:
IA  每次传送后地址加 1;
IB  每次传送前地址加 1;
DA  每次传送后地址减 1;
DB  每次传送前地址减 1;
FD  满递减堆栈;
ED  空递减堆栈;
FA  满递增堆栈;
EA  空递增堆栈;
{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。

STMFD  R13!,{R0,R4-R12,LR}  ;将寄存器列表中的寄存器(R0,R4 到R12,LR)存入堆栈
LDMFD  R13!,{R0,R4-R12,PC} ;将堆栈内容恢复到寄存器(R0,R4到R12,LR)

(14)ORR 指令的格式为:
ORR{条件}{S} 目的寄存器,操作数 1,操作数 2
ORR 指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数 1
应是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数 1 的某些位。
指令示例:
ORR   R0,R0,#3             ; 该指令设置R0的0、1位,其余位保持不变。

(15)BIC 指令的格式为:
BIC{条件}{S} 目的寄存器,操作数 1,操作数 2
BIC指令用于清除操作数1 的某些位,并把结果放置到目的寄存器中。操作数 1 应是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即数。操作数 2 为 32 位的掩码,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不变。
指令示例:
BIC   R0,R0,#%1011     ; 该指令清除 R0 中的位 0、1、和 3,其余的位保持不变。

(16)
ADR(小范围的地址读取伪指令)
ADRL(中等范围的地址读取伪指令)
LDR(大范围的地址读取伪指令)
ldr     r0, =0xFFFFC000
用于将基于PC的地址或基于寄存器的地址读取到寄存器中。
///伪指令通过汇编编译器替换成对应的ARM/Thumb 指令。

以下指令的疑问:

ldr        r2, =(EbootImageSize/16)    // 加小括号代表什么?-----地址空间里存的数据

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值