汇编基础语法及其示例

1.汇编指令

1.1汇编指令的基本格式

<opcode>{<cond>}{s} <Rd> , <Rn> , <shifter_operand>

<功能码>{<条件码>}{cpsr影响位} <目标寄存器> , <第一操作寄存器> , <第二操作数>

注:第一操作寄存器只能是寄存器, 不能写数值

第二操作数可以写寄存器名, 也可以写#一个数值

汇编不区分大小写

操作数可以是一个寄存器,也可以是一个立即数

立即数:能够经过编码后保存到指令空间中直接当作指令一部分去执行的数据。一个32位指令空间中预留了12位空间保存当前操作数, 可以通过某一个规则对操作数进行处理,将处理后数值放在这12个空间中。所以处理完能够保存到12位空间中的数据就是立即数。通常通过循环右移看是否能得到一个0-255之间的数,如果可以,说明该数据就是立即数

1.2数据处理指令

1.2.1数据搬移指令

1.mov {条件码} Rd ,Sh~

将操作数搬移到目标寄存器中

mov R1 , #0x1

MOV R2, R1

2.mvn {条件码} Rd Sh~

将操作数按位取反后搬移到目标寄存器中

mvn R1 , #0x1

MVN R2, R1

3.通过伪指令实现非立即数的搬移:ldr Rd, =非立即数

ldr Rd , =0x81

1.2.2数据移位指令

1.逻辑左移

lsl{<cond>} Rd , Rn , Sh~

将Rn左移Sh~位存到Rd中

2.逻辑右移

lsr{<cond>} Rd , Rn , Sh~

将Rn右移Sh~位存到Rd中

3.循环右移
ror{<cond>} Rd , Rn , Sh~

将Rn循环右移Sh~位存到Rd中

LSL R1 , R2, #(0x1<<2)

LSR R1 , R2, #2)

1.2.3位运算指令

1.与, 与0清零,与1不变

and {<cond>} Rd , Rn , Sh~

and R1, r2 , #(0x1<<2)

将Rn与Sh~进行与运算存于Rd

2.或,有1为1, 全0为0

orr {<cond>} Rd , Rn , Sh~

Orr r1, r2, #(0x1<<2)

将Rn与Sh~进行或运算存于Rd

3.异或 ,相同为0, 不同为1

eor {<cond>} Rd , Rn , Sh~

Eor R2, R1, #(0x1<<0)

将Rn与Sh~进行异或运算存于Rd

4.按位取反,01交换

mvn(见搬移指令2)

5,按位清零,指为1,清为0

bic {<cond>} Rd , Rn , Sh~

将Rn与Sh~取反进行与运算存于Rd

bic r1, r2, #(0x1<<2) === and r1, r2, #(~(0x1<<2))


1.2.4算术运算指令

1.加法指令

add{<cond>}{s} Rd, Rn,Sh~

Rd = Rn+Sh~

adc{<cond>}{s} Rd, Rn,Sh~

Rd = Rn+Sh~+cpsr寄存器的c位

2.减法指令

sub {<cond>}{s} Rd, Rn,Sh~

Rd = Rn-Sh~

sbc{<cond>}{s} Rd, Rn,Sh~

Rd = Rn-Sh~-cpsr寄存器的c位

3.乘法指令

mul{<cond>}{s} Rd, Rn,Sh~

Rd = Rn*Sh~

注 :{s}存在时运算,加法进位和减法不借位时,cpsr位置1

32位处理器进行64位数据运算时先低八位,后高八位,低位运算影响c位,高位运算考虑c位


1.2.5比较指令

1.cmp Rn , Sh~

将Rn和Sh~比较,本质是将二者进行减法运算,并将结果存到cpsr寄存器 的nzcv位,通常和条件码一起使用

2.tst Rd, #(0x1<<N)

判断第N位是否为0.

3.TEQ Rd , sh~

判断二者是否相等

只能影响到z位,无法影响到cvn位


1.2.6跳转指令

1.b 标签

跳转到指定标签下,跳转后LR寄存器不保存程序的返回地址

