#include #include #include #include #include #include #include #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #define ARRAY_COUNT(arr) (sizeof(arr) / sizeof((arr)[0])) #define IS_LITTLE_ENDIAN (((char*)((uint32_t[]){1}))[0] == 1) // Relevant portions of elf.h typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Off; typedef uint32_t Elf32_Word; typedef int32_t Elf32_Sword; typedef uint16_t Elf32_Half; typedef uint16_t Elf32_Section; #define EI_NIDENT (16) typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr; #define EI_CLASS 4 /* File class byte index */ #define ELFCLASS32 1 /* 32-bit objects */ #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ #define EM_PPC 20 /* PowerPC */ typedef struct { Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr; #define SHT_PROGBITS 1 /* Program data */ #define SHT_SYMTAB 2 /* Symbol table */ #define SHT_STRTAB 3 /* String table */ #define SHT_RELA 4 /* Relocation entries with addends */ #define SHT_NOBITS 8 /* Program space with no data (bss) */ #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ #define SHF_EXECINSTR (1 << 2) /* Executable */ typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; #define ELF32_ST_TYPE(val) ((val)&0xf) /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_NOTYPE 0 /* Symbol type is unspecified */ #define STT_FUNC 2 /* Symbol is a code object */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ Elf32_Sword r_addend; /* Addend */ } Elf32_Rela; /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val)&0xff) #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_DOLPHIN_SECTION 202 #define R_DOLPHIN_END 203 // end elf.h struct RelHeader { uint32_t moduleId; // unique module identifier uint32_t nextModule; // always 0; filled in at runtime uint32_t prevModule; // always 0; filled in at runtime uint32_t sectionCount; // number of sections in the section table uint32_t sectionTableOffset; // file position of section table uint32_t moduleNameOffset; // offset of the module name in the string table // (not in this file) uint32_t moduleNameSize; // size of the module name in the string table (not // in this file) uint32_t formatVersion; // REL format version uint32_t bssSize; // size of the BSS section uint32_t relocationTableOffset; // file position of relocation entries uint32_t importTableOffset; // file position of import table uint32_t importTableSize; // size of import table uint8_t prologSection; // section in which the _prolog function is in, or 0 if // absent uint8_t epilogSection; // section in which the _epilog function is in, or 0 if // absent uint8_t unresolvedSection; // section in which the _unresolved function is in, // or 0 if absent uint8_t pad33; uint32_t prologOffset; // offset of the _prolog function in its section uint32_t epilogOffset; // offset of the _epilog function in its section uint32_t unresolvedOffset; // offset of the _unresolved function in its section }; struct RelRelocEntry { int type; // relocation type int patchSection; // section which relocation patch applies to uint32_t patchOffset; // offset where this relocation patch applies int symbolSection; // section of symbol uint32_t symbolAddr; // for dol symbols, absolute address. for rel symbols, // section offset }; struct RelImportEntry { int moduleId; // ID of module from which the relocation symbols are imported // from struct RelRelocEntry* relocs; // relocation entries int relocsCount; // number of relocation entries size_t relocsOffset; // file offset to relocation entries }; struct Module { int moduleId; // unique identifier of the module; the id of the DOL is always // 0 const char* filename; // name of the module's ELF file FILE* file; // ELF file Elf32_Ehdr ehdr; // ELF header Elf32_Sym* symtab; // ELF symbol table entries int symtabCount; // number of ELF symbol table entries char* strtab; // ELF string table size_t strtabSize; // size of ELF string table }; static struct Module dolModule; static struct Module relModule; static struct RelImportEntry* imports; static int importsCount = 0; static int minSectionCount = 0; static int undefinedSymError = 0; static void fatal_error(const char* msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); exit(1); } // Swaps byte order if the system is little endian static void bswap32(uint32_t* ptr) { if (IS_LITTLE_ENDIAN) *ptr = (((*ptr >> 24) & 0xFF) << 0) | (((*ptr >> 16) & 0xFF) << 8) | (((*ptr >> 8) & 0xFF) << 16) | (((*ptr >> 0) & 0xFF) << 24); } static void bswap16(uint16_t* ptr) { if (IS_LITTLE_ENDIAN) *ptr = (((*ptr >> 8) & 0xFF) << 0) | (((*ptr >> 0) & 0xFF) << 8); } static int read_checked(FILE* f, size_t offset, void* out, size_t size) { return fseek(f, offset, SEEK_SET) == 0 && fread(out, size, 1, f) == 1; } static int write_checked(FILE* f, size_t offset, const void* in, size_t size) { return fseek(f, offset, SEEK_SET) == 0 && fwrite(in, size, 1, f) == 1; } static uint32_t align(uint32_t n, unsigned int alignment) { if (alignment == 0 || n % alignment == 0) return n; return n + alignment - (n % alignment); } static int is_supported_reloc_type(int type) { switch (type) { case R_PPC_ADDR32: case R_PPC_ADDR24: case R_PPC_ADDR16_LO: case R_PPC_ADDR16_HA: case R_PPC_REL24: case R_PPC_REL14: return 1; } return 0; } static const char* symbol_name(const struct Module* module, const Elf32_Sym* sym) { if (sym->st_name >= module->strtabSize) return NULL; return module->strtab + sym->st_name; } static int get_symtab_entry(const struct Module* module, int index, Elf32_Sym* sym) { if (index >= module->symtabCount) return 0; *sym = module->symtab[index]; bswap32(&sym->st_name); bswap32(&sym->st_value); bswap32(&sym->st_size); bswap16(&sym->st_shndx); return 1; } static int lookup_symbol_by_name(const struct Module* module, const char* name, Elf32_Sym* sym) { int i; for (i = 0; i < module->symtabCount; i++) { get_symtab_entry(module, i, sym); const char* n = symbol_name(module, sym); if (n != NULL && strcmp(name, n) == 0) return 1; } return 0; } static struct RelImportEntry* get_import_for_module_id(int moduleId) { int i; for (i = 0; i < importsCount; i++) { if (imports[i].moduleId == moduleId) return &imports[i]; } return NULL; } static void add_reloc_entry(const struct Module* module, const Elf32_Rela* reloc, int relocSection) { Elf32_Sym sym; int symIdx = ELF32_R_SYM(reloc->r_info); int relocType = ELF32_R_TYPE(reloc->r_info); struct RelRelocEntry rentry; struct RelImportEntry* import; int moduleId; // module containing the symbol if (!is_supported_reloc_type(relocType)) fatal_error("relocation type %i not supported\n", relocType); rentry.patchSection = relocSection; rentry.patchOffset = reloc->r_offset; rentry.type = relocType; // look for symbol in this module if (!get_symtab_entry(module, symIdx, &sym)) fatal_error("couldn't find symbol index %i\n", symIdx); if (sym.st_shndx != 0) // symbol is in this module { rentry.symbolSection = sym.st_shndx; rentry.symbolAddr = sym.st_value + reloc->r_addend; moduleId = module->moduleId; } else // symbol is in another module (the DOL) { const char* name = symbol_name(&relModule, &sym); if (!lookup_symbol_by_name(&dolModule, name, &sym)) { undefinedSymError = 1; fprintf(stderr, "could not find symbol '%s' in any module\n", name); return; } if (sym.st_shndx >= dolModule.ehdr.e_shnum) fatal_error("bad section index %i\n", sym.st_shndx); rentry.symbolSection = sym.st_shndx; rentry.symbolAddr = sym.st_value + reloc->r_addend; moduleId = dolModule.moduleId; } import = get_import_for_module_id(moduleId); // add import entry if it does not exist. if (import == NULL) { imports = realloc(imports, (importsCount + 1) * sizeof(*imports)); import = &imports[importsCount++]; import->moduleId = moduleId; import->relocs = NULL; import->relocsCount = 0; } // add relocation entry import->relocs = realloc(import->relocs, (import->relocsCount + 1) * sizeof(*import->relocs)); import->relocs[import->relocsCount++] = rentry; } static void module_get_section_header(const struct Module* module, int secNum, Elf32_Shdr* shdr) { size_t offset = module->ehdr.e_shoff + secNum * module->ehdr.e_shentsize; if (secNum >= module->ehdr.e_shnum) fatal_error("no such section index %i\n", secNum); if (!read_checked(module->file, offset, shdr, sizeof(*shdr))) fatal_error("error reading section header\n"); // convert from big endian bswap32(&shdr->sh_name); bswap32(&shdr->sh_type); bswap32(&shdr->sh_flags); bswap32(&shdr->sh_addr); bswap32(&shdr->sh_offset); bswap32(&shdr->sh_size); bswap32(&shdr->sh_link); bswap32(&shdr->sh_info); bswap32(&shdr->sh_addralign); bswap32(&shdr->sh_entsize); } static void module_read_relocs(struct Module* module) { int i; int j; undefinedSymError = 0; for (i = 0; i < (int)module->ehdr.e_shnum; i++) { Elf32_Shdr shdr; Elf32_Shdr forSection; module_get_section_header(module, i, &shdr); if (shdr.sh_type == SHT_RELA) { module_get_section_header(module, shdr.sh_info, &forSection); if (!(forSection.sh_flags & SHF_ALLOC)) continue; for (j = 0; j < shdr.sh_size / sizeof(Elf32_Rela); j++) { Elf32_Rela reloc; read_checked(module->file, shdr.sh_offset + j * sizeof(Elf32_Rela), &reloc, sizeof(reloc)); // convert from big endian bswap32(&reloc.r_offset); bswap32(&reloc.r_info); bswap32((uint32_t*)&reloc.r_addend); add_reloc_entry(&relModule, &reloc, shdr.sh_info); } } } if (undefinedSymError) exit(1); } static int open_module(struct Module* module) { int i; // open file module->file = fopen(module->filename, "rb"); if (module->file == NULL) fatal_error("could not open %s for reading: %s\n", module->filename, strerror(errno)); // read and verify ELF header if (!read_checked(module->file, 0, &module->ehdr, sizeof(module->ehdr))) fatal_error("error reading ELF header\n"); if (memcmp(module->ehdr.e_ident, "\x7F" "ELF", 4) != 0) fatal_error("%s is not a valid ELF file\n", module->filename); // convert from big endian bswap16(&module->ehdr.e_type); bswap16(&module->ehdr.e_machine); bswap32(&module->ehdr.e_version); bswap32(&module->ehdr.e_entry); bswap32(&module->ehdr.e_phoff); bswap32(&module->ehdr.e_shoff); bswap32(&module->ehdr.e_flags); bswap16(&module->ehdr.e_ehsize); bswap16(&module->ehdr.e_phentsize); bswap16(&module->ehdr.e_phnum); bswap16(&module->ehdr.e_shentsize); bswap16(&module->ehdr.e_shnum); bswap16(&module->ehdr.e_shstrndx); if (module->ehdr.e_shentsize < sizeof(Elf32_Shdr)) fatal_error("invalid section header size"); // Verify architecture if (module->ehdr.e_ident[EI_CLASS] != ELFCLASS32 || module->ehdr.e_ident[EI_DATA] != ELFDATA2MSB || module->ehdr.e_machine != EM_PPC) fatal_error("%s: wrong architecture. expected PowerPC 32-bit big endian.\n", module->filename); // Read symbol table and string table for (i = 0; i < (int)module->ehdr.e_shnum; i++) { Elf32_Shdr shdr; module_get_section_header(module, i, &shdr); if (shdr.sh_type == SHT_SYMTAB && module->symtab == NULL) { module->symtabCount = shdr.sh_size / sizeof(Elf32_Sym); module->symtab = malloc(shdr.sh_size); if (!read_checked(module->file, shdr.sh_offset, module->symtab, shdr.sh_size)) fatal_error("error reading symbol table\n"); } else if (shdr.sh_type == SHT_STRTAB && i != module->ehdr.e_shstrndx && module->strtab == NULL) { module->strtabSize = shdr.sh_size; module->strtab = malloc(shdr.sh_size); if (!read_checked(module->file, shdr.sh_offset, module->strtab, shdr.sh_size)) fatal_error("error reading string table\n"); } } if (module->symtab == NULL) fatal_error("%s does not have a symbol table.\n", module->filename); if (module->strtab == NULL) fatal_error("%s does not have a string table.\n", module->filename); return 1; } // searches for the special functions "_prolog", "_epliog", and "_unresolved" static void find_rel_entry_functions(const struct Module* module, struct RelHeader* relHdr) { int i; // puts("finding entry points"); for (i = 0; i < module->symtabCount; i++) { Elf32_Sym sym; Elf32_Shdr shdr; const char* name; get_symtab_entry(module, i, &sym); name = symbol_name(module, &sym); if (name == NULL) continue; if (strcmp(name, "_prolog") == 0) { module_get_section_header(module, sym.st_shndx, &shdr); relHdr->prologSection = sym.st_shndx; relHdr->prologOffset = sym.st_value - shdr.sh_addr; } else if (strcmp(name, "_epilog") == 0) { module_get_section_header(module, sym.st_shndx, &shdr); relHdr->epilogSection = sym.st_shndx; relHdr->epilogOffset = sym.st_value - shdr.sh_addr; } else if (strcmp(name, "_unresolved") == 0) { module_get_section_header(module, sym.st_shndx, &shdr); relHdr->unresolvedSection = sym.st_shndx; relHdr->unresolvedOffset = sym.st_value - shdr.sh_addr; } } } // patches the bl instruction at insnp to jump to offset static void patch_rel24_branch_offset(uint8_t* insnp, int32_t branchOffset) { const uint32_t offsetMask = 0x03FFFFFC; // bits of instruction that contain the offset uint32_t insn = (insnp[0] << 24) // read instruction | (insnp[1] << 16) | (insnp[2] << 8) | (insnp[3] << 0); assert(((insn >> 26) & 0x3F) == 18); // TODO: do other instructions besides bl use R_PPC_REL24? insn = (insn & ~offsetMask) | (branchOffset & offsetMask); // patch instruction // write instruction insnp[0] = (insn >> 24) & 0xFF; insnp[1] = (insn >> 16) & 0xFF; insnp[2] = (insn >> 8) & 0xFF; insnp[3] = (insn >> 0) & 0xFF; } static void patch_code_relocs(struct RelHeader* relHdr, int sectionId, uint8_t* code, size_t size) { struct RelImportEntry* import; struct RelRelocEntry* reloc; int i; // Remove redundant R_PPC_REL24 relocations for calls to functions within // the same module import = get_import_for_module_id(relModule.moduleId); assert(import != NULL); for (i = 0, reloc = &import->relocs[0]; i < import->relocsCount; i++, reloc++) { if (reloc->patchSection == sectionId && reloc->type == R_PPC_REL24) { assert(reloc->patchOffset < size); patch_rel24_branch_offset(code + reloc->patchOffset, reloc->symbolAddr - reloc->patchOffset); // remove the relocation reloc->type = R_PPC_NONE; } } // Patch all calls to functions outside this module to jump to _unresolved // by default. if (relHdr->unresolvedSection == 0) return; import = get_import_for_module_id(0); assert(import != NULL); for (i = 0, reloc = &import->relocs[0]; i < import->relocsCount; i++, reloc++) { if (reloc->patchSection == sectionId && reloc->type == R_PPC_REL24) { assert(reloc->patchOffset < size); patch_rel24_branch_offset(code + reloc->patchOffset, relHdr->unresolvedOffset - reloc->patchOffset); } } } static int compare_relocs(const void* a, const void* b) { const struct RelRelocEntry* relocA = a; const struct RelRelocEntry* relocB = b; // Sort by sections to which these relocations apply if (relocA->patchSection != relocB->patchSection) return relocA->patchSection - relocB->patchSection; // Sort by patch offset if (relocA->patchOffset != relocB->patchOffset) return relocA->patchOffset - relocB->patchOffset; // Otherwise, leave the order alone return (uintptr_t)a - (uintptr_t)b; } static int compare_imports(const void* a, const void* b) { const struct RelImportEntry* impA = a; const struct RelImportEntry* impB = b; return impA->moduleId - impB->moduleId; } static void write_rel_file(struct Module* module, struct RelHeader* relHdr, const char* filename) { int i, j; size_t filePos = sizeof(struct RelHeader); // skip over header for now struct RelImportEntry* imp; FILE* fout = fopen(filename, "wb"); if (fout == NULL) fatal_error("could not open %s for writing: %s\n", filename, strerror(errno)); relHdr->moduleId = module->moduleId; relHdr->formatVersion = 1; find_rel_entry_functions(module, relHdr); // 1. Write section table and section contents relHdr->sectionTableOffset = filePos; relHdr->sectionCount = MAX(module->ehdr.e_shnum, minSectionCount); // section contents follow section info table filePos = relHdr->sectionTableOffset + relHdr->sectionCount * 8; relHdr->bssSize = 0; for (i = 0; i < module->ehdr.e_shnum; i++) { Elf32_Shdr shdr; struct { uint32_t offset; uint32_t size; } secEntry = {0}; module_get_section_header(module, i, &shdr); // write section contents if (shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC)) { size_t sizeAligned = align(shdr.sh_size, 4); uint32_t execflg = (shdr.sh_flags & SHF_EXECINSTR) ? 1 : 0; filePos = align(filePos, shdr.sh_addralign); if (shdr.sh_size > 0) { uint8_t* data = calloc(sizeAligned, 1); if (!read_checked(module->file, shdr.sh_offset, data, shdr.sh_size)) fatal_error("error reading section\n"); if (execflg) patch_code_relocs(relHdr, i, data, sizeAligned); if (!write_checked(fout, filePos, data, shdr.sh_size)) fatal_error("error writing rel section\n"); free(data); } secEntry.offset = filePos | execflg; filePos += shdr.sh_size; } if (shdr.sh_flags & SHF_ALLOC) secEntry.size = shdr.sh_size; // write section table entry bswap32(&secEntry.offset); bswap32(&secEntry.size); write_checked(fout, relHdr->sectionTableOffset + i * 8, &secEntry, sizeof(secEntry)); // calculate total BSS size if ((shdr.sh_flags & SHF_ALLOC) && shdr.sh_type == SHT_NOBITS) relHdr->bssSize += shdr.sh_size; } // 2. Write relocation data relHdr->relocationTableOffset = filePos; // sort imports by module id qsort(imports, importsCount, sizeof(struct RelImportEntry), compare_imports); for (i = 0, imp = &imports[0]; i < importsCount; i++, imp++) { struct RelRelocEntry* reloc; int currSection = -1; uint32_t prevOffset = 0; struct { uint16_t offset; uint8_t type; uint8_t section; uint32_t symaddr; } ent; imp->relocsOffset = filePos; // sort relocation entries by section qsort(imp->relocs, imp->relocsCount, sizeof(struct RelRelocEntry), compare_relocs); for (j = 0, reloc = &imp->relocs[0]; j < imp->relocsCount; j++, reloc++) { if (reloc->type == R_PPC_NONE) // ignore null relocations continue; if (reloc->patchSection != currSection) // section changed { currSection = reloc->patchSection; // write section change ent.offset = 0; ent.type = R_DOLPHIN_SECTION; ent.section = reloc->patchSection; ent.symaddr = 0; bswap16(&ent.offset); bswap32(&ent.symaddr); if (!write_checked(fout, filePos, &ent, sizeof(ent))) fatal_error("error writing relocation entry"); filePos += sizeof(ent); prevOffset = 0; } // write relocation assert(reloc->patchOffset >= prevOffset); ent.offset = reloc->patchOffset - prevOffset; ent.type = reloc->type; ent.section = reloc->symbolSection; ent.symaddr = reloc->symbolAddr; bswap16(&ent.offset); bswap32(&ent.symaddr); if (!write_checked(fout, filePos, &ent, sizeof(ent))) fatal_error("error writing relocation entry"); filePos += sizeof(ent); prevOffset = reloc->patchOffset; } // write end ent.offset = 0; ent.type = R_DOLPHIN_END; ent.section = 0; ent.symaddr = 0; bswap16(&ent.offset); bswap32(&ent.symaddr); if (!write_checked(fout, filePos, &ent, sizeof(ent))) fatal_error("error writing relocation entry"); filePos += sizeof(ent); } // 3. Write module import table relHdr->importTableOffset = filePos; for (i = 0, imp = &imports[0]; i < importsCount; i++, imp++) { // write import table entry struct { uint32_t moduleId; uint32_t relocsOffset; } ent; ent.moduleId = imp->moduleId; ent.relocsOffset = imp->relocsOffset; bswap32(&ent.moduleId); bswap32(&ent.relocsOffset); write_checked(fout, relHdr->importTableOffset + i * 8, &ent, sizeof(ent)); } relHdr->importTableSize = importsCount * 8; // 4. Write REL header. // convert to big endian bswap32(&relHdr->moduleId); bswap32(&relHdr->sectionCount); bswap32(&relHdr->sectionTableOffset); bswap32(&relHdr->moduleNameOffset); bswap32(&relHdr->moduleNameSize); bswap32(&relHdr->formatVersion); bswap32(&relHdr->bssSize); bswap32(&relHdr->relocationTableOffset); bswap32(&relHdr->importTableOffset); bswap32(&relHdr->importTableSize); bswap32(&relHdr->prologOffset); bswap32(&relHdr->epilogOffset); bswap32(&relHdr->unresolvedOffset); write_checked(fout, 0, relHdr, sizeof(*relHdr)); fclose(fout); } static int parse_number(const char* str, int* n) { char* end; *n = strtol(str, &end, 0); return end > str && *end == 0; } int main(int argc, char** argv) { int i; int moduleId = -1; int nameOffset = 0; int nameLen = 0; const char* relName = NULL; struct RelHeader relHdr = {0}; // Read command-line args for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--pad-section-count") == 0) { if (i + 1 < argc && parse_number(argv[i + 1], &minSectionCount)) i++; else goto usage; } else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--module-id") == 0) { if (i + 1 < argc && parse_number(argv[i + 1], &moduleId)) i++; else goto usage; } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--name-offset") == 0) { if (i + 1 < argc && parse_number(argv[i + 1], &nameOffset)) i++; else goto usage; } else if (strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--name-length") == 0) { if (i + 1 < argc && parse_number(argv[i + 1], &nameLen)) i++; else goto usage; } else { if (relModule.filename == NULL) relModule.filename = argv[i]; else if (dolModule.filename == NULL) dolModule.filename = argv[i]; else if (relName == NULL) relName = argv[i]; else goto usage; } } if (relModule.filename == NULL || dolModule.filename == NULL || relName == NULL) goto usage; open_module(&relModule); open_module(&dolModule); dolModule.moduleId = 0; relModule.moduleId = moduleId; module_read_relocs(&relModule); // TODO: Read this information from string table relHdr.moduleNameOffset = nameOffset; relHdr.moduleNameSize = nameLen; write_rel_file(&relModule, &relHdr, relName); fclose(relModule.file); fclose(dolModule.file); free(dolModule.strtab); free(dolModule.symtab); for (i = 0; i < importsCount; i++) free(imports[i].relocs); free(imports); return 0; usage: fprintf(stderr, "usage: %s reloc_elf static_elf rel_file\n" "options:\n" " -i, --module-id sets the module ID in the rel header " "to \n" " -c, --pad-section-count ensures that the rel will have at " "least \n" " sections\n" " -o, --name-offset sets the name offset in the rel " "header to\n" " \n" " -l, --name-length sets the name length in the rel " "header to \n", argv[0]); return 1; }