LLVMのバックエンドにオリジナルターゲットアーキテクチャを追加していくプロジェクト、MYRISCVXターゲットアーキテクチャを追加したら、今度はELFの情報を追加する必要がある。
MYRISCVXはRISC-Vのオリジナル実装なんで、ELFやABIはRISC-Vと全く同一で進めようと思う。
MYRISCVXのELF出力を登録する
include/llvm/BinaryFormat/ELF.h
こちらもELFを生成するにあたり必要だ。ELFのアーキテクチャ番号は、実は取り決めがありhttp://www.sco.com/developers/gabi/latest/ch4.eheader.htmlなどを参考にすること。このページでは、EM_RISCV
は243と決められている。ここでは、まだ誰も使用していない248をMYRISCVXとして使用することにする。
diff --git a/include/llvm/BinaryFormat/ELF.h b/include/llvm/BinaryFormat/ELF.h index ce35d127d43..55a6c7ddb4b 100644 --- a/include/llvm/BinaryFormat/ELF.h +++ b/include/llvm/BinaryFormat/ELF.h @@ -312,6 +312,7 @@ enum { EM_RISCV = 243, // RISC-V EM_LANAI = 244, // Lanai 32-bit processor EM_BPF = 247, // Linux kernel bpf virtual machine + EM_MYRISCVX = 248, // MYRISCVX }; // Object file classes.
さらに、MYRISCVX向けのe_flagsを作成する。e_flagsはプロセッサ固有のフラグを示すのに使われる。たとえば、アーキテクチャ内の固有の実装を示したり、ISAの中のどのカテゴリをサポートしているか、などを示すためにe_flagsが使用される。例えば、MIPSの例を示す。
include/llvm/BinaryFormat/ELF.h
// Mips Specific e_flags enum : unsigned { EF_MIPS_NOREORDER = 0x00000001, // Don't reorder instructions EF_MIPS_PIC = 0x00000002, // Position independent code EF_MIPS_CPIC = 0x00000004, // Call object with Position independent code EF_MIPS_ABI2 = 0x00000020, // File uses N32 ABI EF_MIPS_32BITMODE = 0x00000100, // Code compiled for a 64-bit machine ...
RISC-Vの場合はどうなっているのか?以下の資料を参考にすると、以下の項目を定義しなければならないようだ。
- RISC-V ELF psABI specification
Bit 0 | Bit 1 - 2 | Bit 3 | Bit 4 | Bit 5 - 31 |
---|---|---|---|---|
RVC | Float ABI | RVE | TSO | Reserved |
詳細はリンク先に譲る。ここでは、ELF.hに以下を追加した(というか、本家のRISC-Vと一緒だ)。
enum : unsigned { EF_RISCV_RVC = 0x0001, EF_RISCV_FLOAT_ABI = 0x0006, EF_RISCV_FLOAT_ABI_SOFT = 0x0000, EF_RISCV_FLOAT_ABI_SINGLE = 0x0002, EF_RISCV_FLOAT_ABI_DOUBLE = 0x0004, EF_RISCV_FLOAT_ABI_QUAD = 0x0006, EF_RISCV_RVE = 0x0008 };
リロケーションレコード
関数呼び出しなどをコンパイルするときに、その関数が実際にどこに配置されるかが分からないため、再配置(リロケーション)のためのシンボルが挿入される。
このリロケーションのアルゴリズムはアーキテクチャ毎に決められており、LLVMではリンク時にリロケーションのアルゴリズムに応じてアドレス計算の命令が挿入される。
ELFフォーマットには、リロケーションの情報も含まれており、MYRISCVXもリロケーション情報を登録しなければならない。
ここではRISC-Vと全く同様のリロケーション情報を登録した。
RISC-Vのリロケーションは、https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#relocations で見ることができる。
このリロケーション情報をinclude/llvm/BinaryFormat/ELFRelocs/MYRISCVX.def
に置く。
include/llvm/BinaryFormat/ELFRelocs/MYRISCVX.def
#ifndef ELF_RELOC #error "ELF_RELOC must be defined" #endif ELF_RELOC(R_MYRISCVX_NONE, 0) ELF_RELOC(R_MYRISCVX_32, 1) ELF_RELOC(R_MYRISCVX_64, 2) ELF_RELOC(R_MYRISCVX_RELATIVE, 3) ELF_RELOC(R_MYRISCVX_COPY, 4) ELF_RELOC(R_MYRISCVX_JUMP_SLOT, 5) ELF_RELOC(R_MYRISCVX_TLS_DTPMOD32, 6) ELF_RELOC(R_MYRISCVX_TLS_DTPMOD64, 7) ELF_RELOC(R_MYRISCVX_TLS_DTPREL32, 8) ELF_RELOC(R_MYRISCVX_TLS_DTPREL64, 9) ELF_RELOC(R_MYRISCVX_TLS_TPREL32, 10) ELF_RELOC(R_MYRISCVX_TLS_TPREL64, 11) ELF_RELOC(R_MYRISCVX_BRANCH, 16) ELF_RELOC(R_MYRISCVX_JAL, 17) ELF_RELOC(R_MYRISCVX_CALL, 18) ELF_RELOC(R_MYRISCVX_CALL_PLT, 19) ELF_RELOC(R_MYRISCVX_GOT_HI20, 20) ELF_RELOC(R_MYRISCVX_TLS_GOT_HI20, 21) ELF_RELOC(R_MYRISCVX_TLS_GD_HI20, 22) ELF_RELOC(R_MYRISCVX_PCREL_HI20, 23) ELF_RELOC(R_MYRISCVX_PCREL_LO12_I, 24) ELF_RELOC(R_MYRISCVX_PCREL_LO12_S, 25) ELF_RELOC(R_MYRISCVX_HI20, 26) ELF_RELOC(R_MYRISCVX_LO12_I, 27) ELF_RELOC(R_MYRISCVX_LO12_S, 28) ELF_RELOC(R_MYRISCVX_TPREL_HI20, 29) ELF_RELOC(R_MYRISCVX_TPREL_LO12_I, 30) ELF_RELOC(R_MYRISCVX_TPREL_LO12_S, 31) ELF_RELOC(R_MYRISCVX_TPREL_ADD, 32) ELF_RELOC(R_MYRISCVX_ADD8, 33) ELF_RELOC(R_MYRISCVX_ADD16, 34) ELF_RELOC(R_MYRISCVX_ADD32, 35) ELF_RELOC(R_MYRISCVX_ADD64, 36) ELF_RELOC(R_MYRISCVX_SUB8, 37) ELF_RELOC(R_MYRISCVX_SUB16, 38) ELF_RELOC(R_MYRISCVX_SUB32, 39) ELF_RELOC(R_MYRISCVX_SUB64, 40) ELF_RELOC(R_MYRISCVX_GNU_VTINHERIT, 41) ELF_RELOC(R_MYRISCVX_GNU_VTENTRY, 42) ELF_RELOC(R_MYRISCVX_ALIGN, 43) ELF_RELOC(R_MYRISCVX_RVC_BRANCH, 44) ELF_RELOC(R_MYRISCVX_RVC_JUMP, 45) ELF_RELOC(R_MYRISCVX_RVC_LUI, 46) ELF_RELOC(R_MYRISCVX_GPREL_I, 47) ELF_RELOC(R_MYRISCVX_GPREL_S, 48) ELF_RELOC(R_MYRISCVX_TPREL_I, 49) ELF_RELOC(R_MYRISCVX_TPREL_S, 50) ELF_RELOC(R_MYRISCVX_RELAX, 51) ELF_RELOC(R_MYRISCVX_SUB6, 52) ELF_RELOC(R_MYRISCVX_SET6, 53) ELF_RELOC(R_MYRISCVX_SET8, 54) ELF_RELOC(R_MYRISCVX_SET16, 55) ELF_RELOC(R_MYRISCVX_SET32, 56) ELF_RELOC(R_MYRISCVX_32_PCREL, 57)
このMYRISCVXのリロケーションテーブルは、e_flagと同様、include/llvm/BinaryFormat/ELF.h
上でインクルードされる。
include/llvm/BinaryFormat/ELF.h
// MYRISCVX Specific e_flags enum : unsigned { EF_MYRISCVX_RVC = 0x0001, EF_MYRISCVX_FLOAT_ABI = 0x0006, ... // ELF Relocation types for MYRISCXV enum { #include "ELFRelocs/MYRISCVX.def" };
このリロケーション情報を使ってどのようにしてアドレス計算を行うのかは、おいおい解説していく。