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

发布者:信息巫师最新更新时间:2022-09-22 来源: csdn关键字:OK6410A  开发板  u-boot 手机看文章 扫描二维码
随时随地手机看文章

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  开发板  u-boot 引用地址:OK6410A 开发板 (三) 14 u-boot-2021.01 boot 解析 U-boot 镜像运行部分 boot 详细解析3 relocate_code

上一篇: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

OK6410A学习笔记一:一键烧录Linux
去年5月份买的飞凌OK6410A开发板,但是一直没有怎么用,主要是自己懒,呵呵,都是废话 开发环境: windows7 + vmware 6.5 + ubuntu 9.10 烧录步骤: 1)SD卡,格式化成FAT32格式,然后用SD_Write.exe将mmc.bin烧录进去。 windows7下要在管理员模式下运行SD_Write.exe,烧录mmc.bin之前要点击Format 2)把u-boot.bin,zImage,cramfs拷贝到SD卡中 OK6410A支持cramfs和yaffs2文件系统,前者为compressed ram file system,后者为yet another f
[单片机]
NUC980开发板应用 基于NK-980IoT的国学唐诗学习机
1 项目背景 最近一直在陪小孩学习国学精髓,比如唐诗、宋词这些经典国学常识;恰好看到RT-Thread官方社区有开展一个DIY活动,并且这个板子刚好带有音频相关的外设接口,于是想着试着玩一玩,没准后面可以把功能再升级一下,给小孩做个高级”玩具”(这个成本可不低啊)。 2 开发板简介 开发板简单的介绍,参考如下: 整体上板子的外设情况还是非常不错的,可以做很多有用、好玩的东西。由于我本次的DIY项目主要关于音频,所以我也就重点看了这块的介绍。 音频芯片型号为NAU8822L,其中I2C接口用于配置(MODE引脚低),I2S接口用于传输数据。 I2S_LRCK接FS,用于区分左右通道数据。 I2S_BCLK接BCLK 数据传
[嵌入式]
NUC980<font color='red'>开发板</font>应用 基于NK-980IoT的国学唐诗学习机
i.MX 8M Plus加持的AI领域的里程碑开发板长什么样?200元优惠券等你来领
在越来越多场景都要求智能化的今天 强大的AI为我们的工作生活都提供了便利 一块AI领域里程碑式的开发板 也一定能激发你的更多设计灵感! 欢迎回到『NXP开发板特惠活动』 每期一块i.MX开发板 有颜、有料、有优惠 让你的开发更丝滑~~ 今天隆重登场的开发板 是基于i.MX 8M Plus的MYD-JX8MPQ开发板 不仅拥有异常强悍的高性能处理器 还有丰富的开发资源 完善的软件开发生态支持 强大的边缘计算能力 想要开发AI边缘计算设备 选择它准没错! 特别提示 开发板的『优惠密码』就藏在文章中 一定要看到最后哦~ ▼▼▼ 处理器性能强悍
[嵌入式]
i.MX 8M Plus加持的AI领域的里程碑<font color='red'>开发板</font>长什么样?200元优惠券等你来领
u-boot-2014.10移植(2)设置时钟/SDRAM
时钟修改 vim arch/arm/cpu/arm920t/start.S # if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #5 str r1, /* add by Flinn */
[单片机]
u-boot-2009.08在mini2440上的移植(十)---增加I2C EEPROM功能
移植环境 1,主机环境:VMare下CentOS 5.5 ,1G内存。 2,集成开发环境:Elipse IDE 3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。 4,开发板:mini2440,2M nor flash,128M nand flash。 5,u-boot版本:u-boot-2009.08 6,参考文章: http://blogimg.chinaunix.net/blog/upfile2/100811115954.pdf 10.1,实现u-boot的I2C EEPROM功能 mini2440开发板上的AT24C08A芯片提供了8kbyte的非易失的EEP
[单片机]
OK6410A 开发板 (八) 13 linux-5.11 OK6410A start_kernel 打印角度 第一阶段 console
在 u-boot 中, u-boot 对 console 进行了管理,并通过u-boot的环境变量 stdout 进行控制 在 linux-5.11 中, linux也对 console 进行了管理,并通过 u-boot的bootargs(或dts) 中的 一些字段 进行管理,下面写下bootargs 中的这些字段 // 同的驱动,不同的内核支持不同的 bootargs // 请查找 early_param __setup 1. console=xxx 2. earlyprintk=xxx 3. earlycon=xxx 4. boot_delay=xxx 5. no_console_suspend 这些字段 在
[单片机]
OK6410A 开发板 (三) 3 u-boot-2021.01 boot 解析概览
// 需要分析的一套过程 1.配置文件分析 2.配置过程分析 3.编译过程分析 4.链接过程分析 5.生成文件分析 6.镜像加载分析 7.镜像运行分析 u-boot-2021.01 配置出来了 两个镜像,spl(output/spl/u-boot-spl.bin)和u-boot(output/u-boot.bin) 所以有两套过程需要分析 两套板子 宏观角度上 共享同一个 配置文件,同一个配置过程,同一个编译过程,同一链接过程 但是可以 从微观角度 将 配置过程,编译过程,链接过程 分别分为两个 SPL 1.配置文件分析 ok6410a_mini_defconfig 中的配置中 CONFIG_SPL 开头的配置 是 SPL
[单片机]
基于Ok6410开发板u-boot的移植
前提环境:Win7+VirsualBox+ok6410+u-boot-2010.03 一,下载u-boot-2010.03源码 ftp://ftp.denx.de/pub/u-boot 解压,我这里为了避免麻烦,更改了所有文件的权限 tar jxvf u-boot-2010.03.tar.bz2 sudo chmod -R 777 u-boot-2010.03/* 二,修改源码 为了方便修改,查找代码,你看到u-boot下包含了支持众多CPU和不同架构的代码,这里我根据Ok6410开发板的自身情况,将u-boot下代码进行精简: 1,进入u-boot-2010.03/board,把除samsu
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved