①。 汇编理论知识
7种模式, 32个寄存器
r0 - r7 : 7种模式都是一样的
r8- r12 : 普通模式、 FIQ 下特有的 r8 - r12
r13 - r14 : 每种下都有 , 每种模式都不一样
sp : 每种模式下都有自己的栈, 所以r13 每种模式下都有
lr: 比如从user 模式切换到fiq 模式,把user模式返回地址存的lr中, fiq执行完毕以后就可以直接回到user模式
pc : 程序寄存器, 当前程序执行在哪里, 所以只有一个,一个国家只有一个皇帝 , pc 指向那条指令, cpu执行哪条 , 程序跑飞了, pc寄存器内容不对了
cpsr: 程序状态寄存器,存储cpu的状态
spsr: 保存cpsr 比如User模式下有cspr, 在fiq下把user模式下的cpsr保存到fiq下的spsr ,返回的恢复User模式下状态
栈的集中概念;
* 空栈: sp 指向空位 ,每次存入的时可以直接存入然后栈 指针移动一格 ; 取出的时需要首先移动一格才能取出 empty
* 满栈: sp 指向栈中最后一格数据, 每次存入需要移动栈指针一格在存入 取出的时候直接取出,在移动栈指针 full
增栈: 指针移动时向地址增加方向移动 incrase
减栈: 指针移动时向地址减少方向移动 declare
三面4中模式可以组合,
arm是 减栈 、 空栈 , 空减栈 , ed
分析几条汇编指令:
add r0,r1,#4 r0=r1+4
sub r0,r1,r2 r0=r1-r2
bl : 跳转到某一条指令,并且把返回地址保存 到 lr中,返回地址就是吓一跳指令的地址
ldm : 从内存读取数据到 寄存器, m读内存,写入多个寄存器
stm : 把多个寄存器的值写入内存
ldmia : ia 就是个上面 的 increase after 分配过后增加
例子:
stmdb sp!,{fb,ip,lr,pc} db : declare before 减少在分配之前, 首先减后存
假设: sp = 4096
- 首先减后存 4096-4 = 4092 4095-4092存储pc的值
4091-4088存储ip的值
4087-4084存储lr的值
4083-4080存储fp的值
! 表示 sp = 4080 等于最终被修改的值。
内存模型图:
存储规则: 高编号寄存器,存储在高地址
pc r15
lr r14
ip r12
fp r11
参考
②。 点亮led具体代码分析
start.S 功能: 设置栈、 调用 main 并且返回 地址保存 lr 中 代码 bl main
.text
.global _start
_start:
ldr sp, =4096 /* nand 设置栈*/
// ldr sp, =0x40000000+4096 /* nor 设置栈 */
/* 调用main */
bl main
halt:
b halt
led.c
int main()
{
unsigned int *pGPFCON = (unsigned int *)0x56000050;
unsigned int *pGPFDAT = (unsigned int *)0x56000054;
/* 配置GPF4为输出引脚 */
*pGPFCON = 0x100;
// fun(); ,如果bl main 返回地址保存到lr中, fun()如果返回地址在保存到lr中
// 那么 lr就会被覆盖
// 所以 ,这里面保存 lr等寄存器到栈中需要
/* 设置GPF4输出0 */
*pGPFDAT = 0;
return 0;
}
为什么要设置栈:
1. 局部变量要入栈
2. 保存lr等寄存器, 函数恢复以后,会恢复寄存器
裸机4K内存,下面从0开始表示 汇编指令码,上面是栈 , 4个字节一个格子
bl mainI(int agrs) 调用者如何传递参数给被调用者,子函数?
被调用者传递返回值给调用者?
通过寄存器 r0,r1,r2,r3
在函数中r4-r11 可以被使用,参与程序的操作,函数入口保存它们,函数出口恢复它们
分析:
-----------------------------------------------------------------
# 把nandFlash的内容拷贝到 片内内存的前4K 内存中
led.elf中 --> 0地址拷贝到 栈底,
led.elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
0: e3a0da01 mov sp, #4096 ; 0x1000 上电从0地址开始执行,sp=4096
4: eb000000 bl c <main> 跳到下面的地址[e1a0c00d]开始执行
00000008 <halt>: // 这里表示lr=8, 8就是 bl main 下一条指令的地址
8: eafffffe b 8 <halt>
0000000c <main>:
c: e1a0c00d mov ip, sp ip=4096
10: e92dd800 stmdb sp!, {fp, ip, lr, pc} //高标号对应高地址
// pc(r15) lr(14) ip(12) fp(11) 首先存储pc 在lr 在ip ,在fp , 临时保存,程序执行完毕还要出来 复原
// sp=4096-4*4 = 4080
14: e24cb004 sub fp, ip, #4 ; 0x4
// fp=4096-4=4092
18: e24dd008 sub sp, sp, #8 ; 0x8
// sp= sp- 8 = 4072 //用来存储pCon ,整个是满减栈 ,首先移动栈指针指向空,在插入数据
1c: e3a03456 mov r3, #1442840576 ; 0x56000000
// r3= 0x56000000
20: e2833050 add r3, r3, #80 ; 0x50
// r3= 0x56000050
24: e50b3010 str r3, [fp, #-16]
// r3存储到 [4092 -16= 4076], 这就是局部变量保存到栈中, 入栈
28: e3a03456 mov r3, #1442840576 ; 0x56000000
2c: e2833054 add r3, r3, #84 ; 0x54
// r3=r3+ 0x56000054
30: e50b3014 str r3, [fp, #-20]
// r3=0x56000054 存储到 4072中 -4092-20=4072
// 完成入栈了
34: e51b2010 ldr r2, [fp, #-16]
// r2从 [4092 -16= 4076] 4076取值
38: e3a03c01 mov r3, #256 ; 0x100
3c: e5823000 str r3, [r2]
// 把 0x100 存储到 0x56000050 内存地址上中
//获取4072的值 到r2中 就是 0x56000054
40: e51b2014 ldr r2, [fp, #-20]
44: e3a03000 mov r3, #0 ; 0x0
48: e5823000 str r3, [r2]
// 把0x0存0x56000054 内存地址上
4c: e3a03000 mov r3, #0 ; 0x0
50: e1a00003 mov r0, r3
// 返回值0 保存到r0中
54: e24bd00c sub sp, fp, #12 ; 0xc
// sp = fp(4092)-12= 4080
58: e89da800 ldmia sp, {fp, sp, pc}
// 从栈中恢复寄存器, 从4080开始恢复
// fp=4080
// sp=4096
// pc=8 调回去0x8的地址 ,main返回
Disassembly of section .comment:
//表示注释,不会放到ram中去
00000000 <.comment>:
0: 43434700 cmpmi r3, #0 ; 0x0
4: 4728203a undefined
8: 2029554e eorcs r5, r9, lr, asr #10
c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
10: Address 0x10 is out of bounds.
-----------------------------------------------------------------
总结图:
③。 分析汇编如何传递参数给c 程序
start.S
.text
.global _start
_start:
/* 设置内存:sp 栈 */
ldr sp, =4096 /* nand 启动 */
// ldr sp, =0x40000000+4096 /* nor 启动 */
mov r0, #4
bl led_on
ldr r0, =100000
bl delay
mov r0, #5
bl led_on
halt:
b halt
led.c
void delay(volatile int d)
{
while (d--);
}
int led_on(int which)
{
unsigned int *pGPFCON = (unsigned int *)0x56000050;
unsigned int *pGPFDAT = (unsigned int *)0x56000054;
if (which == 4)
{
/* 配置GPF4为输出引脚 */
*pGPFCON = 0x100;
}
else if (which == 5)
{
/* 配置GPF5为输出引脚 */
*pGPFCON = 0x400;
}
/* GPF4/5输出0 */
*pGPFDAT = 0;
return 0;
}
led.dis汇编分析 :
led.elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
0: e3a0da01 mov sp, #4096 ; 0x1000 //设置栈
4: e3a00004 mov r0, #4 ; 0x4 //r0=0x04 传递参数
8: eb000012 bl 58 <led_on> //跳到led_on
c: e59f000c ldr r0, [pc, #12] ; 20 <.text+0x20> //r0到pc=8+12=20取值, 整个就是伪指令
10: eb000003 bl 24 <delay> //delay 执行
14: e3a00005 mov r0, #5 ; 0x5 // r0=0x5 传递参数
18: eb00000e bl 58 <led_on> //执行led_on
0000001c <halt>:
1c: eafffffe b 1c <halt>
20: 000186a0 andeq r8, r1, r0, lsr #13 // 就是100000 10万
// ldr r0, =100000 值会单独写入一个代码段的
00000024 <delay>: // 分析delay函数
24: e1a0c00d mov ip, sp
28: e92dd800 stmdb sp!, {fp, ip, lr, pc}
2c: e24cb004 sub fp, ip, #4 ; 0x4
30: e24dd004 sub sp, sp, #4 ; 0x4
34: e50b0010 str r0, [fp, #-16] //取出r0,放入[fp-16]
38: e51b3010 ldr r3, [fp, #-16] // 取出放入r3中
3c: e2433001 sub r3, r3, #1 ; 0x1 // r3运算-1
40: e50b3010 str r3, [fp, #-16] // 存入栈中r3
44: e51b3010 ldr r3, [fp, #-16]
48: e3730001 cmn r3, #1 ; 0x1 //比较r3 和 0x01
4c: 0a000000 beq 54 <delay+0x30>
50: eafffff8 b 38 <delay+0x14>
54: e89da808 ldmia sp, {r3, fp, sp, pc}
00000058 <led_on>:
58: e1a0c00d mov ip, sp
5c: e92dd800 stmdb sp!, {fp, ip, lr, pc}
60: e24cb004 sub fp, ip, #4 ; 0x4
64: e24dd00c sub sp, sp, #12 ; 0xc
68: e50b0010 str r0, [fp, #-16]
6c: e3a03456 mov r3, #1442840576 ; 0x56000000
70: e2833050 add r3, r3, #80 ; 0x50
74: e50b3014 str r3, [fp, #-20]
78: e3a03456 mov r3, #1442840576 ; 0x56000000
7c: e2833054 add r3, r3, #84 ; 0x54
80: e50b3018 str r3, [fp, #-24]
84: e51b3010 ldr r3, [fp, #-16]
88: e3530004 cmp r3, #4 ; 0x4
8c: 1a000003 bne a0 <led_on+0x48>
90: e51b2014 ldr r2, [fp, #-20]
94: e3a03c01 mov r3, #256 ; 0x100
98: e5823000 str r3, [r2]
9c: ea000005 b b8 <led_on+0x60>
a0: e51b3010 ldr r3, [fp, #-16]
a4: e3530005 cmp r3, #5 ; 0x5
a8: 1a000002 bne b8 <led_on+0x60>
ac: e51b2014 ldr r2, [fp, #-20]
b0: e3a03b01 mov r3, #1024 ; 0x400
b4: e5823000 str r3, [r2]
b8: e51b3018 ldr r3, [fp, #-24]
bc: e3a02000 mov r2, #0 ; 0x0
c0: e5832000 str r2, [r3]
c4: e3a03000 mov r3, #0 ; 0x0
c8: e1a00003 mov r0, r3
cc: e24bd00c sub sp, fp, #12 ; 0xc
d0: e89da800 ldmia sp, {fp, sp, pc}
Disassembly of section .comment:
00000000 <.comment>:
0: 43434700 cmpmi r3, #0 ; 0x0
4: 4728203a undefined
8: 2029554e eorcs r5, r9, lr, asr #10
c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1}
10: Address 0x10 is out of bounds.