From fbbabe115f53c6472bac19f02fbf8425eb7f3f5e Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 13 Jun 2022 17:46:02 +0200 Subject: [PATCH] Save ELF symbols in a hash table --- source/elna/backend.d | 29 ++++--- source/elna/elf.d | 197 ++++++++++++++++++++++-------------------- source/elna/result.d | 7 -- 3 files changed, 118 insertions(+), 115 deletions(-) diff --git a/source/elna/backend.d b/source/elna/backend.d index e314a81..dc1fd0e 100644 --- a/source/elna/backend.d +++ b/source/elna/backend.d @@ -59,36 +59,37 @@ int generate(string inFile, ref String outputFilename) @nogc auto program = writeNext(ir); auto elf = Elf!ELFCLASS32(move(handle)); auto readOnlyData = Array!ubyte(cast(const(ubyte)[]) "%d\n".ptr[0 .. 4]); // With \0. - Array!Relocation relocationData; + elf.addReadOnlyData(String(".CL0"), readOnlyData); + elf.addCode(program.name, program.text); + + elf.addExternSymbol(String("printf")); foreach (ref reference; program.symbols) { - Relocation relocationEntry; + elf.Rela relocationEntry = { + r_offset: cast(elf.Addr) reference.offset + }; + elf.Rela relocationSub = { + r_offset: cast(elf.Addr) reference.offset, + r_info: R_RISCV_RELAX + }; - relocationEntry.symbol = reference; final switch (reference.target) { case Reference.Target.text: - relocationEntry.typeInformation = R_RISCV_CALL; + relocationEntry.r_info = R_RISCV_CALL; break; case Reference.Target.high20: - relocationEntry.typeInformation = R_RISCV_HI20; + relocationEntry.r_info = R_RISCV_HI20; break; case Reference.Target.lower12i: - relocationEntry.typeInformation = R_RISCV_LO12_I; + relocationEntry.r_info = R_RISCV_LO12_I; break; } - relocationEntry.hasEntry = true; - relocationData.insertBack(relocationEntry); - relocationEntry.typeInformation = R_RISCV_RELAX; - relocationEntry.hasEntry = false; - relocationData.insertBack(relocationEntry); + elf.relocate(reference.name, relocationEntry, relocationSub); } - elf.addReadOnlyData(readOnlyData); - elf.addCode(program.name, program.text, relocationData); - elf.finish(); return 0; diff --git a/source/elna/elf.d b/source/elna/elf.d index 592db13..81dd7da 100644 --- a/source/elna/elf.d +++ b/source/elna/elf.d @@ -4,6 +4,7 @@ import elna.extended; import elna.result; import std.algorithm; import tanya.container.array; +import tanya.container.hashtable; import tanya.container.string; /// Unsigned program address. @@ -327,17 +328,17 @@ enum : Elf64_Xword SHF_MASKPROC = 0xF0000000, } -auto ELF64_R_SYM(I)(I i) +ubyte ELF64_R_SYM(Elf64_Xword i) @nogc nothrow pure @safe { - return i >> 32; + return cast(ubyte) (i >> 32); } -auto ELF64_R_TYPE(I)(I i) +Elf64_Xword ELF64_R_TYPE(Elf64_Xword i) @nogc nothrow pure @safe { return i & 0xffffffffL; } -Elf64_Word ELF64_R_INFO(S)(S s, ubyte t) +Elf64_Xword ELF64_R_INFO(Elf64_Xword s, Elf64_Xword t) @nogc nothrow pure @safe { return (s << 32) + (t & 0xffffffffL); } @@ -352,24 +353,24 @@ ubyte ELF32_ST_TYPE(ubyte i) @nogc nothrow pure @safe return i & 0xf; } -ubyte ELF32_ST_INFO(ubyte b, ubyte t) @nogc nothrow pure @safe +ubyte ELF32_ST_INFO(Elf32_Word b, ubyte t) @nogc nothrow pure @safe { return cast(ubyte) ((b << 4) + (t & 0xf)); } -auto ELF32_R_SYMT(I)(I i) +Elf32_Word ELF32_R_SYM(Elf32_Word i) @nogc nothrow pure @safe { return i >> 8; } -ubyte ELF32_R_TYPE(I)(I i) +ubyte ELF32_R_TYPE(Elf32_Word i) @nogc nothrow pure @safe { return cast(ubyte) i; } -Elf32_Word ELF32_R_INFO(S)(S s, ubyte t) +Elf32_Word ELF32_R_INFO(Elf32_Word s, Elf32_Word t) @nogc nothrow pure @safe { - return cast(Elf32_Word) ((s << 8) + t); + return (s << 8) + t; } enum : uint @@ -602,6 +603,12 @@ auto pad(ubyte elfClass)(size_t value) @nogc } } +private struct Relocation(Sym, Rel) +{ + Sym symbol; + Array!Rel relocations; +} + struct Elf(ubyte elfClass) { static if (elfClass == ELFCLASS32) @@ -620,7 +627,7 @@ struct Elf(ubyte elfClass) alias Rela = Elf32_Rela; alias Sym = Elf32_Sym; - alias R_SYMT = ELF32_R_SYMT; + alias R_SYM = ELF32_R_SYM; alias R_TYPE = ELF32_R_TYPE; alias R_INFO = ELF32_R_INFO; alias ST_BIND = ELF32_ST_BIND; @@ -643,7 +650,7 @@ struct Elf(ubyte elfClass) alias Rela = Elf64_Rela; alias Sym = Elf64_Sym; - alias R_SYMT = ELF64_R_SYMT; + alias R_SYM = ELF64_R_SYM; alias R_TYPE = ELF64_R_TYPE; alias R_INFO = ELF64_R_INFO; alias ST_BIND = ELF64_ST_BIND; @@ -655,16 +662,17 @@ struct Elf(ubyte elfClass) static assert(false, "Invalid ELF class"); } + private alias Relocation = .Relocation!(Sym, Rela); + private Array!Shdr sectionHeaders; private Off currentOffset = Elf32_Ehdr.sizeof; - private Array!Sym symbols; static immutable char[52] sections = "\0.symtab\0.strtab\0.shstrtab\0.text\0.rodata\0.rela.text\0"; private String strings; - private Word lastLocalSymbol; private File output; private Array!ubyte readOnly; - private Array!Rela relocations; + + private HashTable!(String, Relocation) symbolTable; private enum HeaderName { @@ -681,7 +689,6 @@ struct Elf(ubyte elfClass) Elf elf = Elf.init; elf.initializeSectionHeaders(); - elf.insertSymbols(); elf.output = move(output); elf.output.seek(Ehdr.sizeof, File.Whence.set); @@ -700,7 +707,6 @@ struct Elf(ubyte elfClass) void finish() @nogc { - writeRelaTable(); writeRoDataTable(); writeSymbolTable(); writeStringTables(); @@ -712,19 +718,18 @@ struct Elf(ubyte elfClass) writeFileHeader(); } - private void insertSymbols() @nogc + private Sym initializeSymbols() @nogc { // Zero symbol - Elf32_Sym symbol; + Sym symbol; symbol.st_name = 0; // Word symbol.st_value = 0; // Addr symbol.st_size = 0; // Word symbol.st_info = 0; // char symbol.st_other = 0; // char symbol.st_shndx = 0; // Half word - this.symbols.insertBack(symbol); - // All symbols are global. - this.lastLocalSymbol = cast(Elf32_Word) this.symbols.length; + + return symbol; } private void makeStringHeader(HeaderName position)() @nogc @@ -791,25 +796,64 @@ struct Elf(ubyte elfClass) private void writeSymbolTable() @nogc { - auto index = findHeader!(HeaderName.symbol)(); - auto stringIndex = findHeader!(HeaderName.string_)(); + const index = findHeader!(HeaderName.symbol)(); + const stringIndex = findHeader!(HeaderName.string_)(); + const relaIndex = findHeader!(HeaderName.rela); + const textIndex = findHeader!(HeaderName.text)(); assert(index != -1); assert(stringIndex != -1); + assert(relaIndex != -1); + assert(textIndex != -1); this.sectionHeaders[index].sh_offset = this.currentOffset; - this.sectionHeaders[index].sh_info = this.lastLocalSymbol; this.sectionHeaders[index].sh_link = cast(Word) stringIndex; - this.sectionHeaders[index].sh_size = cast(Word) (this.symbols.length * Sym.sizeof); + this.sectionHeaders[index].sh_size = cast(Word) ((1 + symbolTable.length) * Sym.sizeof); - foreach (symbol; this.symbols) + this.sectionHeaders[relaIndex].sh_link = cast(Word) index; + this.sectionHeaders[relaIndex].sh_info = cast(Word) textIndex; + this.sectionHeaders[relaIndex].sh_offset = this.sectionHeaders[index].sh_offset + + this.sectionHeaders[index].sh_size; + + auto initialSymbol = initializeSymbols(); + output.write((cast(ubyte*) &initialSymbol)[0 .. Sym.sizeof]); + this.currentOffset += Sym.sizeof; + + int i = 1; + Array!Relocation symbols = Array!Relocation(this.symbolTable.byValue()); + auto rightRange = symbols[].partition!(symbol => ST_BIND(symbol.symbol.st_info) != STB_GLOBAL); + + // Greater than last local symbol. + this.sectionHeaders[index].sh_info = cast(Word) (symbols.length - rightRange.length + 1); + + foreach (ref symbol; symbols[]) { + this.output.seek(this.sectionHeaders[relaIndex].sh_offset + this.sectionHeaders[relaIndex].sh_size, + File.Whence.set); + + if (!symbol.relocations.empty) + { + foreach (ref relocation; symbol.relocations[]) + { + relocation.r_info = R_INFO(i, R_TYPE(relocation.r_info)); + } + this.sectionHeaders[relaIndex].sh_flags = SHF_ALLOC; + const size = cast(Word) (Rela.sizeof * symbol.relocations.length); + + this.output.write((cast(ubyte*) symbol.relocations.get)[0 .. size]); + this.sectionHeaders[relaIndex].sh_size += size; + this.currentOffset += size; + } + + this.output.seek(this.sectionHeaders[index].sh_offset + i * Sym.sizeof, File.Whence.set); output.write((cast(ubyte*) &symbol)[0 .. Sym.sizeof]); this.currentOffset += Sym.sizeof; + ++i; } + this.output.seek(0, File.Whence.end); } - void addCode(ref String name, ref Array!ubyte text, Array!Relocation usedSymbols) + void addCode(String name, ref Array!ubyte text) @nogc { this.output.write(text.get); @@ -828,57 +872,15 @@ struct Elf(ubyte elfClass) symbol.st_other = 0; // char // .text header index, half word symbol.st_shndx = cast(Half) textHeaderIndex; - this.symbols.insertBack(symbol); + this.symbolTable[name] = Relocation(symbol); this.strings.insertBack(name[]); this.sectionHeaders[textHeaderIndex].sh_size += text.length; this.currentOffset += text.length; - - foreach (usedSymbol; usedSymbols) - { - Rela relocationEntry; - - relocationEntry.r_offset = cast(Addr) usedSymbol.symbol.offset; - if (usedSymbol.hasEntry) - { - if (usedSymbol.symbol.target == Reference.Target.text) - { - relocationEntry.r_info = R_INFO(this.symbols.length, usedSymbol.typeInformation); - this.relocations.insertBack(relocationEntry); - } - else - { - relocationEntry.r_info = R_INFO(1, usedSymbol.typeInformation); - this.relocations.insertBack(relocationEntry); - } - } - else - { - relocationEntry.r_info = R_INFO(0, usedSymbol.typeInformation); - this.relocations.insertBack(relocationEntry); - continue; - } - if (usedSymbol.symbol.target == Reference.Target.text) - { - Sym usedSymbolEntry; - - this.strings.insertBack("\0"); - usedSymbolEntry.st_name = cast(Word) this.strings.length; - usedSymbolEntry.st_value = 0; - usedSymbolEntry.st_size = 0; - usedSymbolEntry.st_info = ST_INFO(STB_GLOBAL, STT_NOTYPE); - usedSymbolEntry.st_other = 0; - usedSymbolEntry.st_shndx = SHN_UNDEF; - - this.strings.insertBack(usedSymbol.symbol.name[]); - this.strings.insertBack("\0"); - this.symbols.insertBack(usedSymbolEntry); - } - } } - void addReadOnlyData(ref Array!ubyte data) @nogc + void addReadOnlyData(String name, ref Array!ubyte data) @nogc { auto roDataIndex = findHeader!(HeaderName.roData)(); assert(roDataIndex != -1); @@ -894,13 +896,40 @@ struct Elf(ubyte elfClass) symbol.st_other = 0; // char // .text header index, half word symbol.st_shndx = cast(Half) roDataIndex; - this.symbols.insertBack(symbol); - ++this.lastLocalSymbol; + this.symbolTable[name] = Relocation(symbol); - this.strings.insertBack(".CL0"); + this.strings.insertBack(name[]); this.readOnly.insertBack(data[]); } + void addExternSymbol(String name) @nogc + { + Sym usedSymbolEntry; + + this.strings.insertBack("\0"); + usedSymbolEntry.st_name = cast(Word) this.strings.length; + usedSymbolEntry.st_value = 0; + usedSymbolEntry.st_size = 0; + usedSymbolEntry.st_info = ST_INFO(STB_GLOBAL, STT_NOTYPE); + usedSymbolEntry.st_other = 0; + usedSymbolEntry.st_shndx = SHN_UNDEF; + + this.strings.insertBack(name[]); + this.strings.insertBack("\0"); + this.symbolTable[name] = Relocation(usedSymbolEntry); + } + + void relocate(String name, Rela[] usedSymbols...) @nogc + { + foreach (usedSymbol; usedSymbols) + { + Rela relocationEntry = usedSymbol; + + relocationEntry.r_info = usedSymbol.r_info; + this.symbolTable[name].relocations.insertBack(relocationEntry); + } + } + private ptrdiff_t findHeader(HeaderName position)() { return countUntil!(header => header.sh_name == position)(this.sectionHeaders[]); @@ -1028,24 +1057,4 @@ struct Elf(ubyte elfClass) this.sectionHeaders.insertBack(table); } - - private void writeRelaTable() @nogc - { - auto index = findHeader!(HeaderName.rela); - auto textIndex = findHeader!(HeaderName.text)(); - auto symbolIndex = findHeader!(HeaderName.symbol)(); - - assert(index != -1); - assert(textIndex != -1); - assert(symbolIndex != -1); - - this.sectionHeaders[index].sh_link = cast(Word) symbolIndex; - this.sectionHeaders[index].sh_info = cast(Word) textIndex; - this.sectionHeaders[index].sh_flags = this.relocations.length == 0 ? 0 : SHF_ALLOC; - this.sectionHeaders[index].sh_offset = this.currentOffset; - this.sectionHeaders[index].sh_size = cast(Word) (Rela.sizeof * this.relocations.length); - - this.output.write((cast(ubyte*) this.relocations.get)[0 .. Rela.sizeof * this.relocations.length]); - this.currentOffset += Rela.sizeof * this.relocations.length; - } } diff --git a/source/elna/result.d b/source/elna/result.d index c99ab50..9427147 100644 --- a/source/elna/result.d +++ b/source/elna/result.d @@ -105,10 +105,3 @@ struct Symbol Array!ubyte text; Array!Reference symbols; } - -struct Relocation -{ - Reference symbol; - ubyte typeInformation; - bool hasEntry = true; -}