c内部机制

①。 汇编理论知识

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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值