2.bl 标签

跳转到指定标签下,跳转后LR寄存器保存程序的返回地址

可实现程序到循环执行操作 ,比如累乘和阶乘


1.2.7内存读写指令

类比c语言通过指针读写地址下内存中的数据

*((unsigned int*)0x12345678) = 数值

向内存中写

1.str Rd,[目标地址]

将Rd中的四字节数据写入到目标地址对应的内存中

2.strh Rd,[目标地址]

将Rd中的2字节数据写入到目标地址对应的内存中

3.strb Rd,[目标地址]

将Rd中的1字节数据写入到目标地址对应的内存中

向内存中读

4.ldr Rd,[目标地址]

从目标地址对应的内存中读取4字节数据保存到Rd中

5.ldrh Rd,[目标地址]

从目标地址对应的内存中读取2字节数据保存到Rd中

6.ldrb Rd,[目标地址]

从目标地址对应的内存中读取1字节数据保存到Rd中

此外还分前索引,后索引和自动索引

前索引:以基地址偏移后为首地址读写

str Rd,[基地址, 偏移量]

将Rd的数据写入到基地址+偏移量为首地址到内存中

ldr Rd,[基地址, 偏移量]

从基地址+偏移量为首地址到内存中读取数据保存到Rd中

后索引:以基地址进行为首地址进行读写,之后基地址在进行偏移

str Rd , [基地址],偏移量

将目标寄存器到数据写入以基地址为首地址的内存中,然后基地址增加偏移量

ldr Rd , [基地址], 偏移量

从以基地址为首地址的内存中读取数据保存到目标寄存器中,然后将基地址增加偏移量的大小

自动索引:以基地址偏移后为首地址进行读写,同时基地址也进行自增自减

str Rd , [基地址,偏移量]!

将基地址自增偏移量大小,再将Rd的数据写入到以基地址为首地址的内存中

ldr Rd,[基地址,偏移量]!

先将基地址自增偏移量大小,再从基地址为首地址到内存中读取数据保存到Rd中

注:基地址要保存到一个寄存器中,偏移量要是一个立即数

此外还可以通过寄存器列表对内存批量读写

写:

stm 基地址, { 寄存器列表}

将寄存器列表中的所有寄存器数据写入到以基地址为首地址的内存中

读:

ldm 基地址,{寄存器列表}

从基地址开始往下读取数据,保存到寄存器列表中的每一个寄存器中

注:

寄存器的写法有:起始寄存器-终止寄存器 /寄存器1、寄存器2、、、、

并且无论寄存器列表编号顺序与否排列,内存读写始终是从小编号寄存器对应着低地址的数据

批量寄存器地址的增长方式有以下四种

ia、ib、da、db

a:先读写,基地址再增长

b:基地址先增长,再进行读写

i:基地址往大地址方向增长

d:基地址往小地址方向增长

栈内存读写

1.空栈和满栈(E&F)

2.增栈和减栈(A&D)

也就形成了四类栈,空增(EA)空减(ED)满增(FA)满减(FD)

ARM默认使用满减栈(FD)

"交叉读写"即:ia写那就db读

对于ARM,满减是由ib写入那么就需要用da读出(对应满减栈就是先读再偏移)

满减栈的实现主要通过三种方式:压栈出栈、strdb和满减栈专用的后缀fd

1.压栈出栈

push {寄存器列表}

pop {寄存器列表}

start:

mov sp ,#0x40000020 @初始化的栈

mov R1, #0x1

mov r2,#0x2

mov r3,#0x3

push {R1-r5}

2.stmdb

将上述代码的push替换成stmdb

3.stmfd(满减专用)

push换成stmfd

最后就是关于叶子函数和非叶子函数的压栈出栈注意事项

关于叶子函数,为了叶子函数在操作寄存器时,不改变非叶子函数的需求,通常将从非叶子函数中已经使用且叶子函数中要使用寄存器数据进行压栈处理,在叶子函数处理完之后进行出栈释放,从而保证函数返回后寄存器的值和调用函数前的保持一致

