【笔记来源:广州大学汇编课程】
一、处理器结构和汇编语言
1.1 计算机语言
1.高级语言
主要是设计应用程序,有良好的库和模组,方便调用和代码的快速实现。
C/C++、java、python、C#、JS、…
2.汇编语言
底层语言,是直接和硬件(处理器的寄存器)打交道的。
汇编语言是和处理器的架构相关的----不同架构的处理器,汇编语言是不一样的。
3.机器语言
机器语言是二进制的机器码。处理器真正执行的代码。
1.2 汇编语言的特点
- 直接和硬件打交道,代码的执行效率比较高
//C语言
void delay(void)
{
int i=0x1000;
while(i--);
}
//高级语言:Linux
void delay(void)
{
sleep(2);
}
//汇编语言:
delay:
mov r4, #0x1000
temp:
sub r4,r4,#1
cmp r4,#0
bne temp
mov pc,lr
- 汇编语言比较节省内存。
现在汇编语言应用的场合:8位的单片机 - 有些场合用高级语言是实现不了的,必须用汇编语言
例如:处理器的初始化,内存初始化,stack初始化、中断的响应过程等。----BIOS程序或者嵌入式平台启动引导程序。 - 记很多汇编指令,代码编写效率低,不能使用现成的库。
1.3 处理器架构
每一种架构的处理器都有它的汇编语言,不同架构之间的汇编语言是不通用的,所以汇编语言是和处理器的架构是相关的。
1、处理器—PC平台
CPU ---- Central Process Unit 。
x86 ---- intel 和 AMD
PowerPC ---- nxp(恩智浦)
2、嵌入式微处理器
MPU ---- Micro Process Unit
ARM ----- ARM公司
RISC-V ---- 相当于Linux,开源免费
Coldfile ---- NXP
MIPS---- ARM公司
3、控制器—单片机
MCU — Micro Control Unit
通常是8位的,做一些简单的控制。
51单片机
AVR单片机
STM8单片机
PIC单片机
1.4 什么是ARM?
ARM公司–>华为海思—>台积电(ASML光刻机)–>麒麟处理器–>华为手机
- ARM是一种处理器的架构
ARM— Advanced RISC Machine 高级的精简指令集计算机系统的机器。
总部英国剑桥。ARM—>softbank—>Navid(英伟达) - ARM也是一家公司的名字
- ARM公司只设计处理器的架构,不生产芯片。
设计ARM芯片的公司:三星、高通、博通、恩智浦、Atmel、海思、…
ARM的中文名—安谋
1.5 ARM处理器的系列
1.V4T
ARM7
ARM9
2.V5TE
ARM10
3.V6
ARM11
4.V7
cortex-A8
Cortex-A9
Cortex-A15
5.V8------>8核64bits处理器。
ARM的内核:Cortex-A53、Cortex-A55,Cortex-A72/A73、Cortex-A77.
实验室:
ARM—>V8—>Cortex-A53—>S5P6818–>samsung
1.6 ARM的框架
以S5P6818处理器为例:
二、计算机平台的硬件功能
1、处理器
程序的运行、数据的处理、接口控制。
S5P6818 ----- 1.4GHz * 8
2、硬盘(电子硬盘–存储内存)
存放数据和代码,但是代码和数据不能在硬盘上运行和处理。硬盘上的数据掉电不丢失,可以永久保存。
辅助存储器—SD卡、U盘、移动硬盘
eMMC-----8GB
3、内存(运行内存–DDR3)
存放正在处理的数据和正在执行的代码。
DDR2 ---- 1GB
4、接口
液晶屏、触摸屏、串口、网口、声音接口、SD卡、USB、LED指示灯、蜂鸣器、按键、ADC、摄像头、看门狗。
ARM处理器的特点:
体积小、功耗低、集成度高、成本低、高性能
2.1 数据类型
struct test {
char a;
int b;
short c;
long d;
};
sizeof(struct test) = ?
基本数据类型的大小
应用环境的位数
数据在内存中存放的时候,有一个对齐的要求
如果在32 bits环境下,这个结构体的大小:1+4+2+4 = 11B(错误)
1、基本数据类型:
字节类型 ---- char ---- 1B
半字类型 ---- short ----2B
字类型 ---- int ------4B
长字类型 ---- long ----- 和处理器的字长保持一致
2、数据对齐的概念
数据是放在内存中,内存中每一个存储空间都有一个地址。针对内存来讲,是通过地址来访问内存中的内容的。
对于存储器来讲,一个地址对应的存储空间一个字节。
数据放到内存中,并不是任意一个地址都可以存放该数据的。地址需要满足一定的对齐要求。
char----任何一个地址都可以存放该数据
short----地址除以2可以整除
int ----地址除以4可以整除
long ----- 地址除以4/8可以整除(需要看处理器的字长)
2.2 数据存储格式
- 存储器:一个存储空间对应一个地址,每个空间存放的数据是一个字节。
- 最常见的数据类型—int型,处理器中,寄存器的地址一般是32bits的,寄存器的内容也还是32bits
问题:
一般我们处理的数据是32bits的数据(地址),是4字节的,该数据存放在内存中的时候,需要4个地址空间---->高字节的数据放在高地址还是放在低地址。
- 大端格式/大尾格式
高字节的数据存放到低地址,低字节的数据存放到高地址 - 小端格式/小尾格式
高字节的数据存放到高地址,低字节的数据存放到低地址
方法1:
unsigned int a=0x12345678;
char *p = &a;
*p == 0x12 ---->大端格式
*p == 0x78 ---->小端格式
方法2:
地址 数据
(*(unsigned int*)0x40000000) = 0x12345678;
大端格式:
(*(unsigned char *)0x40000000) == 0x12;
(*(unsigned char *)0x40000001) == 0x34;
(*(unsigned char *)0x40000002) == 0x56;
(*(unsigned char *)0x40000003) == 0x78;
小端格式:
(*(unsigned char *)0x40000000) == 0x78;
(*(unsigned char *)0x40000001) == 0x56;
(*(unsigned char *)0x40000002) == 0x34;
(*(unsigned char *)0x40000003) == 0x12;
2.3 ARM的寄存器
由两部分组成的
1、ARM内核中的寄存器—ARM公司
- 通用寄存器—所有的ARM处理器都是一样(ARM的版本相关)
只能通过寄存器的名字来访问,只能使用汇编语音进行编程
通用寄存器:R0~R15和CPSR、SPSR
2、ARM外设模块的寄存器----samsung公司
- 特殊功能寄存器-----与具体的ARM芯片相关的
只能通过寄存器的地址来访问,可以使用汇编语言编程,也可以使用C语言编程
2.3.1 ARM的寄存器(内核中的寄存器)
- 通用寄存器:R0~R15
寄存器的常用方法:
1、R0~R3
R0~R3----参数的传递和返回值,多余4个的参数用数据stack来传递。
例:
//main.c
extern int add_xy(int x, inty);
void main(void)
{
int sum;
int a=10,b=20;
sum = add_xy(10,20);
printf("sum = %d\n", sum);
}
//add.S
add_xy: //x和y怎么处理--->第一参数->R0,第二个参数->R1
add R3,R1,R0 //R3=R1+R2
mov R0,R3 //R0=R3
mov PC,LR //子程序的返回。将返回地址(LR)传送到程序计数器(PC)
2、R4~R12:存放局部变量
如果局部变量比较多,局部变会存放在stack中。register关键字定义的局部变量优先存放在寄存器中。
提示:
C语言中的关键字:extern、const、register、volatile、static
int a=100;
int b;
const int e=20
int main(void)
{
int c;
int d;
int *p;
c = a + 10;
b = 20;
d = b + e;
p = malloc(100);
*p = 1;
*(p+1) = 2;
free(p);
return 0;
}
3、R13
R13寄存器有一个别名叫SP—Stack Pointer寄存器中存放的是stack顶的地址。在处理器初始化的时候,会对stack进行初始化,让它等于内存的某个地址。
4、R14
R14寄存器有一个别名,叫LR—Link Register,保存子程序的返回地址。
例:
test程序中,调用了子程序fun,fun自程序执行结束后,会返回test。
test:
---------
---------
BL fun //调转到fun子程序的同时,保存返回地址到LR寄存器
--------- //这条指令在内存中的地址是fun子程序的返回地址
---------
fun:
---------
---------
MOV PC,LR //将返回地址LR传递给PC寄存器,实现子程序的返回。
5、R15
R15寄存器有一个别名–PC(Program Counter),存放正在执行语句的地址。
例:
MOV PC ,#0x00000000
相当于处理器重启。针对ARM处理器来讲,ARM启动的时候,执行的第一条指令在0x00000000地址。
R3 = R2+R1;//C语言不能直接访问通用寄存器,需要使用汇编语言访问。
2.3.2 状态寄存器
1、CPSR ---- 当前程序状态寄存器
CPSR ----- Current Program Status Register
反应当前处理器的状态:
- M[4:0]—工作模式(mode,7种)。
- 通过这个5个位可以获取处理器的工作模式。也可以通过这5个位来设置处理器的工作模式。
- T—工作状态(state,2种)ARM处理器一般有两种工作状态,分别是:
- ARM----- ARM处理器在执行32bits的机器码— 提高指令的执行效率
- Thumb-----ARM处理器在执行16bits的机器码—节省内存空间,降低功耗。
- 通常情况下,ARM处理器是执行32bits的机器码,处于ARM工作状态。处理器刚开始启动的时候,处于ARM状态。
- T–1 Thumb state
- T–0 ARM state
- 中断的开关(中断有两种类型:FIQ—Fast Interrupt reQuest,IRQ—Interrupt ReQuest )
- F—FIQ中断的使能位
- FIQ快速中断
- F–1 disable屏蔽
- F–0 enable
- I—IRQ中断的使能位
- IRQ是一般中断,优先级和响应时间是低于FIQ的。
- I—1 disable
- I—0 enable
- F—FIQ中断的使能位
- 算术运算的时候,运算的结果:是否是整数,是否为0,是否有进位,是否有借位。----状态标志位。
- NZCV—条件码标志位
- 算术运算指令的运算结果可以影响条件码标志位。有条件的汇编指令可以通过条件码标志位来判断是否要执行。
- 例子:
if(a==10)
a=a+1;
else
a=a-1;
CMP R4,#10 //R4里面存放了常数10 CMP---compare,会影响NZCV
ADDEQ R4,R4,#1//R4=R4+1,EQ--EQual
SUBNE R4,R4,#1
ARM汇编指令可以带条件,条件满足就执行,条件不满足,就是一个空指令(NOP)。
CMP R4,#10
SUBS R5,R4,#10//R5=R4-10,运算的影响标志位。
CPSR寄存器:
2、SPSR ---- 备份程序状态寄存器
在ARM处理器在工作模式切换的时候,用来保存CPSR。
2.3.3 ARM的工作模式
工作模式----Operating Mode,ARM处理器在处理不同的功能所处于的工作模式。
1、用户模式:ARM处理器在运行应用程序的时候
2、FIQ模式:ARM处理器正在处理快速中断的时候
3、IRQ模式:ARM处理器正在处理器一般中断的时候
4、管理模式:处理器进入保护模式,一般我们设置cache、设置MMU需要在管理模式,ARM在启动的时候,也是出于管理模式。
5、中止模式:处理器运行程序的过程中的一种出错模式。访问的地址不存在,后者地址禁止访问。
6、系统模式:处理器在运行操作系统应用程序时候的一种工作模式。
7、未定义模式:ARM处理器在执行汇编指令(机器码),是没有办法译码,指令未定义。出现未定义的问题:新版本的扩展指令应用到老版本的处理器上;指令在存储或者读取的过程中出错。
2.4 S5P6818处理器
三、ARM汇编指令
ARM汇编指令的应用场合:
ARM处理器最开始的启动代码、对处理器内核中的模块进行设置(如:cache、MMU、协处理器)、stack初始化(MOV SP, #0x70000000)、中断的进入和退出、任务的调度。
计算机系统的底层代码才用到汇编,往往底层代码都是做好的。
3.1 数据处理指令
只能完成通用寄存器(R0~R15)和立即数(常数前面加#)之间的运算。
1)算术运算指令–ADD、SUB
2)位运算指令—AND、ORR、BIC、EOR
3)比较指令----CMP、TEQ、TST
4)数据传送指令----MOV
注意:并不是所有的立即数都是直接使用在数据处理指令中。如果立即数不合法,可以使用LDR指令来替代。
ADD R1,R0,#0x11FF //不合法
替代:
LDR R2,=0x11FF
ADD R1,R0,R2
3.2 数据传送指令
MOV R1,R0 //将R0的值传输给R1
MOV R1,#20 //将20传送给R1
MOV R1,R0 ,LSL #3 //R1=(R0<<3)
//MVN----取反后再传送。
//不合法:
MOV 10,R1
MOV R1,CPSR //操作CPSR有专门的指令
MOV R1,#2 ,LSL #3 //R1=(2<<3)
3.3 算术运算指令
<<—LSL,>>—LSR, &—AND, |—ORR, ^----EOR(异或)
~&----BIC(位清除)
ADD R3,R2,R1//R3=R2+R1
ADD R3,R2,#30 //R3=R2+30
SUB R0,R1,R2 //R0 = R1 - R2
AND R3,R2,R1 //R3=R2&R1
/*思考:
&与&&
|与||
!与~
<<与>>
^---异或*/
//不合法:
ADD R3,#30,R1
ADD R3,#2,#1----> MOV R2,#2
ADD R3,R2,#1
位运算的例子:
1)unsigned int a,将a的第10位置1,其他位保持不变。
清0—和0进行按位与运算
置1—和1进行按位或运算
//C语言
a = a | 0x400
a |= 0x400
a |= (1<<10)
//汇编语言
ORR R4,R4,#0x400
ORR R4,R4,#(1<<10)
MOV R5,#1
ORR R4,R4,R5, LSL #10
2)unsigned int a,将a的第10位清0,其他位保持不变。
//C语言:
a = a & ~(1<<10)
a &= ~(1<<10)
//汇编语言:
BIC R4,R4,#0x400
BIC R4,R3,#(1<<10)
MOV R5,#1
BIC R4,R4,R5,LSL #10
AND R4,R4,#FFFFFDFF //不合法,立即数超出了范围
3)unsigned int a,将a的第10位取反,其他位保持不变。
//C语言:
a ^= (1<<10)
//汇编语言:
EOR R4,R4,#(1<<10)
MOV R5,#1
EOR R4,R4,R5,LSL #10
大疆笔试题:
有一个32bits的寄存器REGn,寄存器的地址是0x1F000010,写一个安全的函数实现将REGn的指定位反转,其他位保持不变。
思考:
将一个32bits的数0x12345678,写到一个地址为0x40000000的内存中。
*(unsigned int *)0x40000000 = 0x12345678
int regn_toggle(unsigned int x)
{
if(x<0 || x>31)
return -1;
P()
*(volatile unsigned int *)0x1F000010 ^ = (1<<x);
return 0;
V()
}
//汇编:
LDR R1,=0x1F000010 //R0=0x1F000010.MOV R1,#0x1F000010非法
LDR R0,[R1]//读出0x1F000010地址下的内容
EOR R0,R0,#(1<<10)
STR R0,[R1]
3.4 比较指令
- CMP R1 ,#100 ;将寄存器 R1的值与立即数100相减,并根据结果设置CPSR的标志位(NZCV)。
- CMN R1, R0 ;将寄存器 R1 的值与寄存器 R0 的值相加,根据结果设置 CPSR 的标志位。
- TST R1 ,#0xffe ;将寄存器R1的值与立即数0xffe 按位与,并根据结果设置 CPSR 的标志位。、
- TEQ R1 ,R2 ;将寄存器 R1 的值与寄存器 R2 的值按位异或 ;并根据结果设置 CPSR 的标志位,比较R1与R2是否相等
思考:
4)unsigned int a,判断a的第10位是否1?
//C语言:
if(a == (1<<10))错
if(a & (1<<10))对
if(a & (1<<10) == (1<<10))错:==优先级高于& ----if(a&1)
if((a & (1<<10)) == (1<<10))对
//汇编语言:
TST R4,R4,#(1<<10) //逻辑运算的结构是存放在NZCV中
数据处理指令包括:传送指令、算术运算指令、位运算指令、比较指令。比较指令可以自动影响标志位,如果其他的数据处理器指令要影响标志位需要在指令后面加一个“S”。
void delay(void)
{
int data=0x10000;
while(data--);
}
//汇编1:
delay:
MOV R1,#0x10000
tmp:
SUB R1,R1,#1
CMP R1,#0 //比较指令,会自动影响标志位。
BNE tmp
MOV PC,LR
//汇编2:
delay:
MOV R1,#0x10000
tmp:
SUBS R1,R1,#1 //s---会自动影响标志位。
BNE tmp
MOV PC,LR
难点:
数据处理指令中,会经常用到立即数,如:
MOV R0,#0x10000
ADD R1,R0,#0xFF00
BIC R1,R1,#(1<<10)
CMP R4,#0x100
注意:立即数并不是所有的数值都是合法的。主要是受到机器码编码位数的限制。在机器码中,给立即数的位数只有12bits。合法立即数的要求:
1、如果立即数的值是小于256,也就是可以使用8bits数来描述的。
如:100,200,80,250
2、如果一个立即数大于等于256,如果该立即数循环左移偶数位可以得到一个小于256的数,则该立即数是合法的。
0xFF00 —>0x0000FF00—>循环左移24bits得到0x000000FF。
0x101非法—>0001 0000 0001
设计程序的时候,如果要操作非法的立即数,如何处理?
使用LDR指令。
如:将0x1F000010传送到R1