diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f72c5d..3bb4c40 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,6 +31,9 @@ jobs: run: | make -C tests/software-keyboard make -C tests/mii-selector + make -C tests/crotools/elf2cro + make -C tests/crotools/example_cro + make -C tests/crotools/example_inject - name: Upload binaries uses: actions/upload-artifact@v2 diff --git a/tests/crotools/cro.h b/tests/crotools/cro.h new file mode 100644 index 0000000..64327a8 --- /dev/null +++ b/tests/crotools/cro.h @@ -0,0 +1,201 @@ +#ifndef CRO_H +#define CRO_H + +#include + +#define MAGIC_CRO0 (0x304F5243) +#define CRO_TREE_END (0x8000) + +enum CRO_Segment_Type +{ + SEG_TEXT = 0, + SEG_RODATA = 1, + SEG_DATA = 2, + SEG_BSS = 3, +}; + +typedef struct +{ + uint32_t offset; + uint32_t size; + uint32_t type; +} CRO_Segment; + +typedef struct +{ + uint32_t offs_name; + uint32_t seg_offset; +} CRO_Symbol; + +typedef union { + uint16_t raw; + struct + { + uint16_t next_index : 15; + uint16_t is_end : 1; + }; +} CRO_ExportTreeChild; + +typedef struct +{ + uint16_t test_bit : 3; + uint16_t test_byte : 13; + CRO_ExportTreeChild left, right; + + uint16_t export_index; +} CRO_ExportTreeEntry; + +typedef struct +{ + uint32_t seg_offset; + uint8_t type; + uint8_t last_entry; + uint8_t all_loaded; + uint8_t reserved; + uint32_t addend; +} CRO_Relocation; + +typedef struct { + uint32_t offs_mod_name; + uint32_t import_indexed_symbol_table_offset; // pointing to a subtable in + // ImportIndexedSymbolTable + uint32_t import_indexed_symbol_num; + uint32_t import_anonymous_symbol_table_offset; // pointing to a subtable in + // ImportAnonymousSymbolTable + uint32_t import_anonymous_symbol_num; + + char* get_name(void* cro_data) + { + return (char*)cro_data + offs_mod_name; + } + +} CRO_ModuleEntry; + +typedef struct +{ + uint8_t hash_table[0x80]; + uint32_t magic; + uint32_t offs_mod_name; + uint32_t offs_next; + uint32_t offs_prev; + uint32_t size_file; + uint32_t size_bss; + uint32_t reserved_0; + uint32_t reserved_1; + uint32_t offs_control; + uint32_t offs_prologue; + uint32_t offs_epilogue; + uint32_t offs_unresolved; + uint32_t offs_text; + uint32_t size_text; + uint32_t offs_data; + uint32_t size_data; + uint32_t offs_name; + uint32_t size_name; + uint32_t offs_segments; + uint32_t num_segments; + + // Exports + uint32_t offs_symbol_exports; + uint32_t num_symbol_exports; + uint32_t offs_index_exports; + uint32_t num_index_exports; + uint32_t offs_export_strtab; + uint32_t size_export_strtab; + uint32_t offs_export_tree; + uint32_t num_export_tree; + + // Imports + uint32_t offs_import_module; + uint32_t num_import_module; + uint32_t offs_import_patches; + uint32_t num_import_patches; + uint32_t offs_symbol_imports; + uint32_t num_symbol_imports; + uint32_t offs_index_imports; + uint32_t num_index_imports; + uint32_t offs_offset_imports; + uint32_t num_offset_imports; + uint32_t offs_import_strtab; + uint32_t size_import_strtab; + + // Weird static stuff + uint32_t offs_offset_exports; + uint32_t num_offset_exports; + uint32_t offs_static_relocations; + uint32_t num_static_relocations; + uint32_t offs_unk; + uint32_t size_unk; + + CRO_Relocation* get_import_reloc(void* cro_data, int index) + { + return (CRO_Relocation*)((char*)cro_data + offs_import_patches + (index * sizeof(CRO_Relocation))); + } + + CRO_Relocation* get_static_reloc(void* cro_data, int index) + { + return (CRO_Relocation*)((char*)cro_data + offs_static_relocations + (index * sizeof(CRO_Relocation))); + } + + CRO_Symbol* get_index_export(void* cro_data, int index) + { + return (CRO_Symbol*)((char*)cro_data + offs_index_exports + (index * sizeof(CRO_Symbol))); + } + + CRO_Symbol* get_export(void* cro_data, int index) + { + return (CRO_Symbol*)((char*)cro_data + offs_symbol_exports + (index * sizeof(CRO_Symbol))); + } + + CRO_Symbol* get_offset_import(void* cro_data, int index) + { + return (CRO_Symbol*)((char*)cro_data + offs_offset_imports + (index * sizeof(CRO_Symbol))); + } + + CRO_Symbol* get_index_import(void* cro_data, int index) + { + return (CRO_Symbol*)((char*)cro_data + offs_index_imports + (index * sizeof(CRO_Symbol))); + } + + CRO_Symbol* get_import(void* cro_data, int index) + { + return (CRO_Symbol*)((char*)cro_data + offs_symbol_imports + (index * sizeof(CRO_Symbol))); + } + + CRO_ExportTreeEntry* get_export_tree_entry(void* cro_data, int index) + { + return (CRO_ExportTreeEntry*)((char*)cro_data + offs_export_tree + (index * sizeof(CRO_ExportTreeEntry))); + } + + CRO_ModuleEntry* get_module_entry(void* cro_data, int index) + { + return (CRO_ModuleEntry*)((char*)cro_data + offs_import_module + (index * sizeof(CRO_ModuleEntry))); + } + + char* get_name(void* cro_data) + { + return (char*)cro_data + offs_mod_name; + } + + void* get_text_data(void* cro_data) + { + return (void*)((char*)cro_data + offs_text); + } + + void* get_data_data(void* cro_data) + { + return (void*)((char*)cro_data + offs_data); + } + + void* get_segment_data(void* cro_data, int segment) + { + return (void*)((char*)cro_data + get_segments(cro_data)[segment].offset); + } + + CRO_Segment* get_segments(void* cro_data) + { + return (CRO_Segment*)((char*)cro_data + offs_segments); + } +} CRO_Header; + +#endif diff --git a/tests/crotools/cro2elf/Makefile b/tests/crotools/cro2elf/Makefile new file mode 100644 index 0000000..8ba07b9 --- /dev/null +++ b/tests/crotools/cro2elf/Makefile @@ -0,0 +1,32 @@ +# Sources +SRC_DIR = . +OBJS = $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c))) $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) + +# Compiler Settings +OUTPUT = cro2elf +CXXFLAGS = -std=c++11 -g -I. -I.. +CFLAGS = -g -O2 -flto -Wall -Wno-unused-variable -Wno-unused-result -Wno-unused-local-typedefs -I. -std=c11 +CC = gcc +CXX = g++ +ifeq ($(OS),Windows_NT) + #Windows Build CFG + CFLAGS += -Wno-unused-but-set-variable + LIBS += -static-libgcc -static-libstdc++ +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + # OS X + CFLAGS += + LIBS += -liconv + else + # Linux + CFLAGS += -Wno-unused-but-set-variable + LIBS += + endif +endif + +main: $(OBJS) + $(CXX) -o $(OUTPUT) $(LIBS) $(OBJS) + +clean: + rm -rf $(OUTPUT) $(OUTPUT).exe $(OBJS) diff --git a/tests/crotools/cro2elf/cro2elf.cpp b/tests/crotools/cro2elf/cro2elf.cpp new file mode 100644 index 0000000..76208b4 --- /dev/null +++ b/tests/crotools/cro2elf/cro2elf.cpp @@ -0,0 +1,469 @@ +#include +#include +#include + +#include "elfio/elfio.hpp" +#include "elfio/elfio_dump.hpp" +#include "cro.h" + +using namespace ELFIO; + +int counts[3] = {0}; +section* add_relocation_section(elfio& elf, section** sections, section* dynsym_sec, int segment_index) +{ + char* secs[3] = {".text", ".rodata", ".data"}; + char rela_name[32]; + snprintf(rela_name, 32, ".rela%s.%u", secs[segment_index], counts[segment_index]++); + + section* rel_sec = elf.sections.add(rela_name); + rel_sec->set_type(SHT_RELA); + rel_sec->set_entry_size(elf.get_default_entry_size(SHT_RELA)); + rel_sec->set_flags(SHF_ALLOC | SHF_INFO_LINK); + rel_sec->set_info(sections[segment_index]->get_index()); + rel_sec->set_overlay(sections[segment_index]->get_index()); + rel_sec->set_link(dynsym_sec->get_index()); + rel_sec->set_addr_align(4); + return rel_sec; +} + +int main(int argc, char **argv) +{ + if (argc < 3) + { + printf("Usage: %s [cro_list.txt] [code.bin]\n", argv[0]); + return -1; + } + + FILE* cro_file = fopen(argv[1], "rb"); + if (!cro_file) + { + printf("Failed to open file %s! Exiting...\n", argv[1]); + return -1; + } + + bool is_static = false; + FILE* static_file; + void* static_data = nullptr; + uint32_t static_size = 0; + if (argc > 4) + { + static_file = fopen(argv[4], "rb"); + if (!static_file) + { + printf("Failed to open file %s! Exiting...\n", argv[4]); + return -1; + } + + is_static = true; + fseek(static_file, 0, SEEK_END); + static_size = ftell(static_file); + static_data = malloc(static_size); + + fseek(static_file, 0, SEEK_SET); + fread(static_data, sizeof(uint8_t), static_size, static_file); + fclose(static_file); + } + + fseek(cro_file, 0, SEEK_END); + uint32_t cro_size = ftell(cro_file); + void* cro_data = malloc(cro_size); + + fseek(cro_file, 0, SEEK_SET); + fread(cro_data, sizeof(uint8_t), cro_size, cro_file); + fclose(cro_file); + + CRO_Header* cro_header = (CRO_Header*)cro_data; + printf("Loaded CRO %s\n", cro_header->get_name(cro_data)); + + elfio elf; + elf.create(ELFCLASS32, ELFDATA2LSB); + elf.set_os_abi(ELFOSABI_NONE); + elf.set_type(ET_REL); + elf.set_machine(EM_ARM); + elf.set_entry(cro_header->offs_text); + + CRO_Segment* cro_segments = cro_header->get_segments(cro_data); + segment* segments[5]; + section* sections[5]; + for (int i = 0; i < cro_header->num_segments; i++) + { + segment* seg = elf.segments.add(); + printf("Segment %u: offs %x, size %x, type %x\n", i, cro_segments[i].offset, cro_segments[i].size, cro_segments[i].type); + + if (cro_segments[i].type == SEG_TEXT) + { + seg->set_type(PT_LOAD); + seg->set_flags(PF_R | PF_X); + + seg->set_align(0x10); + } + else if (cro_segments[i].type == SEG_RODATA) + { + seg->set_type(PT_LOAD); + seg->set_flags(PF_R); + + seg->set_align(0x4); + } + else if (cro_segments[i].type == SEG_DATA) + { + seg->set_type(PT_LOAD); + seg->set_flags(PF_R | PF_W); + + seg->set_align(0x1000); + } + else if (cro_segments[i].type == SEG_BSS) + { + seg->set_type(PT_LOAD); + seg->set_flags(PF_R | PF_W); + + seg->set_align(0x4); + + seg->set_virtual_address(cro_header->offs_data + cro_header->size_data); + seg->set_physical_address(cro_header->offs_data + cro_header->size_data); + } + + if (cro_segments[i].type != SEG_BSS) + { + seg->set_virtual_address(cro_segments[i].offset); + seg->set_physical_address(cro_segments[i].offset); + } + seg->set_memory_size(cro_segments[i].size); + seg->set_file_size(cro_segments[i].size); + + section* sec; + if (cro_segments[i].type == SEG_TEXT && cro_segments[i].offset == 0) + { + sec = elf.sections.add(".cro_info"); + + sec->set_type(SHT_PROGBITS); + sec->set_flags(SHF_ALLOC | SHF_EXECINSTR); + } + else if (cro_segments[i].type == SEG_TEXT) + { + sec = elf.sections.add(".text"); + sec->set_type(SHT_PROGBITS); + sec->set_flags(SHF_ALLOC | SHF_EXECINSTR); + } + else if (cro_segments[i].type == SEG_RODATA) + { + sec = elf.sections.add(".rodata"); + sec->set_type(SHT_PROGBITS); + sec->set_flags(SHF_ALLOC); + } + else if (cro_segments[i].type == SEG_DATA) + { + sec = elf.sections.add(".data"); + sec->set_type(SHT_PROGBITS); + sec->set_flags(SHF_ALLOC | SHF_WRITE); + } + else if (cro_segments[i].type == SEG_BSS) + { + sec = elf.sections.add(".bss"); + sec->set_type(SHT_NOBITS); + sec->set_flags(SHF_ALLOC | SHF_WRITE); + + sec->set_address(cro_header->offs_data + cro_header->size_data); + } + else + { + sec = elf.sections.add(".unk"); + sec->set_type(SHT_NULL); + } + + sec->set_addr_align(4); + if (cro_segments[i].type != SEG_BSS) + { + sec->set_address(cro_segments[i].offset); + if (is_static) + { + if (i < 4) + sec->set_data((char*)static_data + cro_segments[i].offset - 0x100000, cro_segments[i].size); + } + else + sec->set_data((char*)cro_data + cro_segments[i].offset, cro_segments[i].size); + } + else + { + sec->set_size(cro_header->size_bss); + seg->set_memory_size(cro_segments[i].size); + seg->set_file_size(cro_segments[i].size); + } + seg->add_section_index(sec->get_index(), sec->get_addr_align()); + + sections[i] = sec; + segments[i] = seg; + } + + section* strtab_sec = elf.sections.add(".dynstr"); + { + strtab_sec->set_type(SHT_STRTAB); + strtab_sec->set_flags(SHF_ALLOC); + + strtab_sec->set_overlay(sections[SEG_TEXT]->get_index()); + strtab_sec->set_addr_align(1); + } + string_section_accessor stra(strtab_sec); + + section* dynsym_sec = elf.sections.add(".dynsym"); + { + dynsym_sec->set_type(SHT_DYNSYM); + dynsym_sec->set_flags(SHF_ALLOC); + dynsym_sec->set_entry_size(elf.get_default_entry_size(SHT_SYMTAB)); + + dynsym_sec->set_link(strtab_sec->get_index()); + dynsym_sec->set_info(5+1); + dynsym_sec->set_overlay(sections[SEG_TEXT]->get_index()); + dynsym_sec->set_addr_align(4); + } + symbol_section_accessor symd(elf, dynsym_sec); + + for (int i = 0; i < 5; i++) + { + symd.add_symbol(0, segments[i]->get_virtual_address(), 0, STB_LOCAL, STT_SECTION, 0, sections[i]->get_index()); + } + + int last_rela = -1; + relocation_section_accessor* rel_accessor = nullptr; + + for (int i = 0; i < cro_header->num_symbol_exports; i++) + { + CRO_Symbol* symbol = cro_header->get_export(cro_data, i); + int seg_idx = symbol->seg_offset & 0xf; + int seg_offs = symbol->seg_offset >> 4; + //printf("%x - %x %x\n", symbol->seg_offset, seg_idx, seg_offs); + //printf("%s\n", (char*)cro_data + symbol->offs_name); + + symd.add_symbol(stra, (char*)cro_data + symbol->offs_name, segments[seg_idx]->get_virtual_address() + seg_offs, 0, STB_GLOBAL, STT_NOTYPE, 0, sections[seg_idx]->get_index()); + } + + for (int i = 0; i < cro_header->num_index_exports; i++) + { + CRO_Symbol* symbol = cro_header->get_index_export(cro_data, i); + int seg_idx = symbol->seg_offset & 0xf; + int seg_offs = symbol->seg_offset >> 4; + //printf("index %x - %x %x\n", symbol->seg_offset, seg_idx, seg_offs); + + char name[256]; + snprintf(name, 256, "export_index_%u", symbol->offs_name); + symd.add_symbol(stra, name, segments[seg_idx]->get_virtual_address() + seg_offs, 0, STB_GLOBAL, STT_NOTYPE, 0, sections[seg_idx]->get_index()); + } + + for (int i = 0; i < cro_header->num_index_exports; i++) + { + CRO_Symbol* symbol = cro_header->get_index_export(cro_data, i); + int seg_idx = symbol->seg_offset & 0xf; + int seg_offs = symbol->seg_offset >> 4; + //printf("index %x - %x %x\n", symbol->seg_offset, seg_idx, seg_offs); + + char name[256]; + snprintf(name, 256, "import_index_%u", symbol->offs_name); + symd.add_symbol(stra, name, segments[seg_idx]->get_virtual_address() + seg_offs, 0, STB_GLOBAL, STT_NOTYPE, 0, sections[seg_idx]->get_index()); + } + + for (int i = 0; i < cro_header->num_symbol_imports; i++) + { + CRO_Symbol* symbol = cro_header->get_import(cro_data, i); + uint32_t patch_offs = symbol->seg_offset; + + int index = symd.add_symbol(stra, (char*)cro_data + symbol->offs_name, 0x0, 0, STB_GLOBAL, STT_NOTYPE, 0, 0); + + if (!patch_offs) continue; + + CRO_Relocation* reloc = (CRO_Relocation*)((char*)cro_data + patch_offs); + while(1) + { + int rel_seg_idx = reloc->seg_offset & 0xf; + int rel_seg_offs = reloc->seg_offset >> 4; + + //printf("rel %x %x %x %x\n", reloc->seg_offset, reloc->type, reloc->addend, reloc->last_entry); + + if (last_rela != rel_seg_idx) + { + if (rel_accessor != nullptr) + delete rel_accessor; + rel_accessor = new relocation_section_accessor(elf, add_relocation_section(elf, sections, dynsym_sec, rel_seg_idx)); + } + rel_accessor->add_entry(segments[rel_seg_idx]->get_virtual_address() + rel_seg_offs, index, reloc->type, reloc->addend); + last_rela = rel_seg_idx; + + if (reloc->last_entry) break; + reloc++; + } + } + + int module_count = 0; + int remaining_in_module = cro_header->get_module_entry(cro_data, module_count)->import_indexed_symbol_num; + for (int i = 0; i < cro_header->num_index_imports; i++) + { + CRO_ModuleEntry* module = cro_header->get_module_entry(cro_data, module_count); + + CRO_Symbol* symbol = cro_header->get_index_import(cro_data, i); + uint32_t patch_offs = symbol->seg_offset; + + char name[256]; + snprintf(name, 256, "import_index_%s_%u", module->get_name(cro_data), symbol->offs_name); + int index = symd.add_symbol(stra, name, 0x0, 0, STB_GLOBAL, STT_NOTYPE, 0, 0); + + if (patch_offs) { + CRO_Relocation* reloc = (CRO_Relocation*)((char*)cro_data + patch_offs); + while(1) + { + int rel_seg_idx = reloc->seg_offset & 0xf; + int rel_seg_offs = reloc->seg_offset >> 4; + + //printf("rel index %x %x %x %x\n", reloc->seg_offset, reloc->type, reloc->addend, reloc->last_entry); + + if (last_rela != rel_seg_idx) + { + if (rel_accessor != nullptr) + delete rel_accessor; + rel_accessor = new relocation_section_accessor(elf, add_relocation_section(elf, sections, dynsym_sec, rel_seg_idx)); + } + rel_accessor->add_entry(segments[rel_seg_idx]->get_virtual_address() + rel_seg_offs, index, reloc->type, reloc->addend); + last_rela = rel_seg_idx; + + if (reloc->last_entry) break; + reloc++; + } + } + + remaining_in_module -= 1; + if (remaining_in_module <= 0) { + module_count++; + remaining_in_module = cro_header->get_module_entry(cro_data, module_count)->import_indexed_symbol_num; + } + } + + module_count = 0; + remaining_in_module = cro_header->get_module_entry(cro_data, module_count)->import_anonymous_symbol_num; + for (int i = 0; i < cro_header->num_offset_imports; i++) + { + CRO_ModuleEntry* module = cro_header->get_module_entry(cro_data, module_count); + + CRO_Symbol* symbol = cro_header->get_offset_import(cro_data, i); + uint32_t patch_offs = symbol->seg_offset; + int seg_idx = symbol->offs_name & 0xf; + int seg_offs = symbol->offs_name >> 4; + + char name[256]; + snprintf(name, 256, "offset_import_%s_%x_%x", module->get_name(cro_data), seg_idx, seg_offs); + int index = symd.add_symbol(stra, name, 0x0, 0, STB_GLOBAL, STT_NOTYPE, 0, 0); + + if (patch_offs) { + CRO_Relocation* reloc = (CRO_Relocation*)((char*)cro_data + patch_offs); + while(1) + { + int rel_seg_idx = reloc->seg_offset & 0xf; + int rel_seg_offs = reloc->seg_offset >> 4; + + //printf("rel offset %x %x %x %x\n", reloc->seg_offset, reloc->type, reloc->addend, reloc->last_entry); + + if (last_rela != rel_seg_idx) + { + if (rel_accessor != nullptr) + delete rel_accessor; + rel_accessor = new relocation_section_accessor(elf, add_relocation_section(elf, sections, dynsym_sec, rel_seg_idx)); + } + rel_accessor->add_entry(segments[rel_seg_idx]->get_virtual_address() + rel_seg_offs, index, reloc->type, reloc->addend); + last_rela = rel_seg_idx; + + if (reloc->last_entry) break; + reloc++; + } + } + + remaining_in_module -= 1; + if (remaining_in_module <= 0) { + module_count++; + remaining_in_module = cro_header->get_module_entry(cro_data, module_count)->import_anonymous_symbol_num; + } + } + + for (int i = 0; i < cro_header->num_static_relocations; i++) + { + CRO_Relocation* reloc = cro_header->get_static_reloc(cro_data, i); + int rel_seg_idx = reloc->seg_offset & 0xf; + int rel_seg_offs = reloc->seg_offset >> 4; + int ref_seg_idx = reloc->last_entry; + + //printf("rel static %x %x %x %x\n", reloc->seg_offset, reloc->type, reloc->addend, reloc->last_entry); + + if (last_rela != rel_seg_idx) + { + if (rel_accessor != nullptr) + delete rel_accessor; + rel_accessor = new relocation_section_accessor(elf, add_relocation_section(elf, sections, dynsym_sec, rel_seg_idx)); + } + rel_accessor->add_entry(segments[rel_seg_idx]->get_virtual_address() + rel_seg_offs, ref_seg_idx+1, reloc->type, segments[ref_seg_idx]->get_virtual_address() + reloc->addend); + last_rela = rel_seg_idx; + } + + // Gather offsets that CROs are interested in + std::unordered_map already_added_map; + if (argc > 3) + { + std::ifstream file(argv[3]); + if (file.is_open()) { + std::string line; + while (std::getline(file, line)) { + FILE* cro_file_2 = fopen(line.c_str(), "rb"); + if (!cro_file_2) + { + printf("Failed to open file %s! Exiting...\n", line.c_str()); + return -1; + } + + fseek(cro_file_2, 0, SEEK_END); + uint32_t cro_size_2 = ftell(cro_file_2); + void* cro_data_2 = malloc(cro_size_2); + + fseek(cro_file_2, 0, SEEK_SET); + fread(cro_data_2, sizeof(uint8_t), cro_size_2, cro_file_2); + fclose(cro_file_2); + + CRO_Header* cro_header_2 = (CRO_Header*)cro_data_2; + printf("Loading info from CRO %s\n", cro_header_2->get_name(cro_data_2)); + + if (!strcmp(cro_header->get_name(cro_data), cro_header_2->get_name(cro_data))) { + free(cro_data_2); + continue; + } + + module_count = 0; + remaining_in_module = cro_header_2->get_module_entry(cro_data_2, module_count)->import_anonymous_symbol_num; + for (int i = 0; i < cro_header_2->num_offset_imports; i++) + { + CRO_ModuleEntry* module = cro_header_2->get_module_entry(cro_data_2, module_count); + + CRO_Symbol* symbol = cro_header_2->get_offset_import(cro_data_2, i); + uint32_t patch_offs = symbol->seg_offset; + int seg_idx = symbol->offs_name & 0xf; + int seg_offs = symbol->offs_name >> 4; + + uint32_t static_addr = segments[seg_idx]->get_virtual_address() + seg_offs; + if (!strcmp(module->get_name(cro_data_2), cro_header->get_name(cro_data)) && already_added_map.find(static_addr) == already_added_map.end()) { + char name[256]; + snprintf(name, 256, "offset_import_%s_%x_%x", module->get_name(cro_data_2), seg_idx, seg_offs); + int index = symd.add_symbol(stra, name, static_addr, 0, STB_GLOBAL, STT_NOTYPE, 0, sections[seg_idx]->get_index()); + + already_added_map[static_addr] = 1; + printf("%s\n", name); + } + + remaining_in_module -= 1; + if (remaining_in_module <= 0) { + module_count++; + remaining_in_module = cro_header_2->get_module_entry(cro_data_2, module_count)->import_anonymous_symbol_num; + } + } + + free(cro_data_2); + } + file.close(); + } + } + + elf.save(argv[2]); + + return 0; +} diff --git a/tests/crotools/elf2cro/Makefile b/tests/crotools/elf2cro/Makefile new file mode 100644 index 0000000..9c02d6b --- /dev/null +++ b/tests/crotools/elf2cro/Makefile @@ -0,0 +1,32 @@ +# Sources +SRC_DIR = . +OBJS = $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c))) $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) + +# Compiler Settings +OUTPUT = elf2cro +CXXFLAGS = -std=c++11 -g -I. -I.. +CFLAGS = -g -O2 -flto -Wall -Wno-unused-variable -Wno-unused-result -Wno-unused-local-typedefs -I. -std=c11 +CC = gcc +CXX = g++ +ifeq ($(OS),Windows_NT) + #Windows Build CFG + CFLAGS += -Wno-unused-but-set-variable + LIBS += -static-libgcc -static-libstdc++ +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + # OS X + CFLAGS += + LIBS += -liconv + else + # Linux + CFLAGS += -Wno-unused-but-set-variable + LIBS += + endif +endif + +main: $(OBJS) + $(CXX) -o $(OUTPUT) $(LIBS) $(OBJS) + +clean: + rm -rf $(OUTPUT) $(OUTPUT).exe $(OBJS) diff --git a/tests/crotools/elf2cro/bit_trie.h b/tests/crotools/elf2cro/bit_trie.h new file mode 100644 index 0000000..5244060 --- /dev/null +++ b/tests/crotools/elf2cro/bit_trie.h @@ -0,0 +1,156 @@ +// From https://gist.github.com/wwylele/0bc1ca527fa54ecfb4c5bf2e78a6c2a5 + +#ifndef BIT_TRIE_H +#define BIT_TRIE_H + +#include +#include +#include +#include +#include +#include +#include + +/* +bit_trie + bit_tries are associative containers that store elements formed + by the combination of a key value and a mapped value, and which + allows for fast retrieval of individual elements based on their keys. + Key + Type of the key values. Each element in an bit_tire is uniquely + identified by its key value. + Value + Type of the mapped values. + BitTester + A binary function object type that takes an object of type Key + and a size_t integer (bit address) as arguments and returns a bool. + The bit address is an integer less than bit length. The function + should return a consistent result for the same key and the same + bit address. The results for two differents key should be different + for at least one bit address. +*/ +template < + typename Key, + typename Value, + typename BitTester +> +class bit_trie { + struct Branch{ + int offset; + bool end; + }; + struct Node { + std::size_t bit_address; + Branch left; + Branch right; + Key key; // this can be removed if use only at_no_verify to retrieve elements + Value value; + }; + + BitTester tester; + Node& at_node(const Key& key) { + size_t cur_pos = 0; + Branch next = nodes[0].left; + while (true) { + cur_pos += next.offset; + if (next.end) + return nodes[cur_pos]; + if (tester(key, nodes[cur_pos].bit_address)) { + next = nodes[cur_pos].right; + } else { + next = nodes[cur_pos].left; + } + } + } + void build(typename std::vector::iterator begin, typename std::vector::iterator end, std::size_t bit_length) { + // counting number of elements and numbers passing each bit test + std::vector pass_count(bit_length); + std::size_t count = 0; + std::for_each(begin, end, [&](const Node& node){ + for (std::size_t bit = 0; bit < bit_length; ++bit) { + if (tester(node.key, bit)) + ++pass_count[bit]; + } + ++count; + }); + if (count == 1) + return; + + // find the best address that partition the elements evenly + long badness = LONG_MAX; + std::size_t best_address; + for (std::size_t address = 0; address < bit_length; ++ address) { + long current = std::abs((long)(pass_count[address] - count / 2)); + if (current < badness) { + badness = current; + best_address = address; + } + } + + // partition + auto partition_pos = std::partition(begin, end, [&](const Node& node){ + return !tester(node.key, best_address); + }); + auto partition_distance = std::distance(begin, partition_pos); + if (partition_distance == count || partition_distance == 0) + throw std::invalid_argument("Duplicated keys."); + + // build trie for each partition + build(begin, partition_pos, bit_length); + build(partition_pos, end, bit_length); + + // let right guiding node be the first level node + partition_pos->right = partition_pos->left; + partition_pos->left = begin->left; + partition_pos->left.offset -= partition_distance; + partition_pos->bit_address = best_address; + // and left guiding node be the main guiding node + begin->left.offset = partition_distance; + begin->left.end = false; + } +public: + std::vector nodes; + template + bit_trie( + InputInterator begin, + InputInterator end, + std::size_t bit_length, + const BitTester& tester_ = BitTester() + ) : nodes(std::distance(begin, end)), tester(tester_) { + constexpr std::size_t invalid_bit_address = static_cast(-1); + std::transform(begin, end, nodes.begin(), [](std::pair pair){ + return Node { + invalid_bit_address, + {0, true}, + {0, true}, + pair.first, + pair.second + }; + }); + if (nodes.empty()) + throw std::length_error("Empty range."); + + build(nodes.begin(), nodes.end(), bit_length); + } + + Value& at(const Key& key) { + Node& node = at_node(key); + if (node.key == key) + return node.value; + throw std::out_of_range("Element not found."); + } + + Value& at_no_verify(const Key& key) { + return at_node(key).value; + } + +}; + +bool string_tester(const std::string& key, std::size_t position) { + std::size_t byte = position >> 3; + if (byte >= key.size()) + return false; + return (key[byte] >> (position & 7)) & 1; +} + +#endif diff --git a/tests/crotools/elf2cro/elf2cro.cpp b/tests/crotools/elf2cro/elf2cro.cpp new file mode 100644 index 0000000..b7c741b --- /dev/null +++ b/tests/crotools/elf2cro/elf2cro.cpp @@ -0,0 +1,492 @@ +#include +#include + +#include "elfio/elfio.hpp" +#include "elfio/elfio_dump.hpp" +#include "cro.h" +#include "bit_trie.h" + +#include + +using namespace ELFIO; + +typedef struct +{ + void* cro_data; + size_t cro_size; + CRO_Header* cro_header; +} CRO_Context; + +typedef struct +{ + std::string name; + Elf64_Addr addr; + Elf_Xword size; + uint8_t bind, type, other; + Elf_Half section_index; +} ELF_Symbol; + +void push_data(CRO_Context& context, const void* data, size_t size) +{ + context.cro_data = realloc(context.cro_data, context.cro_size + size); + if (data != NULL) + memcpy((char*)context.cro_data + context.cro_size, data, size); + else + memset((char*)context.cro_data + context.cro_size, 0, size); + context.cro_size += size; + context.cro_header = (CRO_Header*)context.cro_data; +} + +void push_segment(CRO_Context& context, segment* seg) +{ + push_data(context, seg->get_data(), seg->get_file_size()); +} + +void cro_align_up(CRO_Context& context, size_t align, uint8_t fill = 0) +{ + size_t old_size = context.cro_size; + context.cro_size = (context.cro_size + (align - context.cro_size % align) % align); + context.cro_data = realloc(context.cro_data, context.cro_size); + context.cro_header = (CRO_Header*)context.cro_data; + memset((char*)context.cro_data + old_size, fill, context.cro_size - old_size); +} + +uint32_t cro_addr_to_segment(elfio& elf, Elf64_Addr addr) +{ + int seg_idx = -1; + for (int i = 0; i < elf.segments.size(); i++) + { + if (addr >= elf.segments[i]->get_virtual_address() && addr < (elf.segments[i]->get_virtual_address() + elf.segments[i]->get_memory_size())) + { + seg_idx = i; + break; + } + } + + return seg_idx; +} + +uint32_t cro_addr_to_segment_addr(elfio& elf, Elf64_Addr addr) +{ + int seg_idx = cro_addr_to_segment(elf, addr); + + if (seg_idx == -1) return -1; + + return ((addr - elf.segments[seg_idx]->get_virtual_address()) << 4) | (seg_idx & 7); +} + +void ELF_get_symbol(symbol_section_accessor& syma, int index, ELF_Symbol& symbol_out) +{ + syma.get_symbol(index, symbol_out.name, symbol_out.addr, symbol_out.size, symbol_out.bind, symbol_out.type, symbol_out.section_index, symbol_out.other); +} + +int main(int argc, char **argv) +{ + if (argc < 3) + { + printf("Usage: %s \n", argv[0]); + return -1; + } + + elfio elf; + + if (!elf.load(argv[1])) + { + printf("Failed to load file %s! Exiting...\n", argv[1]); + return -1; + } + + CRO_Context cro_ctx; + cro_ctx.cro_data = calloc(1, sizeof(CRO_Header)); + cro_ctx.cro_size = sizeof(CRO_Header); + cro_ctx.cro_header = (CRO_Header*)cro_ctx.cro_data; + + + size_t segment_start[5]; + size_t segment_size[5]; + + cro_align_up(cro_ctx, 0x80); + size_t cro_header_size = cro_ctx.cro_size; + + cro_ctx.cro_header->magic = MAGIC_CRO0; + + // Push .text segment + segment_start[SEG_TEXT] = cro_ctx.cro_size; + push_segment(cro_ctx, elf.segments[SEG_TEXT]); + + // Push .rodata segment + cro_align_up(cro_ctx, 0x1000); + segment_start[SEG_RODATA] = cro_ctx.cro_size; + segment_size[SEG_TEXT] = cro_ctx.cro_size - segment_start[SEG_TEXT]; + push_segment(cro_ctx, elf.segments[SEG_RODATA]); + segment_size[SEG_RODATA] = cro_ctx.cro_size - segment_start[SEG_RODATA]; + cro_align_up(cro_ctx, 0x1000); + size_t text_total_size = cro_ctx.cro_size - segment_start[SEG_TEXT]; + + // Set .bss size + segment_start[SEG_BSS] = 0; + segment_size[SEG_BSS] = elf.segments[SEG_BSS]->get_memory_size(); + + // + // Begin linking info + // + + // Push CRO module name + std::string cro_filename = std::string(argv[2]); + std::string cro_name = cro_filename.substr(0, cro_filename.find_last_of(".")); + + cro_ctx.cro_header->offs_mod_name = cro_ctx.cro_size; + cro_ctx.cro_header->offs_name = cro_ctx.cro_size; + cro_ctx.cro_header->size_name = cro_name.size() + 1; + + push_data(cro_ctx, cro_name.c_str(), cro_name.size() + 1); + + + // Push segments + cro_align_up(cro_ctx, 0x4); + cro_ctx.cro_header->offs_segments = cro_ctx.cro_size; + cro_ctx.cro_header->num_segments = 5; //TODO? + push_data(cro_ctx, NULL, sizeof(CRO_Segment) * cro_ctx.cro_header->num_segments); + + // Push exported symbols + symbol_section_accessor syma(elf, elf.sections[".dynsym"]); + + size_t count_exports = 0; + size_t count_imports = 0; + size_t export_strtab_size = 0; + size_t import_strtab_size = 0; + for (int i = 0; i < syma.get_symbols_num(); i++) + { + ELF_Symbol symbol; + ELF_get_symbol(syma, i, symbol); + + if (symbol.name == "") continue; + + if (symbol.section_index != 0) + { + count_exports++; + export_strtab_size += symbol.name.length() + 1; + } + else + { + count_imports++; + import_strtab_size += symbol.name.length() + 1; + } + } + + // Push symbol exports + cro_ctx.cro_header->offs_symbol_exports = cro_ctx.cro_size; + cro_ctx.cro_header->num_symbol_exports = count_exports; + push_data(cro_ctx, NULL, sizeof(CRO_Symbol) * count_exports); + + // Push export tree + cro_ctx.cro_header->offs_export_tree = cro_ctx.cro_size; + cro_ctx.cro_header->num_export_tree = count_exports; + push_data(cro_ctx, NULL, sizeof(CRO_ExportTreeEntry) * count_exports); + + // Push index exports (TODO) + cro_ctx.cro_header->offs_index_exports = cro_ctx.cro_size; + cro_ctx.cro_header->num_index_exports = 0; + + // Push export strtab + size_t export_strtab_offset = cro_ctx.cro_size; + push_data(cro_ctx, NULL, export_strtab_size); + + // Stub Control, OnLoad, OnUnload, Unresolved funcs + cro_ctx.cro_header->offs_control = 0xffffffff; + cro_ctx.cro_header->offs_prologue = 0xffffffff; + cro_ctx.cro_header->offs_epilogue = 0xffffffff; + cro_ctx.cro_header->offs_unresolved = 0xffffffff; + + cro_ctx.cro_header->offs_export_strtab = export_strtab_offset; + cro_ctx.cro_header->size_export_strtab = export_strtab_size; + cro_align_up(cro_ctx, 0x4); + + // Push import data + + // Count up allocations + + size_t import_relocs_count = 0; + size_t export_relocs_count = 0; + + // Count relocs + + for (int k = 0; k < elf.sections.size(); k++) + { + section* sec = elf.sections[k]; + if (sec->get_type() != SHT_RELA && sec->get_type() != SHT_REL) continue; + + relocation_section_accessor rela(elf, sec); + for (int i = 0; i < rela.get_entries_num(); i++) + { + Elf64_Addr offset; + Elf_Word symbol_idx; + Elf_Word relType; + Elf_Sxword addend; + + rela.get_entry(i, offset, symbol_idx, relType, addend); + + ELF_Symbol symbol; + ELF_get_symbol(syma, symbol_idx, symbol); + + if (symbol.section_index == 0 && symbol.name != "") + import_relocs_count++; + else + export_relocs_count++; + } + } + + // Import modules (TODO) + cro_ctx.cro_header->offs_import_module = cro_ctx.cro_size; + + // Import patches + cro_ctx.cro_header->offs_import_patches = cro_ctx.cro_size; + cro_ctx.cro_header->num_import_patches = import_relocs_count; + push_data(cro_ctx, NULL, sizeof(CRO_Relocation) * import_relocs_count); + + // Import symbols + cro_ctx.cro_header->offs_symbol_imports = cro_ctx.cro_size; + cro_ctx.cro_header->num_symbol_imports = count_imports; + push_data(cro_ctx, NULL, sizeof(CRO_Symbol) * count_imports); + + // Import indexes (TODO) + cro_ctx.cro_header->offs_index_imports = cro_ctx.cro_size; + + // Import offset imports (TODO) + cro_ctx.cro_header->offs_offset_imports = cro_ctx.cro_size; + + // Import strtab + cro_ctx.cro_header->offs_import_strtab = cro_ctx.cro_size; + cro_ctx.cro_header->size_import_strtab = import_strtab_size; + push_data(cro_ctx, NULL, import_strtab_size); + cro_align_up(cro_ctx, 0x4); + + // Export offsets (TODO) + cro_ctx.cro_header->offs_offset_exports = cro_ctx.cro_size; + + // Export unk (TODO?) + cro_ctx.cro_header->offs_unk = cro_ctx.cro_size; + + // Static relocations + cro_ctx.cro_header->offs_static_relocations = cro_ctx.cro_size; + cro_ctx.cro_header->num_static_relocations = export_relocs_count; + push_data(cro_ctx, NULL, sizeof(CRO_Relocation) * export_relocs_count); + + // Push data + segment_start[SEG_DATA] = cro_ctx.cro_size; + push_segment(cro_ctx, elf.segments[SEG_DATA]); + cro_ctx.cro_header->size_data = cro_ctx.cro_size - segment_start[SEG_DATA]; + cro_align_up(cro_ctx, 0x1000, 0xCC); + segment_size[SEG_DATA] = cro_ctx.cro_size - segment_start[SEG_DATA]; + + // Write import/export patches + size_t import_reloc_count = 0; + size_t static_reloc_count = 0; + CRO_Relocation* import_relocs = (CRO_Relocation*)((char*)cro_ctx.cro_data + cro_ctx.cro_header->offs_import_patches); + CRO_Relocation* static_relocs = (CRO_Relocation*)((char*)cro_ctx.cro_data + cro_ctx.cro_header->offs_static_relocations); + std::map symbol_to_patches; + + Elf_Word last_import_symbol_idx; + for (int k = 0; k < elf.sections.size(); k++) + { + section* sec = elf.sections[k]; + if (sec->get_type() != SHT_RELA && sec->get_type() != SHT_REL) continue; + + relocation_section_accessor rela(elf, sec); + for (int i = 0; i < rela.get_entries_num(); i++) + { + Elf64_Addr offset; + Elf_Word symbol_idx; + Elf_Word relType; + Elf_Sxword addend; + + rela.get_entry(i, offset, symbol_idx, relType, addend); + + ELF_Symbol symbol; + ELF_get_symbol(syma, symbol_idx, symbol); + + if (symbol.section_index == 0 && symbol.name != "") + { + import_relocs[import_reloc_count].seg_offset = cro_addr_to_segment_addr(elf, offset); + import_relocs[import_reloc_count].type = relType; + import_relocs[import_reloc_count].last_entry = 1; + + if (symbol_to_patches[symbol_idx] == 0) + symbol_to_patches[symbol_idx] = import_reloc_count; + + if (last_import_symbol_idx == symbol_idx) + import_relocs[import_reloc_count-1].last_entry = 0; + + import_relocs[import_reloc_count++].addend = addend; + + last_import_symbol_idx = symbol_idx; + } + else + { + int sym_seg = cro_addr_to_segment(elf, symbol.addr); + int sym_add = 0; + if (sym_seg == -1) + sym_seg = 0; + else + sym_add = symbol.addr - elf.segments[sym_seg]->get_virtual_address(); + //printf("%x %x %x\n", sym_seg, sym_add, symbol.addr); + + if (relType == 0x15) + relType = 2; + + if (relType == 0x17) + { + int offs_seg = cro_addr_to_segment(elf, offset); + int offs_addr = elf.segments[offs_seg]->get_virtual_address(); + int offs_add = offset - offs_addr; + void* seg_data = cro_ctx.cro_header->get_segment_data(cro_ctx.cro_data, offs_seg); + + uint32_t val_to_change = *(uint32_t*)((char*)cro_ctx.cro_data + offs_addr + offs_add); + *(uint32_t*)((char*)cro_ctx.cro_data + elf.segments[offs_seg]->get_virtual_address() + offs_add) = 0; + + // Adjust the existing value and find the segment + offs_seg = cro_addr_to_segment(elf, val_to_change); + offs_addr = elf.segments[offs_seg]->get_virtual_address(); + + val_to_change -= offs_addr; + addend += val_to_change; + sym_add = val_to_change; + sym_seg = offs_seg; + + //printf("%x (seg %x) %x+%x %x\n", offset, offs_seg, offs_addr, offs_add, val_to_change); + + relType = 2; + } + + static_relocs[static_reloc_count].seg_offset = cro_addr_to_segment_addr(elf, offset); + static_relocs[static_reloc_count].type = relType; + static_relocs[static_reloc_count].last_entry = sym_seg; + if (sec->get_type() == SHT_RELA) + static_relocs[static_reloc_count].addend = addend - symbol.addr; + else + static_relocs[static_reloc_count].addend = sym_add; + + static_reloc_count++; + } + } + } + + // Write symbol exports + index exports + tree + size_t export_name_offset = cro_ctx.cro_header->offs_export_strtab; + size_t import_name_offset = cro_ctx.cro_header->offs_import_strtab; + size_t export_name_count = 0; + size_t import_name_count = 0; + CRO_Symbol* exportSymbols = (CRO_Symbol*)((char*)cro_ctx.cro_data + cro_ctx.cro_header->offs_symbol_exports); + CRO_Symbol* importSymbols = (CRO_Symbol*)((char*)cro_ctx.cro_data + cro_ctx.cro_header->offs_symbol_imports); + CRO_ExportTreeEntry* exportTree = (CRO_ExportTreeEntry*)((char*)cro_ctx.cro_data + cro_ctx.cro_header->offs_export_tree); + for (int i = 0; i < syma.get_symbols_num(); i++) + { + ELF_Symbol symbol; + ELF_get_symbol(syma, i, symbol); + + if (symbol.section_index != 0 && symbol.name != "") + { + //printf("%s %x\n", symbol.name.c_str(), symbol.section_index); + exportSymbols[export_name_count].offs_name = export_name_offset; + exportSymbols[export_name_count++].seg_offset = cro_addr_to_segment_addr(elf, symbol.addr); + + if (symbol.name == "nnroControlObject_") + { + cro_ctx.cro_header->offs_control = cro_addr_to_segment_addr(elf, symbol.addr); + } + //TODO: export tree + //TODO: control offset + //TODO: OnLoad + //TODO: OnExit + //TODO: OnUnresolved + + memcpy((char*)cro_ctx.cro_data + export_name_offset, symbol.name.c_str(), symbol.name.length()+1); + export_name_offset += symbol.name.length()+1; + } + else if (symbol.section_index == 0 && symbol.name != "") + { + //printf("%s %x\n", symbol.name.c_str(), symbol.section_index); + importSymbols[import_name_count].offs_name = import_name_offset; + importSymbols[import_name_count++].seg_offset = cro_ctx.cro_header->offs_import_patches + symbol_to_patches[i] * sizeof(CRO_Relocation); + + memcpy((char*)cro_ctx.cro_data + import_name_offset, symbol.name.c_str(), symbol.name.length()+1); + import_name_offset += symbol.name.length()+1; + } + } + + // Export Tree + std::vector > exportsAndIndexes; + for (int i = 0; i < export_name_count; i++) + { + char* expName = (char*)cro_ctx.cro_data + cro_ctx.cro_header->get_export(cro_ctx.cro_data, i)->offs_name; + std::string expNameStr(expName); + exportsAndIndexes.push_back(std::pair(expNameStr, i)); + } + + std::size_t max_bit_length = 0; + for (const auto& pair : exportsAndIndexes) + { + if (pair.first.size() > max_bit_length) + max_bit_length = pair.first.size(); + } + max_bit_length *= 8; + + bit_trie example(exportsAndIndexes.begin(), exportsAndIndexes.end(), max_bit_length, &string_tester); + + int treeCount = 0; + for (auto& node : example.nodes) + { + CRO_ExportTreeEntry* entry = cro_ctx.cro_header->get_export_tree_entry(cro_ctx.cro_data, treeCount); + + entry->test_bit = static_cast(node.bit_address) % 8; + entry->test_byte = static_cast(node.bit_address) / 8; + entry->left.next_index = node.left.offset + treeCount; + entry->left.is_end = node.left.end; + entry->right.next_index = node.right.offset + treeCount++; + entry->right.is_end = node.right.end; + entry->export_index = node.value; + + if (treeCount == 1) + entry->right.is_end = false; + + //printf("bit %x of byte %04x, %04x %04x \t\t(%s)\n", entry->test_bit, entry->test_byte, entry->left.raw, entry->right.raw, (char*)cro_ctx.cro_data + cro_ctx.cro_header->get_export(cro_ctx.cro_data, entry->export_index)->offs_name); + } + + // Finalize + cro_ctx.cro_header->offs_text = segment_start[SEG_TEXT]; + cro_ctx.cro_header->size_text = text_total_size; + cro_ctx.cro_header->offs_data = segment_start[SEG_DATA]; + + if (elf.sections[".bss"] != nullptr) + cro_ctx.cro_header->size_bss = elf.sections[".bss"]->get_size(); + + CRO_Segment* cro_segments = (CRO_Segment*)((char*)cro_ctx.cro_data + cro_ctx.cro_header->offs_segments); + for (int i = 0; i < cro_ctx.cro_header->num_segments; i++) + { + CRO_Segment* segment = &cro_segments[i]; + segment->offset = segment_start[i]; + segment->size = elf.segments[i]->get_memory_size(); + segment->type = i; + + // CRO header segment(?) + if (i == 4) + { + segment->offset = 0; + segment->size = 0/*cro_header_size*/; + segment->type = SEG_TEXT; + } + } + + cro_ctx.cro_header->size_file = cro_ctx.cro_size; + + FILE* cro_file = fopen(argv[2], "wb"); + if (!cro_file) + { + printf("Failed to open file %s for writing! Exiting...\n", argv[2]); + return -1; + } + + printf("Writing 0x%zx bytes\n", cro_ctx.cro_size); + fwrite(cro_ctx.cro_data, sizeof(uint8_t), cro_ctx.cro_size, cro_file); + fclose(cro_file); +} diff --git a/tests/crotools/elfinject/Makefile b/tests/crotools/elfinject/Makefile new file mode 100644 index 0000000..c00fa9b --- /dev/null +++ b/tests/crotools/elfinject/Makefile @@ -0,0 +1,32 @@ +# Sources +SRC_DIR = . +OBJS = $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c))) $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) + +# Compiler Settings +OUTPUT = elfinject +CXXFLAGS = -std=c++11 -g -I. -I.. +CFLAGS = -g -O2 -flto -Wall -Wno-unused-variable -Wno-unused-result -Wno-unused-local-typedefs -I. -std=c11 +CC = gcc +CXX = g++ +ifeq ($(OS),Windows_NT) + #Windows Build CFG + CFLAGS += -Wno-unused-but-set-variable + LIBS += -static-libgcc -static-libstdc++ +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + # OS X + CFLAGS += + LIBS += -liconv + else + # Linux + CFLAGS += -Wno-unused-but-set-variable + LIBS += + endif +endif + +main: $(OBJS) + $(CXX) -o $(OUTPUT) $(LIBS) $(OBJS) + +clean: + rm -rf $(OUTPUT) $(OUTPUT).exe $(OBJS) diff --git a/tests/crotools/elfinject/elfinject.cpp b/tests/crotools/elfinject/elfinject.cpp new file mode 100644 index 0000000..70e5d7f --- /dev/null +++ b/tests/crotools/elfinject/elfinject.cpp @@ -0,0 +1,394 @@ +#include +#include + +#include "elfio/elfio.hpp" +#include "elfio/elfio_dump.hpp" + +#include + +using namespace ELFIO; + +typedef struct +{ + std::string name; + Elf64_Addr addr; + Elf_Xword size; + uint8_t bind, type, other; + Elf_Half section_index; +} ELF_Symbol; + +bool ELF_get_symbol(symbol_section_accessor& syma, int index, ELF_Symbol& symbol_out) +{ + return syma.get_symbol(index, symbol_out.name, symbol_out.addr, symbol_out.size, symbol_out.bind, symbol_out.type, symbol_out.section_index, symbol_out.other); +} + +bool ELF_get_symbol_by_name(symbol_section_accessor& syma, std::string name, ELF_Symbol& symbol_out) +{ + symbol_out.name = name; + return syma.get_symbol(name, symbol_out.addr, symbol_out.size, symbol_out.bind, symbol_out.type, symbol_out.section_index, symbol_out.other); +} + +int ELF_get_symbol_index_by_name(symbol_section_accessor& syma, std::string name) +{ + for (int i = 0; i < syma.get_symbols_num(); i++) + { + ELF_Symbol symbol; + ELF_get_symbol(syma, i, symbol); + + if (symbol.name == name) + return i; + } + + return -1; +} + +size_t align_up(size_t val, size_t align) +{ + return (val + (align - val % align) % align); +} + +uint32_t addr_to_segment(elfio& elf, Elf64_Addr addr) +{ + int seg_idx = -1; + for (int i = 0; i < elf.segments.size(); i++) + { + if (addr >= elf.segments[i]->get_virtual_address() && addr < (elf.segments[i]->get_virtual_address() + elf.segments[i]->get_memory_size())) + { + seg_idx = i; + break; + } + } + + return seg_idx; +} + +int counts[3] = {0}; +section* add_relocation_section(elfio& elf, int segment_index) +{ + char* secs[3] = {".text", ".rodata", ".data"}; + char rela_name[32]; + snprintf(rela_name, 32, ".rela%s.%u", secs[segment_index], counts[segment_index]++); + + printf("Added %s\n", rela_name); + + section* rel_sec = elf.sections.add(rela_name); + rel_sec->set_type(SHT_RELA); + rel_sec->set_entry_size(elf.get_default_entry_size(SHT_RELA)); + rel_sec->set_flags(SHF_ALLOC | SHF_INFO_LINK); + rel_sec->set_info(elf.sections[segment_index+2]->get_index()); + rel_sec->set_overlay(elf.sections[segment_index+2]->get_index()); + rel_sec->set_link(elf.sections[".dynsym"]->get_index()); + rel_sec->set_addr_align(4); + return rel_sec; +} + +int main(int argc, char **argv) +{ + if (argc < 3) + { + printf("Usage: %s \n", argv[0]); + return -1; + } + + elfio elf_input; + elfio elf_inject; + elfio elf_out; + + if (!elf_input.load(argv[1]) | !elf_out.load(argv[1])) + { + printf("Failed to load file %s! Exiting...\n", argv[1]); + return -1; + } + + if (!elf_inject.load(argv[2])) + { + printf("Failed to load file %s! Exiting...\n", argv[1]); + return -1; + } + + uint32_t next_addr = 0x180; + uint32_t inject_offsets[5]; + uint32_t new_offsets[5]; + size_t added_size = 0; + for (int i = 0; i < elf_inject.segments.size(); i++) + { + if (i >= elf_out.segments.size()) break; + + inject_offsets[i] = align_up(elf_out.segments[i]->get_memory_size(), 0x4); + + if (i == 3) + inject_offsets[i] = align_up(elf_out.sections[i+2]->get_size(), 0x4); + + char *new_data = (char*)calloc(inject_offsets[i] + elf_inject.segments[i]->get_memory_size(), 1); + + // Copy existing data + if (elf_input.segments[i]->get_file_size()) + memcpy(new_data, elf_input.segments[i]->get_data(), elf_input.segments[i]->get_file_size()); + + // Concatenate new data + if (elf_inject.segments[i]->get_file_size()) + memcpy(new_data + inject_offsets[i], elf_inject.segments[i]->get_data(), elf_inject.segments[i]->get_file_size()); + + // Sections should be in order with .text at 2, then .rodata, .data, .bss, .cro_info + elf_out.sections[i+2]->set_data(new_data, inject_offsets[i] + elf_inject.segments[i]->get_memory_size()); + elf_out.segments[i]->add_section_index(elf_out.sections[i+2]->get_index(), elf_out.sections[i+2]->get_addr_align()); + + // Adjust addresses, .data will not be accurate but it doesn't matter really since that will correct with + // elf2cro anyhow. + added_size += (inject_offsets[i] + elf_inject.segments[i]->get_memory_size() - elf_input.segments[i]->get_memory_size()); + new_offsets[i] = next_addr; + elf_out.sections[i+2]->set_address(next_addr); + elf_out.segments[i]->set_physical_address(next_addr); + elf_out.segments[i]->set_virtual_address(next_addr); + elf_out.segments[i]->set_file_size(elf_out.segments[i]->get_file_size() + elf_inject.segments[i]->get_memory_size()); + elf_out.segments[i]->set_memory_size(elf_out.segments[i]->get_memory_size() + elf_inject.segments[i]->get_memory_size()); + + next_addr = align_up(next_addr + inject_offsets[i] + elf_inject.segments[i]->get_file_size(), 0x4); + } + + symbol_section_accessor syma(elf_out, elf_out.sections[".dynsym"]); + string_section_accessor stra(elf_out.sections[".dynstr"]); + symbol_section_accessor syma_in(elf_inject, elf_inject.sections[".dynsym"]); + + // Adjust original symbols + for (int i = 1; i < syma.get_symbols_num(); i++) + { + ELF_Symbol symbol; + ELF_get_symbol(syma, i, symbol); + + // Skip imports + if (!symbol.addr) continue; + + + uint32_t new_addr = symbol.addr - elf_input.segments[addr_to_segment(elf_input, symbol.addr)]->get_physical_address() + new_offsets[addr_to_segment(elf_input, symbol.addr)]; + + //printf("%s old %x new %x\n", symbol.name.c_str(), symbol.addr, new_addr); + ((Elf32_Sym*)elf_out.sections[".dynsym"]->get_data())[i].st_value = new_addr; + } + + // Adjust original relocations + for (int k = 0; k < elf_out.sections.size(); k++) + { + section* sec = elf_out.sections[k]; + if (sec->get_type() != SHT_RELA) continue; + + relocation_section_accessor rela_orig(elf_out, sec); + for (int i = 0; i < rela_orig.get_entries_num(); i++) + { + Elf64_Addr offset; + Elf_Word symbol_idx; + Elf_Word type; + Elf_Sxword addend; + + rela_orig.get_entry(i, offset, symbol_idx, type, addend); + + ELF_Symbol symbol; + ELF_get_symbol(syma, symbol_idx, symbol); + + uint32_t new_offset = offset - elf_input.segments[addr_to_segment(elf_input, offset)]->get_physical_address() + new_offsets[addr_to_segment(elf_input, offset)]; + uint32_t new_addend = addend; + if (type == 0x2 || type == 0x16) + { + if (addr_to_segment(elf_input, addend) != -1) + { + new_addend = addend - elf_input.segments[addr_to_segment(elf_input, addend)]->get_physical_address() + new_offsets[addr_to_segment(elf_input, addend)]; + //printf("Addend %x to %x\n", addend, new_addend); + } + } + else if (type == 0x17) // Relative -> absolute + { + int rel_seg_idx = addr_to_segment(elf_input, offset); + uint32_t seg_offs = new_offset - new_offsets[rel_seg_idx]; + uint32_t orig_value = *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs); + *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs) = 0; + + int32_t relative_target_seg = addr_to_segment(elf_input, orig_value); + + if (relative_target_seg == -1 && orig_value == elf_input.segments[0]->get_virtual_address() + elf_input.segments[0]->get_file_size()) + { + relative_target_seg = 0; + } + + //printf("%x %x %x\n", new_offset, relative_target_seg, orig_value); + uint32_t relative_target = orig_value - elf_input.segments[relative_target_seg]->get_virtual_address() + new_offsets[relative_target_seg]; + //printf("relative %x %x %x\n", relative_target, seg_offs, relative_target_seg); + + ((Elf32_Rela*)sec->get_data())[i].r_info = ELF32_R_INFO(relative_target_seg+1, 2); + new_addend = relative_target; + } + ((Elf32_Rela*)sec->get_data())[i].r_offset = new_offset; + ((Elf32_Rela*)sec->get_data())[i].r_addend = new_addend; + + /*if (offset != new_offset) + printf("old %x new %x\n", offset, new_offset);*/ + } + } + + // Add in new symbols, and adjust for new offsets + for (int i = 0; i < syma_in.get_symbols_num(); i++) + { + ELF_Symbol symbol; + ELF_get_symbol(syma_in, i, symbol); + + if (symbol.name == "") continue; + + if (!strcmp(symbol.name.c_str() + strlen(symbol.name.c_str()) - strlen("_orig"), "_orig")) + { + char *not_orig = (char*)calloc(strlen(symbol.name.c_str()) - strlen("_orig") + 1, 1); + memcpy(not_orig, symbol.name.c_str(), strlen(symbol.name.c_str()) - strlen("_orig")); + if (ELF_get_symbol_index_by_name(syma, std::string(not_orig)) != -1) + { + //printf("Ignore\n"); + continue; + } + + } + + + if (ELF_get_symbol_index_by_name(syma, symbol.name) != -1) + { + int orig_idx = ELF_get_symbol_index_by_name(syma, symbol.name); + ELF_Symbol symbol_orig; + ELF_Symbol symbol_new; + ELF_get_symbol(syma, orig_idx, symbol_orig); + + printf("identical name %s\n", symbol.name.c_str()); + if (symbol.addr) + { + // Rename things + printf("readjusting symbol names\n"); + + // We have two symbols of the same name defined. The injected name takes precedence, + // and the original will be renamed to _orig. + std::string renamed = symbol.name + "_orig"; + uint32_t new_addr = symbol.addr + (symbol.addr ? inject_offsets[addr_to_segment(elf_inject, symbol.addr)] : 0); + int index = syma.add_symbol(stra, renamed.c_str(), new_addr, symbol.size, symbol.bind, symbol.type, symbol.other, symbol.section_index); + ELF_get_symbol(syma, index, symbol_new); + + section *sec = elf_out.sections[".dynsym"]; + + Elf32_Addr temp_value = ((Elf32_Sym*)sec->get_data())[index].st_value; + Elf_Word temp_size = ((Elf32_Sym*)sec->get_data())[index].st_size; + unsigned char temp_info = ((Elf32_Sym*)sec->get_data())[index].st_info; + unsigned char temp_other = ((Elf32_Sym*)sec->get_data())[index].st_other; + Elf_Half temp_shndx = ((Elf32_Sym*)sec->get_data())[index].st_shndx; + + ((Elf32_Sym*)sec->get_data())[index].st_value = ((Elf32_Sym*)sec->get_data())[orig_idx].st_value; + ((Elf32_Sym*)sec->get_data())[index].st_size = ((Elf32_Sym*)sec->get_data())[orig_idx].st_size; + ((Elf32_Sym*)sec->get_data())[index].st_info = ((Elf32_Sym*)sec->get_data())[orig_idx].st_info; + ((Elf32_Sym*)sec->get_data())[index].st_other = ((Elf32_Sym*)sec->get_data())[orig_idx].st_other; + ((Elf32_Sym*)sec->get_data())[index].st_shndx = ((Elf32_Sym*)sec->get_data())[orig_idx].st_shndx; + + ((Elf32_Sym*)sec->get_data())[orig_idx].st_value = temp_value; + ((Elf32_Sym*)sec->get_data())[orig_idx].st_size = temp_size; + ((Elf32_Sym*)sec->get_data())[orig_idx].st_info = temp_info; + ((Elf32_Sym*)sec->get_data())[orig_idx].st_other = temp_other; + ((Elf32_Sym*)sec->get_data())[orig_idx].st_shndx = temp_shndx; + } + } + else + { + printf("Adding %s %i\n", symbol.name.c_str(), addr_to_segment(elf_inject, symbol.addr)); + + uint32_t new_addr = 0; + if (symbol.addr) + new_addr = symbol.addr + inject_offsets[addr_to_segment(elf_inject, symbol.addr)] - elf_inject.segments[addr_to_segment(elf_inject, symbol.addr)]->get_virtual_address() + new_offsets[addr_to_segment(elf_inject, symbol.addr)]; + + int index = syma.add_symbol(stra, symbol.name.c_str(), new_addr, symbol.size, symbol.bind, symbol.type, symbol.other, symbol.section_index); + } + } + + // Add new relocations and adjust + int last_rela = -1; + relocation_section_accessor* rel_accessor = nullptr; + for (int k = 0; k < elf_inject.sections.size(); k++) + { + section* sec = elf_inject.sections[k]; + if (sec->get_type() != SHT_RELA && sec->get_type() != SHT_REL) continue; + + //printf("%s %x\n", sec->get_name().c_str(), sec->get_info()); + + int rel_seg_idx = -1; + int last_rela = -1; + + relocation_section_accessor rela(elf_inject, sec); + for (int i = 0; i < rela.get_entries_num(); i++) + { + Elf64_Addr offset; + Elf_Word symbol_idx; + Elf_Word type; + Elf_Sxword addend; + + rela.get_entry(i, offset, symbol_idx, type, addend); + + ELF_Symbol symbol; + ELF_Symbol symbol_real; + ELF_get_symbol(syma_in, symbol_idx, symbol); + ELF_get_symbol(syma, ELF_get_symbol_index_by_name(syma, symbol.name), symbol_real); + + rel_seg_idx = addr_to_segment(elf_inject, offset); + uint32_t new_addr = offset + (offset ? inject_offsets[rel_seg_idx] : 0); + uint32_t new_sym_addr = symbol.addr + (symbol.addr ? inject_offsets[rel_seg_idx] : 0); + uint32_t new_offset = new_sym_addr - new_offsets[rel_seg_idx]; + //printf("%s %x %x->%x %i %x\n", symbol.name.c_str(), offset, offset, new_addr, rel_seg_idx, symbol_real.addr); + + if (last_rela != rel_seg_idx) + { + if (rel_accessor != nullptr) + delete rel_accessor; + rel_accessor = new relocation_section_accessor(elf_out, add_relocation_section(elf_out, rel_seg_idx)); + } + + if ((symbol_real.addr == 0) && (type == 0x2 || type == 0x16)) // Imports + { + offset = new_addr; + symbol_idx = ELF_get_symbol_index_by_name(syma, symbol.name); + + uint32_t seg_offs = new_addr - new_offsets[rel_seg_idx]; + uint32_t orig_value = *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs); + *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs) = 0; + + type = 0x2; + } + else if (type == 0x2 || type == 0x16) // ABS32 + { + offset = new_addr; + if (symbol.name == "") // Just some generic relocation + { + symbol_idx = rel_seg_idx+1; + addend += new_offset; + } + else // We're importing functions from the ELF being injected into, adjust + { + symbol_idx = addr_to_segment(elf_out, symbol_real.addr)+1; + addend += symbol_real.addr; + type = 0x2; + + uint32_t seg_offs = new_addr - new_offsets[rel_seg_idx]; + *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs) = 0; + } + } + else if (type == 0x17) // Relative -> absolute + { + uint32_t seg_offs = new_addr - new_offsets[rel_seg_idx]; + uint32_t orig_value = *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs); + *(uint32_t*)(elf_out.sections[rel_seg_idx+2]->get_data() + seg_offs) = 0; + + //new_offsets[addr_to_segment(elf_inject, orig_value)] + inject_offsets[addr_to_segment(elf_inject, orig_value)] + uint32_t relative_target_seg = addr_to_segment(elf_inject, orig_value); + uint32_t relative_target = orig_value - elf_inject.segments[relative_target_seg]->get_virtual_address() + new_offsets[addr_to_segment(elf_inject, orig_value)] + inject_offsets[relative_target_seg]; + //printf("relative %x %x %x\n", relative_target, seg_offs, addr_to_segment(elf_inject, orig_value)); + + symbol_idx = relative_target_seg+1; + offset = new_addr; + addend = relative_target; + type = 0x2; + } + + rel_accessor->add_entry(offset, symbol_idx, type, addend); + last_rela = rel_seg_idx; + } + } + + elf_out.save(argv[3]); +} diff --git a/tests/crotools/elfio/elf_types.hpp b/tests/crotools/elfio/elf_types.hpp new file mode 100644 index 0000000..d0abe69 --- /dev/null +++ b/tests/crotools/elfio/elf_types.hpp @@ -0,0 +1,838 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#ifndef ELFIO_NO_OWN_TYPES + #if !defined(ELFIO_NO_CSTDINT) && !defined(ELFIO_NO_INTTYPES) + #include + #else + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned short uint16_t; + typedef signed short int16_t; + #ifdef _MSC_VER + typedef unsigned __int32 uint32_t; + typedef signed __int32 int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; + #else + typedef unsigned int uint32_t; + typedef signed int int32_t; + typedef unsigned long long uint64_t; + typedef signed long long int64_t; + #endif // _MSC_VER + #endif // ELFIO_NO_CSTDINT +#endif // ELFIO_NO_OWN_TYPES + +namespace ELFIO { + +// Attention! Platform depended definitions. +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef int32_t Elf_Sword; +typedef uint64_t Elf_Xword; +typedef int64_t Elf_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; + +#define Elf32_Half Elf_Half +#define Elf64_Half Elf_Half +#define Elf32_Word Elf_Word +#define Elf64_Word Elf_Word +#define Elf32_Sword Elf_Sword +#define Elf64_Sword Elf_Sword + +/////////////////////// +// ELF Header Constants + +// File type +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xFE00 +#define ET_HIOS 0xFEFF +#define ET_LOPROC 0xFF00 +#define ET_HIPROC 0xFFFF + + +#define EM_NONE 0 // No machine +#define EM_M32 1 // AT&T WE 32100 +#define EM_SPARC 2 // SUN SPARC +#define EM_386 3 // Intel 80386 +#define EM_68K 4 // Motorola m68k family +#define EM_88K 5 // Motorola m88k family +#define EM_486 6 // Intel 80486// Reserved for future use +#define EM_860 7 // Intel 80860 +#define EM_MIPS 8 // MIPS R3000 (officially, big-endian only) +#define EM_S370 9 // IBM System/370 +#define EM_MIPS_RS3_LE 10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated +#define EM_res011 11 // Reserved +#define EM_res012 12 // Reserved +#define EM_res013 13 // Reserved +#define EM_res014 14 // Reserved +#define EM_PARISC 15 // HPPA +#define EM_res016 16 // Reserved +#define EM_VPP550 17 // Fujitsu VPP500 +#define EM_SPARC32PLUS 18 // Sun's "v8plus" +#define EM_960 19 // Intel 80960 +#define EM_PPC 20 // PowerPC +#define EM_PPC64 21 // 64-bit PowerPC +#define EM_S390 22 // IBM S/390 +#define EM_SPU 23 // Sony/Toshiba/IBM SPU +#define EM_res024 24 // Reserved +#define EM_res025 25 // Reserved +#define EM_res026 26 // Reserved +#define EM_res027 27 // Reserved +#define EM_res028 28 // Reserved +#define EM_res029 29 // Reserved +#define EM_res030 30 // Reserved +#define EM_res031 31 // Reserved +#define EM_res032 32 // Reserved +#define EM_res033 33 // Reserved +#define EM_res034 34 // Reserved +#define EM_res035 35 // Reserved +#define EM_V800 36 // NEC V800 series +#define EM_FR20 37 // Fujitsu FR20 +#define EM_RH32 38 // TRW RH32 +#define EM_MCORE 39 // Motorola M*Core // May also be taken by Fujitsu MMA +#define EM_RCE 39 // Old name for MCore +#define EM_ARM 40 // ARM +#define EM_OLD_ALPHA 41 // Digital Alpha +#define EM_SH 42 // Renesas (formerly Hitachi) / SuperH SH +#define EM_SPARCV9 43 // SPARC v9 64-bit +#define EM_TRICORE 44 // Siemens Tricore embedded processor +#define EM_ARC 45 // ARC Cores +#define EM_H8_300 46 // Renesas (formerly Hitachi) H8/300 +#define EM_H8_300H 47 // Renesas (formerly Hitachi) H8/300H +#define EM_H8S 48 // Renesas (formerly Hitachi) H8S +#define EM_H8_500 49 // Renesas (formerly Hitachi) H8/500 +#define EM_IA_64 50 // Intel IA-64 Processor +#define EM_MIPS_X 51 // Stanford MIPS-X +#define EM_COLDFIRE 52 // Motorola Coldfire +#define EM_68HC12 53 // Motorola M68HC12 +#define EM_MMA 54 // Fujitsu Multimedia Accelerator +#define EM_PCP 55 // Siemens PCP +#define EM_NCPU 56 // Sony nCPU embedded RISC processor +#define EM_NDR1 57 // Denso NDR1 microprocesspr +#define EM_STARCORE 58 // Motorola Star*Core processor +#define EM_ME16 59 // Toyota ME16 processor +#define EM_ST100 60 // STMicroelectronics ST100 processor +#define EM_TINYJ 61 // Advanced Logic Corp. TinyJ embedded processor +#define EM_X86_64 62 // Advanced Micro Devices X86-64 processor +#define EM_PDSP 63 // Sony DSP Processor +#define EM_PDP10 64 // Digital Equipment Corp. PDP-10 +#define EM_PDP11 65 // Digital Equipment Corp. PDP-11 +#define EM_FX66 66 // Siemens FX66 microcontroller +#define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 bit microcontroller +#define EM_ST7 68 // STMicroelectronics ST7 8-bit microcontroller +#define EM_68HC16 69 // Motorola MC68HC16 Microcontroller +#define EM_68HC11 70 // Motorola MC68HC11 Microcontroller +#define EM_68HC08 71 // Motorola MC68HC08 Microcontroller +#define EM_68HC05 72 // Motorola MC68HC05 Microcontroller +#define EM_SVX 73 // Silicon Graphics SVx +#define EM_ST19 74 // STMicroelectronics ST19 8-bit cpu +#define EM_VAX 75 // Digital VAX +#define EM_CRIS 76 // Axis Communications 32-bit embedded processor +#define EM_JAVELIN 77 // Infineon Technologies 32-bit embedded cpu +#define EM_FIREPATH 78 // Element 14 64-bit DSP processor +#define EM_ZSP 79 // LSI Logic's 16-bit DSP processor +#define EM_MMIX 80 // Donald Knuth's educational 64-bit processor +#define EM_HUANY 81 // Harvard's machine-independent format +#define EM_PRISM 82 // SiTera Prism +#define EM_AVR 83 // Atmel AVR 8-bit microcontroller +#define EM_FR30 84 // Fujitsu FR30 +#define EM_D10V 85 // Mitsubishi D10V +#define EM_D30V 86 // Mitsubishi D30V +#define EM_V850 87 // NEC v850 +#define EM_M32R 88 // Renesas M32R (formerly Mitsubishi M32R) +#define EM_MN10300 89 // Matsushita MN10300 +#define EM_MN10200 90 // Matsushita MN10200 +#define EM_PJ 91 // picoJava +#define EM_OPENRISC 92 // OpenRISC 32-bit embedded processor +#define EM_ARC_A5 93 // ARC Cores Tangent-A5 +#define EM_XTENSA 94 // Tensilica Xtensa Architecture +#define EM_VIDEOCORE 95 // Alphamosaic VideoCore processor +#define EM_TMM_GPP 96 // Thompson Multimedia General Purpose Processor +#define EM_NS32K 97 // National Semiconductor 32000 series +#define EM_TPC 98 // Tenor Network TPC processor +#define EM_SNP1K 99 // Trebia SNP 1000 processor +#define EM_ST200 100 // STMicroelectronics ST200 microcontroller +#define EM_IP2K 101 // Ubicom IP2022 micro controller +#define EM_MAX 102 // MAX Processor +#define EM_CR 103 // National Semiconductor CompactRISC +#define EM_F2MC16 104 // Fujitsu F2MC16 +#define EM_MSP430 105 // TI msp430 micro controller +#define EM_BLACKFIN 106 // ADI Blackfin +#define EM_SE_C33 107 // S1C33 Family of Seiko Epson processors +#define EM_SEP 108 // Sharp embedded microprocessor +#define EM_ARCA 109 // Arca RISC Microprocessor +#define EM_UNICORE 110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University +#define EM_EXCESS 111 // eXcess: 16/32/64-bit configurable embedded CPU +#define EM_DXP 112 // Icera Semiconductor Inc. Deep Execution Processor +#define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor +#define EM_CRX 114 // National Semiconductor CRX +#define EM_XGATE 115 // Motorola XGATE embedded processor +#define EM_C166 116 // Infineon C16x/XC16x processor +#define EM_M16C 117 // Renesas M16C series microprocessors +#define EM_DSPIC30F 118 // Microchip Technology dsPIC30F Digital Signal Controller +#define EM_CE 119 // Freescale Communication Engine RISC core +#define EM_M32C 120 // Renesas M32C series microprocessors +#define EM_res121 121 // Reserved +#define EM_res122 122 // Reserved +#define EM_res123 123 // Reserved +#define EM_res124 124 // Reserved +#define EM_res125 125 // Reserved +#define EM_res126 126 // Reserved +#define EM_res127 127 // Reserved +#define EM_res128 128 // Reserved +#define EM_res129 129 // Reserved +#define EM_res130 130 // Reserved +#define EM_TSK3000 131 // Altium TSK3000 core +#define EM_RS08 132 // Freescale RS08 embedded processor +#define EM_res133 133 // Reserved +#define EM_ECOG2 134 // Cyan Technology eCOG2 microprocessor +#define EM_SCORE 135 // Sunplus Score +#define EM_SCORE7 135 // Sunplus S+core7 RISC processor +#define EM_DSP24 136 // New Japan Radio (NJR) 24-bit DSP Processor +#define EM_VIDEOCORE3 137 // Broadcom VideoCore III processor +#define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture +#define EM_SE_C17 139 // Seiko Epson C17 family +#define EM_TI_C6000 140 // Texas Instruments TMS320C6000 DSP family +#define EM_TI_C2000 141 // Texas Instruments TMS320C2000 DSP family +#define EM_TI_C5500 142 // Texas Instruments TMS320C55x DSP family +#define EM_res143 143 // Reserved +#define EM_res144 144 // Reserved +#define EM_res145 145 // Reserved +#define EM_res146 146 // Reserved +#define EM_res147 147 // Reserved +#define EM_res148 148 // Reserved +#define EM_res149 149 // Reserved +#define EM_res150 150 // Reserved +#define EM_res151 151 // Reserved +#define EM_res152 152 // Reserved +#define EM_res153 153 // Reserved +#define EM_res154 154 // Reserved +#define EM_res155 155 // Reserved +#define EM_res156 156 // Reserved +#define EM_res157 157 // Reserved +#define EM_res158 158 // Reserved +#define EM_res159 159 // Reserved +#define EM_MMDSP_PLUS 160 // STMicroelectronics 64bit VLIW Data Signal Processor +#define EM_CYPRESS_M8C 161 // Cypress M8C microprocessor +#define EM_R32C 162 // Renesas R32C series microprocessors +#define EM_TRIMEDIA 163 // NXP Semiconductors TriMedia architecture family +#define EM_QDSP6 164 // QUALCOMM DSP6 Processor +#define EM_8051 165 // Intel 8051 and variants +#define EM_STXP7X 166 // STMicroelectronics STxP7x family +#define EM_NDS32 167 // Andes Technology compact code size embedded RISC processor family +#define EM_ECOG1 168 // Cyan Technology eCOG1X family +#define EM_ECOG1X 168 // Cyan Technology eCOG1X family +#define EM_MAXQ30 169 // Dallas Semiconductor MAXQ30 Core Micro-controllers +#define EM_XIMO16 170 // New Japan Radio (NJR) 16-bit DSP Processor +#define EM_MANIK 171 // M2000 Reconfigurable RISC Microprocessor +#define EM_CRAYNV2 172 // Cray Inc. NV2 vector architecture +#define EM_RX 173 // Renesas RX family +#define EM_METAG 174 // Imagination Technologies META processor architecture +#define EM_MCST_ELBRUS 175 // MCST Elbrus general purpose hardware architecture +#define EM_ECOG16 176 // Cyan Technology eCOG16 family +#define EM_CR16 177 // National Semiconductor CompactRISC 16-bit processor +#define EM_ETPU 178 // Freescale Extended Time Processing Unit +#define EM_SLE9X 179 // Infineon Technologies SLE9X core +#define EM_L1OM 180 // Intel L1OM +#define EM_INTEL181 181 // Reserved by Intel +#define EM_INTEL182 182 // Reserved by Intel +#define EM_AARCH64 183 // ARM 64-bit architecture +#define EM_res184 184 // Reserved by ARM +#define EM_AVR32 185 // Atmel Corporation 32-bit microprocessor family +#define EM_STM8 186 // STMicroeletronics STM8 8-bit microcontroller +#define EM_TILE64 187 // Tilera TILE64 multicore architecture family +#define EM_TILEPRO 188 // Tilera TILEPro multicore architecture family +#define EM_MICROBLAZE 189 // Xilinx MicroBlaze 32-bit RISC soft processor core +#define EM_CUDA 190 // NVIDIA CUDA architecture +#define EM_TILEGX 191 // Tilera TILE-Gx multicore architecture family +#define EM_CLOUDSHIELD 192 // CloudShield architecture family +#define EM_COREA_1ST 193 // KIPO-KAIST Core-A 1st generation processor family +#define EM_COREA_2ND 194 // KIPO-KAIST Core-A 2nd generation processor family +#define EM_ARC_COMPACT2 195 // Synopsys ARCompact V2 +#define EM_OPEN8 196 // Open8 8-bit RISC soft processor core +#define EM_RL78 197 // Renesas RL78 family +#define EM_VIDEOCORE5 198 // Broadcom VideoCore V processor +#define EM_78KOR 199 // Renesas 78KOR family +#define EM_56800EX 200 // Freescale 56800EX Digital Signal Controller (DSC) +#define EM_BA1 201 // Beyond BA1 CPU architecture +#define EM_BA2 202 // Beyond BA2 CPU architecture +#define EM_XCORE 203 // XMOS xCORE processor family +#define EM_MCHP_PIC 204 // Microchip 8-bit PIC(r) family +#define EM_INTEL205 205 // Reserved by Intel +#define EM_INTEL206 206 // Reserved by Intel +#define EM_INTEL207 207 // Reserved by Intel +#define EM_INTEL208 208 // Reserved by Intel +#define EM_INTEL209 209 // Reserved by Intel +#define EM_KM32 210 // KM211 KM32 32-bit processor +#define EM_KMX32 211 // KM211 KMX32 32-bit processor +#define EM_KMX16 212 // KM211 KMX16 16-bit processor +#define EM_KMX8 213 // KM211 KMX8 8-bit processor +#define EM_KVARC 214 // KM211 KVARC processor +#define EM_CDP 215 // Paneve CDP architecture family +#define EM_COGE 216 // Cognitive Smart Memory Processor +#define EM_COOL 217 // iCelero CoolEngine +#define EM_NORC 218 // Nanoradio Optimized RISC +#define EM_CSR_KALIMBA 219 // CSR Kalimba architecture family +#define EM_Z80 220 // Zilog Z80 +#define EM_VISIUM 221 // Controls and Data Services VISIUMcore processor +#define EM_FT32 222 // FTDI Chip FT32 high performance 32-bit RISC architecture +#define EM_MOXIE 223 // Moxie processor family +#define EM_AMDGPU 224 // AMD GPU architecture +#define EM_RISCV 243 // RISC-V +#define EM_LANAI 244 // Lanai processor +#define EM_CEVA 245 // CEVA Processor Architecture Family +#define EM_CEVA_X2 246 // CEVA X2 Processor Family +#define EM_BPF 247 // Linux BPF – in-kernel virtual machine + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// OS extensions +#define ELFOSABI_NONE 0 // No extensions or unspecified +#define ELFOSABI_HPUX 1 // Hewlett-Packard HP-UX +#define ELFOSABI_NETBSD 2 // NetBSD +#define ELFOSABI_LINUX 3 // Linux +#define ELFOSABI_SOLARIS 6 // Sun Solaris +#define ELFOSABI_AIX 7 // AIX +#define ELFOSABI_IRIX 8 // IRIX +#define ELFOSABI_FREEBSD 9 // FreeBSD +#define ELFOSABI_TRU64 10 // Compaq TRU64 UNIX +#define ELFOSABI_MODESTO 11 // Novell Modesto +#define ELFOSABI_OPENBSD 12 // Open BSD +#define ELFOSABI_OPENVMS 13 // Open VMS +#define ELFOSABI_NSK 14 // Hewlett-Packard Non-Stop Kernel +#define ELFOSABI_AROS 15 // Amiga Research OS +#define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS +// 64-255 Architecture-specific value range + + + +///////////////////// +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_LOOS 0xFF20 +#define SHN_HIOS 0xFF3F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_XINDEX 0xFFFF +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_GNU_HASH 0x6ffffff6 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Processor specific values for the Shdr sh_type field +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) // ARM unwind section +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) // Preemption details +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) // ARM attributes section + +// Section attribute flags +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MERGE 0x10 +#define SHF_STRINGS 0x20 +#define SHF_INFO_LINK 0x40 +#define SHF_LINK_ORDER 0x80 +#define SHF_OS_NONCONFORMING 0x100 +#define SHF_GROUP 0x200 +#define SHF_TLS 0x400 +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xF0000000 + +// Section group flags +#define GRP_COMDAT 0x1 +#define GRP_MASKOS 0x0ff00000 +#define GRP_MASKPROC 0xf0000000 + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOOS 10 +#define STB_HIOS 12 +#define STB_MULTIDEF 13 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_LOOS 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Symbol visibility +#define STV_DEFAULT 0 +#define STV_INTERNAL 1 +#define STV_HIDDEN 2 +#define STV_PROTECTED 3 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_X86_64_NONE 0 +#define R_386_32 1 +#define R_X86_64_64 1 +#define R_386_PC32 2 +#define R_X86_64_PC32 2 +#define R_386_GOT32 3 +#define R_X86_64_GOT32 3 +#define R_386_PLT32 4 +#define R_X86_64_PLT32 4 +#define R_386_COPY 5 +#define R_X86_64_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_X86_64_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_X86_64_JUMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_X86_64_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_X86_64_GOTPCREL 9 +#define R_386_GOTPC 10 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DTPMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 +#define R_X86_64_TLSLD 20 +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 +#define R_X86_64_TPOFF32 23 +#define R_X86_64_PC64 24 +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_GOT64 27 +#define R_X86_64_GOTPCREL64 28 +#define R_X86_64_GOTPC64 29 +#define R_X86_64_GOTPLT64 30 +#define R_X86_64_PLTOFF64 31 +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL 35 +#define R_X86_64_TLSDESC 36 +#define R_X86_64_IRELATIVE 37 +#define R_X86_64_GNU_VTINHERIT 250 +#define R_X86_64_GNU_VTENTRY 251 + +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 /* obsolete static relocation */ +#define R_ARM_TLS_DESC 13 /* dynamic relocation */ +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +/* TLS relocations */ +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +/* 20-31 are reserved for ARM Linux. */ +#define R_ARM_COPY 20 +#define R_ARM_GLOB_DAT 21 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_RELATIVE 23 +#define R_ARM_GOTOFF 24 +#define R_ARM_GOTPC 25 +#define R_ARM_GOT32 26 +#define R_ARM_PLT32 27 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_BASE_ABS 31 +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_ALU_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 // depcreated +#define R_ARM_TARGET1 38 +#define R_ARM_SBREL31 39 // deprecated +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_MOVW_PREL_NC 45 +#define R_ARM_MOVT_PREL 46 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +#define R_ARM_THM_MOVW_PREL_NC 49 +#define R_ARM_THM_MOVT_PREL 50 +/* 96-111 are reserved to G++. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 +#define R_ARM_THM_PC9 103 +/* More TLS relocations */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of */ +#define R_ARM_TLS_LE32 108 +#define R_ARM_TLS_LDO12 109 +#define R_ARM_TLS_LE12 110 +#define R_ARM_TLS_IE12GP 111 +/* 112-127 are reserved for private experiments. */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Processor specific values for the Phdr p_type field +#define PT_ARM_EXIDX (PT_LOPROC + 1) // ARM unwind segment + +// Segment flags +#define PF_X 1 // Execute +#define PF_W 2 // Write +#define PF_R 4 // Read +#define PF_MASKOS 0x0ff00000 // Unspecified +#define PF_MASKPROC 0xf0000000 // Unspecified + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_MAXPOSTAGS 34 +#define DT_LOOS 0x6000000D +#define DT_HIOS 0x6ffff000 +#define DT_GNU_HASH 0x6ffffef5 +#define DT_VERDEF 0x6ffffffc +#define DT_VERSYM 0x6ffffff0 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +// DT_FLAGS values +#define DF_ORIGIN 0x1 +#define DF_SYMBOLIC 0x2 +#define DF_TEXTREL 0x4 +#define DF_BIND_NOW 0x8 +#define DF_STATIC_TLS 0x10 + + +// ELF file header +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + + +// Section header +struct Elf32_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf_Word sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Word sh_addralign; + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf_Xword sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Xword sh_addralign; + Elf_Xword sh_entsize; +}; + + +// Segment header +struct Elf32_Phdr { + Elf_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf_Word p_filesz; + Elf_Word p_memsz; + Elf_Word p_flags; + Elf_Word p_align; +}; + +struct Elf64_Phdr { + Elf_Word p_type; + Elf_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf_Xword p_filesz; + Elf_Xword p_memsz; + Elf_Xword p_align; +}; + + +// Symbol table entry +struct Elf32_Sym { + Elf_Word st_name; + Elf32_Addr st_value; + Elf_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; +}; + +struct Elf64_Sym { + Elf_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; + Elf64_Addr st_value; + Elf_Xword st_size; +}; + + +#define ELF_ST_BIND(i) ((i)>>4) +#define ELF_ST_TYPE(i) ((i)&0xf) +#define ELF_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#define ELF_ST_VISIBILITY(o) ((o)&0x3) + + +// Relocation entries +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf_Word r_info; + Elf_Sword r_addend; +}; + +struct Elf64_Rel { + Elf64_Addr r_offset; + Elf_Xword r_info; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf_Xword r_info; + Elf_Sxword r_addend; +}; + + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s,t) ((((int64_t)s)<<32)+((t)&0xffffffffL)) + +// Dynamic structure +struct Elf32_Dyn { + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn { + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +}; + +} // namespace ELFIO + +#endif // ELFTYPES_H diff --git a/tests/crotools/elfio/elfio.hpp b/tests/crotools/elfio/elfio.hpp new file mode 100644 index 0000000..77c08d0 --- /dev/null +++ b/tests/crotools/elfio/elfio.hpp @@ -0,0 +1,904 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#ifdef _MSC_VER +#pragma warning ( push ) +#pragma warning(disable:4996) +#pragma warning(disable:4355) +#pragma warning(disable:4244) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header->get_##FNAME(); \ +} + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header->get_##FNAME(); \ +} \ +void \ +set_##FNAME( TYPE val ) \ +{ \ + header->set_##FNAME( val ); \ +} \ + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class elfio +{ + public: +//------------------------------------------------------------------------------ + elfio() : sections( this ), segments( this ) + { + header = 0; + current_file_pos = 0; + create( ELFCLASS32, ELFDATA2LSB ); + } + +//------------------------------------------------------------------------------ + ~elfio() + { + clean(); + } + +//------------------------------------------------------------------------------ + void create( unsigned char file_class, unsigned char encoding ) + { + clean(); + convertor.setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + +//------------------------------------------------------------------------------ + bool load( const std::string& file_name ) + { + std::ifstream stream; + stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !stream ) { + return false; + } + + return load(stream); + } + +//------------------------------------------------------------------------------ + bool load( std::istream &stream ) + { + clean(); + + unsigned char e_ident[EI_NIDENT]; + + // Read ELF file signature + stream.seekg( 0 ); + stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || + e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || + e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 )) { + return false; + } + + convertor.setup( e_ident[EI_DATA] ); + + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( 0 == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream ); + load_segments( stream ); + + return true; + } + +//------------------------------------------------------------------------------ + bool save( const std::string& file_name ) + { + std::ofstream f( file_name.c_str(), std::ios::out | std::ios::binary ); + + if ( !f ) { + return false; + } + + bool is_still_good = true; + + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( segments.size() ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = header->get_header_size() + + header->get_segment_entry_size() * header->get_segments_num(); + + is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( f ); + is_still_good = is_still_good && save_sections( f ); + is_still_good = is_still_good && save_segments( f ); + + f.close(); + + return is_still_good; + } + +//------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + +//------------------------------------------------------------------------------ + const endianess_convertor& get_convertor() const + { + return convertor; + } + +//------------------------------------------------------------------------------ + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void clean() + { + delete header; + header = 0; + + std::vector::const_iterator it; + for ( it = sections_.begin(); it != sections_.end(); ++it ) { + delete *it; + } + sections_.clear(); + + std::vector::const_iterator it1; + for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) { + delete *it1; + } + segments_.clear(); + } + +//------------------------------------------------------------------------------ + elf_header* create_header( unsigned char file_class, unsigned char encoding ) + { + elf_header* new_header = 0; + + if ( file_class == ELFCLASS64 ) { + new_header = new elf_header_impl< Elf64_Ehdr >( &convertor, + encoding ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = new elf_header_impl< Elf32_Ehdr >( &convertor, + encoding ); + } + else { + return 0; + } + + return new_header; + } + +//------------------------------------------------------------------------------ + section* create_section() + { + section* new_section; + unsigned char file_class = get_class(); + + if ( file_class == ELFCLASS64 ) { + new_section = new section_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_section = new section_impl( &convertor ); + } + else { + return 0; + } + + new_section->set_index( (Elf_Half)sections_.size() ); + sections_.push_back( new_section ); + + return new_section; + } + + +//------------------------------------------------------------------------------ + segment* create_segment() + { + segment* new_segment; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + new_segment = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_segment = new segment_impl( &convertor ); + } + else { + return 0; + } + + new_segment->set_index( (Elf_Half)segments_.size() ); + segments_.push_back( new_segment ); + + return new_segment; + } + +//------------------------------------------------------------------------------ + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + +//------------------------------------------------------------------------------ + Elf_Half load_sections( std::istream& stream ) + { + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + sec->load( stream, (std::streamoff)offset + i * entry_size ); + sec->set_index( i ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + Elf_Half shstrndx = get_section_name_str_index(); + + if ( SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( offset ); + if ( p != 0 ) { + sections[i]->set_name( p ); + } + } + } + + return num; + } + +//------------------------------------------------------------------------------ + bool load_segments( std::istream& stream ) + { + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + segment* seg; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + seg = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + seg = new segment_impl( &convertor ); + } + else { + return false; + } + + seg->load( stream, (std::streamoff)offset + i * entry_size ); + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for( Elf_Half j = 0; j < sections.size(); ++j ) { + const section* psec = sections[j]; + + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if( psec->get_flags() & SHF_ALLOC + ? (segVBaseAddr <= psec->get_address() + && psec->get_address() + psec->get_size() + <= segVEndAddr) + : (segBaseOffset <= psec->get_offset() + && psec->get_offset() + psec->get_size() + <= segEndOffset)) { + seg->add_section_index( psec->get_index(), + psec->get_addr_align() ); + } + } + + // Add section into the segments' container + segments_.push_back( seg ); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool save_header( std::ofstream& f ) + { + return header->save( f ); + } + +//------------------------------------------------------------------------------ + bool save_sections( std::ofstream& f ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + section *sec = sections_.at(i); + + std::streampos headerPosition = + (std::streamoff)header->get_sections_offset() + + header->get_section_entry_size() * sec->get_index(); + + sec->save(f,headerPosition,sec->get_offset()); + } + return true; + } + +//------------------------------------------------------------------------------ + bool save_segments( std::ofstream& f ) + { + for ( unsigned int i = 0; i < segments_.size(); ++i ) { + segment *seg = segments_.at(i); + + std::streampos headerPosition = header->get_segments_offset() + + header->get_segment_entry_size()*seg->get_index(); + + seg->save( f, headerPosition, seg->get_offset() ); + } + return true; + } + +//------------------------------------------------------------------------------ + bool is_section_without_segment( unsigned int section_index ) + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( unsigned int k = 0; + !found && ( k < segments[j]->get_sections_num() ); + ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + +//------------------------------------------------------------------------------ + bool is_subsequence_of( segment* seg1, segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + +//------------------------------------------------------------------------------ + std::vector get_ordered_segments( ) + { + std::vector res; + std::deque worklist; + + res.reserve(segments.size()); + std::copy( segments_.begin(), segments_.end(), + std::back_inserter( worklist )) ; + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for( size_t i = 0; i < worklist.size(); ++i ) { + if( i != nextSlot && worklist[i]->is_offset_initialized() + && worklist[i]->get_offset() == 0 ) { + std::swap(worklist[i],worklist[nextSlot]); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment *seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) + worklist.push_back(seg); + else + res.push_back(seg); + } + + return res; + } + + +//------------------------------------------------------------------------------ + bool layout_sections_without_segments( ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + section *sec = sections_[i]; + + Elf_Xword section_align = sec->get_addr_align(); + if ( section_align > 1 && current_file_pos % section_align != 0 ) { + current_file_pos += section_align - + current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + +//------------------------------------------------------------------------------ + bool layout_segments_and_their_sections( ) + { + std::vector worklist; + std::vector section_generated(sections.size(),false); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( unsigned int i = 0; i < worklist.size(); ++i ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + segment* seg = worklist[i]; + + if (seg->get_overlay() != 0) { + continue; + } + + // Special case: PHDR segment + // This segment contains the program headers but no sections + else if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * header->get_segments_num(); + } + // Special case: + // Segments which start with the NULL section and have further sections + else if ( seg->get_sections_num() > 1 + && sections[seg->get_section_index_at( 0 )]->get_type() == SHT_NULL ) { + seg_start_pos = 0; + if ( seg->get_sections_num() ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() + && !section_generated[seg->get_section_index_at( 0 )] ) { + Elf64_Off cur_page_alignment = current_file_pos % seg->get_align(); + Elf64_Off req_page_alignment = seg->get_virtual_address() % seg->get_align(); + Elf64_Off error = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + error ) % seg->get_align(); + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() ) { + seg_start_pos = sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[ index ]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type()) { + section_generated[index] = true; + continue; + } + + if (0 != sec->get_overlay()) { + section_generated[index] = true; + continue; + } + + Elf_Xword secAlign = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() + && SHT_NOBITS != sec->get_type() + && SHT_NULL != sec->get_type() + && 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + secAlign = req_offset - cur_offset; + } + else if (!section_generated[index]) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if (align == 0) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + secAlign = ( align - error ) % align; + } + else { + // Alignment for already generated sections + secAlign = sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( (sec->get_flags() & SHF_ALLOC) + && !( (sec->get_flags() & SHF_TLS) && (seg->get_type() != PT_TLS) + && ( SHT_NOBITS == sec->get_type())) ) + segment_memory += sec->get_size() + secAlign; + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + segment_filesize += sec->get_size() + secAlign; + + // Nothing to be done when generating nested segments + if(section_generated[index]) { + continue; + } + + current_file_pos += secAlign; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos); + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + current_file_pos += sec->get_size(); + section_generated[index] = true; + } + + for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[ index ]; + if ( 0 == sec->get_overlay() ) { + continue; + } + + section* overlay = sections[ sec->get_overlay() ]; + Elf_Xword offset = sec->get_address() - overlay->get_address(); + sec->set_offset( overlay->get_offset() + offset ); + } + + //seg->set_file_size( segment_filesize ); + //seg->set_memory_size( segment_memory ); + seg->set_offset( seg_start_pos ); + } + + for (unsigned int i = 0; i < worklist.size(); ++i) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + segment* seg = worklist[i]; + + if (seg->get_overlay() != 0) { + segment* overlay = segments[seg->get_overlay()]; + seg_start_pos = overlay->get_offset(); + + if (seg->get_sections_num() == 0) continue; + Elf_Xword min_bound = sections[seg->get_section_index_at(0)]->get_address(); + Elf_Xword max_bound = min_bound + sections[seg->get_section_index_at(0)]->get_size(); + + for (unsigned int j = 0; j < seg->get_sections_num(); ++j) { + Elf_Half index = seg->get_section_index_at(j); + section* sec = sections[index]; + + if (sec->get_address() < min_bound) + min_bound = sec->get_address(); + + if (sec->get_address() + sec->get_size() > max_bound) + max_bound = sec->get_address() + sec->get_size(); + } + + Elf_Xword offset = min_bound - overlay->get_virtual_address(); + + seg->set_file_size(max_bound - min_bound); + seg->set_memory_size(max_bound - min_bound); + seg->set_offset(seg_start_pos + offset); + } + } + + return true; + } + +//------------------------------------------------------------------------------ + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 4; + current_file_pos += ( 4 - alignmentError ) % 4; + header->set_sections_offset(current_file_pos); + return true; + } + + +//------------------------------------------------------------------------------ + public: + friend class Sections; + class Sections { + public: +//------------------------------------------------------------------------------ + Sections( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->sections_.size(); + } + +//------------------------------------------------------------------------------ + section* operator[]( unsigned int index ) const + { + section* sec = 0; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index]; + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* operator[]( const std::string& name ) const + { + section* sec = 0; + + std::vector::const_iterator it; + for ( it = parent->sections_.begin(); + it != parent->sections_.end(); + ++it ) { + if ( (*it)->get_name() == name ) { + sec = *it; + break; + } + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* add( const std::string& name ) + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index] ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->sections_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->sections_.end(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } sections; + +//------------------------------------------------------------------------------ + public: + friend class Segments; + class Segments { + public: +//------------------------------------------------------------------------------ + Segments( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->segments_.size(); + } + +//------------------------------------------------------------------------------ + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index]; + } + + +//------------------------------------------------------------------------------ + segment* add() + { + return parent->create_segment(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->segments_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->segments_.end(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } segments; + +//------------------------------------------------------------------------------ + private: + elf_header* header; + std::vector sections_; + std::vector segments_; + endianess_convertor convertor; + + Elf_Xword current_file_pos; +}; + +} // namespace ELFIO + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // ELFIO_HPP diff --git a/tests/crotools/elfio/elfio_dump.hpp b/tests/crotools/elfio/elfio_dump.hpp new file mode 100644 index 0000000..3c1ca29 --- /dev/null +++ b/tests/crotools/elfio/elfio_dump.hpp @@ -0,0 +1,978 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace ELFIO { + + +static struct class_table_t { + const char key; + const char* str; +} class_table [] = +{ + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + + +static struct endian_table_t { + const char key; + const char* str; +} endian_table [] = +{ + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + + +static struct version_table_t { + const Elf64_Word key; + const char* str; +} version_table [] = +{ + { EV_NONE , "None" }, + { EV_CURRENT, "Current" }, +}; + + +static struct type_table_t { + const Elf32_Half key; + const char* str; +} type_table [] = +{ + { ET_NONE, "No file type" }, + { ET_REL , "Relocatable file" }, + { ET_EXEC, "Executable file" }, + { ET_DYN , "Shared object file" }, + { ET_CORE, "Core file" }, +}; + + +static struct machine_table_t { + const Elf64_Half key; + const char* str; +} machine_table [] = +{ + { EM_NONE , "No machine" }, + { EM_M32 , "AT&T WE 32100" }, + { EM_SPARC , "SUN SPARC" }, + { EM_386 , "Intel 80386" }, + { EM_68K , "Motorola m68k family" }, + { EM_88K , "Motorola m88k family" }, + { EM_486 , "Intel 80486// Reserved for future use" }, + { EM_860 , "Intel 80860" }, + { EM_MIPS , "MIPS R3000 (officially, big-endian only)" }, + { EM_S370 , "IBM System/370" }, + { EM_MIPS_RS3_LE , "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011 , "Reserved" }, + { EM_res012 , "Reserved" }, + { EM_res013 , "Reserved" }, + { EM_res014 , "Reserved" }, + { EM_PARISC , "HPPA" }, + { EM_res016 , "Reserved" }, + { EM_VPP550 , "Fujitsu VPP500" }, + { EM_SPARC32PLUS , "Sun's v8plus" }, + { EM_960 , "Intel 80960" }, + { EM_PPC , "PowerPC" }, + { EM_PPC64 , "64-bit PowerPC" }, + { EM_S390 , "IBM S/390" }, + { EM_SPU , "Sony/Toshiba/IBM SPU" }, + { EM_res024 , "Reserved" }, + { EM_res025 , "Reserved" }, + { EM_res026 , "Reserved" }, + { EM_res027 , "Reserved" }, + { EM_res028 , "Reserved" }, + { EM_res029 , "Reserved" }, + { EM_res030 , "Reserved" }, + { EM_res031 , "Reserved" }, + { EM_res032 , "Reserved" }, + { EM_res033 , "Reserved" }, + { EM_res034 , "Reserved" }, + { EM_res035 , "Reserved" }, + { EM_V800 , "NEC V800 series" }, + { EM_FR20 , "Fujitsu FR20" }, + { EM_RH32 , "TRW RH32" }, + { EM_MCORE , "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE , "Old name for MCore" }, + { EM_ARM , "ARM" }, + { EM_OLD_ALPHA , "Digital Alpha" }, + { EM_SH , "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9 , "SPARC v9 64-bit" }, + { EM_TRICORE , "Siemens Tricore embedded processor" }, + { EM_ARC , "ARC Cores" }, + { EM_H8_300 , "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H , "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S , "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500 , "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64 , "Intel IA-64 Processor" }, + { EM_MIPS_X , "Stanford MIPS-X" }, + { EM_COLDFIRE , "Motorola Coldfire" }, + { EM_68HC12 , "Motorola M68HC12" }, + { EM_MMA , "Fujitsu Multimedia Accelerator" }, + { EM_PCP , "Siemens PCP" }, + { EM_NCPU , "Sony nCPU embedded RISC processor" }, + { EM_NDR1 , "Denso NDR1 microprocesspr" }, + { EM_STARCORE , "Motorola Star*Core processor" }, + { EM_ME16 , "Toyota ME16 processor" }, + { EM_ST100 , "STMicroelectronics ST100 processor" }, + { EM_TINYJ , "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64 , "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP , "Sony DSP Processor" }, + { EM_PDP10 , "Digital Equipment Corp. PDP-10" }, + { EM_PDP11 , "Digital Equipment Corp. PDP-11" }, + { EM_FX66 , "Siemens FX66 microcontroller" }, + { EM_ST9PLUS , "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7 , "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16 , "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11 , "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08 , "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05 , "Motorola MC68HC05 Microcontroller" }, + { EM_SVX , "Silicon Graphics SVx" }, + { EM_ST19 , "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX , "Digital VAX" }, + { EM_CRIS , "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN , "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH , "Element 14 64-bit DSP processor" }, + { EM_ZSP , "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX , "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY , "Harvard's machine-independent format" }, + { EM_PRISM , "SiTera Prism" }, + { EM_AVR , "Atmel AVR 8-bit microcontroller" }, + { EM_FR30 , "Fujitsu FR30" }, + { EM_D10V , "Mitsubishi D10V" }, + { EM_D30V , "Mitsubishi D30V" }, + { EM_V850 , "NEC v850" }, + { EM_M32R , "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300 , "Matsushita MN10300" }, + { EM_MN10200 , "Matsushita MN10200" }, + { EM_PJ , "picoJava" }, + { EM_OPENRISC , "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5 , "ARC Cores Tangent-A5" }, + { EM_XTENSA , "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE , "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP , "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K , "National Semiconductor 32000 series" }, + { EM_TPC , "Tenor Network TPC processor" }, + { EM_SNP1K , "Trebia SNP 1000 processor" }, + { EM_ST200 , "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K , "Ubicom IP2022 micro controller" }, + { EM_MAX , "MAX Processor" }, + { EM_CR , "National Semiconductor CompactRISC" }, + { EM_F2MC16 , "Fujitsu F2MC16" }, + { EM_MSP430 , "TI msp430 micro controller" }, + { EM_BLACKFIN , "ADI Blackfin" }, + { EM_SE_C33 , "S1C33 Family of Seiko Epson processors" }, + { EM_SEP , "Sharp embedded microprocessor" }, + { EM_ARCA , "Arca RISC Microprocessor" }, + { EM_UNICORE , "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University" }, + { EM_EXCESS , "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP , "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2 , "Altera Nios II soft-core processor" }, + { EM_CRX , "National Semiconductor CRX" }, + { EM_XGATE , "Motorola XGATE embedded processor" }, + { EM_C166 , "Infineon C16x/XC16x processor" }, + { EM_M16C , "Renesas M16C series microprocessors" }, + { EM_DSPIC30F , "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE , "Freescale Communication Engine RISC core" }, + { EM_M32C , "Renesas M32C series microprocessors" }, + { EM_res121 , "Reserved" }, + { EM_res122 , "Reserved" }, + { EM_res123 , "Reserved" }, + { EM_res124 , "Reserved" }, + { EM_res125 , "Reserved" }, + { EM_res126 , "Reserved" }, + { EM_res127 , "Reserved" }, + { EM_res128 , "Reserved" }, + { EM_res129 , "Reserved" }, + { EM_res130 , "Reserved" }, + { EM_TSK3000 , "Altium TSK3000 core" }, + { EM_RS08 , "Freescale RS08 embedded processor" }, + { EM_res133 , "Reserved" }, + { EM_ECOG2 , "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE , "Sunplus Score" }, + { EM_SCORE7 , "Sunplus S+core7 RISC processor" }, + { EM_DSP24 , "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3 , "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17 , "Seiko Epson C17 family" }, + { EM_TI_C6000 , "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000 , "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500 , "Texas Instruments TMS320C55x DSP family" }, + { EM_res143 , "Reserved" }, + { EM_res144 , "Reserved" }, + { EM_res145 , "Reserved" }, + { EM_res146 , "Reserved" }, + { EM_res147 , "Reserved" }, + { EM_res148 , "Reserved" }, + { EM_res149 , "Reserved" }, + { EM_res150 , "Reserved" }, + { EM_res151 , "Reserved" }, + { EM_res152 , "Reserved" }, + { EM_res153 , "Reserved" }, + { EM_res154 , "Reserved" }, + { EM_res155 , "Reserved" }, + { EM_res156 , "Reserved" }, + { EM_res157 , "Reserved" }, + { EM_res158 , "Reserved" }, + { EM_res159 , "Reserved" }, + { EM_MMDSP_PLUS , "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C , "Cypress M8C microprocessor" }, + { EM_R32C , "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA , "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6 , "QUALCOMM DSP6 Processor" }, + { EM_8051 , "Intel 8051 and variants" }, + { EM_STXP7X , "STMicroelectronics STxP7x family" }, + { EM_NDS32 , "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1 , "Cyan Technology eCOG1X family" }, + { EM_ECOG1X , "Cyan Technology eCOG1X family" }, + { EM_MAXQ30 , "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16 , "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK , "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2 , "Cray Inc. NV2 vector architecture" }, + { EM_RX , "Renesas RX family" }, + { EM_METAG , "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS , "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16 , "Cyan Technology eCOG16 family" }, + { EM_CR16 , "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU , "Freescale Extended Time Processing Unit" }, + { EM_SLE9X , "Infineon Technologies SLE9X core" }, + { EM_L1OM , "Intel L1OM" }, + { EM_INTEL181 , "Reserved by Intel" }, + { EM_INTEL182 , "Reserved by Intel" }, + { EM_AARCH64 , "ARM 64-bit architecture" }, + { EM_res184 , "Reserved by ARM" }, + { EM_AVR32 , "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8 , "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64 , "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO , "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE , "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA , "NVIDIA CUDA architecture " }, +}; + + +static struct section_type_table_t { + const Elf64_Word key; + const char* str; +} section_type_table [] = +{ + { SHT_NULL , "NULL" }, + { SHT_PROGBITS , "PROGBITS" }, + { SHT_SYMTAB , "SYMTAB" }, + { SHT_STRTAB , "STRTAB" }, + { SHT_RELA , "RELA" }, + { SHT_HASH , "HASH" }, + { SHT_DYNAMIC , "DYNAMIC" }, + { SHT_NOTE , "NOTE" }, + { SHT_NOBITS , "NOBITS" }, + { SHT_REL , "REL" }, + { SHT_SHLIB , "SHLIB" }, + { SHT_DYNSYM , "DYNSYM" }, + { SHT_INIT_ARRAY , "INIT_ARRAY" }, + { SHT_FINI_ARRAY , "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY , "PREINIT_ARRAY" }, + { SHT_GROUP , "GROUP" }, + { SHT_SYMTAB_SHNDX , "SYMTAB_SHNDX " }, + { SHT_GNU_HASH , "GNU_HASH" }, + { SHT_ARM_EXIDX , "ARM_EXIDX" }, + { SHT_ARM_ATTRIBUTES, "ARM_ATTRIBUTES" }, + { SHT_ARM_PREEMPTMAP, "ARM_PREEMPTMAP" }, +}; + + +static struct segment_type_table_t { + const Elf_Word key; + const char* str; +} segment_type_table [] = +{ + { PT_NULL , "NULL" }, + { PT_LOAD , "LOAD" }, + { PT_DYNAMIC , "DYNAMIC" }, + { PT_INTERP , "INTERP" }, + { PT_NOTE , "NOTE" }, + { PT_SHLIB , "SHLIB" }, + { PT_PHDR , "PHDR" }, + { PT_TLS , "TLS" }, + { PT_ARM_EXIDX, "ARM_EXIDX" }, +}; + + +static struct segment_flag_table_t { + const Elf_Word key; + const char* str; +} segment_flag_table [] = +{ + { 0, "" }, + { 1, "X" }, + { 2, "W" }, + { 3, "WX" }, + { 4, "R" }, + { 5, "RX" }, + { 6, "RW" }, + { 7, "RWX" }, +}; + + +static struct symbol_bind_t { + const Elf_Word key; + const char* str; +} symbol_bind_table [] = +{ + { STB_LOCAL , "LOCAL" }, + { STB_GLOBAL , "GLOBAL" }, + { STB_WEAK , "WEAK" }, + { STB_LOOS , "LOOS" }, + { STB_HIOS , "HIOS" }, + { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC , "LOPROC" }, + { STB_HIPROC , "HIPROC" }, +}; + + +static struct symbol_type_t { + const Elf_Word key; + const char* str; +} symbol_type_table [] = +{ + { STT_NOTYPE , "NOTYPE" }, + { STT_OBJECT , "OBJECT" }, + { STT_FUNC , "FUNC" }, + { STT_SECTION, "SECTION" }, + { STT_FILE , "FILE" }, + { STT_COMMON , "COMMON" }, + { STT_TLS , "TLS" }, + { STT_LOOS , "LOOS" }, + { STT_HIOS , "HIOS" }, + { STT_LOPROC , "LOPROC" }, + { STT_HIPROC , "HIPROC" }, +}; + + +static struct dynamic_tag_t { + const Elf_Word key; + const char* str; +} dynamic_tag_table [] = +{ + { DT_NULL , "NULL" }, + { DT_NEEDED , "NEEDED" }, + { DT_PLTRELSZ , "PLTRELSZ" }, + { DT_PLTGOT , "PLTGOT" }, + { DT_HASH , "HASH" }, + { DT_STRTAB , "STRTAB" }, + { DT_SYMTAB , "SYMTAB" }, + { DT_RELA , "RELA" }, + { DT_RELASZ , "RELASZ" }, + { DT_RELAENT , "RELAENT" }, + { DT_STRSZ , "STRSZ" }, + { DT_SYMENT , "SYMENT" }, + { DT_INIT , "INIT" }, + { DT_FINI , "FINI" }, + { DT_SONAME , "SONAME" }, + { DT_RPATH , "RPATH" }, + { DT_SYMBOLIC , "SYMBOLIC" }, + { DT_REL , "REL" }, + { DT_RELSZ , "RELSZ" }, + { DT_RELENT , "RELENT" }, + { DT_PLTREL , "PLTREL" }, + { DT_DEBUG , "DEBUG" }, + { DT_TEXTREL , "TEXTREL" }, + { DT_JMPREL , "JMPREL" }, + { DT_BIND_NOW , "BIND_NOW" }, + { DT_INIT_ARRAY , "INIT_ARRAY" }, + { DT_FINI_ARRAY , "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ , "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ , "FINI_ARRAYSZ" }, + { DT_RUNPATH , "RUNPATH" }, + { DT_FLAGS , "FLAGS" }, + { DT_ENCODING , "ENCODING" }, + { DT_PREINIT_ARRAY , "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS , "MAXPOSTAGS" }, + { DT_GNU_HASH , "GNU_HASH" }, +}; + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +class dump +{ +#define DUMP_DEC_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::dec << std::right +#define DUMP_HEX_FORMAT( width ) std::setw(width) << std::setfill( '0' ) << \ + std::hex << std::right +#define DUMP_STR_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::hex << std::left + + public: +//------------------------------------------------------------------------------ + static void + header( std::ostream& out, const elfio& reader ) + { + out << "ELF Header" << std::endl << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) << std::endl + << " Version: " << str_version( reader.get_version() ) << std::endl + << " Entry: " << "0x" << std::hex << reader.get_entry() << std::endl + << " Flags: " << "0x" << std::hex << reader.get_flags() << std::endl + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg Lk Inf Al Name" << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size ES Flg" << std::endl + << " Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_header( std::ostream& out, Elf_Half no, const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + + out.flags(original_flags); + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Segment headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type VirtAddr PhysAddr Flags" << std::endl + << " FileSize Mem.Size Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_header( std::ostream& out, Elf_Half no, const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address() << " " + << DUMP_STR_FORMAT( 16 ) << str_segment_flag( seg->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_align() << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + symbol_tables( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) { + symbol_section_accessor symbols( reader, sec ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no > 0 ) { + out << "Symbol table (" << sec->get_name() << ")" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size Type Bind Sect" << std::endl + << " Name" + << std::endl; + } + for ( Elf_Half i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, section, other ); + symbol_table( out, i, name, value, size, bind, type, section, reader.get_class() ); + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + symbol_table( std::ostream& out, + Elf_Half no, + std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << value << " " + << DUMP_HEX_FORMAT( 8 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 16 ) << value << " " + << DUMP_HEX_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << std::endl + << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + notes( std::ostream& out, const elfio& reader ) + { + Elf_Half no = reader.sections.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec ); + int no_notes = notes.get_notes_num(); + if ( no > 0 ) { + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Type Name" + << std::endl; + for ( int j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + void* desc; + Elf_Word descsz; + + if ( notes.get_note(j, type, name, desc, descsz) ) { + // 'name' usually contains \0 at the end. Try to fix it + name = name.c_str(); + note( out, j, type, name ); + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name ) + { + out << " [" + << DUMP_DEC_FORMAT( 2 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << type << " " + << DUMP_STR_FORMAT( 1 ) << name + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + dynamic_tags( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no > 0 ) { + out << "Dynamic section (" << sec->get_name() << ")" << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + for ( int i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, reader.get_class() ); + if ( DT_NULL == tag ) { + break; + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + dynamic_tag( std::ostream& out, + int no, + Elf_Xword tag, + Elf_Xword value, + std::string str, + unsigned int /*elf_class*/ ) + { + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ){ + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + + private: +//------------------------------------------------------------------------------ + template< typename T, typename K > + std::string + static + find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table )/sizeof( table[0] ); ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + +//------------------------------------------------------------------------------ + template< typename T, typename K > + static + std::string + format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + +//------------------------------------------------------------------------------ + template< typename T > + static + std::string + format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + +//------------------------------------------------------------------------------ + static + std::string + section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + + return ret; + } + + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template< typename T > \ + static \ + std::string \ + str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump + + +}; // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/tests/crotools/elfio/elfio_dynamic.hpp b/tests/crotools/elfio/elfio_dynamic.hpp new file mode 100644 index 0000000..6f2d041 --- /dev/null +++ b/tests/crotools/elfio/elfio_dynamic.hpp @@ -0,0 +1,253 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class dynamic_section_accessor +{ + public: +//------------------------------------------------------------------------------ + dynamic_section_accessor( const elfio& elf_file_, section* section_ ) : + elf_file( elf_file_ ), + dynamic_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != dynamic_section->get_entry_size() ) { + nRet = dynamic_section->get_size() / dynamic_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn< Elf32_Dyn >( index, tag, value ); + } + else { + generic_get_entry_dyn< Elf64_Dyn >( index, tag, value ); + } + + // If the tag may have a string table reference, prepare the string + if ( tag == DT_NEEDED || + tag == DT_SONAME || + tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + const char* result = strsec.get_string( value ); + if ( 0 == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword& tag, + Elf_Xword& value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Dyn >( tag, value ); + } + else { + generic_add_entry< Elf64_Dyn >( tag, value ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword& tag, + std::string& str ) + { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if( dynamic_section->get_data() == 0 || + ( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = reinterpret_cast( + dynamic_section->get_data() + + index * dynamic_section->get_entry_size() ); + tag = convertor( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = convertor( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = convertor( pEntry->d_un.d_ptr ); + break; + } + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf_Xword tag, Elf_Xword value ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = convertor( value ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = convertor( value ); + break; + } + + entry.d_tag = convertor( tag ); + + dynamic_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* dynamic_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/tests/crotools/elfio/elfio_header.hpp b/tests/crotools/elfio/elfio_header.hpp new file mode 100644 index 0000000..d689a88 --- /dev/null +++ b/tests/crotools/elfio/elfio_header.hpp @@ -0,0 +1,146 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +class elf_header +{ + public: + virtual ~elf_header() {}; + virtual bool load( std::istream& stream ) = 0; + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + + +template< class T > struct elf_header_impl_types; +template<> struct elf_header_impl_types { + typedef Elf32_Phdr Phdr_type; + typedef Elf32_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS32; +}; +template<> struct elf_header_impl_types { + typedef Elf64_Phdr Phdr_type; + typedef Elf64_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS64; +}; + +template< class T > class elf_header_impl : public elf_header +{ + public: + elf_header_impl( endianess_convertor* convertor_, + unsigned char encoding ) + { + convertor = convertor_; + + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = EV_CURRENT; + header.e_version = (*convertor)( header.e_version ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = (*convertor)( header.e_ehsize ); + header.e_shstrndx = (*convertor)( (Elf_Half)1 ); + header.e_phentsize = sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = (*convertor)( header.e_phentsize ); + header.e_shentsize = (*convertor)( header.e_shentsize ); + } + + bool + load( std::istream& stream ) + { + stream.seekg( 0 ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return (stream.gcount() == sizeof( header ) ); + } + + bool + save( std::ostream& stream ) const + { + stream.seekp( 0 ); + stream.write( reinterpret_cast( &header ), sizeof( header ) ); + + return stream.good(); + } + + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Word, version, header.e_version ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header; + endianess_convertor* convertor; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/tests/crotools/elfio/elfio_note.hpp b/tests/crotools/elfio/elfio_note.hpp new file mode 100644 index 0000000..35c6fe3 --- /dev/null +++ b/tests/crotools/elfio/elfio_note.hpp @@ -0,0 +1,166 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +class note_section_accessor +{ + public: +//------------------------------------------------------------------------------ + note_section_accessor( const elfio& elf_file_, section* section_ ) : + elf_file( elf_file_ ), note_section( section_ ) + { + process_section(); + } + +//------------------------------------------------------------------------------ + Elf_Word + get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + +//------------------------------------------------------------------------------ + bool + get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + void*& desc, + Elf_Word& descSize ) const + { + if ( index >= note_section->get_size() ) { + return false; + } + + const char* pData = note_section->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + type = convertor( *(Elf_Word*)( pData + 2*align ) ); + Elf_Word namesz = convertor( *(Elf_Word*)( pData ) ); + descSize = convertor( *(Elf_Word*)( pData + sizeof( namesz ) ) ); + Elf_Word max_name_size = note_section->get_size() - note_start_positions[index]; + if ( namesz > max_name_size || + namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3*align, namesz - 1); + if ( 0 == descSize ) { + desc = 0; + } + else { + desc = const_cast ( pData + 3*align + + ( ( namesz + align - 1 )/align )*align ); + } + + return true; + } + +//------------------------------------------------------------------------------ + void add_note( Elf_Word type, + const std::string& name, + const void* desc, + Elf_Word descSize ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = convertor( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = convertor( descSize ); + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = convertor( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, align - nameLen % align ); + } + if ( desc != 0 && descSize != 0 ) { + buffer.append( reinterpret_cast( desc ), descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, align - descSize % align ); + } + } + + note_start_positions.push_back( note_section->get_size() ); + note_section->append_data( buffer ); + } + + private: +//------------------------------------------------------------------------------ + void process_section() + { + const endianess_convertor& convertor = elf_file.get_convertor(); + const char* data = note_section->get_data(); + Elf_Xword size = note_section->get_size(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( 0 == data || 0 == size ) { + return; + } + + int align = sizeof( Elf_Word ); + while ( current + 3*align <= size ) { + note_start_positions.push_back( current ); + Elf_Word namesz = convertor( + *(Elf_Word*)( data + current ) ); + Elf_Word descsz = convertor( + *(Elf_Word*)( data + current + sizeof( namesz ) ) ); + + current += 3*sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * align + + ( ( descsz + align - 1 ) / align ) * align; + } + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* note_section; + std::vector note_start_positions; +}; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/tests/crotools/elfio/elfio_relocation.hpp b/tests/crotools/elfio/elfio_relocation.hpp new file mode 100644 index 0000000..d13d8b2 --- /dev/null +++ b/tests/crotools/elfio/elfio_relocation.hpp @@ -0,0 +1,369 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template<> struct get_sym_and_type< Elf32_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf32_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; + + +//------------------------------------------------------------------------------ +class relocation_section_accessor +{ + public: +//------------------------------------------------------------------------------ + relocation_section_accessor( const elfio& elf_file_, section* section_ ) : + elf_file( elf_file_ ), + relocation_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / relocation_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf32_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf32_Rela >( index, offset, symbol, + type, addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf64_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf64_Rela >( index, offset, symbol, + type, addend ); + } + } + + return true; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + Elf_Word& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half section; + unsigned char other; + + symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, + size, bind, symbolType, section, other ); + + if ( ret ) { // Was it successful? + switch ( type ) { + case R_386_NONE: // none + calcValue = 0; + break; + case R_386_32: // S + A + calcValue = symbolValue + addend; + break; + case R_386_PC32: // S + A - P + calcValue = symbolValue + addend - offset; + break; + case R_386_GOT32: // G + A - P + calcValue = 0; + break; + case R_386_PLT32: // L + A - P + calcValue = 0; + break; + case R_386_COPY: // none + calcValue = 0; + break; + case R_386_GLOB_DAT: // S + case R_386_JMP_SLOT: // S + calcValue = symbolValue; + break; + case R_386_RELATIVE: // B + A + calcValue = addend; + break; + case R_386_GOTOFF: // S + A - GOT + calcValue = 0; + break; + case R_386_GOTPC: // GOT + A - P + calcValue = 0; + break; + default: // Not recognized symbol! + calcValue = 0; + break; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rel >( offset, info ); + } + else { + generic_add_entry< Elf64_Rel >( offset, info ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO((Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rela >( offset, info, addend ); + } + else { + generic_add_entry< Elf64_Rela >( offset, info, addend ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + +//------------------------------------------------------------------------------ + void + add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned char type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = convertor( pEntry->r_addend ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + entry.r_addend = convertor( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* relocation_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/tests/crotools/elfio/elfio_section.hpp b/tests/crotools/elfio/elfio_section.hpp new file mode 100644 index 0000000..a50cbfb --- /dev/null +++ b/tests/crotools/elfio/elfio_section.hpp @@ -0,0 +1,313 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include + +namespace ELFIO { + +class section +{ + friend class elfio; + public: + virtual ~section() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, overlay ); + + virtual const char* get_data() const = 0; + virtual void set_data( const char* pData, Elf_Word size ) = 0; + virtual void set_data( const std::string& data ) = 0; + virtual void append_data( const char* pData, Elf_Word size ) = 0; + virtual void append_data( const std::string& data ) = 0; + + protected: + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual void load( std::istream& f, + std::streampos header_offset ) = 0; + virtual void save( std::ostream& f, + std::streampos header_offset, + std::streampos data_offset ) = 0; + virtual bool is_address_initialized() const = 0; +}; + + +template< class T > +class section_impl : public section +{ + public: +//------------------------------------------------------------------------------ + section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + is_address_set = false; + data = 0; + data_size = 0; + overlay = 0; + } + +//------------------------------------------------------------------------------ + ~section_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS ( Elf64_Addr, address, header.sh_addr ); + +//------------------------------------------------------------------------------ + Elf_Word + get_overlay() const + { + return overlay; + } + +//------------------------------------------------------------------------------ + void + set_overlay(Elf_Word value) + { + overlay = value; + } + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + + +//------------------------------------------------------------------------------ + std::string + get_name() const + { + return name; + } + +//------------------------------------------------------------------------------ + void + set_name( std::string name_ ) + { + name = name_; + } + +//------------------------------------------------------------------------------ + void + set_address( Elf64_Addr value ) + { + header.sh_addr = value; + header.sh_addr = (*convertor)( header.sh_addr ); + is_address_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_address_initialized() const + { + return is_address_set; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + void + set_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + delete [] data; + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + size = 0; + } + if ( 0 != data && 0 != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data ); + } + } + + set_size( size ); + } + +//------------------------------------------------------------------------------ + void + set_data( const std::string& str_data ) + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + void + append_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + if ( get_size() + size < data_size ) { + std::copy( raw_data, raw_data + size, data + get_size() ); + } + else { + data_size = 2*( data_size + size); + char* new_data; + try { + new_data = new char[data_size]; + } catch (const std::bad_alloc&) { + new_data = 0; + size = 0; + } + if ( 0 != new_data ) { + std::copy( data, data + get_size(), new_data ); + std::copy( raw_data, raw_data + size, new_data + get_size() ); + delete [] data; + data = new_data; + } + } + set_size( get_size() + size ); + } + } + +//------------------------------------------------------------------------------ + void + append_data( const std::string& str_data ) + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + Elf_Xword size = get_size(); + if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() ) { + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + } + if ( 0 != size ) { + stream.seekg( (*convertor)( header.sh_offset ) ); + stream.read( data, size ); + data_size = size; + } + } + } + +//------------------------------------------------------------------------------ + void + save( std::ostream& f, + std::streampos header_offset, + std::streampos data_offset ) + { + if ( 0 != get_index() ) { + header.sh_offset = data_offset; + header.sh_offset = (*convertor)( header.sh_offset ); + } + + save_header( f, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != 0 ) { + save_data( f, data_offset ); + } + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + save_header( std::ostream& f, + std::streampos header_offset ) const + { + f.seekp( header_offset ); + f.write( reinterpret_cast( &header ), sizeof( header ) ); + } + +//------------------------------------------------------------------------------ + void + save_data( std::ostream& f, + std::streampos data_offset ) const + { + f.seekp( data_offset ); + f.write( get_data(), get_size() ); + } + +//------------------------------------------------------------------------------ + private: + T header; + Elf_Half index; + std::string name; + char* data; + Elf_Word data_size; + const endianess_convertor* convertor; + bool is_address_set; + Elf_Word overlay; +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/tests/crotools/elfio/elfio_segment.hpp b/tests/crotools/elfio/elfio_segment.hpp new file mode 100644 index 0000000..cecf50f --- /dev/null +++ b/tests/crotools/elfio/elfio_segment.hpp @@ -0,0 +1,237 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include + +namespace ELFIO { + +class segment +{ + friend class elfio; + public: + virtual ~segment() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, overlay ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + + virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0; + virtual Elf_Half get_sections_num() const = 0; + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + virtual bool is_offset_initialized() const = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual const std::vector& get_sections() const = 0; + virtual void load( std::istream& stream, std::streampos header_offset ) = 0; + virtual void save( std::ostream& f, std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + + +//------------------------------------------------------------------------------ +template< class T > +class segment_impl : public segment +{ + public: +//------------------------------------------------------------------------------ + segment_impl( endianess_convertor* convertor_ ) : + convertor( convertor_ ) + { + is_offset_set = false; + std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); + data = 0; + overlay = 0; + } + +//------------------------------------------------------------------------------ + virtual ~segment_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + +//------------------------------------------------------------------------------ + Elf_Word + get_overlay() const + { + return overlay; + } + +//------------------------------------------------------------------------------ + void + set_overlay(Elf_Word value) + { + overlay = value; + } + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + Elf_Half + add_section_index( Elf_Half sec_index, Elf_Xword addr_align ) + { + sections.push_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_sections_num() const + { + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_section_index_at( Elf_Half num ) const + { + if ( num < sections.size() ) { + return sections[num]; + } + + return -1; + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ + void + set_offset( Elf64_Off value ) + { + ph.p_offset = value; + ph.p_offset = (*convertor)( ph.p_offset ); + is_offset_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_offset_initialized() const + { + return is_offset_set; + } + +//------------------------------------------------------------------------------ + const std::vector& + get_sections() const + { + return sections; + } + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + is_offset_set = true; + + if ( PT_NULL != get_type() && 0 != get_file_size() ) { + stream.seekg( (*convertor)( ph.p_offset ) ); + Elf_Xword size = get_file_size(); + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + } + if ( 0 != data ) { + stream.read( data, size ); + } + } + } + +//------------------------------------------------------------------------------ + void save( std::ostream& f, + std::streampos header_offset, + std::streampos data_offset ) + { + ph.p_offset = data_offset; + ph.p_offset = (*convertor)(ph.p_offset); + f.seekp( header_offset ); + f.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + +//------------------------------------------------------------------------------ + private: + T ph; + Elf_Half index; + char* data; + std::vector sections; + endianess_convertor* convertor; + bool is_offset_set; + Elf_Word overlay; +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/tests/crotools/elfio/elfio_strings.hpp b/tests/crotools/elfio/elfio_strings.hpp new file mode 100644 index 0000000..df952a2 --- /dev/null +++ b/tests/crotools/elfio/elfio_strings.hpp @@ -0,0 +1,96 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class string_section_accessor +{ + public: +//------------------------------------------------------------------------------ + string_section_accessor( section* section_ ) : + string_section( section_ ) + { + } + + +//------------------------------------------------------------------------------ + const char* + get_string( Elf_Word index ) const + { + if ( string_section ) { + if ( index < string_section->get_size() ) { + const char* data = string_section->get_data(); + if ( 0 != data ) { + return data + index; + } + } + } + + return 0; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const char* str ) + { + Elf_Word current_position = 0; + + if (string_section) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)string_section->get_size(); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 ); + } + + return current_position; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + +//------------------------------------------------------------------------------ + private: + section* string_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/tests/crotools/elfio/elfio_symbols.hpp b/tests/crotools/elfio/elfio_symbols.hpp new file mode 100644 index 0000000..80e498d --- /dev/null +++ b/tests/crotools/elfio/elfio_symbols.hpp @@ -0,0 +1,278 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class symbol_section_accessor +{ + public: +//------------------------------------------------------------------------------ + symbol_section_accessor( const elfio& elf_file_, section* symbol_section_ ) : + elf_file( elf_file_ ), + symbol_section( symbol_section_ ) + { + find_hash_section(); + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_symbols_num() const + { + Elf_Xword nRet = 0; + if ( 0 != symbol_section->get_entry_size() ) { + nRet = symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + Elf_Word nbucket = *(Elf_Word*)hash_section->get_data(); + Elf_Word nchain = *(Elf_Word*)( hash_section->get_data() + + sizeof( Elf_Word ) ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + + Elf_Word y = *(Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + if ( str == name ) { + ret = true; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + find_hash_section() + { + hash_section = 0; + hash_section_index = 0; + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() ) { + hash_section = sec; + hash_section_index = i; + } + } + } + +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_hash_table_index() const + { + return hash_section_index; + } + +//------------------------------------------------------------------------------ + template< class T > + bool + generic_get_symbol( Elf_Xword index, + std::string& name, Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + + section* string_section = elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = str_reader.get_string( convertor( pSym->st_name ) ); + if ( 0 != pStr ) { + name = pStr; + } + value = convertor( pSym->st_value ); + size = convertor( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = convertor( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + +//------------------------------------------------------------------------------ + template< class T > + Elf_Word + generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = convertor( name ); + entry.st_value = value; + entry.st_value = convertor( entry.st_value ); + entry.st_size = size; + entry.st_size = convertor( entry.st_size ); + entry.st_info = convertor( info ); + entry.st_other = convertor( other ); + entry.st_shndx = convertor( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; + + return nRet; + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* symbol_section; + Elf_Half hash_section_index; + const section* hash_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/tests/crotools/elfio/elfio_utils.hpp b/tests/crotools/elfio/elfio_utils.hpp new file mode 100644 index 0000000..f8423bd --- /dev/null +++ b/tests/crotools/elfio/elfio_utils.hpp @@ -0,0 +1,209 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( TYPE value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( TYPE value ) = 0 + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class endianess_convertor { + public: +//------------------------------------------------------------------------------ + endianess_convertor() + { + need_conversion = false; + } + +//------------------------------------------------------------------------------ + void + setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + +//------------------------------------------------------------------------------ + uint64_t + operator()( uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00000000000000FFull ) << 56 ) | + ( ( value & 0x000000000000FF00ull ) << 40 ) | + ( ( value & 0x0000000000FF0000ull ) << 24 ) | + ( ( value & 0x00000000FF000000ull ) << 8 ) | + ( ( value & 0x000000FF00000000ull ) >> 8 ) | + ( ( value & 0x0000FF0000000000ull ) >> 24 ) | + ( ( value & 0x00FF000000000000ull ) >> 40 ) | + ( ( value & 0xFF00000000000000ull ) >> 56 ); + + return value; + } + +//------------------------------------------------------------------------------ + int64_t + operator()( int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int64_t)(*this)( (uint64_t)value ); + } + +//------------------------------------------------------------------------------ + uint32_t + operator()( uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | + ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | + ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + +//------------------------------------------------------------------------------ + int32_t + operator()( int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int32_t)(*this)( (uint32_t)value ); + } + +//------------------------------------------------------------------------------ + uint16_t + operator()( uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00FF ) << 8 ) | + ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + +//------------------------------------------------------------------------------ + int16_t + operator()( int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int16_t)(*this)( (uint16_t)value ); + } + +//------------------------------------------------------------------------------ + int8_t + operator()( int8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + uint8_t + operator()( uint8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + unsigned char + get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *(char*)&tmp ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + +//------------------------------------------------------------------------------ + private: + bool need_conversion; +}; + + +//------------------------------------------------------------------------------ +inline +uint32_t +elf_hash( const unsigned char *name ) +{ + uint32_t h = 0, g; + while ( *name ) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/tests/crotools/example_cro/Makefile b/tests/crotools/example_cro/Makefile new file mode 100644 index 0000000..2aa4bc2 --- /dev/null +++ b/tests/crotools/example_cro/Makefile @@ -0,0 +1,71 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +include $(DEVKITARM)/3ds_rules + +CC = arm-none-eabi-gcc +# LINK = arm-none-eabi-gcc +LINK = arm-none-eabi-ld +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +CFLAGS += -g -Wall -std=c99 -march=armv6 -O2 -I"$(CTRULIB)/include" -I$(DEVKITPRO)/libnds/include +LDFLAGS += --script=ccd00.ld -shared -L"$(CTRULIB)/lib" +ELF2CRO = ../elf2cro/elf2cro + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.S) +OFILES += $(SFILES:source/%.S=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( source/`(echo $(> source/`(echo $(> source/`(echo $( build/$*.d + +build/%.o: source/%.S + $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo $(notdir $<) + @$(bin2o) diff --git a/tests/crotools/example_cro/ccd00.ld b/tests/crotools/example_cro/ccd00.ld new file mode 100644 index 0000000..4b266bb --- /dev/null +++ b/tests/crotools/example_cro/ccd00.ld @@ -0,0 +1,44 @@ +OUTPUT_ARCH(arm) + +PHDRS { + seg_text PT_LOAD FLAGS(0x01 | 0x04); + seg_rodata PT_LOAD FLAGS(0x04); + seg_data PT_LOAD FLAGS(0x02 | 0x04); + seg_bss PT_LOAD FLAGS(0x02 | 0x04); + seg_cro PT_LOAD FLAGS(0x01 | 0x04); + seg_linking PT_LOAD FLAGS(0x04); +} + +SECTIONS +{ + . = 0x180; + .text : ALIGN(0x4) { + build/crt0.o(.init) + *(.text) + *(.plt) + } : seg_text + + .got ALIGN(32) : { *(.got*) } : seg_text + + .rodata : ALIGN(0x4) { + *(.rodata) + } : seg_rodata + + .rel.dyn ALIGN(32) : { *(.rel.dyn*) } : seg_linking + .rel.plt ALIGN(32) : { *(.rel.plt*) } : seg_linking + .dynsym ALIGN(32) : { *(.dynsym*) } : seg_linking + .dynstr ALIGN(32) : { *(.dynstr*) } : seg_linking + .dynamic ALIGN(32) : { *(.dynamic*) } : seg_linking + .hash ALIGN(32) : { *(.hash*) } : seg_linking + + .data : ALIGN(0x4) { + *(.data) + } : seg_data + + .bss : ALIGN(0x4) { + *(.bss) + } : seg_bss + + +} + diff --git a/tests/crotools/example_cro/ccd00.specs b/tests/crotools/example_cro/ccd00.specs new file mode 100644 index 0000000..ccff243 --- /dev/null +++ b/tests/crotools/example_cro/ccd00.specs @@ -0,0 +1,4 @@ +%rename link old_link + +*link: +%(old_link) -T ./ccd00.ld%s diff --git a/tests/crotools/example_cro/source/crt0.S b/tests/crotools/example_cro/source/crt0.S new file mode 100644 index 0000000..aa4586a --- /dev/null +++ b/tests/crotools/example_cro/source/crt0.S @@ -0,0 +1,18 @@ +.section ".init" +.arm +.align 4 +.global _start + +_start: + add lr, lr, #0x4 + + push {r0-r12,lr} + blx _main + pop {r0-r12,lr} + + @accomodate for replaced code + ldrb r1, [r0, #0x2] + cmp r1, #0x4 + addcc lr, lr, #0x18 + + bx lr diff --git a/tests/crotools/example_cro/source/main.c b/tests/crotools/example_cro/source/main.c new file mode 100644 index 0000000..edc1dff --- /dev/null +++ b/tests/crotools/example_cro/source/main.c @@ -0,0 +1,79 @@ + +extern int test(char* data, char* data_data); + +char data[0x200]; +char data_data[5] = {1,2,3,4,5}; +const char rodata[6] = {6,5,4,3,2,1}; + +int _main(int argc, char **argv) +{ + int ret = test(data, data_data); + + switch(ret) + { + case 1: + data[0] = 2; + break; + case 2: + data[3] = 4; + break; + case 3: + data[4] = 7; + break; + case 4: + data[3] = 1; + break; + case 5: + data[9] = 2; + break; + case 6: + data[11] = 3; + break; + case 7: + data[123] = 7; + break; + case 8: + data[11] = 1; + break; + case 9: + data[777] = 7; + break; + case 10: + data[122] = 9; + break; + case 11: + data[0] = 12; + break; + case 12: + data[3] = 14; + break; + case 13: + data[4] = 17; + break; + case 14: + data[3] = 11; + break; + case 15: + data[9] = 12; + break; + case 16: + data[11] = 13; + break; + case 17: + data[123] = 17; + break; + case 18: + data[11] = 11; + break; + case 19: + data[777] = 17; + break; + case 20: + data[122] = _main; + break; + } + + test(data, data_data); + + return 0; +} diff --git a/tests/crotools/example_inject/Makefile b/tests/crotools/example_inject/Makefile new file mode 100644 index 0000000..349d069 --- /dev/null +++ b/tests/crotools/example_inject/Makefile @@ -0,0 +1,67 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +include $(DEVKITARM)/3ds_rules + +CC = arm-none-eabi-gcc +# LINK = arm-none-eabi-gcc +LINK = arm-none-eabi-ld +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +CFLAGS += -g -Wall -std=c99 -march=armv6 -O2 -I"$(CTRULIB)/include" -I$(DEVKITPRO)/libnds/include +LDFLAGS += --script=ccd00.ld -shared -L"$(CTRULIB)/lib" +ELF2CRO = ../elf2cro/elf2cro + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.S) +OFILES += $(SFILES:source/%.S=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( source/`(echo $(> source/`(echo $(> source/`(echo $( build/$*.d + +build/%.o: source/%.S + $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo $(notdir $<) + @$(bin2o) diff --git a/tests/crotools/example_inject/ccd00.ld b/tests/crotools/example_inject/ccd00.ld new file mode 100644 index 0000000..4b266bb --- /dev/null +++ b/tests/crotools/example_inject/ccd00.ld @@ -0,0 +1,44 @@ +OUTPUT_ARCH(arm) + +PHDRS { + seg_text PT_LOAD FLAGS(0x01 | 0x04); + seg_rodata PT_LOAD FLAGS(0x04); + seg_data PT_LOAD FLAGS(0x02 | 0x04); + seg_bss PT_LOAD FLAGS(0x02 | 0x04); + seg_cro PT_LOAD FLAGS(0x01 | 0x04); + seg_linking PT_LOAD FLAGS(0x04); +} + +SECTIONS +{ + . = 0x180; + .text : ALIGN(0x4) { + build/crt0.o(.init) + *(.text) + *(.plt) + } : seg_text + + .got ALIGN(32) : { *(.got*) } : seg_text + + .rodata : ALIGN(0x4) { + *(.rodata) + } : seg_rodata + + .rel.dyn ALIGN(32) : { *(.rel.dyn*) } : seg_linking + .rel.plt ALIGN(32) : { *(.rel.plt*) } : seg_linking + .dynsym ALIGN(32) : { *(.dynsym*) } : seg_linking + .dynstr ALIGN(32) : { *(.dynstr*) } : seg_linking + .dynamic ALIGN(32) : { *(.dynamic*) } : seg_linking + .hash ALIGN(32) : { *(.hash*) } : seg_linking + + .data : ALIGN(0x4) { + *(.data) + } : seg_data + + .bss : ALIGN(0x4) { + *(.bss) + } : seg_bss + + +} + diff --git a/tests/crotools/example_inject/ccd00.specs b/tests/crotools/example_inject/ccd00.specs new file mode 100644 index 0000000..ccff243 --- /dev/null +++ b/tests/crotools/example_inject/ccd00.specs @@ -0,0 +1,4 @@ +%rename link old_link + +*link: +%(old_link) -T ./ccd00.ld%s diff --git a/tests/crotools/example_inject/source/crt0.S b/tests/crotools/example_inject/source/crt0.S new file mode 100644 index 0000000..c4cda38 --- /dev/null +++ b/tests/crotools/example_inject/source/crt0.S @@ -0,0 +1,7 @@ +.section ".init" +.arm +.align 4 +.global _start + +_start: +@ You can do stuff here if you really want an entrypoint? diff --git a/tests/crotools/example_inject/source/main.c b/tests/crotools/example_inject/source/main.c new file mode 100644 index 0000000..7ac74d9 --- /dev/null +++ b/tests/crotools/example_inject/source/main.c @@ -0,0 +1,15 @@ +// This is an example for Smash 4's menu/menu CRO + +extern void _ZN3app17BootSequenceSceneC1Ev_orig(void); + +// Override _ZN3app17BootSequenceSceneC1Ev, the original function will be renamed to +// _ZN3app17BootSequenceSceneC1Ev_orig and can be (optionally) called +void _ZN3app17BootSequenceSceneC1Ev(void) +{ + // Pre-hook stuff + + // Call the original function + _ZN3app17BootSequenceSceneC1Ev_orig(); + + // Post-hook stuff +}