From 674275bf369ab476505139379f934e5dc27215e4 Mon Sep 17 00:00:00 2001 From: Alex Malyshev Date: Mon, 15 Apr 2024 13:14:49 -0700 Subject: [PATCH] Reorganize ELF writer, add jit::elf namespace Summary: There's a lot of changes in this diff, but it's just refactoring, the resulting ELF object is unchanged. Switches to writing the section headers first, then the segment headers (aka the program headers). The segments will be defined in terms of the sections. Moves the scattered state of the file (symbol tables, string tables, current section offset) into an `Object` class that represents the entire file, minus the code entries themselves. Also prepare for adding more segments by turning the segment header field into an array. Reviewed By: swtaarrs Differential Revision: D56069175 fbshipit-source-id: cc905d4a3beef78d8733aa0a11c94a51bd40958c --- cinderx/Jit/elf.cpp | 430 ++++++++---------------------- cinderx/Jit/elf.h | 276 ++++++++++++++++++- cinderx/Jit/pyjit.cpp | 6 +- cinderx/RuntimeTests/elf_test.cpp | 8 +- 4 files changed, 382 insertions(+), 338 deletions(-) diff --git a/cinderx/Jit/elf.cpp b/cinderx/Jit/elf.cpp index a9a41b672c5..73835cb4a6d 100644 --- a/cinderx/Jit/elf.cpp +++ b/cinderx/Jit/elf.cpp @@ -5,255 +5,113 @@ #include "cinderx/Common/log.h" #include "cinderx/Common/util.h" -#include #include -#include -namespace jit { +namespace jit::elf { namespace { -// See https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_layout -// for how the ELF 64-bit file layout is structured. - -// Program header types. -constexpr uint32_t kLoadableSegment = 0x1; - -// Program header flags. -constexpr uint32_t kSegmentExecutable = 0x1; -constexpr uint32_t kSegmentReadable = 0x4; - -// Section header types. -constexpr uint32_t kProgram = 0x01; -constexpr uint32_t kSymbolTable = 0x02; -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; - -// Symbol flags. -constexpr uint8_t kGlobal = 0x10; -constexpr uint8_t kFunc = 0x02; - -// Section header indices / ordering. -enum class SectionIdx : uint32_t { - // Null section is index 0. - - kText = 1, - kSymtab, - kStrtab, - kShstrtab, - kTotal, -}; - -constexpr uint32_t raw(SectionIdx idx) { - return static_cast(idx); +// ELF structures are all expected to be a set size. +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; + +void initFileHeader(Object& elf) { + FileHeader& header = elf.file_header; + header.segment_header_offset = offsetof(Object, segment_headers); + header.segment_header_count = raw(SegmentIdx::kTotal); + header.section_header_offset = offsetof(Object, section_headers); + header.section_header_count = raw(SectionIdx::kTotal); + header.section_name_index = raw(SectionIdx::kShstrtab); } -// Header that describes a memory segment loaded from an ELF file. -struct ElfProgramHeader { - // Type of this program segment. - uint32_t type{0}; - - // Executable, writable, and readable bits. - uint32_t flags{0}; - - // Offset of the memory segment in the file. - uint64_t offset{0}; - - // Virtual address of the memory segment. - uint64_t address{0}; - - // Unused, only applies to systems where raw physical memory access is - // relevant. - const uint64_t physical_address{0}; - - // Size of the memory segment. - // - // `file_size` is the number of bytes inside of the ELF file, but `mem_size` - // is how big the segment should be after it is loaded. If `mem_size` is - // bigger than `file_size`, then the remaining bytes will be padded with zeros - // when it is loaded. This is how .bss gets implemented. - uint64_t file_size{0}; - uint64_t mem_size{0}; - - // Required alignment of the memory segment. An alignment of 0 or 1 means the - // segment is unaligned, otherwise the value must be a power of two. - uint64_t align{0}; -}; - -// Header that describes an ELF section. -struct ElfSectionHeader { - // Offset into .shstrtab section for the name of this section. - uint32_t name_offset{0}; - - // Type of this section (e.g. program data, symbol table, etc.). - uint32_t type{0}; - - // Flags for the section (e.g. writable, executable, contains strings, etc.). - uint64_t flags{0}; - - // Virtual address of the section in memory, if it is loaded into memory. - uint64_t address{0}; - - // Offset of the section in the file. - uint64_t offset{0}; +void initTextSection(Object& elf, const std::vector& entries) { + uint64_t text_end_address = kTextStartAddress; - // Size of the section in the file. - uint64_t size{0}; - - // Use depends on the section type. Generally only needed for the symbol - // table for Cinder's purposes. - uint32_t link{0}; - uint32_t info{0}; - - // Required alignment of the section. An alignment of 0 means the section is - // unaligned, otherwise the value must be a power of two. - uint64_t align{0}; - - // If this is a special section type that contains fixed-size entries - // (e.g. symbol table), then this will be the entry size. Zero for all other - // sections. - uint64_t entry_size{0}; -}; - -// Header of an ELF file. Comes with some default values for convenience. -struct ElfFileHeader { - const uint8_t magic[4]{0x7f, 'E', 'L', 'F'}; - - // 64-bit. - uint8_t elf_class{2}; - - // Little endian. - uint8_t endian{1}; - - // ELF version is always 1. - const uint8_t elf_version{1}; - - // Linux. - uint8_t osabi{3}; - - // Unused on Linux. - uint8_t abi_version{0}; - uint8_t padding[7] = {0}; - - // Dynamic library. - uint16_t type{3}; - - // AMD x86-64. - uint16_t machine{0x3e}; - - // Duplicate of the previous version field. - const uint32_t version{1}; - - // For executable files, this is where the program starts. - const uint64_t entry_address{0}; - - // Will point to the start of the program header and section header tables. - uint64_t program_header_offset{0}; - uint64_t section_header_offset{0}; - - // Unused for x86, very likely unused for x86-64 as well. - const uint32_t flags{0}; - - // The size of this struct itself. - const uint16_t header_size{64}; - - // Size and number of program headers. - const uint16_t program_header_size{sizeof(ElfProgramHeader)}; - uint16_t program_header_count{0}; + 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)); - // Size and number of section headers. - const uint16_t section_header_size{sizeof(ElfSectionHeader)}; - uint16_t section_header_count{0}; + // TODO(T176630885): Not writing the filename or lineno yet. - // Section header table index that contains the section names table. - uint16_t section_name_index{0}; -}; + text_end_address += entry.code.size(); + } -// The layout of all of the ELF headers, combined. -struct ElfHeader { - ElfFileHeader file_header; - ElfProgramHeader prog_header; - std::array section_headers; + size_t text_size = text_end_address - kTextStartAddress; - ElfSectionHeader& getSectionHeader(SectionIdx idx) { - return section_headers[raw(idx)]; - } -}; - -// String table encoded for ELF. -class ElfStringTable { - public: - ElfStringTable() { - // All string tables begin with a NUL character. - bytes_.push_back(0); - } + // 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.offset = elf.section_offset; + header.size = text_size; + header.align = 0x1000; + + elf.section_offset += header.size; +} - // Insert a string into the symbol table, return its offset. - uint32_t insert(std::string_view s) { - size_t start_off = bytes_.size(); - // Strings are always encoded with a NUL terminator. - bytes_.resize(bytes_.size() + s.size() + 1); - std::memcpy(&bytes_[start_off], s.data(), s.size()); - JIT_CHECK( - fitsInt32(start_off), "ELF symbol table only deals in 32-bit offsets"); - return static_cast(start_off); - } +void initSymtabSection(Object& elf) { + SectionHeader& header = elf.getSectionHeader(SectionIdx::kSymtab); + header.name_offset = elf.shstrtab.insert(".symtab"); + header.type = kSymbolTable; + header.flags = kSectionInfoLink; + header.offset = elf.section_offset; + header.size = elf.symtab.bytes().size(); + header.link = raw(SectionIdx::kStrtab); + // This is the index of the first global symbol, i.e. the first symbol after + // the null symbol. + header.info = 1; + header.entry_size = sizeof(Symbol); - std::span bytes() const { - return std::as_bytes(std::span{bytes_}); - } + elf.section_offset += header.size; +} - private: - std::vector bytes_; -}; - -struct ElfSymbol { - uint32_t name_offset{0}; - - // Type of symbol this is. - uint8_t info{kGlobal | kFunc}; - - // Controls symbol visibility. Zero means to compute visibility from the - // `info` field. - const uint8_t other{0}; - - // Index of the section that this symbol points to. - uint16_t section_index{0}; - uint64_t address{0}; - uint64_t size{0}; -}; - -class ElfSymbolTable { - public: - ElfSymbolTable() { - // Symbol table must always start with an undefined symbol. - ElfSymbol null_sym; - std::memset(&null_sym, 0, sizeof(null_sym)); - insert(null_sym); - } +void initStrtabSection(Object& elf) { + SectionHeader& header = elf.getSectionHeader(SectionIdx::kStrtab); + header.name_offset = elf.shstrtab.insert(".strtab"); + header.type = kStringTable; + header.flags = kSectionStrings; + header.offset = elf.section_offset; + header.size = elf.strtab.bytes().size(); - template - void insert(T&& sym) { - syms_.emplace_back(std::forward(sym)); - } + elf.section_offset += header.size; +} - std::span bytes() const { - return std::as_bytes(std::span{syms_}); - } +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(); - private: - std::vector syms_; -}; + elf.section_offset += header.size; +} -// ELF structures are all expected to be a set size. -static_assert(sizeof(ElfProgramHeader) == 56); -static_assert(sizeof(ElfSectionHeader) == 64); -static_assert(sizeof(ElfFileHeader) == ElfFileHeader{}.header_size); +void initTextSegment(Object& elf) { + SectionHeader& section = elf.getSectionHeader(SectionIdx::kText); + + // The .text section immediately follows all the ELF headers. + SegmentHeader& header = elf.getSegmentHeader(SegmentIdx::kText); + header.type = kLoadableSegment; + header.flags = kSegmentExecutable | kSegmentReadable; + header.offset = section.offset; + header.address = section.address; + header.file_size = section.size; + header.mem_size = header.file_size; + header.align = 0x1000; +} template void write(std::ostream& os, T* data, size_t size) { @@ -267,111 +125,33 @@ void write(std::ostream& os, std::span bytes) { } // namespace -void writeElfEntries( - std::ostream& os, - const std::vector& entries) { - ElfStringTable section_names; - - ElfSymbolTable symbols; - ElfStringTable symbol_names; - - // TODO(T176630720): This should not be a hardcoded value. - uint64_t text_start_address = 0x1000000; - uint64_t text_end_address = text_start_address; - - for (const ElfCodeEntry& entry : entries) { - ElfSymbol sym; - sym.name_offset = symbol_names.insert(entry.func_name); - sym.section_index = raw(SectionIdx::kText); - sym.address = text_end_address; - sym.size = entry.code.size(); - symbols.insert(std::move(sym)); - - // TODO(T176630885): Not writing the filename or lineno yet. - - text_end_address += entry.code.size(); - } - - size_t text_size = text_end_address - text_start_address; - - ElfHeader elf; - - ElfFileHeader& file_header = elf.file_header; - file_header.program_header_offset = offsetof(ElfHeader, prog_header); - file_header.program_header_count = 1; - file_header.section_header_offset = offsetof(ElfHeader, section_headers); - file_header.section_header_count = raw(SectionIdx::kTotal); - file_header.section_name_index = raw(SectionIdx::kShstrtab); - - // The memory segment loaded into memory immediately follows all the ELF - // headers. - ElfProgramHeader& prog_header = elf.prog_header; - prog_header.type = kLoadableSegment; - prog_header.flags = kSegmentExecutable | kSegmentReadable; - prog_header.offset = sizeof(ElfHeader); - prog_header.address = text_start_address; - prog_header.file_size = text_size; - prog_header.mem_size = text_size; - prog_header.align = 0x1000; +void writeEntries(std::ostream& os, const std::vector& entries) { + Object elf; + initFileHeader(elf); // Sections begin after all the headers are written out. - uint32_t section_offset = sizeof(ElfHeader); + elf.section_offset = offsetof(Object, header_stop); // Null section needs no extra initialization. + initTextSection(elf, entries); + initSymtabSection(elf); + initStrtabSection(elf); + initShstrtabSection(elf); - // Program bits. Occupies memory and is executable. Text immediately follows - // the section header table. - ElfSectionHeader& text_header = elf.getSectionHeader(SectionIdx::kText); - text_header.name_offset = section_names.insert(".text"); - text_header.type = kProgram; - text_header.flags = kSectionAlloc | kSectionExecutable; - text_header.address = prog_header.address; - text_header.offset = section_offset; - text_header.size = text_size; - text_header.align = 0x1000; - section_offset += text_header.size; - - ElfSectionHeader& symbol_header = elf.getSectionHeader(SectionIdx::kSymtab); - symbol_header.name_offset = section_names.insert(".symtab"); - symbol_header.type = kSymbolTable; - symbol_header.flags = kSectionInfoLink; - symbol_header.offset = section_offset; - symbol_header.size = symbols.bytes().size(); - symbol_header.link = raw(SectionIdx::kStrtab); - // This is the index of the first global symbol, i.e. the first symbol after - // the null symbol. - symbol_header.info = 1; - symbol_header.entry_size = sizeof(ElfSymbol); - section_offset += symbol_header.size; - - ElfSectionHeader& symbol_string_header = - elf.getSectionHeader(SectionIdx::kStrtab); - symbol_string_header.name_offset = section_names.insert(".strtab"); - symbol_string_header.type = kStringTable; - symbol_string_header.flags = kSectionStrings; - symbol_string_header.offset = section_offset; - symbol_string_header.size = symbol_names.bytes().size(); - section_offset += symbol_string_header.size; - - ElfSectionHeader& section_string_header = - elf.getSectionHeader(SectionIdx::kShstrtab); - section_string_header.name_offset = section_names.insert(".shstrtab"); - section_string_header.type = kStringTable; - section_string_header.flags = kSectionStrings; - section_string_header.offset = section_offset; - section_string_header.size = section_names.bytes().size(); - section_offset += section_string_header.size; + initTextSegment(elf); // Write out all the headers. - write(os, &elf, sizeof(elf)); + 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)); // Write out the actual sections themselves. - for (const ElfCodeEntry& entry : entries) { + for (const CodeEntry& entry : entries) { write(os, entry.code.data(), entry.code.size()); } - write(os, symbols.bytes()); - write(os, symbol_names.bytes()); - write(os, section_names.bytes()); + write(os, elf.symtab.bytes()); + write(os, elf.strtab.bytes()); + write(os, elf.shstrtab.bytes()); } -} // namespace jit +} // namespace jit::elf diff --git a/cinderx/Jit/elf.h b/cinderx/Jit/elf.h index 3a177f609c9..b68b4cb2bd4 100644 --- a/cinderx/Jit/elf.h +++ b/cinderx/Jit/elf.h @@ -2,16 +2,282 @@ #pragma once +#include "cinderx/Common/log.h" +#include "cinderx/Common/util.h" + #include +#include #include #include #include #include -namespace jit { +namespace jit::elf { + +// See https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_layout +// for how the ELF 64-bit file layout is structured. + +// Section header types. +constexpr uint32_t kProgram = 0x01; +constexpr uint32_t kSymbolTable = 0x02; +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. +constexpr uint32_t kLoadableSegment = 0x1; + +// Segment header flags. +constexpr uint32_t kSegmentExecutable = 0x1; +constexpr uint32_t kSegmentReadable = 0x4; + +// Symbol flags. +constexpr uint8_t kGlobal = 0x10; +constexpr uint8_t kFunc = 0x02; + +// Section header indices / ordering. +enum class SectionIdx : uint32_t { + // Null section is index 0. + + kText = 1, + kSymtab, + kStrtab, + kShstrtab, + kTotal, +}; + +// Segment header indices / ordering. +enum class SegmentIdx : uint32_t { + kText, + kTotal, +}; + +constexpr uint32_t raw(SectionIdx idx) { + return static_cast(idx); +} + +constexpr uint32_t raw(SegmentIdx idx) { + return static_cast(idx); +} + +// Header that describes an ELF section. +struct SectionHeader { + // Offset into .shstrtab section for the name of this section. + uint32_t name_offset{0}; + + // Type of this section (e.g. program data, symbol table, etc.). + uint32_t type{0}; + + // Flags for the section (e.g. writable, executable, contains strings, etc.). + uint64_t flags{0}; + + // Virtual address of the section in memory, if it is loaded into memory. + uint64_t address{0}; + + // Offset of the section in the file. + uint64_t offset{0}; + + // Size of the section in the file. + uint64_t size{0}; + + // Use depends on the section type. Generally only needed for the symbol + // table for Cinder's purposes. + uint32_t link{0}; + uint32_t info{0}; + + // Required alignment of the section. An alignment of 0 means the section is + // unaligned, otherwise the value must be a power of two. + uint64_t align{0}; + + // If this is a special section type that contains fixed-size entries + // (e.g. symbol table), then this will be the entry size. Zero for all other + // sections. + uint64_t entry_size{0}; +}; + +// Header that describes a memory segment loaded from an ELF file. +struct SegmentHeader { + // Type of this segment. + uint32_t type{0}; + + // Executable, writable, and readable bits. + uint32_t flags{0}; + + // Offset of the memory segment in the file. + uint64_t offset{0}; + + // Virtual address of the memory segment. + uint64_t address{0}; + + // Unused, only applies to systems where raw physical memory access is + // relevant. + const uint64_t physical_address{0}; + + // Size of the memory segment. + // + // `file_size` is the number of bytes inside of the ELF file, but `mem_size` + // is how big the segment should be after it is loaded. If `mem_size` is + // bigger than `file_size`, then the remaining bytes will be padded with zeros + // when it is loaded. This is how .bss gets implemented. + uint64_t file_size{0}; + uint64_t mem_size{0}; + + // Required alignment of the memory segment. An alignment of 0 or 1 means the + // segment is unaligned, otherwise the value must be a power of two. + uint64_t align{0}; +}; + +// Header of an ELF file. Comes with some default values for convenience. +struct FileHeader { + const uint8_t magic[4]{0x7f, 'E', 'L', 'F'}; + + // 64-bit. + uint8_t elf_class{2}; + + // Little endian. + uint8_t endian{1}; + + // ELF version is always 1. + const uint8_t elf_version{1}; + + // Linux. + uint8_t osabi{3}; + + // Unused on Linux. + uint8_t abi_version{0}; + uint8_t padding[7] = {0}; + + // Dynamic library. + uint16_t type{3}; + + // AMD x86-64. + uint16_t machine{0x3e}; + + // Duplicate of the previous version field. + const uint32_t version{1}; + + // For executable files, this is where the program starts. + const uint64_t entry_address{0}; + + // Will point to the start of the segment and section header tables. + uint64_t segment_header_offset{0}; + uint64_t section_header_offset{0}; + + // Unused for x86, very likely unused for x86-64 as well. + const uint32_t flags{0}; + + // The size of this struct itself. + const uint16_t header_size{64}; + + // Size and number of segment headers. + const uint16_t segment_header_size{sizeof(SegmentHeader)}; + uint16_t segment_header_count{0}; + + // Size and number of section headers. + const uint16_t section_header_size{sizeof(SectionHeader)}; + uint16_t section_header_count{0}; + + // Section header table index that contains the section names table. + uint16_t section_name_index{0}; +}; + +// String table encoded for ELF. +class StringTable { + public: + StringTable() { + // All string tables begin with a NUL character. + bytes_.push_back(0); + } + + // Insert a string into the symbol table, return its offset. + uint32_t insert(std::string_view s) { + size_t start_off = bytes_.size(); + // Strings are always encoded with a NUL terminator. + bytes_.resize(bytes_.size() + s.size() + 1); + std::memcpy(&bytes_[start_off], s.data(), s.size()); + JIT_CHECK( + fitsInt32(start_off), "ELF symbol table only deals in 32-bit offsets"); + return static_cast(start_off); + } + + std::span bytes() const { + return std::as_bytes(std::span{bytes_}); + } + + private: + std::vector bytes_; +}; + +struct Symbol { + uint32_t name_offset{0}; + + // Type of symbol this is. + uint8_t info{0}; + + // Controls symbol visibility. Zero means to compute visibility from the + // `info` field. + const uint8_t other{0}; + + // Index of the section that this symbol points to. + uint16_t section_index{0}; + uint64_t address{0}; + uint64_t size{0}; +}; + +class SymbolTable { + public: + SymbolTable() { + // Symbol table must always start with an undefined symbol. + insert(Symbol{}); + } + + template + void insert(T&& sym) { + syms_.emplace_back(std::forward(sym)); + } + + std::span bytes() const { + return std::as_bytes(std::span{syms_}); + } + + private: + std::vector syms_; +}; + +// Represents an ELF object/file. +// +// The headers are laid out in the exact order that they will appear in the +// file. +struct Object { + FileHeader file_header; + std::array section_headers; + std::array segment_headers; + + // Zero-length field that gives the offset into the ELF object where the + // headers stop. + char header_stop[0]; + + SymbolTable symtab; + StringTable strtab; + StringTable shstrtab; + + uint32_t section_offset{0}; + + SectionHeader& getSectionHeader(SectionIdx idx) { + return section_headers[raw(idx)]; + } + + SegmentHeader& getSegmentHeader(SegmentIdx idx) { + return segment_headers[raw(idx)]; + } +}; // Code entry to add to an ELF file. -struct ElfCodeEntry { +struct CodeEntry { std::span code; std::string func_name; std::string file_name; @@ -21,8 +287,6 @@ struct ElfCodeEntry { // Write function or code objects out to a new ELF file. // // The output ELF file is always a shared library. -void writeElfEntries( - std::ostream& os, - const std::vector& entries); +void writeEntries(std::ostream& os, const std::vector& entries); -} // namespace jit +} // namespace jit::elf diff --git a/cinderx/Jit/pyjit.cpp b/cinderx/Jit/pyjit.cpp index e9ebf331df2..6456beb568e 100644 --- a/cinderx/Jit/pyjit.cpp +++ b/cinderx/Jit/pyjit.cpp @@ -1154,12 +1154,12 @@ static PyObject* dump_elf(PyObject* /* self */, PyObject* arg) { Py_ssize_t filename_size = 0; const char* filename = PyUnicode_AsUTF8AndSize(arg, &filename_size); - std::vector entries; + std::vector entries; for (BorrowedRef func : jit_ctx->compiledFuncs()) { BorrowedRef code{func->func_code}; CompiledFunction* compiled_func = jit_ctx->lookupFunc(func); - ElfCodeEntry entry; + elf::CodeEntry entry; // TODO: What about the staticEntry? entry.code = { reinterpret_cast(compiled_func->vectorcallEntry()), @@ -1174,7 +1174,7 @@ static PyObject* dump_elf(PyObject* /* self */, PyObject* arg) { } std::ofstream out{filename}; - writeElfEntries(out, entries); + elf::writeEntries(out, entries); Py_RETURN_NONE; } diff --git a/cinderx/RuntimeTests/elf_test.cpp b/cinderx/RuntimeTests/elf_test.cpp index 35cf4b371a2..96724a539ab 100644 --- a/cinderx/RuntimeTests/elf_test.cpp +++ b/cinderx/RuntimeTests/elf_test.cpp @@ -17,7 +17,7 @@ void verifyMagic(std::string_view s) { TEST_F(ElfTest, EmptyEntries) { std::stringstream ss; - writeElfEntries(ss, {}); + elf::writeEntries(ss, {}); std::string result = ss.str(); verifyMagic(result); @@ -26,13 +26,13 @@ TEST_F(ElfTest, EmptyEntries) { TEST_F(ElfTest, OneEntry) { std::stringstream ss; - ElfCodeEntry entry; - entry.code = {reinterpret_cast(writeElfEntries), 0x40}; + elf::CodeEntry entry; + entry.code = {reinterpret_cast(elf::writeEntries), 0x40}; entry.func_name = "funcABC"; entry.file_name = "spaghetti.exe"; entry.lineno = 15; - writeElfEntries(ss, {entry}); + elf::writeEntries(ss, {entry}); std::string result = ss.str(); verifyMagic(result);