1.2.ARM裸机第二部分-ARM体系结构与汇编指令

时间:2023-01-17 09:00:31

1.2.1.可编程器件的编程原理

电子器件的发展方向

模拟器件 -> 数字器件
ASIC -> 可编程器件

可编程器件的特点

CPU在固定频率的时钟控制下节奏运行。
CPU可以通过总线读取外部存储设备中的二进制指令集,然后解码执行。

这些可以被CPU解码执行的二进制指令集是CPU设计的时候确定的,是CPU的设计者(ARM公司)定义的,本质上是一串由1和0组成的数字。这就是CPU的汇编指令集。

整个编程及运行过程

程序员用汇编指令编程 --经汇编器汇编成二进制可执行程序文件-->二进制文件被CPU读取进去-->CPU内部电路对二进制文件解码-->解码通过则CPU执行指令、完成指令动作。
如果程序员用C语言等高级语言编程,则编译器先将C语言程序编译为汇编程序,再进行上面的后续部分。

从源代码到CPU执行过程

1.2.ARM裸机第二部分-ARM体系结构与汇编指令

1.2.2.指令集对CPU的意义


1.2.3.RISC和CISC的区别


1.2.4.统一编址&独立编址&哈佛结构&冯诺依曼结构


1.2.5.软件编程控制硬件的关键-寄存器

寄存器的演示

两类寄存器

1、SoC中有2类寄存器:通用寄存器和SFR
2、通用寄存器(ARM中有37个)是CPU的组成部分,CPU的很多活动都需要通用寄存器的支持和参与。
3、SFR(special function register,特殊功能寄存器)不在CPU中,而存在于CPU的外设中,我们通过访问外设的SFR来编程操控这个外设,这就是硬件编程控制的方法。

编程访问寄存器的方法

汇编
ldr r1, =0xE0200280    #把0xE0200280放到r1这个寄存器中
str r0, [r1] #把r0中的数放到以r1这个数为地址的内存中去
mov r0, #0 #把0这个数字放到r0这个寄存器中

C语言
int *p = (int *)0x30008000;
*p = 16;

1.2.6.ARM体系结构要点总结


1.2.7.S5PV210的内存映射详解

什么是内存映射

1、S5PV210属于ARM Cortex-A8架构,32位CPU,CPU设计时就有32根地址线&32根数据线。

2、32根地址线决定了CPU的地址空间为4G,那么这4G空间如何分配使用?这个问题就是内存映射问题(好像准确点应该叫地址映射吧,我懒的改标题了,大家注意这个小坑)。

S5PV210 datasheet中内存映射位置


一些专业术语

ROM:read only memory 只读存储器
RAM:ramdom access memory 随机访问存储器

IROM:internal rom 内部ROM,指的是集成到SoC内部的ROM

IRAM:internal ram 内部RAM,指的是集成到SoC内部的RAM

DRAM:dynamic ram 动态RAM

SRAM:static ram 静态RAM

SROM:static rom? sram and rom?
ONENAND/NAND: 

SFR:special function register

1.2.8.CPU和外部存储器的接口

内存 内部存储器 用来运行程序的 RAM 举例(DRAM SRAM DDR)
外存 外部存储器 用来存储东西的 ROM 举例(硬盘 Flash(Nand iNand···· U盘、SSD) 光盘)

CPU连接内存和外存的连接方式不同。内存需要直接地址访问,所以是通过地址总线&数据总线的总线式访问方式连接的(好处是直接访问,随机访问;坏处是占用CPU的地址空间,大小受限);外存是通过CPU的外存接口来连接的(好处是不占用CPU的地址空间,坏处是访问速度没有总线式快,访问时序较复杂)

SoC常用外存:
NorFlash 总线式访问,接到SROM bank,优点是可以直接总线访问,一般用来启动。

NandFlash: 分为SLC和MLC
eMMC/iNand/moviNand eMMC(embeded MMC)iNand是SanDisk公司出产的eMMC,moviNand是三星公司出产的eMMC
oneNAND oneNand是三星公司出的一种Nand
SD卡/TF卡/MMC卡
eSSD

SATA硬盘(机械式访问、磁存储原理、SATA是接口)

外部总线接口(EBI)被用作S5PV210外围。它依赖于内存控制器释放  外部请求外部总线空闲内存控制器时,因为它没有当内存的知识  访问将开始或完成。它使一个SROM控制器、一个OneNAND控制器和一个快闪记忆体  控制器、分享外部内存总线、内存端口0。

