[心得] relocation

楼主: descent (“雄辩是银,沉默是金”)   2019-01-10 22:58:55
( https://goo.gl/bZc9q7 )
与智者同行, 你会不同凡响; 与高人为伍, 你能登上巅峰。
这次来谈谈 relocation, 对于 relocation 的概念疑惑很久了, 一直想找个方法来验
证, 知道概念很简单, 要怎么实作一个小程式来验证就困难很多, 大概是 1:50 的难度。
在看过以下 2 篇有关 u-boot relocation 的文章之后, 再复习一下“程式设计师的自我
修养 chapter 7”, 我终于有了实作的方向。
uboot的relocation原理详细分析 ( https://goo.gl/a8RjuK )
[uboot] (番外篇)uboot relocation介绍 ( https://goo.gl/ZCzqCv )
建议先阅读以上 2 篇文章, 因为以上 2 篇文章写的内容我不会在重复介绍。
一开始思考要在 arm 还是 x86 写这个测试程式, 毕竟是从 u-boot 借镜而来 (u-boot
也有 x86 版本), 想了一阵子之后, 打算从 x86 来实作这个程式, 在 arm 上有些环境实
在不好设置, 用 qemu 模拟不太有真实感, 用真实的开发板, 开发环境又很麻烦, 也不一
定每个人都有一样的开发板, 没 ice/jtag 更麻烦, 所以最后还是选了 x86, 对每个人来
说都是容易接触的环境。而且 x86 和 arm 的 relocation 实作有点不同, 还好选了
x86, 我才能理解这些不同之处, 算是意外的收获。
本来打算使用 bare-metal 方式, 但 legcy bios 512 byte 限制真的太麻烦, 最后这个
程式超过 512 很多, uefi 我还没能完全掌握, 改用 dos .com 来实作, 不怕, 之前都做
过了, 不辛苦, 这是“累积”的力量, 程式本身大概花了 3 天。
期间出动了 qemu/bochs 这 2 个模拟神器, bochs 内建除错器帮了很大的忙, 让我找出
程式的错误, 学会她是很有帮助的。其实我很不想靠这些工具, 希望靠自己的“冥想”可
以想出问题点, 但我实在抵挡不了“时间”的诱惑, 用这些除错工具, 我能在短时间就找
到问题, 用“冥想”的话, 可能要超过一天才能想出问题吧!
疑! 不是说用模拟器会有不保险的问题吗? 怎么还是用了, 在 x86 上, 可以很容易把模
拟器的环境在真实 PC 上测试, 没问题的。
reloc.cpp 学习“uboot的relocation原理详细分析 ( https://goo.gl/a8RjuK )”这篇
文章, L40 ~ 46 就是一模一样的程式码。
不过和 arm 的 machine code 不同, L41 test_val 不需要做 relocation 的处理。这让
我知道原来不同的 cpu, 是有不同的 relocation 情形, 而我也知道为什么作者要加上
function pointer 的测试。最后我自己还加上 bss section 的测试, 该篇文章没提到这
个。
一开始的观念很模糊, 不太好掌握, 什么位址无关的程式码, share object 之类的, 一
堆和 relocate 相关的 elf section, 把我搞的一团乱, 我把这些东西都搅和在一起了,
后来选定目标, 就类似 u-boot, 把自己 relocalte 到新位址, 这么做, 就比 share
object 单纯一些, 只要看 rel.dyn section 就可以。如果是要处理类似 share object
的东西, 就要看更多的 section。
要作到 relocation 需要:
cpu 支援
编译器支援
自己还需要写额外的程式来处理
由以上条件看来, relocation 相当不容易处理, 除了靠自己, 还得靠别人帮忙。
x86/arm 这么流行的 cpu 当然符合第一、二个条件。
“程式设计师的自我修养”7.3.3 在说明这个, 不清楚这观念的朋友可以参考这章节, 也
会提到 GOT 这东西, 不过我的实做参考 u-boot 作法, 不使用 GOT, 只使用 rel.dyn
section。
ld 加上 -pie, 就可以制作出一个可以 relocation 的执行档。
ld -pie -m elf_i386 -static -Treloc.ld -nostdlib -o reloc.elf
cpp_init.reloc.o reloc.o dos_io.o
-pie 是 ld 选项, 用来造出可 relocaltion 的执行档, 当然并不是只加上这个选项, 你
的执行档就有能力 relocation (有这么简单就好了), 而是额外造出 .rel.dyn
section, 让程式码在 relocation 时, 可以针对这些项目做修改, 进而达到
relocation 的能力。
Relocation section '.rel.dyn' at offset 0xa28 contains 28 entries:
Offset Info Type Sym.Value Sym. Name
在移动自己的时候, 会需要这个资讯来修正对应的值。
-fPIC 则是在 share object 时会看到, 那在移动自己的时候, 需要使用 -fPIC 来编译
吗? 你写的程式加载到 0x100 可以执行, 加载到 0x500 也可以执行, 这就是 PIC, 和位
址无关的程式码。
如果你对于加载到 0x100, 0x500 觉得没有差异的话, 表示 link 的概念还不熟。
测试使用了 -fno-pic + -pie 的组合, 发现还是会输出 .rel.dyn section, 但是会多出
很多项目, 猜测不需要 -fPIC 还是可以做到移动自己, 只是需要改变的项目会比较多,
这部份待以后有时间在研究。
本来我以为需要加入 -fPIC 的选项来输出 PIC 的组合语言, 不过却发现默认好像就是输
出 PIC 的组合语言, 不同的 gcc 版本, 默认的 option 不同。
-fPIC 会输出 list 3 L1 这种程式, 令人看不懂的是 ebx 值是多少, 因为若不知道
ebx 的值, 就无法看懂这个组合语言, list 3 L2 之后, ebx 会是 2c3 (2c3 就是 list
3 L2 这行程式码本身的位址), 相当于 arm 的 PC, 很神奇吧! “程式设计师的自我修养
”有说明这段 code, 就不重复了。
在 x86-64 之后, 可以直接使用 rip, 不需要在用这么迂回的作法, ref:64下PIC的新
寻址方式:RIP相对寻址 ( https://goo.gl/f1AS4R ), 有点类似 arm 的 pc。
list 3. -fPIC
1 2bd: 66 e8 bb 06 00 00 calll 97e <__x86.get_pc_thunk.bx>
2 2c3: 66 81 c3 1d 0a 00 00 add $0xa1d,%ebx
编译器已经做好他该做的事情, 剩下的该程式本身自己来了, 需要做的有:
复制程式本身到新位址
修改需要 relocation 的变量/函式
如何跳到新位址
大家猜猜看, 那个最难?
没有相关经验的程式员, 光第一点就会难倒人。因为这需要修改 linker script, 一般程
式员几乎是不会去修改这个的, 但这只是最简单的第一关而已。
这次的范例程式大胆的使用了 c++, 甚至使用了 c++17 标准 (因为我用了 g++8), 但其
实和 c 不会差太多, 因为 c++17 的很多特性我也不会, 有些地方麻烦了一点, 但已经难
不倒我了。
reloc.cpp
1 __asm__(".code16gcc\n");
2 #include "io.h"
3 #include "obj.h"
4
5 typedef signed char s8;
6 typedef signed short s16;
7 typedef signed int s32;
8
9 typedef unsigned char u8;
10 typedef unsigned short u16;
11 typedef unsigned int u32;
12
13 extern "C" void jmp_to_reloc_addr();
14 extern "C" u32 get_pc();
15
16 #define R_386_RELATIVE 0x00000008
17
18 #define BOCHS_MB __asm__ __volatile__("xchg %bx, %bx");
19
20 extern int _start_ctors;
21 extern int _end_ctors;
22
23 void s16_print_int(int i, int radix);
24 void print_str(const char *s);
25
26 void s32_memcpy(u8 *dest, const u8 *src, u32 n)
27 {
28 for (u32 i=0; i < n ; ++i)
29 *dest++ = *src++;
30 }
31
32 void test_func(void)
33 {
34 print_str("test func\r\n");
35 u32 v = get_pc();
36 s16_print_int(v, 16);
37 print_str("\r\n");
38 }
39
40 static auto test_func_val = test_func;
41 static int test_val = 10;
42 int data1;
43
44 void (*data2)(void);
45
46 int rel_dyn_test()
47 {
48 BOCHS_MB
49 print_str("data_1: ");
50 s16_print_int(data1, 16);
51 print_str("\r\n");
52 //data1 = 5;
53 data2 = test_func;
54 int i;
55 i = test_val;
56 print_str("test_func_val: ");
57 s16_print_int((int)test_func_val, 16);
58 print_str("\r\n");
59 (*test_func_val)();
60 //printf("test = 0x%x\n", test_func);
61 //printf("test_func = 0x%x\n", test_func_val);
62 test_func();
63 return i + data1;
64 }
65
66 extern int __image_copy_start;
67 extern int __image_copy_end;
68 extern int __rel_dyn_start;
69 extern int __rel_dyn_end;
70 extern u32 __bss_start__;
71 extern u32 __bss_end__;
72
73 void init_reloc_bss(u32 reloc_offset)
74 {
75 u32 reloc_bss_b = (int)&__bss_start__ + reloc_offset;
76 u32 reloc_bss_e = (int)&__bss_end__ + reloc_offset;
77 print_str("reloc_bss_b: ");
78 s16_print_int(reloc_bss_b, 16);
79 print_str("\r\n");
80 print_str("reloc_bss_e: ");
81 s16_print_int(reloc_bss_e, 16);
82 print_str("\r\n");
83 for (u32 b = reloc_bss_b ; b < reloc_bss_e ; b++)
84 {
85 *(u8*)b = 1;
86 }
87 }
88
89 void reloc(u32 reloc_addr)
90 {
91 int from = (int)&__image_copy_start;
92 int to = (int)&__image_copy_end;
93 int image_size = to - from;
94 u32 reloc_off = reloc_addr - from;
95
96 print_str("reloc_addr: ");
97 s16_print_int(reloc_addr, 16);
98 print_str("\r\n");
99
100 print_str("reloc_off: ");
101 s16_print_int(reloc_off, 16);
102 print_str("\r\n");
103
104
105 int rel_dyn_from = (int)&__rel_dyn_start;
106 int rel_dyn_to = (int)&__rel_dyn_end;
107
108 s16_print_int(from, 16);
109 print_str("\r\n");
110 s16_print_int(to, 16);
111 print_str("\r\n");
112 s16_print_int(rel_dyn_from, 16);
113 print_str("\r\n");
114 s16_print_int(rel_dyn_to, 16);
115 print_str("\r\n");
116
117 s32_memcpy((u8*)reloc_addr, (u8*)from, image_size);
118 init_reloc_bss(reloc_off);
119 s16_print_int(image_size, 16);
120 print_str("\r\n");
121
122 // modify rel.dyn section
123 for (int i = rel_dyn_from ; i < rel_dyn_to ; i+=8)
124 {
125 u32 v1 = *(u32*)i;
126 u32 v2 = *(u32*)(i+4);
127 #if 0
128 print_str("v1: ");
129 s16_print_int(v1, 16);
130 print_str("\r\n");
131
132 print_str("v2: ");
133 s16_print_int(v2, 16);
134 print_str("\r\n");
135 #endif
136 if (v2 == R_386_RELATIVE)
137 {
138 u32 mem_data = *(u32*)(v1 + reloc_off); // 0xa2c
139 #if 0
140 print_str("mem_data: ");
141 s16_print_int(mem_data, 16);
142 print_str("\r\n");
143 #endif
144
145 *(u32*)(v1+reloc_off) = mem_data + reloc_off; // locate offset
146 mem_data = *(u32*)(v1 + reloc_off);
147 #if 0
148 print_str("after reloc mem_data: ");
149 s16_print_int(mem_data, 16);
150 print_str("\r\n");
151 #endif
152 }
153 print_str("\r\n");
154 }
155
156 //s16_print_int(rel_dyn_to, 16);
157 //print_str("\r\n");
158 //s16_print_int(v, 16);
159 //print_str("\r\n");
160
161 }
162
163 extern "C" int cpp_main(void)
164 {
165 print_str("cpp_main\r\n");
166 //s16_print_int(obj_count, 10);
167 rel_dyn_test();
168 u32 v = get_pc();
169 print_str("before reloc pc: ");
170 s16_print_int(v, 16);
171 print_str("\r\n");
172
173 reloc(0x1100);
174 jmp_to_reloc_addr();
175
176 print_str("after reloc to %cs:0x1100\r\n");
177
178 v = get_pc();
179 print_str("after reloc pc: ");
180 s16_print_int(v, 16);
181 print_str("\r\n");
182
183 rel_dyn_test();
184
185 return 0;
186 }
[移动自己]
这需要靠 linker script 帮忙, reloc.ld L7, L24 将执行档本身的 text, rodata,
data section 的开始/结束位址记录下来, 将他们复制到新的位址 0x1100 即可, 选择移
动到 cs:0x1100 也不是胡乱选的, 这是思考之后的决定, 最主要是除错时比较方便。
reloc.cpp L117 的 s32_memcpy 就是在做这件事情。
reloc.ld
1 /* for cb.c */
2 ENTRY(_start);
3 SECTIONS
4 {
5
6 . = 0x100;
7 __image_copy_start = .;
8 .text :
9 {
10 *(.text)
11 *(.gnu.linkonce.t*)
12 }
13 .rodata :
14 {
15 *(.rodata*)
16 *(.gnu.linkonce.r*)
17 }
18
19 .data :
20 {
21 *(.data.*)
22 *(.gnu.linkonce.d*)
23 }
24 __image_copy_end = .;
25
26 . = ALIGN(4);
27
28 __rel_dyn_start = .;
29 .rel.dyn : {
30 *(.rel.dyn*)
31 }
32 __rel_dyn_end = .;
33
34 /* for g++ 4.7 */
35 .init_array :
36 {
37 __start_global_ctor__ = .;
38 }
39 __end_global_ctor__ = .;
40 .ctors :
41 {
42 start_ctors = .; _start_ctors = .; __start_ctors = .;
43 *(.ctor*)
44 end_ctors = .; _end_ctors = .; __end_ctors = .;
45 /* . = ALIGN(0x1000); */
46 }
47 /*
48 .dtors :
49 {
50 start_dtors = .; _start_dtors = .; __start_dtors = .;
51 *(.dtor*)
52 end_dtors = .; _end_dtors = .; __end_dtors = .;
53 . = ALIGN(0x1000);
54 }
55 */
56
57
58 .bss :
59 {
60 sbss = .; __bss_start__ = .;
61 *(.bss)
62 ebss = .; __bss_end__ = .;
63 *(COMMON)
64 *(.gnu.linkonce.b*)
65 }
66
67 /DISCARD/ :
68 {
69 *(.comment)
70 *(.eh_frame) /* discard this, unless you are implementing runtime
support for C++ exceptions. */
71 }
72 }
简单吧!
[修正 test_func_val]
list 2 L10, 11 是 test_val, L21, 22 是 test_func_val, 和 arm 的版本不同, x86
没有 lable 这种东西, 直接就定位到 static 变量的位址, 所以处理 relocation 的方
式也不同。
需要修改的只有 test_func_val, 因为 test_func_val 的值是 23d (list 2 L29,30),
是 test_func() 的位址, relocate 之后, test_func() 会变成 123d (我把整个程式从
cs:0x100 移动到 cs:0x1100), 所以 test_func_val (a48, list 2 L29) 的值要从 23d
改成 0x123d, 但是 test_func_val 也从 a48 移动到 1a48 了, 所以真正要改的位址是
1a48, 其内容要改成 0x123d, 很复杂吧! 知道理论和写出程式难度还真的不同, 理论的
话, 刚刚提到的细节都不用管, 只要知道 test_func_val 要做 relocation 的修改即可

再来就是我怎么会知道要改这个呢? 总不能每次都人工反组译看吧, 所以编译器很义气的
帮我们产生 rel.dyn section, 这样就知道要改的就是这个地方。
list 2 L54 .rel.dyn section 不就告诉我们 a48 这个地方要调整吗? 就是我上述说明
的那样修改。
修改方式:https://goo.gl/Gy86jZ (
https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html#chapter6-26
)
就是下表 Table 12-15, R_386_RELATIVE 的改法, 取 32bit 长度, 加上一个 base
address。
32-bit x86: Relocation Types
The relocations that are listed in the following table are defined for 32–
bit x86.
Table2-15 32-bit x86: ELF Relocation Types
( https://goo.gl/K1GXXw ) ( https://goo.gl/jTrRQg ) ( https://goo.gl/jTrRQg
) ( https://goo.gl/yEbHWp ) ( https://goo.gl/jTrRQg ) ( https://goo.gl/yEbHWp
) ( https://goo.gl/yEbHWp ) ( https://goo.gl/GSdxiZ ) ( https://goo.gl/U4j4aK
) ( https://goo.gl/ULDpGZ ) ( https://goo.gl/ULDpGZ ) ( https://goo.gl/ki6Mzk
) ( https://goo.gl/ULDpGZ ) ( https://goo.gl/ki6Mzk ) ( https://goo.gl/ki6Mzk
) ( https://goo.gl/JM8D7R ) ( https://goo.gl/PgvaYF ) ( https://goo.gl/ursjYF
) ( https://goo.gl/ursjYF ) ( https://goo.gl/NAFERH ) ( https://goo.gl/ursjYF
) ( https://goo.gl/NAFERH ) ( https://goo.gl/NAFERH ) ( https://goo.gl/vucM1Z
)
Name
Value
Field
Calculation
R_386_NONE
0
None
None
R_386_32
1
word32
S + A
R_386_PC32
2
word32
S + A - P
R_386_GOT32
3
word32
G + A
R_386_PLT32
4
word32
L + A - P
R_386_COPY
5
None
Refer to the explanation following this table.
R_386_GLOB_DAT
6
word32
S
R_386_JMP_SLOT
7
word32
S
R_386_RELATIVE
8
word32
B + A
R_386_GOTOFF
9
word32
S + A - GOT
R_386_GOTPC
10
word32
GOT + A - P
R_386_32PLT
11
word32
L + A
R_386_16
20
word16
S + A
R_386_PC16
21
word16
S + A - P
R_386_8
22
word8
S + A
R_386_PC8
23
word8
S + A - P
R_386_SIZE32
38
word32
Z + A
[bss section 的修改]
bss section 一样被移动到 0x1100 的地方, 所以也需要修改其内容,
L72, L80 2c3+a05+54 = d1c
刚好是 data1 的位址
readelf -a reloc.elf
45: 00000d1c 4 OBJECT GLOBAL DEFAULT 14 data1
52: 00000d1c 0 NOTYPE GLOBAL DEFAULT 14 __bss_start__
57: 00000d24 0 NOTYPE GLOBAL DEFAULT 14 __bss_end__
data1 位于 bss section, 而 bss 落在 00000d1c - 00000d24, 8 byte 就是 data1,
data2 占的空间。
移动之后的 bss 会落在 1d1c ~ 1d24, 只要把这里清成 0 即可。
[跳到 relocation 之后的位址]
这是个大问题, 也是理论派不会注意的地方, 因为这也和平台有关, arm 是这样做, x86
又是另外的作法。我用了类似 __x86.get_pc_thunk.b 来移动到新的位址, 这是我自己想
出来的作法, 不确定有没有什么比较正规的作法。
呼叫 jmp_to_reloc_addr() 之后会 jmp 到新的位址, 怎么办到的?
jmp_to_reloc_addr() 结束之后, 会执行下一个位址也就是 reloc.cpp L176
print_str(), 我得让他跳到新的 print_str() 而不是原来的那个 print_str(), 只要我
可以得知这个位址, 加上 0x1100 - 0x100 就可以跳到新位址的 print_str(),
jmp_to_reloc_addr() 就是在做这件事情。
list 2 的反组译和 reloc.cpp 有点不同, 因为 reloc.cpp 我后来有再次修改, 反组译
的结果就不更新了。
list 2. objdump -m i8086 -CD reloc.elf
91 0000023d <test_func()>:
92 23d: 66 55 push %ebp
93 23f: 66 89 e5 mov %esp,%ebp
94 242: 66 53 push %ebx
95 244: 66 83 ec 14 sub $0x14,%esp
96 248: 66 e8 47 07 00 00 calll 995 <__x86.get_pc_thunk.bx>
97 24e: 66 81 c3 f2 08 00 00 add $0x8f2,%ebx
98 255: 66 83 ec 0c sub $0xc,%esp
99 259: 67 66 8d 83 5c fe ff lea -0x1a4(%ebx),%eax
90 260: ff
91 261: 66 50 push %eax
92 263: 66 e8 e5 04 00 00 calll 74e <print_str(char const*)>
93 269: 66 83 c4 10 add $0x10,%esp
94 26d: 66 e8 d2 fe ff ff calll 145 <get_pc>
95 273: 67 66 89 45 f4 mov %eax,-0xc(%ebp)
96 278: 67 66 8b 45 f4 mov -0xc(%ebp),%eax
97 27d: 66 83 ec 08 sub $0x8,%esp
98 281: 66 6a 10 pushl $0x10
99 284: 66 50 push %eax
90 286: 66 e8 96 06 00 00 calll 922 <s16_print_int(int, int)>
1 000002b2 <rel_dyn_test()>:
71 2bd: 66 e8 2d 08 00 00 calll af0 <__x86.get_pc_thunk.bx>
72 2c3: 66 81 c3 05 0a 00 00 add $0xa05,%ebx
73 2ca: 87 db xchg %bx,%bx
74 2cc: 66 83 ec 0c sub $0xc,%esp
75 2d0: 67 66 8d 83 3e fe ff lea -0x1c2(%ebx),%eax
76 2d7: ff
77 2d8: 66 50 push %eax
78 2da: 66 e8 c9 05 00 00 calll 8a9 <print_str(char const*)>
79 2e0: 66 83 c4 10 add $0x10,%esp
80 2e4: 67 66 8b 83 54 00 00 mov 0x54(%ebx),%eax // data1
2 2b2: 66 55 push %ebp
3 2b4: 66 89 e5 mov %esp,%ebp
4 2b7: 66 53 push %ebx
5 2b9: 66 83 ec 14 sub $0x14,%esp
6 2bd: 66 e8 ab 06 00 00 calll 96e <__x86.get_pc_thunk.bx>
7 2c3: 66 81 c3 45 08 00 00 add $0x845,%ebx
8 2ca: 87 db xchg %bx,%bx
9
10 test_val
11 2cc: 67 66 8b 83 64 ff ff mov -0x9c(%ebx),%eax
12 2d3: ff
13 2d4: 67 66 89 45 f4 mov %eax,-0xc(%ebp)
14 2d9: 66 83 ec 0c sub $0xc,%esp
15 2dd: 67 66 8d 83 7c fe ff lea -0x184(%ebx),%eax
16 2e4: ff
17 2e5: 66 50 push %eax
18 2e7: 66 e8 3a 04 00 00 calll 727 <print_str(char const*)>
19 2ed: 66 83 c4 10 add $0x10,%esp
20
21 test_func_val
22 2f1: 67 66 8b 83 40 ff ff mov -0xc0(%ebx),%eax
23 2f8: ff
24 2f9: 66 83 ec 08 sub $0x8,%esp
25 2fd: 66 6a 10 pushl $0x10
26 300: 66 50 push %eax
27 302: 66 e8 f3 05 00 00 calll 8fb <s16_print_int(int, int)>
28
29 00000a48 <test_func_val>:
30 a48: 3d 02 00 cmp $0x2,%ax
31 ...
32
33
34 00000a6c <test_val>:
35 a6c: 0a 00 or (%bx,%si),%al
36 ...
37
38 Disassembly of section .dynamic:
39
40 00000a70 <_DYNAMIC>:
41 a70: 04 00 add $0x0,%al
42 a72: 00 00 add %al,(%bx,%si)
43 a74: 20 0a and %cl,(%bp,%si)
44 a76: 00 00 add %al,(%bx,%si)
45 a78: f5 cmc
46 a79: fe (bad)
47
48 [email protected]:dos_cpp$ readelf -r reloc.elf
49
50 Relocation section '.rel.dyn' at offset 0xb14 contains 3 entries:
51 Offset Info Type Sym.Value Sym. Name
52 0000014e 00000008 R_386_RELATIVE
53 00000154 00000008 R_386_RELATIVE
54 00000a48 00000008 R_386_RELATIVE
[relocate stack]
需要 relocate stack 吗? u-boot 有 relocate stack 吗? 我不知道, 但就算要做也不
困难。好吧! 有点难, 和我想的不太一样, 花了一天搞定, 嘴炮果然轻松多了。
本来使用 c++ function 来写这功能, 一直有错, 后来用了 bochs 除错, 看了很多组合
语言之后, 决定改用组合语言来写这段 (因为 c++ 怎么写都写不出来), 终于搞定。
list 3. qemu 执行结果
1 Booting from Hard Disk...
2 Boot failed: could not read the boot disk
3
4 Booting from Floppy...
5 Starting MS-DOS...
6
7 A:\>reloc
8 cpp_main
9 data_1: 0
10 test_func_val: 26A
11 test func
12 2A0
13 test func
14 2A0
15 before reloc pc: 968
16 reloc_addr: 1100
17 reloc_off: 1000
18 100
19 DB4
20 E70
21 EB8
22 reloc_bss_b: 1EB8
23 reloc_bss_e: 1EC0
24 CB4
25
作者: sunneo (艾斯寇德)   2019-01-10 23:09:00
越来越hardcore了 真不错
作者: sarafciel (Cattuz)   2019-01-11 17:47:00
推 每次看d大的文章都会觉得自己要学的东西还很多
作者: bigbite (子子孙孙永保用)   2019-01-11 18:39:00
作者: BlazarArc (Midnight Sun)   2019-01-12 20:21:00
作者: mikukonn (mikukon)   2019-01-13 12:37:00
作者: PkmX (阿猫)   2019-01-14 02:22:00
-fno-pic + -pie 会有text relocation 造成SO的.text无法被共用 且某些架构(例如RISCV)或memory model下非pic的codelinker也是没办法插dynamic relocation让它变成pic的另外x86_64 ABI有规定把.dynamic的位置塞在GOT的头可以从_GLOBAL_OFFSET_TABLE_拿或是直接用_DYNAMIC这个符号简易版从.dynamic找.rel[a].dyn做reloc可以参考我之前写的u-boot/tools/prelink-riscv.inc 不过这是static time时操作
楼主: descent (“雄辩是银,沉默是金”)   2019-01-15 13:13:00
感谢分享

Links booklink

Contact Us: admin [ a t ] ucptt.com