首页 > 编程语言 >uboot的重定向汇编详细分析--Apple的学习笔记

uboot的重定向汇编详细分析--Apple的学习笔记

时间:2023-11-01 23:32:32浏览次数:35  
标签:r0 Apple -- start 地址 relocate uboot copy r1

一,前言

既然是第二轮学习,当然要比第一轮增加深度,获取更多技能和通用方法论。之前我想通过代码关闭relocate功能,结果一尝试就复位了,看来没我想的简单,还是先了解下relocate的代码。

二,源码分析

调用前r0有传参为gd->relocaddr,也就是一个指针地址保存在r0。

arch/arm/lib/crt0.S
	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code

relocate_code的整个过程分析,关于我的理解都添加了注释。

arch/arm/lib/relocate.S

ENTRY(relocate_code)
relocate_base:
	adr	r3, relocate_base       /* 读取运行地址到r3 */
	ldr	r1, _image_copy_start_ofs /* _image_copy_start和relocate_base的地址差保存到r1 */
	add	r1, r3			/* 运行时的_image_copy_start地址保存到r1 */
        /* 这里说下,要获取运行时候地址正常来说是可以直接读,但是_image_copy_start是编译时候的一个变量值,这个变量值代表了一个地址,所以才要用这样的方法 */
	subs	r4, r0, r1		/* gd->relocaddr的指针地址,再减去运行时候_image_copy_start_ofs的值,获取差值,是relocate要修改的offset值  */
	beq	relocate_done		/* 若差值为0就不做重定向了 */
	ldr	r1, _image_copy_start_ofs
	add	r1, r3			/* r1 <- Run &__image_copy_start */
	ldr	r2, _image_copy_end_ofs
	add	r2, r3			/* r2 <- Run &__image_copy_end   */
/* 如上4行就是获取运行时候的_image_copy_start和_image_copy_end地址保存到r1和r2中
copy_loop:
	ldmia	r1!, {r10-r11}		/* copy from source address [r1] */
	stmia	r0!, {r10-r11}		/* copy to   target address [r0] */
	cmp	r1, r2			/* until source end address [r2] */
	blo	copy_loop
/* 如上4行时copy命令,就是r1地址中的值先缓存到r10-r11,然后r1地址加2,然后将缓存中的内容保存到r0地址(gd->relocaddr)中,由于r1是源,然后源地址加加后直到与r2地址值一样,就停止copy了。而r1是运行时的image_copy_start,r2是image_copy_end,这样就完成了uboot的重定向copy */
/* 根据u-boot.lds__image_copy_end后紧接着就是__rel_dyn_start,而这段是重定向的关键,但是内容不做迁移,仅对内容值做修改 */
	/*
	 * fix .rel.dyn relocations
	 */
	ldr	r1, _rel_dyn_start_ofs
	add	r2, r1, r3		/* r2 <- Run &__rel_dyn_start */
	ldr	r1, _rel_dyn_end_ofs
	add	r3, r1, r3		/* r3 <- Run &__rel_dyn_end */
/* 如上4行一样的是是获取运行时的开始和结束地址 */
fixloop:
	ldmia	r2!, {r0-r1}		/* (r0,r1) <- (SRC location,fixup) */
	and	r1, r1, #0xff           
	cmp	r1, #R_ARM_RELATIVE
	bne	fixnext
/* 如上4行意思是从首地址拿出2个值到缓存r0和r1,而2个值的含义是一个代表函数或变量位置,第二个代表是否支持重定向,所以第二个值比较关键,也就是r1的值最后uint8是R_ARM_RELATIVE(23)代表是重定向类型则会继续,否则调用fixnext,继续遍历到dyn_end */
	/* relative fix: increase location by offset */
	add	r0, r0, r4              /* r0增加offset值后保存到r0 */
	/*一开始不明白的是这里r0也就是r2开始的_rel_dyn_start中的内容,为什么要先加offset,后来知道由于.rel.dyn段不copy,其实用了直接设置值的方法,也就是在image copy完后,继续在image内容后面,写入新的值,之前image直接写入gd->relocaddr地址的,而这个地址和编译生成的地址的offset保存在r4,所以r0需要加r4,接下来就是写值了,看起来是提取2个值,但是写入的新值仅1个,猜测已经够了,应该是23不需要再写入了。*/
	ldr	r1, [r0]                /* 把r0地址中的值保存到r1 */
	add	r1, r1, r4              /* r1增加offset值后保存到r1 */
	str	r1, [r0]                /* 把r1的值保存到r0地址的内容中 */