S5PV210支持的外部存储器

见datasheet Section2.6 booting sequence
见datasheet Section5全部,memory

见datasheet Section8.7 SD/MMC部分

X210开发板支持的外部存储器

X210有2个版本,Nand版和iNand版,分别使用Nandflash和iNand为外部存储器。我们使用的是iNand版本,板载4GB iNand
S5PV210共支持4个SD/MMC通道,其中通道0和2依次用作启动。X210开发板中SD/MMC0通道用于连接板载MMC,因此外部启动时只能使用SD/MMC2通道(注意通道3不能启动)。见《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》中P6

1.2.9.S5PV210的启动过程详解1

内存:
SRAM静态内存特点就是容量小、价格高,优点是不需要软件初始化直接上电就能用
DRAM动态内存特点就是容量大、价格低,缺点就是上电后不能直接使用,需要软件初始化后才可以使用。
单片机中:内存需求量小,而且希望开发尽量简单,适合全部用SRAM
嵌入式系统:内存需求量大,而且没有NorFlash等可启动介质
PC机: 内存需求量大,而且软件复杂,不在乎DRAM的初始化开销,适合全部用DRAM

外存:
NorFlash:特点是容量小,价格高,优点是可以和CPU直接总线式相连,CPU上电后可以直接读取,所以一般用作启动介质。
NandFlash(跟硬盘一样):特点是容量大,价格低,缺点是不能总线式访问,也就是说不能上电CPU直接读取,需要CPU先运行一些初始化软件,然后通过时序接口读写。

所以一般PC机都是:很小容量的BIOS(NorFlash)+ 很大容量的硬盘(类似于NandFlash)+ 大容量的DRAM
一般的单片机: 很小容量的NorFlash + 很小容量的SRAM
嵌入式系统:因为NorFlash很贵,随意现在很多嵌入式系统倾向于不用NorFlash,
直接用:外接的大容量Nand + 外接大容量DRAM + SoC内置SRAM


S5PV210使用的启动方式是:外接的大容量Nand + 外接大容量DRAM + SoC内置SRAM
实际上210的启动还要更好玩一些,210内置了一块96KB大小的SRAM(叫iRAM),同时还有一块内置的64KB大小的NorFlash(叫iROM)。210的启动过程大致是:
第一步:CPU上电后先从内部IROM中读取预先设置的代码(BL0),执行。这一段IROM代码首先做了一些基本的初始化(CPU时钟、关看门狗···)(这一段IROM代码是三星出厂前设置的,三星也不知道我们板子上将来接的是什么样的DRAM,因此这一段IROM是不能负责初始化外接的DRAM的,因此这一段代码只能初始化SoC内部的东西);然后这一段代码会判断我们选择的启动模式(我们通过硬件跳线可以更改板子的启动模式),然后从相应的外部存储器去读取第一部分启动代码(BL1,大小为16KB)到内部SRAM。
第二步:从IRAM去运行刚上一步读取来的BL1(16KB),然后执行。BL1负责初始化NandFlash,然后将BL2读取到IRAM(剩余的80KB)然后运行
第三步:从IRAM运行BL2,BL2初始化DRAM,然后将OS读取到DRAM中,然后启动OS,启动过程结束。

思路:因为启动代码的大小是不定的,有些公司可能96kb就够了,有些公司可能1MB都不够。所以刚才说的2步的启动方式不合适。三星的解决方案是:把启动代码分为2半(BL1和BL2),这两部分协同工作来完成启动。

wakeup status 唤醒状态(复位状态)

1.2.10.S5PV210的启动过程详解2

Second boot support  二次启动

 - When 1stboot mode fails, SD/MMC boot will be tried through SD/MMC channel 2 with 4-bit data
当第一次启动模式失败(eMMC0),SD/MMC会偿试通过SD/MMC通道2(4-bit数据线)来启动

BL0做了什么?

