RAM学习路线03-RAM汇编语言

1. ARM汇编程序的结构

1.1 段

        ARM的汇编语言程序由段组成,段是相对独立的指令或数据单位,每个段由AREA伪指令定义,并定义段的属性:READONLY(只读)或READWRITE(读写)。AREA用于定义一个代码段或数据段,若段名以数字开头则该段名需要用“|”括起来,如“1_data”。
        在一个汇编程序中,至少包含一个或多个代码段;0个或多个初始化数据段;0个或多个未初始化数据段。

如汇编程序Hello.S:

@ Hello.S

/**
 * 1.代码段
 * 由CODE属性定义,READONLY表示只读
 */
AREA |.text|,CODE,READONLY
    ENTRY
    EXPORT sqr
    EXPORT num
sqr
    MUL r1, r0, r0
    MOV r0, r1
    MOV lr, pc

/**
 * 2.数据段
 * 由DATA属性定义,READWRITE表示读写
 */
AREA |.data|,DATA,READWRITE
num
    DCD 10

/**
 * 3.未初始化数据段
 * 由NOINIT属性定义,READWRITE表示读写
 */
AREA |.bass|,NOINIT,READWRITE
data
    SPACE 1024
    END
1.2 标识符

        在汇编程序里标识符用于表示指令或数据的地址,如Hello.S中的sqr和num。局部标识符是0~99的十进制数,局部标识符的引用格式为:
%{F|B}{A|T} N(0~99)
如:

2
  CMP r3, r1
  STRCC r2, [r3], #4
  BCC  %B2

其中,

  • F——只向前(forwards)搜索局部标识符
  • B——只向后(backwards)搜索局部标识符
  • A——在所有的宏里搜索局部标识符
  • T——只在当前宏里搜索局部标识符
    如果F和B都没指定,那么搜索的顺序先向后再向前;如果A和T都没指定,那么搜索的顺序只从但前宏向高层宏搜索。
    局部标识符的作用范围在当前ROUT和下一个ROUT之间,如:
LocalStart ROUT
  ...
1
  ...
2
  ...
LocalEnd ROUT

所有的标识符必须在一行开头顶格写不能有空格,标识符后不能加“:“。ARM汇编器对标识符的大小写敏感,标识符大小写要一致。

1.3 程序入口

        在C语言中程序的入口是main,而在ARM汇编语言中,用ENTRY来表示程序的入口。在一个源文件中只能指定一个入口,但在一个完整的项目中至少有一个入口,可以有多个。当有多个入口时,程序的真正入口点由链接器通过entry参数指定。
注意:在ARM汇编语言里,用ENTRY(大小写均可)来表示程序的入口。
在用armlink链接时,可以用参数entry来指定入口。

1.4 程序出口

        在汇编源文件里,用END来表示汇编源程序的结束。

1.5 包含其它汇编源文件

        GET将一个源文件包含到当前源文件中,并将被包含的源文件在当前位置展开进行汇编处理。INCLUDEGET有相同的作用。GET/INCLUDE只能用于包含源文件,包含其它类型的文件(如目标文件或数据文件)则需要用到INCBIN伪指令。

1.6 引用外部标识符

        IMPORT告诉编译器它后面的这个标识符要在当前源文件中使用,但是在其它源文件中定义的。如果在链接时找不到该标识符,链接就会报错:

Error:L6218E:Undefined sysmbol xxxx (referred from param.o)

如果在IMPORT时使用WEAK参数,在链接时即使找不到也不会报错,如:

IMPORT printff, WEAK

如果该标识符是B或BL的地址,如果链接时找不到,B或BL就无处可跳,那么B或BL指令就是一条空指令:NOP。
除B或BL的其它情况如果链接时找不到,标识符的值会被置成0。

2. ARM汇编程序的常量、变量

常量

  • 数字常量:num SETA 100ram_start DCD 0xC000000LDR R1, =&1000FFFF
  • 字符串常量:DCB “Hello,World”, CR
  • 逻辑常量:{TRUE}、{FALSE}
  • 字符常量:LDR R4, = #'B'
    变量的定义和赋值
  • 数字变量:LCLS num_1GBLA num_g
  • 字符串变量:LCLS s_lGBLS s_g
  • 逻辑变量:LCLL debug_lGBLL debug_g
    变量替换
    变量的替换通过操作符“$”来实现。