针对于非叶子函数,还要额外的将返回地址进行压栈出栈处理将LR寄存器压栈非叶子函数调用完成后将其中 的地址数据出栈于sp寄存器中使程序继续正常运行

核心即压栈保护现场push{}出栈恢复现场pop{}


1.2.8状态寄存器传送指令

读取状态寄存器

mrs Rd,cpsr

读取CPSR的数值,保存到Rd中

修改状态寄存器

MSR cpsr , sh~

修改cpsr寄存器的数值为操作数

注:在特权模式下可以通过修改CPSR到非特权模式(USER模式),但是非特权模式不能通过修改cpsr寄存器的数值实现转化为特权模式,只有当对应的特权事件发生之后,处理器会自动进入对应的特权模式

1.2.9异常产生指令

1.2.9.1软中断产生指令

当软中断产生指令执行后会产生一个如饭中断,让处理器进入SVC模式下进行软中断的处理

swi sh~

sh~是一个立即数即产生软中断的中断号

例子

start:

MRS r0 , cpsr @

Msr cpsr,#0x1

swi 1

loop

b loop

end

1.2.9.2异常模式和异常源

前者时处理器发生异常后进入的工作模式,后者是引发处理器产生异常的源头

总共分为五种异常模式和7种异常源

异常向量表:

ARM处理器在处理异常时采用了异常向量机制,通过在内存中申请一段空间为异常向量表,作为异常处理程序的索引项,根据索引项进入异常处理程序去执行。

cortex------a处理器的异常向量表时32字节,平分为8份。每一份时44字节,正好对应一条汇编指令,每一种异常源都会在异常向量表中有一个位置,剩下一份位置保留

1.2.9.3异常的处理(4⃣️大步3⃣️小步)

1.保存cpsr于spsr

2.修改cpsr(三小步)

修改为对应的异常模式【4;0】

修改工作状态为ARM状态【5】-》0

根据当前的异常的优先级禁用中断【7:6】

3.保存程序的返回地址到异常模式的LR寄存器中

4.修改PC的值到对应异常在异常向量表中的位置

1.2.9.4异常的返回

注:异常的返回必须要手动返回

1.将异常模式下的spsr数值赋值给cpsr,恢复程序的状态

2.将异常模式下的LR的数值赋值给PC,恢复程序执行的位置


1.2.10协处理器指令

2.伪操作:能够在编译过程中起到编译引导作用的 内容

.test .gloabal .if .else ..endif . .....

3.伪指令:不是汇编指令,但是可以起到指令的作用,也会占用一定的内存空间

4.注释

单行注释:@ 或 ;

多行注释:/**/

条件注释:

.if 逻辑值

指令段

.else

指令段

.endif

5.混合编程

目的:使c语言资源和汇编资源相互调用

要求:符合ATPCS规范,将变量传递给从低到高的寄存器实现二者之间的相互调用

函数与标签:函数名汇编中当标签使用,标签c语言中当函数名使用

内联汇编格式

asm volatile(

"汇编指令\n\t"

。。。。。。

输出列表

输入列表

破坏列表

);

相关推荐
我在人间贩卖青春3 天前
汇编之伪指令
汇编·伪指令
我在人间贩卖青春4 天前
汇编之伪操作
汇编·伪操作
济6174 天前
FreeRTOS基础--堆栈概念与汇编指令实战解析
汇编·嵌入式·freertos
myloveasuka4 天前
汇编TEST指令
汇编
我在人间贩卖青春4 天前
汇编编程驱动LED
汇编·点亮led
我在人间贩卖青春4 天前
汇编和C编程相互调用
汇编·混合编程
myloveasuka5 天前
寻址方式笔记
汇编·笔记·计算机组成原理
请输入蚊子5 天前
《操作系统真象还原》 第六章 完善内核
linux·汇编·操作系统·bochs·操作系统真像还原
myloveasuka5 天前
指令格式举例
汇编·笔记·计算机组成原理
我在人间贩卖青春5 天前
汇编之分支跳转指令
汇编·arm·分支跳转