1. Disable the Watch-Dog Timer 
关看门狗
2. Initialize the instruction cache
初始化指令缓存
3. Initialize the stack region (see “memory map” on chap 2.5)
初始化栈
4. Initialize the heap region. (see “memory map” on chap 2.5)
初始化堆
5. Initialize the Block Device Copy Function. (see “Device Copy Function” on chap 2.7)
初始化块设备复制函数device copy functio
6. Initialize the PLL and Set system clock. (see “clock configuration” on chap 2.11)
设置SoC时钟系统
7. Copy the BL1 to the internal SRAM region (see “Device Copy Function” on chap 2.7)
复制BL1到内部IRAM(16KB)
8. Verify the checksum of BL1.
If checksum fails, iROM will try the second boot up. (SD/MMC channel 2)
检查BL1的校验和
9. Check if it is secure-boot mode or not.
If the security key value is written in S5PV210, It’s secure-boot mode.
If it is secure-boot mode, verify the integrity of BL1.
检查是否是安全启动
10. Jump to the start address of BL1
跳转到BL1去执行

S5PV210的所有启动

先1st启动,通过OMpin选择启动介质

再2nd启动,从SD2

再Uart启动

再USB启动

1.2.ARM裸机第二部分-ARM体系结构与汇编指令

1.2.ARM裸机第二部分-ARM体系结构与汇编指令

1.2.11.如何在开发板上选择不同启动方式


1.2.12.ARM的编程模式和7种模式

ARM的基本设定

ARM 采用的是32位架构.
ARM 约定:
Byte : 8 bits
Halfword :16 bits (2 byte)
Word : 32 bits (4 byte)


大部分ARM core 提供:
ARM 指令集(32-bit) 
Thumb 指令集(16-bit )
Thumb2指令集(16 & 32bit)
Jazelle cores 支持 Java bytecode

ARM处理器工作模式

 ARM 有7个基本工作模式:
User : 非特权模式,大部分任务执行在这种模式

FIQ :   当一个高优先级(fast) 中断产生时将会进入这种模式
IRQ :   当一个低优先级(normal) 中断产生时将会进入这种模式
Supervisor :当复位或软中断指令执行时将会进入这种模式 Abort : 当存取异常时将会进入这种模式 Undef : 当执行未定义指令时会进入这种模式
System : 使用和User模式相同寄存器集的特权模式

注意

除User(用户模式)是Normal(普通模式)外,其他6种都是Privilege(特权模式)。
Privilege中除Sys模式外,其余5种为异常模式。

各种模式的切换,可以是程序员通过代码主动切换(通过写CPSR寄存器);也可以是CPU在某些情况下自动切换。

各种模式下权限和可以访问的寄存器不同。

CPU为什么设计这些模式?

CPU是硬件,OS是软件,软件的设计要依赖硬件的特性,硬件的设计要考虑软件需要,便于实现软件特性。
操作系统有安全级别要求,因此CPU设计多种模式是为了方便操作系统的多种角色安全等级需要。

1.2.13.ARM的37个寄存器详解

1.2.ARM裸机第二部分-ARM体系结构与汇编指令

1、ARM总共有37个寄存器,但是每种模式下最多只能看到18个寄存器,其他寄存器虽然名字相同但是在当前模式不可见。
2、对r13这个名字来说,在ARM*有6个名叫r13(又叫sp)的寄存器,但是在每种特定处理器模式下,只有一个r13是当前可见的,其他的r13必须切换到他的对应模式下才能看到。这种设计叫影子寄存器(banked register)

1.2.ARM裸机第二部分-ARM体系结构与汇编指令

总结

ARM共有37个寄存器,都是32位长度
37个寄存器中30个为“通用”型,1个固定用作PC,一个固定用作CPSR,5个固定用作5种异常模式下的SPSR。

CPSR程序状态寄存器

 条件位:
       N = Negative result from ALU 
       Z = Zero result from ALU
       C = ALU operation Carried out
       V = ALU operation oVerflowed 

Q 位:
       仅ARM 5TE/J架构支持1.2.ARM裸机第二部分-ARM体系结构与汇编指令
       指示饱和状态

J 位
       仅ARM 5TE/J架构        支持
J = 1:  处理器处于                   Jazelle状态

中断禁止位:
       I  = 1: 禁止  IRQ.
       F = 1: 禁止  FIQ.

T Bit
      仅ARM  xT架构支持
      T = 0: 处理器处于 ARM 状态
      T = 1: 处理器处于 Thumb 状态 

Mode位:
      处理器模式位
判断3和3是否相等,也就是3-3是否等于0,
如果等于0,Z位就会置1,然后就会跳转,
并且跳转前把返回地址存到lr寄存器中
sub 3 3
BLE:branch lrequal