3. ARM汇编程序的运算符和表达式

数字表达式

  • 算术运算符:加、减、乘、除
  • 移位运算符:ROL、ROR、SHL、SHR
  • 逻辑运算符:AND、OR、NOT、EOR
    逻辑表达式
    逻辑表达式

    字符串表达式
  • LEN: 字符串长度: LEN : S
  • CHA: 0~255的整数转换成一个字符: CHA : M
  • STR: 转换成一个字符串: STR : N
  • LEFT: 返回某个字符串左端的一个字符串S : LEFT : N
  • RIGHT: 返回某个字符串右端的一个字符串S : RIGHT : N
  • CC: 将两个字符串连成一个字符串S1 : CC : S2
  • DEF: 用于判断是否定义了某个符号: DEF : S

4. ARM汇编程序的数据定义

        数据定义的目的是为特定的数据分配存储单元,同时对分配的存储单元进行初始化。
LTORG
LTORG用于声明一个文字池(literal pool)。

文字池是什么?
它是镶嵌在代码中的一段存储空间,用来存放常量。
用它来做什么?
文字池不能远离LDR指令,它必须在LDR指令前后4KB地址范围。

编译器会在每一个段的末尾放一个缺省的文字池,如果这个段很长这个缺省文字池和LDR的距离可能会超过4KB,那么LDR就失去了装载的功能。这种情况下就要自己在适当的地方加入新的LTORG来生命一个新的文字池,当然,条件时LDR的周围。

DCB、DCW、DCD和SPACE
DCB:用于分配一片连续的字节存储单元,并用指定的表达式初始化。可用“=”代替。

str DCB "This is a test"

DCW:用于分配一片连续的半字存储单元,并用指定的表达式初始化。

Halfword DCW 1,2,3

DCD:用于分配一片连续的字存储单元,并用指定的表达式初始化。

word DCD 4,5,6

SPACE:用于分配一片连续的存储区域并初始化0。可用“%”代替。

space SPACE 100

MAP和FILED
MAP:用于定义一个结构化内存表的首地址。MAP可用“^”代替。

MAP 0x100, R9   @ 内存表的首地址为:R9 + 0x100

FIELD:用于定于一个机构话内存表的数据域。FIELD可用“#”代替。语法格式如下:

{label} FELD expr

其中lable是可选的,当指令中包含这一项时,label的值为当前内存表的位置计数器{VAR}的值。expr表示本数据域在内存中所占的字节数,当汇编编译器处理了FIELD伪操作后,内存表计数器的值将加上expr。

5. ARM汇编程序的控制结构

选择结构

IF 逻辑表达式
    指令1
    ELSE
    指令2
ENDIF

循环结构

WHILE 逻辑表达式
    指令
WEND

6. ARM汇编程序实例

(1)计算一个以0结束的字符串包含的字符个数

PRESERVE8                       @ 伪指令指示当前文件保持堆栈为 8 字节对齐
    AREA str, CODE, READONLY
    ENTRY

start
    LDR R0, =val1
    MOV R1, #-1

count
    ADD R1, R1, #1              @ R1 = R1 + 1
    LDRB R2, [R0], #1           @ 读取字节数据,源地址加 1
    CMP R2, #0
    BNE count

    STR R1, rel
    SWI &11


    AREA data1, DATA            @ 数据段1
val1
    DCB "This is a example", 0
    ALIGN


    AREA data2, DATA            @ 数据段2
rel
    DCD 0

    END

(2)把字符串前面的0用空格替换

PRESERVE8
    AREA zero, CODE, READONLY  @ 段zero
blank EQU ''                   @ EQU 伪指令为数字常量,基于寄存器的值和程序中的标号定义一个名称。*与EQU同义
zero  EQU '0'                  @ EQU 伪指令的作用类似于 C 语言中的#define
    ENTRY

/**
 * 读取字符串的地址
 * 把空格和0装载到寄存器
 */
start
    LDR R0, =data
    MOV R1, #zero
    MOV R3, #blank

/**
 * 读取字符串的字符
 * 判断是否为0
 */
replace
    LDRB R2, [R0}, #1
    CMP R2, R1
    BNE done           /* 不为0,直接中断 */

    /**
     * 为0,把空格装载到0的位置,然后跳转循环
     */
    SUB R0, R0, #1
    STRB R3, [R0]
    ADD R0, R0, #1
    BAL replace

