[心得] 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