注意

CPSR中各个bit位表明了CPU的某些状态信息,这些信息非常重要,和后面学到的汇编指令息息相关(譬如BLE指令中的E就和CPSR中的Z标志位有关)
CPSR中的I、F位和开中断、关中断有关

CPSR中的mode位(bit4~bit0共5位)决定了CPU的工作模式,在uboot代码中会使用汇编进行设置。

PC(r15)程序控制寄存器

PC(Program control register)为程序指针,PC指向哪里,CPU就会执行哪条指令(所以程序跳转时就是把目标地址代码放到PC中)
整个CPU中只有一个PC(CPSR也只有一个,但SPSR有5个)。

1.2.14.ARM的异常处理方式简单介绍

什么是异常

正常工作之外的流程都叫异常
异常会打断正在执行的工作,并且一般我们希望异常处理完成后继续回来执行原来的工作

中断是异常的一种

异常向量表

所有的CPU都有异常向量表,这是CPU设计时就设定好的,是硬件决定的。
当异常发生时,CPU会自动动作(PC跳转到异常向量处处理异常,有时伴有一些辅助动作)

异常向量表是硬件向软件提供的处理异常的支持。
同步:靠中断来实现(一种特殊的异常)
异步:同步时钟

ARM的异常处理机制

1、当异常产生时, ARM core:
        (1)拷贝 CPSR 到 SPSR_<mode>                         保护当前状态1.2.ARM裸机第二部分-ARM体系结构与汇编指令
                          
        (2)设置适当的 CPSR 位:  CPU自动的
                  改变处理器状态进入 ARM 态
                  改变处理器模式进入相应的异常模式
                 设置中断禁止位禁止相应中断 (如果需要)

(3)保存返回地址到 LR_<mode>

(4)设置 PC 为相应的异常向量

2、返回时, 异常处理需要:

(1)从 SPSR_<mode>恢复CPSR

(2)从LR_<mode>恢复PC 

(3)Note:这些操作只能在 ARM 态执行.

总结

异常处理中有一些是硬件自动做的,有一些是程序员需要自己做的。需要搞清楚哪些是需要自己做的,才知道如何写代码。
以上说的是CPU设计时提供的异常向量表,一般成为一级向量表。有些CPU为了支持多个中断,还会提供二级中断向量表,处理思路类似于这里说的一级中断向量表。

1.2.15_16.ARM汇编指令集1_2

两个概念:指令与伪指令

指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。
伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。

两种不同风格的ARM指令

ARM官方的ARM汇编风格:指令一般用大写、Windows中IDE开发环境(如ADS、MDK等)常用。如: LDR R0, [R1]
GNU风格的ARM汇编:指令一般用小写字母、linux中常用。如:ldr r0, [r1]

ARM汇编特点1:LDR/STR架构

ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。
ldr(load register)指令将内存内容加载入通用寄存器。

str(store register)指令将寄存器内容存入内存空间中。

ldr/str组合用来实现 ARM CPU和内存数据交换

ARM汇编特点2:8种寻址方式

寄存器寻址 mov r1, r2把r2中的内容放到r1中
立即寻址 mov r0, #0xFF00把0xFF00直接放到r0中,前面加#表示这是一个数字

寄存器移位寻址         mov r0, r1, lsl #3把r1左移3位得到的数再给r0

寄存器间接寻址         ldr r1, [r2]把r2这个内存地址中的值赋给r1,相当于指针

