iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 28
1

前情提要


昨日設計了一個更適合接下來的開發的小程式,並且將展示重定區段的功能新增進入 readelf 裡面。今天的目標就是試試看我們能不能產生重定區段,並且讓連結器能夠使用呢?

實作目標


繼續沿用我們的測試程式,簡單回顧一下的話,fin2.s 是進入點,並且在裡面呼叫了 write 函式;fin1.s 則定義了該函式。所以實作的大方向就是要在組譯結果的 fin2.o 中安插一個重定區段。細節來講,我們必須在 as 中做到:

  • 理解 call 虛擬指令,將之轉換為 auipc+jalr 指令配對
  • 製造相對應的重定區段
    • 有一個 R_RISCV_NONE 的空重定
    • 一個 R_RISCV_CALL 的重定 Rela64 結構內容
      • Off 成員在 call 的位置
      • Info 成員是 R_RISCV_CALL 重定型態與該標籤編號的複合體
      • Addend 成員的值是 0

理論上這樣就足夠了。

讓 as 理解 call 虛擬指令


嚴格來說,這應該是 rvgc 函式庫的責任:因為 as 抓到一個指令之後,會送交給 rvgc.InstToBin 去處理。所以這裡我們先新增一個指令型態叫做虛擬指令:

type RV_INST_TYPE uint32

const (
...
        RV_INST_U_TYPE RV_INST_TYPE = 5
        RV_INST_J_TYPE RV_INST_TYPE = 6
        RV_INST_PSEUDO RV_INST_TYPE = 7
)

然後,我們可以將 call 指令視為這個新的形態:

var mnem2type = map[string]RV_INST_TYPE{
...
        "ecall": RV_INST_NONE,

        "call": RV_INST_PSEUDO,
}

由於虛擬指令並沒有真正的 opcode,所以 InstToBin 的起始邏輯需要稍微修正:

func InstToBin(inst []string) []byte {

        t := mnem2type[inst[0]]
        if t != RV_INST_PSEUDO {
                op := mnem2opcode[inst[0]]
        }

於是就可以在後面的 switch 結構之中加入相關的處理了!為了避免重複造輪子,我們可以呼叫自己兩次:

...
        case RV_INST_NONE:
                bits |= uint32(op)
        case RV_INST_PSEUDO:
                if inst[0] == "call" {
                        ret := make([]byte, 0)
                        ret = append(ret, InstToBin("auipc ra, 0"))
                        ret = append(ret, InstToBin("jalr ra, 0(ra)"))
                        return ret
                }

重定的判斷


這個部分筆者決定繼續修改 rvgc 的行為,因為關於指令的分析處理,幾乎都是在 rvgc 函式庫之內進行,若是要將這個流程拿出來到 as 裡面,會變得綁手綁腳的。這裡決定讓 InstToBin 函數多回傳一個參數:重定型態。所以,必須修改 as 的 inst 函式

func (asu *asUtil) inst(d []string) {
        b, r := rvgc.InstToBin(d)

	asu.obj.sections[currentSection].content = append(asu.obj.sections[currentSection].content, string(b))

        if r != elf.R_RISCV_NONE {

如果這個指令有回傳重定型態,則必須開始一連串安插重定區段的步驟。

小結


今日完成的是初步的處理,我們明日再來嘗試把這個部分補完吧!


上一篇
第二十七日:readelf 重定擴充
下一篇
第二十九日:as 強化(下)
系列文
與妖精共舞:在 RISC-V 架構上使用 GO 語言實作 binutils 工具包30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言