iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 25
1
Software Development

與妖精共舞:在 RISC-V 架構上使用 GO 語言實作 binutils 工具包系列 第 25

第二十五日:眾裡尋 relocation type 千百度......

前情提要


昨日正準備要有所作為,卻發現上游裡面有根本的短少!這該怎麼辦才好呢?決定今天來好好研究一下貢獻的規則,go 語言社群的規則和 github 上面直接單純的 PR 模式是不一樣的。

RISC-V 的連結選項


我們先重新回顧昨日展示的繼有重定型態

1730 // Relocation types for RISC-V processors.
1731 type R_RISCV int
1732
1733 const (
1734         R_RISCV_NONE         R_RISCV = 0  /* No relocation. */
1735         R_RISCV_32           R_RISCV = 1  /* Add 32 bit zero extended symbol value */
1736         R_RISCV_64           R_RISCV = 2  /* Add 64 bit symbol value. */
1737         R_RISCV_RELATIVE     R_RISCV = 3  /* Add load address of shared object. */
1738         R_RISCV_COPY         R_RISCV = 4  /* Copy data from shared object. */
1739         R_RISCV_JUMP_SLOT    R_RISCV = 5  /* Set GOT entry to code address. */
1740         R_RISCV_TLS_DTPMOD32 R_RISCV = 6  /* 32 bit ID of module containing symbol */
1741         R_RISCV_TLS_DTPMOD64 R_RISCV = 7  /* ID of module containing symbol */
1742         R_RISCV_TLS_DTPREL32 R_RISCV = 8  /* 32 bit relative offset in TLS block */
1743         R_RISCV_TLS_DTPREL64 R_RISCV = 9  /* Relative offset in TLS block */
1744         R_RISCV_TLS_TPREL32  R_RISCV = 10 /* 32 bit relative offset in static TLS block */
1745         R_RISCV_TLS_TPREL64  R_RISCV = 11 /* Relative offset in static TLS block */
1746 )

這是 src/debug/elf/elf.go 檔案裡面的重定部分,未免也太少了吧!來看在 RISC-V 基金會的官方文件裡面有多少個?目前有定義的有 0~56,共 57 個,剩下的則是保留區。由於篇幅太多,筆者就不引用以免灌水。

看來,目前 riscv-go 上面的實作這 12 個重定型態的編號與手冊上的編號恰好一樣,但有沒有可能這只是巧合?我們有兩個地方可以檢查,

  1. 使用 git 工具觀察 riscv-go 源碼的狀況,看看當初上述這幾行的 commit 的 patch 是不是有什麼特殊考量才只放了這 12 個。
  2. 借鏡隔壁的 riscv-binutils-gdb 專案,看看他們怎麼解碼那些重定型態。

git 考古學

首先我們查查看當初的 commit 在哪裡

git blame src/debug/elf/elf.go

從裡面隨意挑一行來看,比方說 1734 行的 R_RISCV_NONE 無重定型態好了,