基址变址寻址 ldr r1, [r2, #4]把r2+4之后这个地址中的值赋给r1

多寄存器寻址 ldmia r1!, {r2-r7, r12}把r1理解成数组,r1就是数组名即数组头地址,然后把r1开始往后的7个元素读到r2~r7,r12寄存器中

堆栈寻址 stmfd sp!, {r2-r7, lr}压栈,把r2-r7,lr7个寄存器存储到sp起始地址并一直往下压直到结束


相对寻址     beq flag
                   flag:                         冒号表示标号,用来标示后面一句指令的地址的,一般表示入口地址,类似于函数名等,有了标号,就可以跳转到标号处去执行
 相对寻址:当前PC执行到哪,然后跳转以PC为基地址+偏移量的地方去执行                   

ARM汇编特点3:指令后缀

同一指令经常附带不同后缀,变成不同的指令。经常使用的后缀有:
B(byte)功能不变,操作长度变为8位

H(half word)功能不变,长度变为16位

S(signed)功能不变,操作数变为有符号

如 ldr ldrb ldrh ldrsb ldrsh

S(S标志)功能不变,影响CPSR标志位
如 mov和movs movs r0, #0

ARM汇编特点4:条件执行后缀

1.2.ARM裸机第二部分-ARM体系结构与汇编指令
mov r0, r1@ 相当于C语言中的r0 = r1;
moveq r0, r1@ 如果eq后缀成立,则直接执行mov r0, r1;如果eq不成立则本句代码直接作废,相当于没有
@ 类似于C语言中 if (eq){r0 = r1;}

条件后缀执行注意2点:
1、条件后缀是否成立,不是取决于本句代码,而是取决于这句代码之前的代码运行后的结果。
2、条件后缀决定了本句代码是否被执行,而不会影响上一句和下一句代码是否被执行。

GT greater than
LT less than

ARM汇编特点5:多级指令流水线

为增加处理器指令流的速度,ARM使用多级流水线.,下图为3级流水线工作原理示意图。(S5PV210使用13级流水线,ARM11为8级)
允许多个操作同时处理,而非顺序执行。

PC指向正被取指的指令,而非正在执行的指令
1.2.ARM裸机第二部分-ARM体系结构与汇编指令

1.2.17.ARM汇编指令集3

常用ARM指令1:数据处理指令

数据传输指令 mov mvn
mov(move)mov r1, r0@两个寄存器之间数据传递
mov r1, #0xff@ 将立即数赋值给寄存器

mvn和mov用法一样,区别是mov是原封不动的传递,而mvn是按位取反后传递
按位取反的含义:
譬如r1 = 0x000000ff,然后mov r0, r1 后,r0 = 0xff但是我mvn r0, r1后,r0=0xffffff00

算术指令 add sub rsb adc sbc rsc 

逻辑指令 and orr eor bic
and逻辑与
orr逻辑或
eor裸机异或

bic位清除指令

bicr0,r1,#0x1f@ 将r1中的数的bit0到bit4清零后赋值给r00x1f = 0x0000001f=0x0000```11111

比较指令 cmp cmn tst teq
cmpcmp r0, r1  等价于 sub r2, r0, r1 (r2 = r0 - r1)
cmncmn r0, r1 等价于 add r0, r1
tsttst r0, #0xf@测试r0的bit0~bit3是否全为0
teq
比较指令用来比较2个寄存器中的数
注意:比较指令不用后加s后缀就可以影响cpsr中的标志位。

乘法指令 mvl mla umull umlal smull smlal

前导零计数 clz

常用ARM指令2:cpsr访问指令

mrs & msr

mrs用来读psr,msr用来写psr

CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。
cpsr和spsr的区别和联系:cpsr是程序状态寄存器,整个SoC中只有1个;而spsr有5个,分别在5种异常模式下,
作用是当从普通模式进入异常模式时,用来保存之前普通模式下的cpsr的,以在返回普通模式时恢复原来的cpsr。

常用ARM指令3:跳转(分支)指令

b & bl & bx

b 直接跳转(就没打开算返回)

bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用

bx跳转同时切换到ARM模式,一般用于异常处理的跳转。

常用ARM指令4:访存指令

ldr/str & ldm/stm & swp

单个字/半字/字节访问 ldr/str

多字批量访问  ldm/stm

swp r1, r2, [r0]    把r0这个内存地址中的值读到r1,然后把r2放到r0这个内存地址中

swp r1, r1, [r0]

ARM汇编中的立即数

合法立即数与非法立即数

ARM指令都是32位,除了指令标记和操作标记外,本身只能附带很少位数的立即数。因此立即数有合法和非法之分。

合法立即数:经过任意位数的移位后非零部分可以用8位表示的即为合法立即数
合法立即数: 0x000000ff0x00ff0000 0xf000000f 
非法立即数: 0x000001ff

常用ARM指令5:软中断指令

swi(software interrupt)

软中断指令用来实现操作系统中系统调用

1.2.18.ARM汇编指令集4

协处理器cp15操作指令

mcr & mrc

mrc用于读取CP15中的寄存器

mcr用于写入CP15中的寄存器

什么是协处理器

SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定任务。
ARM设计上支持多达16个协处理器,但是一般SoC只实现其中的CP15.(cp:coprocessor)

协处理器和MMU、cache、TLB等处理有关,功能上和操作系统的虚拟地址映射、cache管理等有关。

MRC & MCR的使用方法

mcr{<cond>}   p15, <opcode_1>, <Rd>, <Crn>, <Crm>, {<opcode_2>}
opcode_1:对于cp15永远为0

Rd:ARM的普通寄存器

Crn:cp15的寄存器,合法值是c0~c15

Crm:cp15的寄存器,一般均设为c0

opcode_2:一般省略或为0

举例(来自于uboot)

mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0


其他见uboot源码start.S中相关代码

协处理器学习要点

不必深究,将uboot中和kernel中起始代码中的一般操作搞明白即可。
只看一般用法,不详细区分参数细节,否则会陷入很多复杂未知中。

关键在于理解,而不在于记住。

1.2.19.ARM汇编指令集5

为什么需要多寄存器访问指令

ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm
ldm(load register mutiple)

stm(store register mutiple)

举例(uboot start.S 537行)

stmia sp, {r0 - r12}
将r0存入sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后地址再+4(指向0x30001008),将r2存入该地址······直到r12内容放入(0x3001030),指令完成。
一个访存周期同时完成13个寄存器的读写

8种后缀

ia(increase after)先传输,再地址+4
ib(increase before)先地址+4,再传输

da(decrease after)先传输,再地址-4

db(decrease before)先地址-4,再传输

fd(full decrease)满递减堆栈

ed(empty decrease)空递减堆栈

fa(·······) 满递增堆栈

ea(·······)空递增堆栈

8种后缀

ia(increase after)先传输,再地址+4
ib(increase before)先地址+4,再传输

da(decrease after)先传输,再地址-4

db(decrease before)先地址-4,再传输

fd(full decrease)满递减堆栈

ed(empty decrease)空递减堆栈

fa(·······) 满递增堆栈

ea(·······)空递增堆栈

四种栈

空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出
满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针

增栈:栈指针移动时向地址增加的方向移动的栈

减栈:栈指针移动时向地址减小的方向移动的栈

!的作用

ldmia r0, {r2 - r3}
ldmia r0!, {r2 - r3}

感叹号的作用就是r0的值在ldm过程中发生的增加或者减少最后写回到r0去,也就是说ldm时会改变r0的值。

^的作用

ldmfd sp!, {r0 - r6, pc}
ldmfd sp!, {r0 - r6, pc}^


^的作用:在目标寄存器中有pc时,会同时将spsr写入到cpsr,一般用于从异常模式返回。

总结

批量读取或写入内存时要用ldm/stm指令
各种后缀以理解为主,不需记忆,最常见的是stmia和stmfd

谨记:操作栈时使用相同的后缀就不会出错,不管是满栈还是空栈、增栈还是减栈

1.2.20.ARM汇编伪指令

伪指令的意义

伪指令不是指令,伪指令和指令的根本区别是经过编译后会不会生成机器码。
伪指令的意义在于指导编译过程。

伪指令是和具体的编译器相关的,我们使用gnu工具链,因此学习gnu环境下的汇编伪指令。

gnu汇编中的一些符号

@ 用来做注释。可以在行首也可以在代码后面同一行直接跟,和C语言中//类似
# 做注释,一般放在行首,表示这一行都是注释而不是代码。

:以冒号结尾的是标号

.  点号在gnu汇编中表示当前指令的地址

# 立即数前面要加#或$,表示这是个立即数

常用gnu伪指令

.global _start @ 给_start外部链接属性
.section .text @ 指定当前段为代码段

.ascii .byte .short .long .word 

.quad .float .string @ 定义数据

.align 4 @ 以16字节对齐
.balignl 16 0xabcdefgh @ 16字节对齐填充

.equ @ 类似于C中宏定义

偶尔会用到的gnu伪指令

.end @标识文件结束
.include @ 头文件包含

.arm / .code32 @声明以下为arm指令

.thumb / .code16 @声明以下为thubm指令

最重要的几个伪指令

ldr 大范围的地址加载指令
adr 小范围的地址加载指令
adrl 中等范围的地址加载指令
nop 空操作


ARM中有一个ldr指令,还有一个ldr伪指令
一般都使用ldr伪指令而不用ldr指令

adr与ldr

adr编译时会被1条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理;
adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里

ldr加载的地址和链接时给定的地址有关,由链接脚本决定。