3. 伪操作

Download Report

Transcript 3. 伪操作

微机原理与接口技术
第三章:汇编语言程序设计
主讲人:鞠 雷
山东大学
计算机科学与技术学院
内容提要
汇编语言源程序格式
2
ARM源程序文件
引入其他程序中
的变量或函数,在
本程序使用.
使用简单的文本
编辑器或者其他
.h文件给出函数
和变量的声明.
.c文件给出函数
扩展名
文件类型
的定义.
汇编语言文件
.s
C语言源文件
.c
C++源文件
.cpp
引入文件
.INC
头文件
.h
的编程开发环境
进行编辑.
3
Arm源程序汇编连接过程:
例 armasm hello.s
armlink hello.o -o hello.axf
armsd -exec hello.axf ;
armcc -g hello.s -o hello.axf
汇编语言源程序格式
1
汇编语言程序的结构
2
汇编语言的行构成
3
伪指令
1.汇编语言程序的结构
在ARM(Thumb)汇编语言程序中,以程序段为单位组织
汇编源程序示例第一部分
(test0源程序)
代码。
CODE32
ARM的汇编语言程序
;32位的ARM指令段
用AREA伪指令定义一个段,并说明所定义段的相关属性.
一般由几个段组成,
AREA codesec,
CODE, READONLY ;代码段,名称codesec,属性为
段是相对独立的指令或数据序列,具有特定的名称。
段可以分为多种,如代码段、
每个段均由AREA伪操
;只读
段分为代码段和数据段,代码段的内容为执行代码,数据段
数据段、通用段,每个段又有
作定义。
main PROC
;函数main
本程序定义了两个段,
存放代码运行时需要用到的数据。
不同的属性,代码段的默认
多个代码段的情况,一个源文件只能含一个代码段并单独编译,多
STMFD
sp!,{lr}
;保存返回地址到数据栈
第一个段为代码段codesec;
个代码段分别编译最后连接成映象文件。
一个汇编程序至少应该有一个代码段,当程序较长时,可以
属性为READONLY,数据段的默
ADR
r0,strhello
;取标签strhello的地址
可执行映象文件的构成:
分割为多个代码段和数据段,多个段在程序编译链接时最终形
认属性为READWRITE。
BL
_printf
;调用C运行时库的_printf函数
成一个可执行的映象文件。
一个或多个代码段,代码段的属性为只读。
;打印“Hello world!”字符串
零个或多个包含初始化数据的数据段,数据段的属性为可读写。
BL
welcomefun
;调用子函数welcomfun
零个或多个不包含初始化数据的数据段,数据段的属性为可读写。
LDMFD
sp!,{pc}
;返回调用函数
strhello
DCB
ENDP
;strhello代表本地字符串的地址
"Hello world!\n\0"
;定义一段字节空间
;函数main结束
1.汇编语言程序的结构
汇编源程序示例第二部分
welcomefun
;子函数welcomfun
STMFD
sp!,{lr}
;保存返回地址到数据栈
ADR
r0,adrstrarm
;取adrstrarm的地址放到寄存器r0中
LDR
r0,[r0,#0]
;将strarm的值放到r0中
BL 本程序定义了两个段,
_printf
;调用C运行时库的_printf函数打印
; “Welcom to ARM world!”字符串
第二个段为数据段constdatasec
LDMFD
sp!,{pc}
adrstrarm
DCD
;返回调用函数
;adrstrarm标签
strarm
;保存strarm的地址
AREA constdatasec, DATA, READONLY,ALIGN=0
;
7
1.汇编语言程序的结构
导出main函数供
汇编源程序示例第三部分
其他程序使用.
strarm
DCB
导入main PROC
ENDP,在本程序
"Welcome to ARM world!\n\0"使用.
;存放“Welcome to ARM
; world!”字符串
EXPORT main
;导出main函数供外部调用
;引入三个C运行时库函数和ARM库
IMPORT _main
IMPORT __main
IMPORT _printf
导入ARM库。
WEAK,若导入
符号不存在不给
出错误信息.
IMPORT ||Lib$$Request$$armlib||, WEAK
END
;源程序结束
8
2.汇编语言的行构成
 格式:
[标签] 指令/伪操作 操作数 [;语句的注释]



所有的标签必须在一行的开头顶格写,前面不能留空格,后面不
加“:”;
ARM汇编器对标识符的大小写敏感,书写标号及指令时字母的大
小写要一致;
注释使用“;”符号,注释的内容从“;”开始到该行的结尾结束。
 例:


Labeladd add r0,r0,r1
;加法指令
Str1
SETS “This is a string.”
;给字符串Str1赋值
9
2.汇编语言的行构成
1.标签:









标签是一个符号,可以代表指令的地址、变量、数据的地址和常数。

一般以字母开头,由字母、数字、下划线组成。

标签不能采用关键字。
标签(标号)代表可执行语句地址。
标号按其作用域可分为段内标号和和段外标号:
段内标号的地址值在汇编时确定。
例
welcomefun
段外标号的地址值在链接时确定。
例
EXPORT main
段外调用:BL main
局部标号,宏中使用的标号称之为局部标号。
10
2.汇编语言的行构成
2.指令/伪操作:
指令/伪操作的助记符或者定义符,通知ARM的处理器应该执
行什么样的操作或者通知汇编程序伪操作的功能。
3.操作数
由寄存器名、变量名和常量组成的表达式。
例 add r0,r1, r2
x dcd 0x12
11
2.汇编语言的行构成
伪操作使用的常量:
 数字常量(伪操作不加#)
 十进制数,如1、2、123
 十六进制数,如 0x123,0xabc
 2_1010
 字符常量
 由单引号及中间的字符组成,包括C语言中的转义字符,
如‘\a’,‘\n’ ( 响铃,换行)
 字符串常量
 由一对双引号及中间的字符串表示,中间也可以使用C语
言中的转义字符,比如:“abcdef\a\r\n”
 逻辑常量
 {TRUE},{FALSE},注意带大括号
12
3.伪操作
Ø
Ø
Ø
1.
2.
3.
没有相对应的操作码或者机器码,通常称为伪指令。
作用是为完成汇编程序作各种准备工作的,由汇编程序在源程
序的汇编期间进行处理,仅在汇编过程中起作用 (取地址伪指令
与其他伪指令有较大区别) 。
有如下几种伪操作:
符号定义伪操作 定义一个内存变量。
数据定义伪操作 分配连续内存并初始化。定义多个连续内存变
量。
汇编控制伪操作 控制汇编过程。
13
3. 伪操作
1. 符号定义伪操作(定义一个内存变量)


用于定义ARM汇编程序中的变量、对变量赋值等。
符号定义有如下几种伪操作:
用于定义局部变量的LCLA、LCLL、LCLS
(在宏中使用,不讲)
 用于定义全局变量的GBLA、GBLL、GBLS ;
 用于对变量赋值的SETA、SETL、SETS ;
局部变量在宏中定义使用!

14
3.伪操作
GBLA、GBLL、GBLS 伪操作
定义一个汇编程序中的全局变量。
格式:GBLA/ GBLL/ GBLS 变量名
定义一个全
局的数字变
量,并初始
化为0
定义一个全
局的逻辑变
量,并初始
化为F
定义一个全
局字符串变
量,并初始
化为空串
全局变量在整个程序范围内变量名必须唯一。
15
3.伪操作
例:






GBLA
num1
GBLL
l2
GBLS
str3
num1 ;定义一个全局的数字变量num1,初值0
SETA 0xabcd
l2
;定义一个全局的逻辑变量,变
;量名为l2,初值为F
SETL {FALSE} ;将该变量赋值为假
str3
;定义一个全局的字符串变量str3,初值空串。
SETS “Hello!”
16
3.伪操作
SETA、SETL、SETS
格式:变量名 SETA/SETL/SETS
III.
表达式
给一个数 给一个逻 给一个字
字变量赋 辑变量赋 符串变量
值
值
赋值
格式中的变量名必须为已经定义过的全局或
局部变量,表达式为将要赋给变量的值。
17
3.伪操作
例:
num1
;定义全局数字变量
 num1
SETA 0x1234 ;赋值为0x1234
 GBLS
str3
;定义全局字符串变量
 str3
SETS “Hello!” ;赋值为“Hello!”
 GBLA
18
3.伪操作
2. 数据定义伪操作
定义多个连续内
存变量.

分配存储单元,并初始化。

数据定义有如下几种伪指令:
 DCB
分配字节
定义连续内存空
间.
 DCW/DCWU 分配半字
 DCD/DCDU
分配字
 SPACE
定义内存表.
 MAP
 FIELD
19
3.伪操作
I.
DCB
DCB用于分配一块字节单元并用伪指令中指定的表
达式进行初始化。
格式:标号/变量 DCB 表达式
DCB可用“=”
代替
例:
表达式可以为
使用双引号的
字符串或0255的数字
Array1 DCB
1,2,3,4,5
;数组
str1
“Your are welcome!”
;构造字符串
DCB
;并分配空间
20
3.伪操作
II.
DCW/DCWU
格式:标号/变量 DCW/DCWU 表达式
DCW分配若干个半字存
储单元并用表达式值初
始化,存 储空间半字对
齐。
DCWU 功 能 跟
DCW 类 似 , 只 是
分配的字存储单元
不严格半字对齐
例:
Arrayw1 DCW
0xa,-0xb,0xc,-0xd
;构造固定数组并分
; 配半字存储单元
21
3.伪操作
DCD/DCDU
格式:标号/变量
III.
DCD/DCDU
分配若干个字存储单元并用
表达式初始化,存储空间字
对齐。也可用“&”代替
表达式
DCDU 只 是
分配的存储
单元不严格
字对齐
例:
Arrayd1 DCD 1334,234,345435 ;构造固定数组并分配
Label
DCD str1
;字为单元的存储单元
;该字单元存放str1的地址
22
3.伪操作
SPACE
格式: 标号 SPACE
IV.
表达式
SPACE用于分配一片连
续的存储区域并初始化
为0,也可用“%”代替
表达式为要
分配的字节
数
例:
Freespace
SPACE
1000
;分配1000字节的存储空间
23
3.伪操作
V.
MAP
格式:MAP
MAP 定 义 一
个结构化的
内存表的首
地址。
表达式
[,基址寄存器]
表 达 式 可 内存表首地址=
以为程序
(基址寄存器)+表达式
中的标号
或数学表
达式
MAP可以与FIELD伪操作配合使用来定义结构化的内存
表。
例:
MAP 0x130,R2
;内存表首地址为0x130+R2
24
3.伪操作
VI.
FILED
格式:标号 FIELD
字节数
定义一个结构化内存表中数据
域的的字节数。
可用“#”来代替FILED
FIELD常与MAP配合使用:
MAP
定义内存表的首地址
FIELD 定义内存表中的各个数据域的字节数并分配存储单元。
25
3.伪操作
例:
MAP 0xF10000
;定义结构化内存表首地址为
;0xF10000
count FIELD 4 ;定义count的长度为4字节,
;位置为0xF10000
x
FIELD 4 ;定义x的长度为4字节,位置
;为0xF10004
y
FIELD 4 ;定义y的长度为4字节,位置
;为0xF10008
26
其他伪操作
1. AREA
格式: AREA 段名 属性,……
AREA 用 于 定 义 一个
代码段、数据段或者
特定属性的段
属性部分表示该代码段/数
据段的相关属性,多个属
性可以用“,”分隔。
常见属性如下:
DATA:定义数据段。
 CODE:定义代码段。
READONLY:表示本段为只读。
READWRITE:表示本段可读写。
27
其他伪操作
 一个汇编程序至少应该包含一个代码段,当程序太长时,也可
以将程序分为多个代码段和数据段。
 例:
出现非法字符”.”,
以”||”使其合法化.

AREA test,CODE,READONLY

AREA ||.text||, CODE, READONLY
28
其他伪操作
2. CODE16、CODE32
格式: CODE16/CODE32
CODE16伪操作指示 CODE32伪操作指示
编译器后面的代码为 编译器后面的代码为
16位的Thumb指令
32位的ARM指令
在汇编源代码中同时包含Thumb和ARM指令时,须用
“CODE32”和“CODE16”伪指令通知编译器其后的指令序列
的类型。
“CODE32”和“CODE16”不能对处理器进行状态的切换。
29
其他伪操作
3. ENTRY
格式: ENTRY
ENTRY用于指定汇编程序的入口。
在一个完整的汇编程序中至少要有一
个ENTRY,也可以有多个。
下面的代码使用了ENTRY:
AREA subrout, CODE, READONLY
ENTRY
;指定程序入口
start
MOV
r0, #10
MOV
r1, #3
BL
doadd
;设置参数
;调用子函数
30
其他伪操作
stop
MOV
LDR
SWI
doadd
ADD
MOV
END
r0, #0x18
r1, =0x20026
0x123456
;设置软中断输入参数
r0, r0, r1
pc, lr
;子函数代码
;子函数返回
; 源文件结束
;调用ARM 软中断返回
;cpu控制权交给调试器
31
其他伪操作
4. END
格式: END
END告诉编译器
已经到了源程序
的结尾
例:
AREA
constdata,DATA,READONLY
……
END
;结尾
32
其他伪操作
5. EQU
格式:名称
EQU
表达式[,类型]
将程序中的数字常量、标号
赋予一个等效的名称。
若表达式为32位的常量或32位地址
常量,可以指定表达式的数据类型。
有以下三种类型:
DATA
表明该地址处为数据区
CODE16 表明该地址处为
thumb指令
例:
num1
EQU 1234
addr5
EQU str1+0x50
;定义num1为1234
CODE32 表明该地址处为arm指
令
d1 EQU 0x2400,CODE32
;定义d1的值为0x2400,且
;该处为32位的ARM指令
33
其他伪操作
6. EXPORT
格式: EXPORT
标号[,WEAK]
EXPORT 在程序中声
明一个全局标号,其他
文件中的代码可以引用
该标号。用户也可以用
GLOBAL代替EXPORT
[,WEAK]可选项
若其他文件有同
名的标号,则其
他文件同名标号
优先被引用。
例:
AREA
||.text||,CODE,READONLY
main
PROC
……
ENDP
EXPORT main
END
;声明一个可全局引用的函数main
34
其他伪操作
7. IMPORT
格式: IMPORT 标号 [,WEAK]
通知编译器此标号在当
前源文件中使用,但标号是
在其他的源文件中定义的。
[,WEAK]选项表示如果所有
的源文件都没有找到这个标号
的定义,编译器也不会提示错
误信息。
不管当前源文件是否使用
过该标号,这个标号都被加
出错时该标号置为0。如果
入到当前源文件的符号表中 这个标号被B或BL指令引用,
例:
则将B或BL指令替换为NOP操
作。
AREA
mycode,CODE,READONLY
IMPORT
END
_printf
;通知编译器当前文件要引用函
;数_printf
35
其他伪操作
8. EXTERN
格式: EXTERN
标号 [,WEAK]
通知编译器此标号在当前
源文件中使用,但标号是在其
他的源文件中定义的。
[,WEAK]选项表示如果所有
的源文件都没有找到这个标号
的定义,编译器也不会提示错
误信息。
与IMPORT不同的是,如果
出错时该标号置为0。如果
该标号未被引用,则该标号不
被加入到当前文件的符号表中。 这个标号被B或BL指令引用,
则将B或BL指令替换为NOP操
例:
作。
AREA
||.text||,CODE,READONLY
EXTERN
_printf ,WEAK
;告诉编译器当前文件要引用标
;号,如果找不到,则不提示错误
36
END
其他伪操作
9. INCBIN
格式: INCBIN
文件名
INCBIN将一个数据文件或者目标
文件包含到当前的源文件中,编
译时被包含的文件不作任何变动
的存放在当前文件中,编译器从
例: 后面开始继续处理。
AREA
INCBIN
INCBIN
constdata,DATA,READONLY
data1.dat
;源文件包含文件data1.dat
E:\DATA\data2.bin ;源文件包含文件
;E:\DATA\data2.bin
END
37
ARM Procedure Call Standard (APCS)
 ARM过程调用规范
 一套函数调用者与被调用之间的协议
 对寄存器使用的限制。
 使用栈的惯例。
 在函数调用之间传递/返回参数。
 可以被‘回溯’的基于栈的结构的格式,用来提供从
失败点到程序入口的函数(和给予的参数)的列表。
 APCS 不一个单一的给定标准,而是一系列类似但在
特定条件下有所区别的标准
 牺牲部分的系统性能,提升程序的通用性
APCS
 子程序间通过寄存器R0-R3来传递参数,这时,寄存器R0-R3
可以记作A1-A4。被调用的子程序在返回前无需恢复寄存器R0R3的内容。
 在子程序中,使用寄存器R4-R11来保存局部变量.这时,寄存
器R4-R11可以记作V1-V8。如果在子程序中使用到了寄存器
V1-V8中的某些寄存器,子程序进入时必须保存这些寄存器的
值,在返回前必须恢复这些寄存器的值;对于子程序中没有用
到的寄存器则不必进行这些操作。在Thumb程序中,通常只能
使用寄存器R4-R7来保存局部变量。
 寄存器R12用作子程序间scratch寄存器(用于保存SP,在函数
返回时使用该寄存器出栈),记作ip。在子程序间的连接代码
段中常有这种使用规则。
APCS
 寄存器R13用作数据栈指针,记作sp。在子程序中寄存器R13
不能用作其他用途。寄存器sp在进入子程序时的值和退出子程
序时的值必须相等。
 寄存器R14称为连接寄存器,记作lr。它用于保存子程序的返回
地址。如果在子程序中保存了返回地址,寄存器R14则可以用
作其他用途。
 寄存器R15是程序计数器,记作pc。它不能用作其他用途。
补充习题
1、利用全局变量和局部变量声明伪操作及其赋值伪操
作,分别定义算术变量、逻辑变量和串变量并为其赋
值。
2、读懂下面一段程序,子程序dststr执行过程中寄存器R0、
R1、R2中的内容如何变化?试分析并给出子程序执行后的
结果(dststr所存内容)。
AREA StrCopy, CODE, READONLY
ENTRY
; mark the first instruction to call
start
LDR
r1, =srcstr
; pointer to first string
LDR
r0, =dststr
; pointer to second string
BL
strcopy
; call subroutine to do copy
stop
MOV
r0, #0x18
LDR
r1, =0x20026
SWI
0x123456
strcopy
LDRB
r2, [r1],#1
STRB
r2, [r0],#1
CMP
r2, #0
BNE
strcopy
MOV
pc,lr
; Return
AREA Strings, DATA, READWRITE
srcstr DCB "First string - source",0
dststr DCB "Second string - destination",0
END
AREA max_min, CODE, READONLY
ENTRY
ldr r0,=BUFF
LDR R1,[R0];R1=MAX 最大值
MOV R2,R1 ;R2=MIN 最小值
MOV R4,#0 ;counter
BEGIN
LDR R3,[R0]
CMP R3,R1
BLT LESS
MOV R1,R3
LESS
CMP R3,R2
BGT GREAT
MOV R2,R3
44
GREAT
ADD R0,R0,#4 ;
ADD R4,R4,#1
CMP R4,#9
BNE BEGIN
str r1,max
str r2,min
MOV
r0, #0x18
LDR
r1, =0x20026
SWI
0x123456
AREA data, DATA, READWRITE
BUFF DCD 0,-1,2,-3,4,5,6,7,9
max dcd 0
min dcd 0
END
45