...
a5e7fc4fc62 src/debug/elf/elf.go     (Amol Bhave           2016-11-16 23:49:56
...

我們發現是 Amol Bhave 這個人在前年底的貢獻。有了 commit 號碼之後,也能夠看看這個 patch 長什麼樣了:

$ git show a5e7fc4fc62
commit a5e7fc4fc62b6ed21bc30fd934f53a55111d1238
Author: Amol Bhave <ammubhave@gmail.com>
Date:   Wed Nov 16 23:49:56 2016 +0000

    debug/elf: Add RISC-V definitions to debug/elf
    
    This is the first step in getting cgo to work. cgo uses debug/elf
    for elf parsing.
    
    Change-Id: I7ec1c73206ed0b89e483660fe572fd53aa37a905

diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go
index 6e6c801a49..17a9549e82 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -237,6 +237,7 @@ const (
        EM_TINYJ       Machine = 61  /* Advanced Logic Corp. TinyJ processor. */
        EM_X86_64      Machine = 62  /* Advanced Micro Devices x86-64 */
        EM_AARCH64     Machine = 183 /* ARM 64-bit Architecture (AArch64) */
+       EM_RISCV       Machine = 243 /* RISC-V */
...

哇,RISC-V 的機器編號竟然是在這裡訂的?那這可是一個重要 patch 呢!裡面的描述是,這是讓 cgo 函式庫能夠正確運作的第一步(果然重要)。省略的部份之後不久就有我們一開始引用的那些重定型態定義。

但是這又更啟筆者疑竇:這些重定就足夠 cgo 運作了嗎?

riscv-binutils-gdb 考察


從 git 考古沒有什麼進展,看看另外這個專案吧!至少人家的完整度是有目共睹的。先來到 /riscv-tools/riscv-gnu-toolchain/riscv-binutils-gdb 路徑之內搜尋,預計應該會在某個標頭檔裡面吧?

$ find ./ -name "*.h" | xargs grep R_RISCV_CALL
./bfd/bfd-in2.h:  BFD_RELOC_RISCV_CALL,
./bfd/bfd-in2.h:  BFD_RELOC_RISCV_CALL_PLT,
./bfd/libbfd.h:  "BFD_RELOC_RISCV_CALL",
./bfd/libbfd.h:  "BFD_RELOC_RISCV_CALL_PLT",
./include/elf/riscv.h:  RELOC_NUMBER (R_RISCV_CALL, 18)
./include/elf/riscv.h:  RELOC_NUMBER (R_RISCV_CALL_PLT, 19)

抓到了,大概就是最後面這兩行吧。進去看看:


 /* Relocation types.  */
 START_RELOC_NUMBERS (elf_riscv_reloc_type)
   /* Relocation types used by the dynamic linker.  */
   RELOC_NUMBER (R_RISCV_NONE, 0)
   RELOC_NUMBER (R_RISCV_32, 1)
   RELOC_NUMBER (R_RISCV_64, 2)
   RELOC_NUMBER (R_RISCV_RELATIVE, 3)
   RELOC_NUMBER (R_RISCV_COPY, 4)
   RELOC_NUMBER (R_RISCV_JUMP_SLOT, 5)
   RELOC_NUMBER (R_RISCV_TLS_DTPMOD32, 6)
   RELOC_NUMBER (R_RISCV_TLS_DTPMOD64, 7)
   RELOC_NUMBER (R_RISCV_TLS_DTPREL32, 8)
   RELOC_NUMBER (R_RISCV_TLS_DTPREL64, 9)
   RELOC_NUMBER (R_RISCV_TLS_TPREL32, 10)
   RELOC_NUMBER (R_RISCV_TLS_TPREL64, 11)

   /* Relocation types not used by the dynamic linker.  */
   RELOC_NUMBER (R_RISCV_BRANCH, 16)
   RELOC_NUMBER (R_RISCV_JAL, 17)
   RELOC_NUMBER (R_RISCV_CALL, 18)
   RELOC_NUMBER (R_RISCV_CALL_PLT, 19)
   RELOC_NUMBER (R_RISCV_GOT_HI20, 20)
...

唉呀,看這個註解,找到原因啦!所有的線索都兜在一起了!因為他們的最終目標是 cgo,而 go 語言與 C 語言的聯動是透過動態連結來完成的,所以他們就對 12 之後的部份不屑一顧啦!

那筆者究竟該如何自處呢?這真是個好問題......

小結


最近幾天實在忙到有點崩壞,還好今天在考古的過程中還能挖掘出一些之前想不懂的東西。事實上,就算他們目標是 cgo 而已,也不代表 elf.go 這個檔案就只能有這個能力;我們不是擺明了有的用途嗎?而且其他的每一種架構也都有完整的重定型態列表,所以這不能阻止筆者的貢獻!問題只在要摸清楚他們的貢獻模式了,目前還不是很懂 GerritHub 的用法。無論如何,趁著週末好好研究衝刺一下鐵人賽的終點線吧!各位讀者,我們明日再會!


上一篇
第二十四日:RISC-V 的重定向項目
下一篇
第二十六日:探究 Rela 結構
系列文
與妖精共舞:在 RISC-V 架構上使用 GO 語言實作 binutils 工具包30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言