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 funcn");
+
+}
+
+static void * test_func_val = test_func;
+int test_val = 10;
+
+void rel_dyn_test()
+{
+ test_val += 20;
+ printf("test_val = 0x%xn", test_val);
+ printf("test_val addr = 0x%xn", &test_val);
+ printf("test = 0x%xn", test_func);
+ printf("test_func = 0x%xn", 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%xn", test_val);
+ printf("after relocate test_val addr = 0x%xn", &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 5fb08fb8: e92d4010 push {r4, lr} 5fb08fbc: e5993004 ldr r3, [r9, #4] --- 5fb08fc0: e59f4060 ldr r4, [pc, #96] ; 5fb09028 --- 5fb08fc4: e59f5060 ldr r5, [pc, #96] ; 5fb0902c 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 5fb08fd8: eb006ec2 bl 5fb24ae8 5fb08fdc: e1a01004 mov r1, r4 5fb08fe0: e59f004c ldr r0, [pc, #76] ; 5fb09034 5fb08fe4: eb006ebf bl 5fb24ae8 5fb08fe8: e1a06005 mov r6, r5 5fb08fec: e4953004 ldr r3, [r5], #4 5fb08ff0: e3530000 cmp r3, #0 5fb08ff4: 0a00000a beq 5fb09024 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 5fb09010: e5962000 ldr r2, [r6] 5fb09014: e59f1010 ldr r1, [pc, #16] ; 5fb0902c 5fb09018: e59f0018 ldr r0, [pc, #24] ; 5fb09038 5fb0901c: e0422004 sub r2, r2, r4 5fb09020: eb006eb0 bl 5fb24ae8 5fb09024: eb006577 bl 5fb22608 --- 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 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 代码 代码运行时的地址与 u-boot.map u-boot.map 中的地址为 链接地址,和 链接选项 -Ttext 0x5FB00000 有关 如果加载的时候加载到了 0x5FB00000 ,那么u-boot代码函数 relocate 前的运行地址 等于 链接地址(也即是 u-boot.map 中的地址) 在此情况下,重定位后的代码函数 和 u-boot.map中的关系 addr in u-boot.map + gd->reloc_off = 重定位后的代码函数地址
上一篇:OK6410A 开发板 (三) 15 u-boot-2021.01 boot 解析 U-boot 镜像编译部分 Makefile解析
下一篇:OK6410A 开发板 (三) 13 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析2 relocate_vectors
推荐阅读最新更新时间:2024-11-04 23:10
设计资源 培训 开发板 精华推荐
- EVAL-AD1940AZ,汽车用 28 位音频处理器评估板
- LT8330HDDB 4V 至 16V 输入、-5V 反相转换器的典型应用电路
- AM30EW-480515TZ 5V 单路输出 DC/DC 转换器的典型应用
- 使用 NXP Semiconductors 的 UBA3077HN/1,518 的参考设计
- eLQFP64封装的SPC570Sx的插槽式微型模块
- Cree XLamp CXA3050 LED 壁挂灯参考设计
- 单管放大电路
- LT1377IS8 具有直接反馈的正负转换器的典型应用
- 使用 Analog Devices 的 LTC1450LIN 的参考设计
- LT1377CS8 2 锂离子电池至 5V SEPIC 转换器的典型应用