Save ELF symbols in a hash table
This commit is contained in:
parent
72a60be386
commit
fbbabe115f
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -105,10 +105,3 @@ struct Symbol
|
||||
Array!ubyte text;
|
||||
Array!Reference symbols;
|
||||
}
|
||||
|
||||
struct Relocation
|
||||
{
|
||||
Reference symbol;
|
||||
ubyte typeInformation;
|
||||
bool hasEntry = true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user