目录
学习目的:了解硬件指令执行逻辑,知道c语言如何编译和运行的,了解汇编指令中的专业术语
基础知识
汇编文件格式:
.text //代码段的开始
@代码指令
//代码存储区(只读)
.data //数据段
@ 数据存储区 可读可写
.end //结束
- 汇编中的符号:
- 标识符:本身不会生成指令,只是一些标志
- 汇编指令:每一条汇编指令,都可以编译为与之对应的一个机器码
- 伪指令:该指令编译后可能生成的机器指令不只一个
- 汇编指令结构:
指令码 <目标寄存器>,<第一操作寄存器>,<第二操作寄存器或 立即数 移位>
mov r0,#1
- ARMcpu使用的ARM指令集是一种精简处理器指令集(RISC)
它保留了简单的、使用频率高的指令,追求结构简单,成本低功耗低
- X86使用的是复杂处理器指令集(CISC),追求的是高效率,很多复杂的动作都有指令与之对应
- ARM指令集指令定长,每个指令固定长度为4字节;而复杂处理器指令集(CISC)是变长指令集,1-16字节,仅有的几个指令可以条件执行
- 一条ARM指令的 指令码 构成:
4bit 条件码 4bit 指令码 4bit 目标寄存器编号 4bit 第一操作寄存器编号 12bit 第二操作寄存编号或立即数或寄存器移位
ARM汇编:
数据操作指令
mov指令
格式:mov 目标寄存器(R0-R15),立即数或寄存器移位
立即数概念:为了解决在12bit空间内,能够覆盖更广的数值空间
立即数即一个8bit的数,循环右移偶数位,能够得到的数,就是立即数
测试练习: 判断下列哪些是立即数
0x123 不是
0b0001 0010 0011
0x188000 是
0b 0001 1000 1000 0000 0000 0000
0x7080 不是
0b 0111 0000 1000 0000
mvn指令:取反
伪指令
将非立即数想办法变成立即数
例如:ldr r0,=0x12345678 ‘=’表示立即数,‘ldr'表示伪指令
移位运算解释
<< 逻辑左移 高位移出丢弃 低位补0
>> 逻辑右移 低位移出丢弃 高位补0
算数左移 高位移出丢弃 低位补0
算数右移 低位移出丢弃 高位补符号位
算数运算
adc 带进位的加法,主要用于高于32位数的加法
add +
SUB:-
sbc:带错位的减法
rsb:逆向减法
rsc:带错位的逆向减法
mul:乘法
- ARM中的除法:
软件除法: 将除法运算 通过 其他运算实现 - >> <<
硬件除法: FPU 浮点运算单元
位操作指令
- bic--位清除操作:
- C中逻辑: && || !
- C中位 : & | ~ ^
- 汇编: and orr mvn eor
& 按位与: 与0得0 与1不变 对某些bit进行置0操作 或 保留某些bit的值
| 按位或: 或1得1 或0不变 对某些bit进行置1操作
^ 按位亦或: 相同得0 不同得1 对某些bit进行取反操作
测试指令
- tst--位测试指令,其结果直接影响cpsr,不产生放到目的寄存器的结果,属于比较指令
- teq--相等测试
- cmp--大小测试指令
指令的条件执行
- 内存读写操作指令
单寄存器操作: 一次性从内存中读写 一个寄存器(4个字节)数据 地址必须要4字节对齐
LDR: 从内存中 读取一个数据到 寄存器中
STR: 将寄存器中的一个数据 写入 到内存中
ldrh 从内存中 读取一个short数据到 寄存器中
strh 将寄存器中的一个short(最低16bit)数据 写入 到内存中
ldrb 从内存中 读取一个字节数据到 寄存器中
strb 将寄存器中的一个字节(最低8bit)数据 写入 到内存中
汇编中 连续操作内存 使用 索引
前索引: 基地址 先 + 偏移量 然后操作这个地址中的数据 不会更改基地址 *(p+1)
后索引: 先操作基地址中的数据, 然后 基地址 += 偏移量 会更改基地址 *p++
自动索引: 基地址 先 += 偏移量 然后操作这个地址中的数据 会 更改基地址 *++p
程序跳转(函数调用)
跳转指令: 本质是 修改PC
C语言中 goto while for case
不带返回链接的跳转
示例: b stop // 跳转到stop标记位置
例1:
C switch case switch(a) // a =r0 b=r1 { case 0: b = 1; break; case 1: b = 2; case 2: b = 3; break; default: b = 4; }
对应汇编 mov r0,#1 @ a = 1 teq r0,#0 @ case 0: moveq r1,#1 @ b = 1; beq stop @ 跳转指令 break; teqne r0,#1 moveq r1,#2 teqne r0,#2 moveq r1,#3 beq stop @ 跳转指令 movne r1,#4 stop: @ 地址标记 nop @ 空指令
例2:
求 1+2+3+.. 100 = ? int sum = 0; // r1 int i = 1; // r0 for(i=1; i<101; i++) sum += i; mov r0,#1 @ int i = 1 mov r1,#0 @ int sum = 0 mov r0,#1 @ for(i=1; loop: cmp r0,#101 @ i < 101 addlt r1,r0 @ sum += i; addlt r0,#1 @ i++; blt loop nop BL : C语言中 函数调用
带返回的跳转 在跳转动作执行时,会将PC备份到LR中
main()
{
int a = 10,b=20;
int c = func(a,b);
..../
}
int func(a,b) // a=r0 b=r1
{
static int x = 5;
// 将r4-r12 入栈保存
int i,sum = 0; // i= r2 sum = r3
for(i=a; i<b; i++)
sum += i;
return sum; // sum = r0 , 弹栈恢复 r4-r12
}
//C编译器约定 参数通过 R0-R3传递 超过4个的参数 使用栈传递
// 函数返回值 通过 R0传递
main:
mov r0,#10 @ 准备参数
mov r1,#20
bl func @ 调用函数
nop @ c = r0
nop
50M
@函数 func
func:
mov r2,r0 @ for(i=a;
loop:
cmp r2,r1 @ i < b
addlt r3,r2 @ sum += i;
addlt r2,#1 @ i++;
blt loop
mov r0,r3 @ return sum;
mov pc,lr
nop
b和bl 的 特性: 本质是 修改PC
b 和 bl 是一个相对于当前PC的一个跳转, 是相对跳转 跳转距离较短
往前或后 跳转 24bit 描述 跳转的范围
+- 2^23-1 * 4 字节
+- 32M 地址空间 0-4G
长跳转, 直接修改PC 将要跳转的地址 装载到PC中
Start.s文件示例:
.text
@ldr r0,=0x12345678 @ 伪指令
@mov r0,#1 @ 数据搬移指令
@mov r1,#2
@add r3,r0,r1
@ 64位+法
@ a = 0x12345678 99999999
@ b = 0x12345678 88888888
@ldr r0,=0x99999999
@ldr r1,=0x88888888
@ldr r2,=0x12345678
@ldr r3,=0x12345678
@adds r4,r0,r1 @ 若有溢出,cpsr 溢出位设置
@adcs r5,r2,r3 @ r5 = r2+r3 + c;
@mov r0,#5 @ 0b0101
@sub r1,r0,#10 @ r1 = r0-10
@rsb r2,r0,#10 @ r2 = 10-r0
@mul r3,r0,r2
@and r1,r0,#0xfffffffe
@and r1,r0,#-2
@bic r1,r0,#5
@teq r0,#5
@MoV r0,#5 @ a=5
@mov r1,#6 @ b=6
@cmp r0,r1
@movgt r0,r1 @ a>b a,b是有符号数
@movle r1,r0 @ a<=b a,b是有符号数
/*
switch(a) // a =r0 b=r1
{
case 0:
b = 1;
break;
case 1:
b = 2;
case 2:
b = 3;
break;
default:
b = 4;
}
...
*/
/*
mov r0,#1 @ a = 1
teq r0,#0 @ case 0:
moveq r1,#1 @ b = 1;
beq stop @ 跳转指令 break;
teqne r0,#1
moveq r1,#2
teqne r0,#2
moveq r1,#3
beq stop @ 跳转指令
movne r1,#4
stop: @ 地址标记
nop @ 空指令
*/
/*
mov r0,#1 @ int i = 1
mov r1,#0 @ int sum = 0
mov r0,#1 @ for(i=1;
loop:
cmp r0,#101 @ i < 101
addlt r1,r0 @ sum += i;
addlt r0,#1 @ i++;
blt loop
*/
@ bl 指令
/*
main:
mov r0,#10 @ 准备参数
mov r1,#20
bl func @ 调用函数
nop
nop
@函数 func
func:
mov r2,r0 @ for(i=a;
loop:
cmp r2,r1 @ i < b
addlt r3,r2 @ sum += i;
addlt r2,#1 @ i++;
blt loop
mov r0,r3 @ return sum;
mov pc,lr
*/
/*
nop
b loop @ 2
b loop @ 1
b loop @ 0 ===>
b loop @ -1
loop:
b loop @ -2 pc
b loop @ -3
b loop @ -4
b loop
*/
@ 内存操作指令
ldr r0,=a @ 得到a的地址
ldr r1,[r0] @ r1 = *r0
ldr r2,=m
str r1,[r2] @ *r2 = r1
ldr r3,=name
ldrb r0,[r3]
mov pc,#0
@只读
@const char *name1 = "hello";
name1: .byte 'h','e','l','l','o',0
.data @ 数据段开始
@ int a = 10; //全局变量
a: .word 10
@ int m;
m: .space 4
@ char c = 'b';
c: .byte 'b'
@char name[] = "hello";
name: .byte 'h','e','l','l','o',0
@int arr[5];
arr: .space 5*4
@int arr1[5] = {1,2,3,4};
arr1: .word 1,2,3,4,0
.end