/* 如上3行的时候,r1其实之前mask过0xff已经不需要保存了,可以用来做其它事情,所以3行主要是处理r0地址中的内容,为其加offset值后在存入r0 */
fixnext: /* 全部遍历完r2(start)值已经增长到了r3(end),那么就停止循环了。*/
	cmp	r2, r3
	blo	fixloop

relocate_done:

这里add r0, r0, r4我有一个猜测,就是23类型不用再写入了。但是地址信息需要写入,这是什么原理,我要继续找原因。

三,源码仿真调试

之前qemu可以仿真vexpress,所以我单步调试了下。对我理解的代码进行了闭环验证,至少我理解是正确的。关于寄存器值的变换我都添加在每行后面了。

ENTRY(relocate_code)
relocate_base:
	adr	r3, relocate_base           // r3 = 0x60801608 , r0 = 0x7ff55000
	ldr	r1, _image_copy_start_ofs   // r1 = 0xffffe9f8
	add	r1, r3			/* r1 <- Run &__image_copy_start */   // r1 =0x60800000
	subs	r4, r0, r1		/* r4 <- Run to copy offset      */  // r4 = 0x1f755000
	beq	relocate_done		/* skip relocation               */
	ldr	r1, _image_copy_start_ofs   // r1 = 0xffffe9f8
	add	r1, r3			/* r1 <- Run &__image_copy_start */   // r1 =0x60800000
	ldr	r2, _image_copy_end_ofs     // r2=0x903ec
	add	r2, r3			/* r2 <- Run &__image_copy_end   */   // r2=0x608919f4
copy_loop:
	ldmia	r1!, {r10-r11}		/* copy from source address [r1] */
	stmia	r0!, {r10-r11}		/* copy to   target address [r0] */
	cmp	r1, r2			/* until source end address [r2] */
	blo	copy_loop

	/*
	 * fix .rel.dyn relocations
	 */                          // in mapfile .rel_dyn_start  0x608919f4
	ldr	r1, _rel_dyn_start_ofs   //r1 = 0x903ec
	add	r2, r1, r3		/* r2 <- Run &__rel_dyn_start */  //r2 = 0x608919f4
	ldr	r1, _rel_dyn_end_ofs     //r1 = 0x9d69c
	add	r3, r1, r3		/* r3 <- Run &__rel_dyn_end */    //r3 = 0x6089eca4
fixloop:
	ldmia	r2!, {r0-r1}		/* (r0,r1) <- (SRC location,fixup) */  // r0=0x60800020
	and	r1, r1, #0xff
	cmp	r1, #R_ARM_RELATIVE
	bne	fixnext

	/* relative fix: increase location by offset */
	add	r0, r0, r4             // r0=0x7ff55020
	ldr	r1, [r0]               // r1=0x60800060
	add	r1, r1, r4             // r1=0x7ff55060
	str	r1, [r0]               // r0地址内容从原来的0x60800060变成了7FF55060
fixnext:
	cmp	r2, r3
	blo	fixloop

relocate_done:

rel_dyn_start_ofs地址中的值确实能看到23,见下图

uboot的重定向汇编详细分析--Apple的学习笔记_uboot

四,疑问项

之前我猜测rel_dyn_start_ofs中仅需要前4个字节改变地址,后面23不需要了,这是为什么呢,之后再研究。估计就是要symbol表得到地址,所以23可以不需要,但是地址是需要的。

五,小结

