我重新組織原本的文章, 將其拆成幾部份, 一口氣把所有東西塞到原本文章可能太複雜, 這篇只說明和 relocation 相關的部份, relocation 要做的事情, 以及哪些程式碼需要做 relocation, 以下正文開始。改寫之後, 篇幅短了不少, 希望不會太燒腦。
此作法我不確定是不是正統作法, 這是從 u-boot 上看來的方法, 查看 linux vmlinux, 似乎沒看到 dynamic section, 不知道 linux kernel relocation 是怎麼辦到的?
首先仿造
之前的作法, 加上 k.c L19 ~ L44 的程式碼來測試 relocation。
|
只要功夫深, 鐵杵磨成針 |
編譯過後應該會看到 .rela.dyn section, 不過一開始連 .rela.dyn section 資訊都沒有出現, 查了很久, 原來是 k.ld L56 的問題, 由於 DISCARD .rela.dyn section, 所以 .rela.dyn section 被刪除了。
把 k.ld L56 刪除, 重新 link 之後, 就可以看到 list 1 的內容。
只有一個地方需要處理 relocation (k.c L24 的 test_func_val)。list 2 L4412, test_func_val 在 link 完成之後的值是 6336 (little endian), L1558 test_func 就在這個位址。
再來是觀察以下 symbol 的值:
image_base
entry point
test_func
test_func_val
原本 elf 紀錄的資訊:
image_base: 0
entry point: 0x5010
test_func: 0x6336
test_func_val: 0xb420, 內容是: 0x6336
當將 k64.elf 載入到 0x6882018 時 (參閱 fig 1):
image_base: 0x687e018
entry point: 0x6883028
test_func: 0x688434e
test_func_val: ??, 內容是: 0x6336
而test_func_val 並不知道我們現在不在預期的位址上, 得在開始執行 (*test_func_val)() 前, 修正它, 這就是 relocation, 改成 0x688434e, 而 list 1 的資訊就是告知我們要把 0xb420 (test_fun_val 的位址) 其內容值 0x6336 改成 0x688434e。
|
fig 1 load kernel elf to 0x6882018 address |
原本 elf 內容的
test_func - image_base = 0x6336 - 0 = 0x6336
=>
test_func = 6336 + image_base;
test_func_val - image_base = 0xb420 - 0 = 0xb420
當將 k64.elf 載入到 0x6882018 時 (參閱 fig 1), 這時候的 image_base 是 0x688434e。
test_func - image_base = 0x688434e - 0x687e018 = 6336
test_func = 6336 + image_base;
test_func = 6336 + 0x687e018;
test_func_val - image_base = test_func_val - 0x687e018 = 0xb420
test_func_val = 0xb420 + image_base
test_func_val = 0xb420 + 0x687e018 =
有了新的 test_func_val, test_func 位址, 就可以做 relocation 了。
所以重點在怎麼取得執行時期的 image_base, 我們會很需要 image_base 來處理 relocation, 下篇再來說明。
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。