OK6410A 开发板 (三) 14 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析3 relocate_code

		adr lr, here // 存放 lr, 为  b(跳转) 做准备
		ldr r0, [r9, #76] // 将 new_gd 中的 reloc_off 存放到r0,用作新的lr的计算
		add lr, lr, r0 	 // 更改lr ,让 relocate_code 返回时,跳转到 已经 搬移好的代码 中去,
		ldr r0, [r9, #56] // 将 new_gd 中的 relocaddr存放到r0,作为第一个参数
		b relocate_code
			// 搬移 u-boot的 code 段
			arch/arm/lib/relocate.S +80
			搬移,修复绝对地址???

  • arch/arm/lib/relocate.S

// 拷贝, 从哪里(__image_copy_start)到哪里(relocaddr,已经存放在r0中),拷贝多少




.globl relocate_code ; .align 0 ; relocate_code:


/**
	拷贝
**/

 // 将 拷贝源 的开始地址 __image_copy_start 放到 r1 中
 ldr r1, =__image_copy_start
 // 计算 目标地址和源地址 差值 ,放到 r4 
 subs r4, r0, r1
 beq relocate_done
 
 // 计算 拷贝源 的末端地址
 ldr r2, =__image_copy_end

copy_loop:
 // 将源数据放到r10 r11 中
 ldmia r1!, {
    
    r10-r11}
 // 将 r10 r11 放到 目标地址中
 stmia r0!, {
    
    r10-r11}
 cmp r1, r2
 blo copy_loop


/**
	fix 指的是 对引用地址的修改
	对.code段 引用地址(变量地址,函数地址,指针地址等) 的修改
**/

// 链接器根据-pie参数才会生成rel.dyn段
 // fix .rel.dyn relocations
 ldr r2, =__rel_dyn_start
 ldr r3, =__rel_dyn_end
fixloop:
 // rel.dyn 段 是 gcc链接器根据-pie参数生成的
 // 一个数对标识了一个 ??? 
 ldmia r2!, {
    
    r0-r1}
 and r1, r1, #0xff
 // rel.dyn段中每一个rel section(8个字节)第二个4字节,0x17,是一种label的类型R_ARM_RELATIVE
 // 这个是 gcc 做的标记, 表示 这个需要 relative fix
 cmp r1, #23
 bne fixnext

 // relative fix: increase location by offset
 add r0, r0, r4
 ldr r1, [r0]
 add r1, r1, r4
 str r1, [r0]
 // 整个过程 中 看到 来来往往, 只有一条指令修改了内存中的值
 // str r1, [r0]
 // 修改的是 一个地址中的值 ,这个地址是 (一个数对中的第二个数+offset)
 // 这个地址位于代码段中
 // fixloop 具体做了什么事 
 // 全局搜索 fixloop做的事
 // "fixloop做的事" 体现了 改了 一处值 , 但 实际上是改了 rel.dyn 段 内所有满足条件(数据对中第二个低八位为0x17(也就是十进制的23))的值


fixnext:
 cmp r2, r3
 blo fixloop

relocate_done:
 bx lr


.type relocate_code STT_FUNC ; .size relocate_code, .-relocate_code

我的关于 rel.dyn段的实验

以变量 test_val  为参考对象
探索copy_loop&fixloop前后的 test_val  地址变化 以及原因
  • 代码修改处
$ git diff  lib/display_options.c 
diff --git a/lib/display_options.c b/lib/display_options.c
index b2025ee..487bfe0 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -40,6 +40,28 @@ char *display_options_get_banner(bool newlines, char *buf, int size)
        return display_options_get_banner_priv(newlines, BUILD_TAG, buf, size);
 }
 
+void test_func(void)
+{
    
    
+       printf("test func\n");
+
+}
+
+static void * test_func_val = test_func;
+int test_val = 10; 
+
+void rel_dyn_test()
+{
    
    
+       test_val += 20; 
+       printf("test_val = 0x%x\n", test_val);
+       printf("test_val addr = 0x%x\n", &test_val);
+       printf("test = 0x%x\n", test_func);
+       printf("test_func = 0x%x\n", test_func_val);
+       test_func();
+
+}
+
+
+
 int display_options(void)
 {
    
    
        char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
@@ -47,6 +69,8 @@ int display_options(void)
        display_options_get_banner(true, buf, sizeof(buf));
        printf("%s", buf);
 
+       rel_dyn_test();
+
        return 0;
 }

$ git diff common/board_r.c
diff --git a/common/board_r.c b/common/board_r.c
index 29dd7d2..590c74b 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -898,6 +898,8 @@ static init_fnc_t init_sequence_r[] = {
    
    
        run_main_loop,
 };
 
+extern int test_val;
+
 void board_init_r(gd_t *new_gd, ulong dest_addr)
 {
    
    
        /*
@@ -919,11 +921,15 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
 #endif
        gd->flags &= ~GD_FLG_LOG_READY;
 
+       printf("after relocate test_val = 0x%x\n", test_val);
+       printf("after relocate test_val addr = 0x%x\n", &test_val);
+
 #ifdef CONFIG_NEEDS_MANUAL_RELOC
        for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
                init_sequence_r[i] += gd->reloc_off;
 #endif
 
+
        if (initcall_run_list(init_sequence_r))
                hang();
 

  • 打印的数据
test_val = 0x1e
test_val addr = 0x5fb35f4c
test = 0x5fb21ff0
test_func = 0x5fb21ff0
test func
Relocation Offset is: 004b3000
after relocate test_val = 0x1e
after relocate test_val addr = 0x5ffe8f4c

  • 反汇编的数据(被 — 包围起来的数据为重点参考数据)

5fb08fb8 <board_init_r>:
5fb08fb8:	e92d4010 	push	{
    
    r4, lr}
5fb08fbc:	e5993004 	ldr	r3, [r9, #4]
---
5fb08fc0:	e59f4060 	ldr	r4, [pc, #96]	; 5fb09028 <board_init_r+0x70>
---
5fb08fc4:	e59f5060 	ldr	r5, [pc, #96]	; 5fb0902c <board_init_r+0x74>
5fb08fc8:	e3c33902 	bic	r3, r3, #32768	; 0x8000
5fb08fcc:	e5893004 	str	r3, [r9, #4]
5fb08fd0:	e5941000 	ldr	r1, [r4]
5fb08fd4:	e59f0054 	ldr	r0, [pc, #84]	; 5fb09030 <board_init_r+0x78>
5fb08fd8:	eb006ec2 	bl	5fb24ae8 <printf>
5fb08fdc:	e1a01004 	mov	r1, r4
5fb08fe0:	e59f004c 	ldr	r0, [pc, #76]	; 5fb09034 <board_init_r+0x7c>
5fb08fe4:	eb006ebf 	bl	5fb24ae8 <printf>
5fb08fe8:	e1a06005 	mov	r6, r5
5fb08fec:	e4953004 	ldr	r3, [r5], #4
5fb08ff0:	e3530000 	cmp	r3, #0
5fb08ff4:	0a00000a 	beq	5fb09024 <board_init_r+0x6c>
5fb08ff8:	e5994004 	ldr	r4, [r9, #4]
5fb08ffc:	e2144001 	ands	r4, r4, #1
5fb09000:	1599404c 	ldrne	r4, [r9, #76]	; 0x4c
5fb09004:	e12fff33 	blx	r3
5fb09008:	e2503000 	subs	r3, r0, #0
5fb0900c:	0afffff5 	beq	5fb08fe8 <board_init_r+0x30>
5fb09010:	e5962000 	ldr	r2, [r6]
5fb09014:	e59f1010 	ldr	r1, [pc, #16]	; 5fb0902c <board_init_r+0x74>
5fb09018:	e59f0018 	ldr	r0, [pc, #24]	; 5fb09038 <board_init_r+0x80>
5fb0901c:	e0422004 	sub	r2, r2, r4
5fb09020:	eb006eb0 	bl	5fb24ae8 <printf>
5fb09024:	eb006577 	bl	5fb22608 <hang>
---
5fb09028:	5fb35f4c 	svcpl	0x00b35f4c
fixloop做的事 就是 将 这一行的 5fb35f4c 改为 5ffe8f4c (5fb35f4c+004b3000)

---
5fb0902c:	5fb359f0 	svcpl	0x00b359f0
5fb09030:	5fb2becd 	svcpl	0x00b2becd
5fb09034:	5fb2beed 	svcpl	0x00b2beed
5fb09038:	5fb2be70 	svcpl	0x00b2be70

---
5fb35f4c <test_val>:
5fb35f4c:	0000000a 	andeq	r0, r0, sl
---



Disassembly of section .rel.dyn:

...
...
---
5fb37d30:	5fb09028 	svcpl	0x00b09028
5fb37d34:	00000017 	andeq	r0, r0, r7, lsl r0
---

...
...

---
5fb39c68:	5fb220f8 	svcpl	0x00b220f8
5fb39c6c:	00000017 	andeq	r0, r0, r7, lsl r0
---

...
...


  • 模型
// copy_loop前
// 注意: 加载位置和链接位置是一样的
.rel.dyn
	存储了C

.code
	
	值B 和  存储B的地址C

.data
	值A 和 存储A的地址B

---------------------
// copy_loop后,fixloop前
.rel.dyn
	存储了C // 通过 C+gd->reloc_off 得到 C_

.code
	
	值B 和  存储B的地址C_ // 通过 B+gd->reloc_off 得到 B_ 

.data
	值A 和 存储A的地址B_ 
---------------------
// copy_loop后,fixloop后
.rel.dyn
	存储了C // 通过 C+gd->reloc_off 得到 C_

.code
	
	值B_ 和  存储B_的地址C_ // 通过 B+gd->reloc_off 得到 B_ // 然后将B_写入 C_

.data
	值A 和 存储A的地址B_ 
  • 模型对应的数据
// copy_loop前
// 注意: 加载位置和链接位置是一样的
.rel.dyn
	存储了C (5fb09028    svcpl   0x00b09028)
	
.code
	
	值B(5fb35f4c) 和  存储B的地址C(5fb09028)

.data
	值A(0000000a) 和 存储A的地址B(5fb35f4c)

---------------------
// copy_loop后,fixloop前
.rel.dyn
	存储了C (5fb09028    svcpl   0x00b09028) // 通过 C+gd->reloc_off 可得到 C_

.code
	
	值B(5fb35f4c) 和  存储B的地址C_(5fb09028+004b3000=0x5FFBC028) // 通过 B+gd->reloc_off 得到 B_ 

.data
	值A(0000000a) 和 存储A的地址B_(5fb35f4c+004b3000=0x5ffe8f4c)
---------------------
// copy_loop后,fixloop后
.rel.dyn
	存储了C (5fb09028    svcpl   0x00b09028) // 通过 C+gd->reloc_off 可得到 C_

.code
	
	值B_(5fb35f4c+004b3000=0x5ffe8f4c) 和  存储B_的地址C_(5fb09028+004b3000=0x5ffbc028) // 通过 B+gd->reloc_off 得到 B_ // 然后将B_写入 C_

.data
	值A(0000000a) 和 存储A的地址B_(5fb35f4c+004b3000=0x5ffe8f4c)

思考

 // 具体参考 https://blog.csdn.net/skyflying2012/article/details/37660265

u-boot 之所以能做 fixloop ,是 gcc 支持 .rel.dyn 这项技术
而u-boot 做的 fixloop 也就是 gcc 打开 .rel.dyn 技术 后,代码需要做的部分而已

所以想知道更多,请查阅 gcc 文档 或 gcc 代码


猜你喜欢

转载自blog.csdn.net/u011011827/article/details/115241203