深度思考就是多问几个why。为什么要这样设计,为什么其他人会知道答案,我不知道,原因就是我一定缺少或者误解了某些信息。看来我要再看一遍<程序员的自我修养>,我记得里面对代码编译链接都写的很详细,以前细节估计看漏了,或者理解不清晰导致我会有这样的疑问项。

标签:r0,Apple,--,start,地址,relocate,uboot,copy,r1
From: https://blog.51cto.com/AppleCai/8134281

相关文章

  • 当代农村年轻娃的出路是什么?
    农村年轻人有多种选择来寻找未来的出路。以下是一些可能的出路:农业创新和农村发展:农村年轻人可以通过农业创新来推动农村发展。他们可以探索新的农业技术、可持续农业实践和农产品加工,以提高农业产量和增加农民的收入。创业和小企业:农村年轻人可以考虑创办自己的小企业或家庭农场。......
  • 23年,大批程序员失业,一直找不到工作,大龄程序员出路在哪里?
    对于大龄程序员而言,虽然可能会面临更大的就业竞争,但还是有许多出路可以考虑。以下是一些可能的选择:不断学习和更新技能:随着科技的迅速变化,持续学习和更新技能是至关重要的。大龄程序员可以通过参加各种培训课程、在线学习平台或自学来更新自己的技能,以适应新的技术需求。寻找适合的......
  • 刚入职大厂程序员,感觉信仰崩塌,程序员到底为了什么?
    作为程序员,每个人的动机和目标可能会有所不同,但有几个共同的方面可以帮助你理解程序员为什么选择这个职业:创造力和解决问题:程序员可以通过编写代码来实现自己的创意和创造力。他们喜欢面临挑战并找到解决复杂问题的方法。这种创造力和问题解决的过程给程序员带来了满足感和成就感。......
  • 用结构化思维解一切BUG(2):实践原则
    背景本文是系列文章《用结构化思维解一切BUG》的第二篇。本系列文章主要介绍一种「无需掌握技术细节,只需结构化思维和常识即可解一切BUG的方法」。在前序文章《用结构化思维解一切BUG(1):核心思路》中,我介绍了用结构化思维解BUG的核心思路。即,基于结构化的「假设树」,通过重复多次执......
  • 11.1
    11.1转义字符、语句、注释转义字符\?:在书写连续多个问号时防止被解析三字字母\':表示字符常量'\":表示字符常量"\\:表示双斜杠防止它被解释为一个转义序列符\a:警报\b:退格键,不删除字符,回退光标\f:换页符\n:换行符\r:回车符,光标移到同一行的开头\t:制表符,光标移到下一个水平制......
  • docker 配置 ElasticSearch + Kibana + ik分词器
    docker配置ElasticSearch+Kibana+ik分词器下载镜像文件dockerpullelasticsearch:7.4.2#存储和检索数据dockerpullkibana:7.4.2#可视化检索数据创建实例配置外置挂在目录,echo这一行命令配置可以被任意主机访问mkdir-p/mydata/elasticsearch/configmkdir-p/......
  • 模拟实现.net中的Task机制:探索异步编程的奥秘
    .net中使用Task可以方便地编写异步程序,为了更好地理解Task及其调度机制,接下来模拟Task的实现,目的是搞清楚:Task是什么Task是如何被调度的基本的Task模拟实现从最基本的Task用法开始Task.Run(Actionaction)这个命令的作用是将action作为一项任务提交给调度器,调度器会安排......
  • 验证2个节点udp和tcp可通性
    -u表示udp,默认是tcp。-l表示作为server监听。server:192.168.0.104上开启udp123端口server发送11client:连接192.168.0.104上udp123端口client发送100 server:192.168.0.104上开启tcp123端口server发送102client:连接192.168.0.104上tcp123端口client发送101......
  • 企业erp流程图
     ......
  • ⭐ go gorm 映射框架 好用到爆炸!!!
    使用Golandide插件搜索Gorm直接安装连接数据库并且选择表,鼠标右键gorm之后按照你的项目要求生成crud直接快人一步释放双手啦......