Skip to content

Commit

Permalink
Write ELF with .dynsym and .dynstr, in a new readonly segment
Browse files Browse the repository at this point in the history
Summary:
Making it closer to what a proper ELF file would look like.  Properly aligns the
segments as well.

Differential Revision: D56079908

fbshipit-source-id: 4eb2d3bd4a47fb57bf8b0587112f709b5c8dd367
  • Loading branch information
Alex Malyshev authored and facebook-github-bot committed Apr 16, 2024
1 parent 674275b commit 8c0d62e
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 46 deletions.
146 changes: 105 additions & 41 deletions cinderx/Jit/elf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,25 @@ static_assert(sizeof(SectionHeader) == 64);
static_assert(sizeof(SegmentHeader) == 56);
static_assert(sizeof(FileHeader) == FileHeader{}.header_size);

// TODO(T176630720): This should not be a hardcoded value.
constexpr uint64_t kTextStartAddress = 0x1000000;
constexpr uint64_t kPageSize = 0x1000;

constexpr uint64_t kTextStartAddress = kPageSize;

constexpr uint64_t alignUp(uint64_t n) {
uint64_t mask = kPageSize - 1;
return (n + mask) & ~mask;
}

constexpr bool isAligned(uint64_t n) {
return n == alignUp(n);
}

uint64_t alignOffset(Object& elf) {
uint64_t new_offset = alignUp(elf.section_offset);
uint64_t delta = new_offset - elf.section_offset;
elf.section_offset = new_offset;
return delta;
}

