LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。
第10章は、ELF形式のサポートと、objdump
コマンドを動かす。
まずは、ELFの形式をサポートする。ELFの形式は、以下のように表現される。
まずは通常通りllcでオブジェクトファイルを生成して、ELFのヘッダを確認してみる。
Machineの項は<unknown>: 0xf8
となっており、認識できない。
$ ./bin/llc -march=myriscvx32 -relocation-model=pic -filetype=obj ch6_1.bc -o ch6_1.myriscvx.o $ readelf -h ch6_1.myriscvx.o ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: <unknown>: 0xf8 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 572 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 8 Section header string table index: 1
次に、MIPSのオブジェクトファイルを生成してみる。Machineの項はMIPS R3000
と認識されている。
$ ./bin/llc -march=mips -relocation-model=pic -filetype=obj ch6_1.bc -o ch6_1.mips.o $ readelf -h ch6_1.mips.o ELF Header: Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, big endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: MIPS R3000 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 700 (bytes into file) Flags: 0x50001007, noreorder, pic, cpic, o32, mips32 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 14 Section header string table index: 1
これらのオブジェクトは実行ファイルではないので、セグメントは入っていない。
$ readelf -l ch6_1.myriscvx.o There are no program headers in this file.
オブジェクトのセクション情報を確認してみる。
$ readelf -S ch6_1.myriscvx.o There are 8 section headers, starting at offset 0x23c: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .strtab STRTAB 00000000 0001d4 000068 00 0 0 1 [ 2] .text PROGBITS 00000000 000034 00004c 00 AX 0 0 4 [ 3] .rel.text REL 00000000 0001a4 000030 08 7 2 4 [ 4] .data PROGBITS 00000000 000080 000008 00 WA 0 0 4 [ 5] .comment PROGBITS 00000000 000088 0000bb 01 MS 0 0 1 [ 6] .note.GNU-stack PROGBITS 00000000 000143 000000 00 0 0 1 [ 7] .symtab SYMTAB 00000000 000144 000060 10 1 2 4 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), p (processor specific)
$ objdump -s ch6_1.myriscvx.o ch6_1.myriscvx.o: file format elf32-little Contents of section .text: 0000 b7010000 93e10100 b3814100 37050000 ..........A.7... 0010 13050500 130181ff 23224400 33010400 ........#"D.3... 0020 23200000 37050000 33053500 03200500 # ..7...3.5.. .. 0030 03200500 23200500 03200500 33040100 . ..# ... ..3... 0040 03224400 13018100 67800000 ."D.....g... Contents of section .data: 0000 03000000 64000000 ....d... Contents of section .comment: 0000 00636c61 6e672076 65727369 6f6e2037 .clang version 7 0010 2e302e31 20286874 7470733a 2f2f6769 .0.1 (https://gi 0020 74687562 2e636f6d 2f6c6c76 6d2d6d69 thub.com/llvm-mi 0030 72726f72 2f636c61 6e672e67 69742034 rror/clang.git 4 0040 35313965 32363337 66636334 62663665 519e2637fcc4bf6e 0050 33303439 61306138 30653661 35653762 3049a0a80e6a5e7b 0060 39373636 37636229 20286874 7470733a 97667cb) (https: 0070 2f2f6769 74687562 2e636f6d 2f6d7379 //github.com/msy 0080 6b737068 696e7a2f 6c6c766d 2e676974 ksphinz/llvm.git 0090 20633431 36633731 33363062 61633966 c416c71360bac9f 00a0 62336233 30396661 33643839 33326637 b3b309fa3d8932f7 00b0 62633664 66363436 612900 bc6df646a).
$ readelf -tr ch6_1.myriscvx.o There are 8 section headers, starting at offset 0x23c: Section Headers: [Nr] Name Type Addr Off Size ES Lk Inf Al Flags [ 0] NULL 00000000 000000 000000 00 0 0 0 [00000000]: [ 1] .strtab STRTAB 00000000 0001d4 000068 00 0 0 1 [00000000]: [ 2] .text PROGBITS 00000000 000034 00004c 00 0 0 4 [00000006]: ALLOC, EXEC [ 3] .rel.text REL 00000000 0001a4 000030 08 7 2 4 [00000000]: [ 4] .data PROGBITS 00000000 000080 000008 00 0 0 4 [00000003]: WRITE, ALLOC [ 5] .comment PROGBITS 00000000 000088 0000bb 01 0 0 1 [00000030]: MERGE, STRINGS [ 6] .note.GNU-stack PROGBITS 00000000 000143 000000 00 0 0 1 [00000000]: [ 7] .symtab SYMTAB 00000000 000144 000060 10 1 2 4 [00000000]: Relocation section '.rel.text' at offset 0x1a4 contains 6 entries: Offset Info Type Sym.Value Sym. Name 00000000 00000305 unrecognized: 5 00000000 _gp_disp 00000004 00000306 unrecognized: 6 00000000 _gp_disp 0000000c 00000305 unrecognized: 5 00000000 _gp_disp 00000010 00000306 unrecognized: 6 00000000 _gp_disp 00000024 00000416 unrecognized: 16 00000004 gI 0000002c 00000417 unrecognized: 17 00000004 gI
objdumpをサポートする
objdump
をサポートするためには、Disassembler
を追加する。
diff --git a/lib/Target/MYRISCVX/CMakeLists.txt b/lib/Target/MYRISCVX/CMakeLists.txt index 2257f4cf37a..b55c0fbf701 100644 --- a/lib/Target/MYRISCVX/CMakeLists.txt +++ b/lib/Target/MYRISCVX/CMakeLists.txt @@ -13,6 +13,7 @@ tablegen(LLVM MYRISCVXGenCallingConv.inc -gen-callingconv) tablegen(LLVM MYRISCVXGenCodeEmitter.inc -gen-emitter) tablegen(LLVM MYRISCVXGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM MYRISCVXGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM MYRISCVXGenDisassemblerTables.inc -gen-disassembler) # MYRISCVXCommonTableGen must be defined add_public_tablegen_target(MYRISCVXCommonTableGen) @@ -45,3 +46,4 @@ add_llvm_target(MYRISCVXCodeGen add_subdirectory(TargetInfo) add_subdirectory(MCTargetDesc) add_subdirectory(InstPrinter) +add_subdirectory(Disassembler)
Disassemblerには、いくつかのオペランドの出力についてケアをする必要がある。
例えば、ストア命令は3つのオペランド(書き込みレジスタ、ベースアドレス、測地アドレス)を取るが、Target Descriptionファイルには2つのオペランドしか記述していない。
よく見ると、AlignedStore
の項目に$val, $ptr
にオペランドが2つ入っており、これを合わせてメモリアクセス命令のディスアセンブリを出力する必要がある。
class AlignedStore<PatFrag Node> : PatFrag<(ops node:$val, node:$ptr), (Node node:$val, node:$ptr), [{ StoreSDNode *SD = cast<StoreSDNode>(N); return SD->getMemoryVT().getSizeInBits()/8 <= SD->getAlignment(); }]>; ... defm SW : StoreM32<0b0100011, 0b010, "sw", store_a >; multiclass StoreM32<bits<7> opcode, bits<3> funct3, string instr_asm, PatFrag OpNode, bit Pseudo = 0> { def #NAME# : StoreM<opcode, funct3, instr_asm, OpNode, GPR, mem, Pseudo>; } ... class StoreM<bits<7> opcode, bits<3> funct3, string instr_asm, PatFrag OpNode, RegisterClass RC, Operand MemOpnd, bit Pseudo>: FS<opcode, funct3, (outs), (ins RC:$rs1, MemOpnd:$addr), !strconcat(instr_asm, "\t$rs1, $addr"), [(OpNode RC:$rs1, addr:$addr)], IIStore> { let isPseudo = Pseudo; }
この表記を上手く順番を並べ替えてフォーマットする。
lib/Target/MYRISCVX/Disassembler/MYRISCVXDisassembler.cpp
// @DecodeStore { static DecodeStatus DecodeStore(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { // @DecodeStore body { int Offset = SignExtend32<12>((fieldFromInstruction(Insn, 25, 7) << 5) | (fieldFromInstruction(Insn, 7, 5))); int Reg = (int)fieldFromInstruction(Insn, 20, 5); int Base = (int)fieldFromInstruction(Insn, 15, 5); Inst.addOperand(MCOperand::createReg(CPURegsTable[Base])); Inst.addOperand(MCOperand::createReg(CPURegsTable[Reg])); Inst.addOperand(MCOperand::createImm(Offset)); return MCDisassembler::Success; } ... // @DecodeLoad { static DecodeStatus DecodeLoad (MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { // @DecodeLoad body { int Offset = SignExtend32<12>((Insn >> 20) & 0x0fff); int Dest = (int)fieldFromInstruction(Insn, 7, 5); int Base = (int)fieldFromInstruction(Insn, 15, 5); Inst.addOperand(MCOperand::createReg(CPURegsTable[Dest])); Inst.addOperand(MCOperand::createReg(CPURegsTable[Base])); Inst.addOperand(MCOperand::createImm(Offset)); return MCDisassembler::Success; }
これでLLVMを再ビルドし、llvm-objdump
を実行してみる。
./bin/clang -c -target mips-unknown-linux-gnu ../lbdex/input/ch6_1.cpp -emit-llvm ./bin/llvm-objdump -d ch6_1.myriscvx.o
ch6_1.myriscvx.o: file format ELF32-unknown Disassembly of section .text: _Z11test_globalv: 0: b7 01 00 00 lui x3, 0 4: 93 e1 01 00 ori x3, x3, 0 8: b3 81 41 00 add x3, x3, x4 c: 37 05 00 00 lui x10, 0 10: 13 05 05 00 addi x10, x10, 0 14: 13 01 81 ff addi x2, x2, -8 18: 23 22 44 00 sw x8, 4(x4) 1c: 33 01 04 00 move x2, x8 20: 23 20 00 00 sw x0, 0(x0) ...
一応出力できたようだが、オペランドの順番が逆だ。add x3, x3, x4
はadd x4, x3, x3
にならないといけないと気がする。おかしいなあ。