目录
[内存操作 LOAD/STORE 指令](#内存操作 LOAD/STORE 指令)
汇编整体分类
1.指令
编译完生成一条机器码存储在内存单元当中,CPU执行时能完成对应的操作(类似于C中的语句)
2.伪操作
伪操作(相当于c中的#的内容,告诉编译器怎么编译),不会生成机器码也不会占用内存,其作用是告诉编译器怎样编译(类似于C中的预处理指令)
3.伪指令
伪指令不是指令,编译器在编译时将其替换成等效的指令 (如:cpu中没有乘法器,对应没有乘法指令,3*3 ---》用加法器实现3+3+3,替换实现)
汇编代码
汇编初始化
bash
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
loop
B loop
END
1.AREA STACK, NOINIT, READWRITE : 这一行指定了一个名为STACK的内存区域,它用于存储堆栈。NOINIT表示这个内存区域在程序启动时不需要初始化,READWRITE表示这个内存区域可以被读取和写入。
2.__initial_sp : 这一行定义了一个名为`__initial_sp`的符号,它表示堆栈指针的初始值。在这里,它被定义为堆栈的起始地址。通常,这个符号会在链接脚本中进一步定义为实际的堆栈内存区域的起始地址。
3.AREA RESET, DATA, READONLY : 这一行指定了一个名为RESET的内存区域,用于存储重置向量表。DATA表示这个区域包含数据,READONLY表示这个区域只能被读取。
4.__Vectors DCD __initial_sp : 这一行定义了一个重置向量表,用于指示程序启动时应该执行的操作。`DCD`表示存储一个双字(32位)的数据。在这里,第一个双字存储的是堆栈指针的初始值,即__initial_sp。
5.DCD main : 这一行将程序的入口地址(main函数)添加到重置向量表中。这意味着程序在启动时将跳转到main函数开始执行。
6.AREA |.text|, CODE, READONLY : 这一行指定了一个名为.text的内存区域,用于存储代码。CODE表示这个区域包含代码,READONLY表示这个区域只能被读取。
7.ENTRY main : 这一行指定了程序的入口点为main函数。这意味着程序将从`main`函数开始执行。
8.loop B loop : 这一行是一个无限循环,它会不断地跳转到`loop`标签所在的位置,导致程序永远循环执行这条指令。
9.END: 这一行表示程序的结束。
数据搬运指令
改变PC的值实现程序跳转
cpp
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
MOVS R0,#2
MOVS R1,R0
;改变PC的值实现程序跳转,0x08000008
;先把地址给一个寄存器,再把这个寄存器的值赋给PC
LDR R2,=0x08000008
MOV PC,R2
loop
B loop
END
算术运算指令
加法
bash
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
MOVS R0,#2
MOVS R1,R0
ADDS R3,R0,R1 ;R3=0X04
LDR R8,=0X01
ADD R8,R8,R3 ;R8=R8+R3 =0X05
loop
B loop
END
减法
bash
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
MOVS R0,#2
MOVS R2,#2
MOVS R1,R0
SUBS R2,R0,R1 ;R2=R0-R1
loop
B loop
END
乘法
bash
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
MOVS R0,#2
MOVS R2,#2
MOVS R1,R0
MULS R2,R0,R2 ;R2=R0*R2
loop
B loop
END
比较指令
跳转指令
bash
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
JUMP
MOVS R0,#1
MOVS R2,#1
LDR R3,=0X0800001A
MOV PC,R3
main
MOVS R0,#2
MOVS R2,#2
MOVS R1,R0
CMP R0,R2 ;if(a==b)
BEQ JUMP
MOVS R0,#3
loop
B loop
END
cpp
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
JUMP
MOVS R0,#1
MOVS R2,#1
MOV PC,LR
main
MOVS R0,#2
MOVS R2,#2
MOVS R1,R0
BL JUMP
MOVS R0,#3
loop
B loop
END
逻辑运算指令
与或,异或
bash
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
MOVS R0,#2 ;R0:0010
MOVS R1,#1 ;R1:0001
ANDS R1,R1,R0 ;R1=R1&R0 R1=0000
EORS R1,R1,R0 ; 0010 0000 0010
loop
B loop
END
左移右移
cpp
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
MOVS R0,#2 ;R0:0010 左移1位 0100--4
MOVS R1,#1 ;R1:1
LSLS R0,R0,R1
loop
B loop
END
内存操作 LOAD/STORE 指令
写
读
CPU的栈机制
栈的概念
栈是一种具有特殊的访问方式的存储空间,特殊性就在于后进先出
栈的种类
1.空栈(Empty)
栈指针指向的地址是空的,在栈中存储数据时,可以直接存储,存储完成之后需要将栈指针再次指向空的位置。
EA:Empty Ascending 空增栈
ED:Empty Descending 空减栈
2.满栈(Full)
栈指针指向的地址有数据,在栈中存储数据时,需要先将栈指针,指向一个空的位置,然后在存储数据。
增栈(Ascending)
栈指针向高地址方向移动
减栈(Descending)
栈指针向低地址方向移动
FA:Full Ascending 满增
FD:Full Descending 满减
ARM默认采用的是满减栈栈指针指向有数据的顶,接收数据时,栈指针先移动,再放数据。指针的移动是地址的降低
栈的基本操作
栈有两种基本的操作:入栈和出栈
1.入栈:将一个新的元素放到栈顶
2.出栈:从栈顶取出一个元素
栈顶元素总是最后一个入栈的,需要出的时候,又会是第一个被取出的
操作规则:LIFO后进先出
PUSH/POP
PUSH 入栈,压栈
POP 出栈,弹栈
bash
//主程序给R1,R2,R3,R4分别存入:0x11111111 0x22222222 0x33333333 0x44444444然后跳入函数JUMP
//2.写一个函数JUMP,函数内修改R1为0x20000001 R3为0x00000000
//3.修改结束后返回主函数
//4.主函数再使R1和R3相加后存入R1跳出主程序进入死循环
//子程序返回主程序时,不可以使用MOV指令和B BL BX BXL
AREA STACK, NOINIT, READWRITE
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp
DCD main
AREA |.text|, CODE, READONLY
ENTRY
main
ADD SP,SP,#0X100;上调栈指针
LDR R1,=0X11111111;
LDR R2,=0X22222222;
LDR R3,=0X33333333;
LDR R4,=0X44444444;
BL JUMP
ADD R1,R1,R3
B loop
JUMP
PUSH {R0-R4,LR} ;保护现场
LDR R1,=0X44324302;
LDR R3,=0X33222055;
POP{R0-R4,PC} ;恢复现场
loop
B loop
END
栈的应用
叶子函数
叶子函数是指一个函数内部没有调用其他函数的函数,也就是说,它是程序调用树的末端节点,不依赖于其他函数。
非叶子函数
非叶子函数是指一个函数内部调用了其他函数的函数,也就是说,它不是程序调用树的末端节点,可以被其他函数调用。