void initFileHeader(Object& elf) {
FileHeader& header = elf.file_header;
Expand All @@ -28,47 +45,41 @@ void initFileHeader(Object& elf) {
header.section_name_index = raw(SectionIdx::kShstrtab);
}

void initTextSection(Object& elf, const std::vector<CodeEntry>& entries) {
uint64_t text_end_address = kTextStartAddress;

for (const CodeEntry& entry : entries) {
Symbol sym;
sym.name_offset = elf.strtab.insert(entry.func_name);
sym.info = kGlobal | kFunc;
sym.section_index = raw(SectionIdx::kText);
sym.address = text_end_address;
sym.size = entry.code.size();
elf.symtab.insert(std::move(sym));

// TODO(T176630885): Not writing the filename or lineno yet.

text_end_address += entry.code.size();
}
void initTextSection(Object& elf, uint64_t text_size) {
// Program bits. Occupies memory and is executable. Text follows the section
// header table after some padding.

size_t text_size = text_end_address - kTextStartAddress;
JIT_CHECK(
isAligned(elf.section_offset),
"Text section starts at unaligned address {:#x}",
elf.section_offset);

// Program bits. Occupies memory and is executable. Text immediately follows
// the section header table.
SectionHeader& header = elf.getSectionHeader(SectionIdx::kText);
header.name_offset = elf.shstrtab.insert(".text");
header.type = kProgram;
header.flags = kSectionAlloc | kSectionExecutable;
header.address = kTextStartAddress;
header.address = elf.section_offset;
header.offset = elf.section_offset;
header.size = text_size;
header.align = 0x1000;
header.align = 0x10;

elf.section_offset += header.size;
}

void initSymtabSection(Object& elf) {
SectionHeader& header = elf.getSectionHeader(SectionIdx::kSymtab);
header.name_offset = elf.shstrtab.insert(".symtab");
void initDynsymSection(Object& elf) {
JIT_CHECK(
isAligned(elf.section_offset),
"Dynsym section starts at unaligned address {:#x}",
elf.section_offset);

SectionHeader& header = elf.getSectionHeader(SectionIdx::kDynsym);
header.name_offset = elf.shstrtab.insert(".dynsym");
header.type = kSymbolTable;
header.flags = kSectionInfoLink;
header.flags = kSectionAlloc | kSectionInfoLink;
header.address = elf.section_offset;
header.offset = elf.section_offset;
header.size = elf.symtab.bytes().size();
header.link = raw(SectionIdx::kStrtab);
header.size = elf.dynsym.bytes().size();
header.link = raw(SectionIdx::kDynstr);
// This is the index of the first global symbol, i.e. the first symbol after
// the null symbol.
header.info = 1;
Expand All @@ -77,13 +88,14 @@ void initSymtabSection(Object& elf) {
elf.section_offset += header.size;
}

void initStrtabSection(Object& elf) {
SectionHeader& header = elf.getSectionHeader(SectionIdx::kStrtab);
header.name_offset = elf.shstrtab.insert(".strtab");
void initDynstrSection(Object& elf) {
SectionHeader& header = elf.getSectionHeader(SectionIdx::kDynstr);
header.name_offset = elf.shstrtab.insert(".dynstr");
header.type = kStringTable;
header.flags = kSectionStrings;
header.flags = kSectionAlloc;
header.address = elf.section_offset;
header.offset = elf.section_offset;
header.size = elf.strtab.bytes().size();
header.size = elf.dynstr.bytes().size();

elf.section_offset += header.size;
}
Expand All @@ -92,7 +104,6 @@ void initShstrtabSection(Object& elf) {
SectionHeader& header = elf.getSectionHeader(SectionIdx::kShstrtab);
header.name_offset = elf.shstrtab.insert(".shstrtab");
header.type = kStringTable;
header.flags = kSectionStrings;
header.offset = elf.section_offset;
header.size = elf.shstrtab.bytes().size();

Expand All @@ -113,6 +124,23 @@ void initTextSegment(Object& elf) {
header.align = 0x1000;
}

void initReadonlySegment(Object& elf) {
SectionHeader& dynsym = elf.getSectionHeader(SectionIdx::kDynsym);
SectionHeader& dynstr = elf.getSectionHeader(SectionIdx::kDynstr);
JIT_CHECK(
dynsym.address < dynstr.address,
"Expecting sections to be in a specific order");

SegmentHeader& header = elf.getSegmentHeader(SegmentIdx::kReadonly);
header.type = kLoadableSegment;
header.flags = kSegmentReadable;
header.offset = dynsym.offset;
header.address = dynsym.address;
header.file_size = dynsym.size + dynstr.size;
header.mem_size = header.file_size;
header.align = 0x1000;
}

template <class T>
void write(std::ostream& os, T* data, size_t size) {
os.write(reinterpret_cast<const char*>(data), size);
Expand All @@ -123,34 +151,70 @@ void write(std::ostream& os, std::span<const std::byte> bytes) {
write(os, bytes.data(), bytes.size());
}

void pad(std::ostream& os, size_t size) {
for (size_t i = 0; i < size; ++i) {
os.put(0);
}
}

} // namespace

void writeEntries(std::ostream& os, const std::vector<CodeEntry>& entries) {
Object elf;
initFileHeader(elf);

// Sections begin after all the headers are written out.
// Initialize symbols before any of the sections.
uint64_t text_end_address = kTextStartAddress;
for (const CodeEntry& entry : entries) {
Symbol sym;
sym.name_offset = elf.dynstr.insert(entry.func_name);
sym.info = kGlobal | kFunc;
sym.section_index = raw(SectionIdx::kText);
sym.address = text_end_address;
sym.size = entry.code.size();
elf.dynsym.insert(std::move(sym));

// TODO(T176630885): Not writing the filename or lineno yet.

text_end_address += entry.code.size();
}
uint64_t text_size = text_end_address - kTextStartAddress;

// The headers are all limited to the zeroth page, sections begin on the next
// page.
elf.section_offset = offsetof(Object, header_stop);
uint64_t header_padding = alignOffset(elf);
JIT_CHECK(
elf.section_offset == kTextStartAddress,
"ELF headers were too big and went past the zeroth page: {:#x}",
elf.section_offset);

// Null section needs no extra initialization.
initTextSection(elf, entries);
initSymtabSection(elf);
initStrtabSection(elf);

initTextSection(elf, text_size);
uint64_t text_padding = alignOffset(elf);

initDynsymSection(elf);
initDynstrSection(elf);
initShstrtabSection(elf);

initTextSegment(elf);
initReadonlySegment(elf);

// Write out all the headers.
write(os, &elf.file_header, sizeof(elf.file_header));
write(os, &elf.section_headers, sizeof(elf.section_headers));
write(os, &elf.segment_headers, sizeof(elf.segment_headers));
pad(os, header_padding);

// Write out the actual sections themselves.
for (const CodeEntry& entry : entries) {
write(os, entry.code.data(), entry.code.size());
}
write(os, elf.symtab.bytes());
write(os, elf.strtab.bytes());
pad(os, text_padding);

write(os, elf.dynsym.bytes());
write(os, elf.dynstr.bytes());
write(os, elf.shstrtab.bytes());
}

Expand Down
10 changes: 5 additions & 5 deletions cinderx/Jit/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ constexpr uint32_t kStringTable = 0x03;
// Section header flags.
constexpr uint64_t kSectionAlloc = 0x02;
constexpr uint64_t kSectionExecutable = 0x04;
constexpr uint64_t kSectionStrings = 0x20;
constexpr uint64_t kSectionInfoLink = 0x40;

// Segment header types.
Expand All @@ -44,15 +43,16 @@ enum class SectionIdx : uint32_t {
// Null section is index 0.

kText = 1,
kSymtab,
kStrtab,
kDynsym,
kDynstr,
kShstrtab,
kTotal,
};

// Segment header indices / ordering.
enum class SegmentIdx : uint32_t {
kText,
kReadonly,
kTotal,
};

Expand Down Expand Up @@ -261,8 +261,8 @@ struct Object {
// headers stop.
char header_stop[0];

SymbolTable symtab;
StringTable strtab;
SymbolTable dynsym;
StringTable dynstr;
StringTable shstrtab;

uint32_t section_offset{0};
Expand Down

0 comments on commit 8c0d62e

Please sign in to comment.