done
    SWI &11


    AREA data, DATA    @ 段data
val1 DCB "00000001"
    ALIGN

    END

7. 伪操作

        伪操作不像机器指令那样在计算机运行期间由机器执行,它是在源程序汇编期间由汇编程序处理的。

7.1 符号定义伪操作

符号定义(Symbol definition)伪操作主要用于定义变量定义寄存器名称等。包括以下伪操作:

  • GBLA、GBLL和GBLS        声明全局变量
  • LBLA、LBLL和LBLS        声明局部变量
  • SETA、SETL和SETS        给变量赋值
  • RLIST        为通用寄存器列表定义名称
  • CN        为协处理器的寄存器定义名称
  • CP        为协处理器定义名称
  • DN和SN        为VFP的寄存器定义名称
  • FN        为FPA的浮点寄存器定义名称
7.2 数据定义伪操作

数据定义(Data definition)伪操作包括:

  • LTORG        声明一个数据缓冲池的开始
  • MAP        定义一个结构化的内存表的首地址
  • FIELD        定义结构化的内存表中的一个数据域
  • SPACE        分配一块内存单元,并用0初始化
  • DCB        分配一段字节的内存单元,并用执行的数据初始化
  • DCD及DCDU        分配一段字的内存单元,并用指定的数据初始化
  • DCDO        分配一段字的内存单元,并将该单元的内容初始化成该单元相对于静态基值寄存器的偏移量
  • DCFD及DCFDU       分配一段双字的内存单元,并用双精度的浮点数据初始化
  • DCFS及DCFSU        分配一段字的内存单元,并用单精度的浮点数据初始化
  • DCI        分配一段字节的内存单元,用指定的数据初始化,指定内存单元中存放的是代码,而不是数据
  • DCQ及DCQU        分配一段双字的内存单元,并用64位的整数数据初始化
  • DCW及DCWU        分配一段半字的内存单元,并用指定的数据初始化
  • DATA        在代码段中使用数据。现已不再使用,只用于向前兼容。
7.3 汇编控制伪操作

汇编控制(Assembly control)伪操作包括:

  • IF、ELSE及ENDIF
  • WHILE及WEND
  • MACRO及MEND
  • MEXIT
7.4 框架描述伪操作

栈中数据描述伪操作主要用于调试。

7.5 信息报告伪操作

信息报告(Reporting)伪操作如下:

  • ASSERT
  • INFO
  • OPT
  • TTL及SUBL
7.6 其它伪操作

这些杂类的伪操作包括:

  • ALIGN
  • AREA
  • CODE16及CODE32
  • ENTRY及END
  • EQU
  • EXPORT及GLOBAL
  • EXTERN
  • GET及INCLUDE
  • IMPORT
  • INCBIN
  • KEEP
  • NOFP
  • REQUIRE
  • REQUIRE8及PRESERVE8
  • RN
  • ROUT

8. 伪指令

        伪指令在汇编编译器对源程序进行汇编处理时,被替换成对应的ARM或者Thumb指令(序列)。ARM伪指令包括:ADR、ADRL、LDR、NOP。

  • ADR:小范围的地址读取伪指令。该指令将基于PC的地址值或基于寄存器的地址值读取到寄存器中。
  • ADRL:中等范围的地址读取伪指令。比ADR伪指令可以读取更大范围的地址。
  • LDR:大范围的地址读取伪指令。将一个32位的常数或者一个地址值读取到寄存器中。
  • NOP:空操作伪指令。在汇编时将被替换成一个空操作。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 按照编译器不同,汇编分为两大量:一类是ADS的汇编程序,一类是GNU汇编格式任。 以冒号结尾的标识符都被认为是...
    柏666阅读 3,313评论 0 0
  • 数据处理指令: 数据处理指令只可用于寄存器之间或寄存器与立即数之间 移位指令 Rotate left(ROL) 可...
    jingr1阅读 5,066评论 0 2
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,183评论 0 9
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,779评论 0 27
  • 我刚刚走出一个非常难过的困境,所以想写些东西,坐在电脑前,我知道我不是这个世界最特别的那个,甚至无数的人一次一次告...
    总被当成变态怎么办阅读 399评论 0 4