/* * Links the module into the kernel. */ void module_load(void *elf, char *moduleName) { elf_header_t *header = (elf_header_t *) elf; elf_section_entry_t *sections = elf + header->sh_offset; // Verify header if(ELF_CHECK_MAGIC(header->ident.magic)) { KERROR("Module '%s' has invalid ELF magic of 0x%X%X%X%X\n", moduleName, header->ident.magic[0], header->ident.magic[1], header->ident.magic[2], header->ident.magic[3]); goto nextModule; } // Variables used for mapping of sections unsigned int progbits_start = 0, progbits_size = 0, progbits_offset = 0, progbits_size_raw = 0; unsigned int nobits_start = 0, nobits_size = 0; // Symbol table elf_symbol_entry_t *symtab = NULL; unsigned int symtab_entries = 0; // String and section string tables char *strtab = NULL; char *shstrtab = NULL; elf_section_entry_t *shstrtab_sec = §ions[header->sh_str_index]; shstrtab = elf + shstrtab_sec->sh_offset; // Relocation table(s) unsigned int currentRtab = 0; struct { elf_program_relocation_t *rtab; unsigned int rtab_entries; } rtabs[16]; // Read the section table for(unsigned int s = 0; s < header->sh_entry_count; s++) { elf_section_entry_t *section = §ions[s]; char *section_name = shstrtab + section->sh_name; // Does this section have physical memory associated with it? if(section->sh_type == SHT_PROGBITS) { // Ignore .eh_frame section if(strcmp(".eh_frame", section_name)) { progbits_size += section->sh_size; if(!progbits_offset) { progbits_offset = section->sh_offset; } } } else if(section->sh_type == SHT_NOBITS) { // NOBITS? nobits_size += section->sh_size; // Ensure consecutive NOBITS sections are properly handled if(!nobits_start) { nobits_start = section->sh_addr; } } else if(section->sh_type == SHT_REL) { // relocation // Ignore .eh_frame section if(strcmp(".rel.eh_frame", section_name)) { rtabs[currentRtab].rtab = elf + section->sh_offset; rtabs[currentRtab++].rtab_entries = section->sh_size / sizeof(elf_program_relocation_t); } } else if(section->sh_type == SHT_SYMTAB) { // symbol table symtab = elf + section->sh_offset; symtab_entries = section->sh_size / sizeof(elf_symbol_entry_t); } else if(section->sh_type == SHT_STRTAB) { // string table if((elf + section->sh_offset) != shstrtab) { strtab = elf + section->sh_offset; } } } // Sane-ify section addresses and sizes progbits_size_raw = progbits_size; progbits_size += 0x1000; progbits_size &= 0xFFFFF000; progbits_start = module_placement_addr; // Traverse symbol table to find "module_entry" and "compiler" unsigned int init_addr = 0; char *compilerInfo = NULL, *supportedKernel = NULL; bool entry_found = false; for(unsigned int s = 0; s < symtab_entries; s++) { elf_symbol_entry_t *symbol = &symtab[s]; // Look for some symbols if(symbol->st_info & STT_OBJECT) { char *name = strtab + symbol->st_name; // Note how sh_offset is used, as we read out of the loaded elf if(!strcmp(name, "compiler")) { elf_section_entry_t *section = §ions[symbol->st_shndx]; compilerInfo = elf + section->sh_offset + symbol->st_address; } else if(!strcmp(name, "supported_kernel")) { elf_section_entry_t *section = §ions[symbol->st_shndx]; supportedKernel = elf + section->sh_offset + symbol->st_address; } } } // Check if we're using compatible compiler versions if(strcmp(compilerInfo, KERNEL_COMPILER)) { if(!hal_config_get_bool("module_ignore_compiler")) { KERROR("'%s' has incompatible compiler of '%s', expected '%s'", moduleName, compilerInfo, KERNEL_COMPILER); goto nextModule; } else { KWARNING("'%s' has incompatible compiler of '%s', but loading anyways", moduleName, compilerInfo); } } // Check if the module is for this kernel version if(strcmp(supportedKernel, KERNEL_VERSION)) { if(!hal_config_get_bool("module_ignore_version")) { KERROR("'%s' requires TSOS version '%s', but kernel is '%s'", moduleName, supportedKernel, KERNEL_VERSION); goto nextModule; } else { KERROR("'%s' requires TSOS version '%s', but kernel is '%s', loading anyways", moduleName, supportedKernel, KERNEL_VERSION); } } /* * To determine the entry function to initialise this module, we * depend on the ELF file's entry header field to have the correct * value. This means that the module's entry point MUST be extern C, * and be named "start". */ unsigned int init_function_addr = progbits_start + header->entry; /* * In order for the module to be able to properly call into kernel * functions, relocation needs to be performed so it has the proper * addresses for kernel functions. * * To do this, the relocation table is searched for entries whose * type is R_386_PC32, and who are marked as "undefined" in the * symbol table. * * If all of the above conditions are met for a symbol, it's looked * up in the kernel symbol table. If this lookup fails, module * loading is aborted, as the module may crash later in hard to * debug ways if a function is simply left unrelocated. */ for(unsigned int u = 0; u < currentRtab; u++) { elf_program_relocation_t *rtab = rtabs[u].rtab; unsigned int rtab_entries = rtabs[u].rtab_entries; // Perform relocation for this rtab. for(unsigned int r = 0; r < rtab_entries; r++) { elf_program_relocation_t *ent = &rtab[r]; unsigned int symtab_index = ELF32_R_SYM(ent->r_info); // Function call relocations? if(ELF32_R_TYPE(ent->r_info) == R_386_PC32) { /* * The ELF spec says that R_386_PC32 relocation entries must * add the value at the offset to the symbol address, and * subtract the section base address added to the offset. */ // Look up only non-NULL relocations if(symtab_index != STN_UNDEF) { // Get symbol in question elf_symbol_entry_t *symbol = &symtab[symtab_index]; char *name = strtab + symbol->st_name; unsigned int *ptr = elf + progbits_offset + ent->r_offset; unsigned int kern_symbol_loc = 0; // Search the module first for(unsigned int i = 0; i < symtab_entries; i++) { elf_symbol_entry_t *entry = &symtab[i]; char *symbol_name = strtab + entry->st_name; // Symbol found in module? if(unlikely(!strcmp(name, symbol_name)) && likely(entry->st_shndx != STN_UNDEF)) { kern_symbol_loc = (entry->st_address + module_placement_addr); *ptr = kern_symbol_loc + *ptr - (module_placement_addr + ent->r_offset); #if DEBUG_MOBULE_RELOC KDEBUG("0x%08X -> 0x%08X (%s, module)", (unsigned int) ent->r_offset, *ptr, name); #endif goto linkNext; } } // We drop down here if the symbol isn't in the module kern_symbol_loc = find_symbol_in_kernel(name); if(kern_symbol_loc) { // Perform the relocation. *ptr = kern_symbol_loc + *ptr - (module_placement_addr + ent->r_offset); #if DEBUG_MOBULE_RELOC KDEBUG("0x%08X -> 0x%08X (%s, kernel)", (unsigned int) ent->r_offset, *ptr, name); #endif } else { KERROR("Module %s references '%s', but symbol does not exist", moduleName, name); goto nextModule; } } else { KERROR("Module %s has undefined linkage", moduleName); goto nextModule; } } else if(ELF32_R_TYPE(ent->r_info) == R_386_32) { /* * The ELF spec says that R_386_32 relocation entries must * add the value at the offset to the symbol address. */ elf_symbol_entry_t *symbol = &symtab[symtab_index]; // If name = 0, relocating section if(symbol->st_name == 0) { // Get the section requested unsigned int sectionIndex = symbol->st_shndx; elf_section_entry_t *section = §ions[sectionIndex]; char *name = shstrtab + section->sh_name; // Get virtual address of the section unsigned int addr = section->sh_addr + module_placement_addr; // Perform relocation unsigned int *ptr = elf + progbits_offset + ent->r_offset; *ptr = addr + *ptr; #if DEBUG_MOBULE_RELOC KDEBUG("0x%08X -> 0x%08X (section: %s+0x%X)", (unsigned int) ent->r_offset, *ptr, name, *ptr - addr); #endif } else { // Get symbol name and a placeholder address char *name = strtab + symbol->st_name; unsigned int addr = 0; #if DEBUG_MOBULE_RELOC bool inKernel = false; #endif // Search through the module's symbols first for(unsigned int i = 0; i < symtab_entries; i++) { elf_symbol_entry_t *entry = &symtab[i]; char *symbol_name = strtab + entry->st_name; // Symbol found in module? if(unlikely(!strcmp(name, symbol_name)) && likely(entry->st_shndx != STN_UNDEF)) { addr = entry->st_address + module_placement_addr; // Take into account the section's address elf_section_entry_t *section = §ions[symbol->st_shndx]; addr += section->sh_addr; // Go to the relocation code #if DEBUG_MOBULE_RELOC inKernel = false; #endif goto R_386_32_reloc_good; } } // See if the kernel has the symbol if(unlikely(!(addr = find_symbol_in_kernel(name)))) { KERROR("Module %s references '%s', but symbol does not exist", moduleName, name); goto nextModule; } #if DEBUG_MOBULE_RELOC inKernel = true; #endif // Perform relocation R_386_32_reloc_good: ; unsigned int *ptr = elf + progbits_offset + ent->r_offset; *ptr = addr + *ptr; #if DEBUG_MOBULE_RELOC KDEBUG("0x%08X -> 0x%08X (%s, %s)", (unsigned int) ent->r_offset, addr, name, inKernel ? "kernel" : "module"); #endif } } // Drop down here to link the next symbol linkNext: ; } } // Move PROGBITS from the file forward however many bytes the offset is memmove(elf, elf+progbits_offset, progbits_size_raw); // Perform mapping for the PROGBITS section #if DEBUG_MODULE_MAPPING KDEBUG("Mapping PROGBITS from 0x%08X to 0x%08X", module_placement_addr, module_placement_addr+progbits_size); #endif unsigned int progbits_end = module_placement_addr + progbits_size; for(unsigned int a = module_placement_addr; a < progbits_end; a += 0x1000) { unsigned int progbits_offset = a - module_placement_addr; unsigned int progbits_virt_addr = ((unsigned int) elf) + progbits_offset; // Get the page whose physical address we want page_t *elf_page = paging_get_page(progbits_virt_addr, false, kernel_directory); // Create a page in the proper virtual space, and assign physical address of above page_t *new_page = paging_get_page(a, true, kernel_directory); new_page->rw = 1; new_page->present = 1; new_page->frame = elf_page->frame; // KDEBUG("0x%08X -> 0x%08X (0x%08X)", a, progbits_offset, progbits_virt_addr); } module_placement_addr += progbits_size; // Perform mapping for NOBITS section, if needed if(nobits_size) { nobits_size += 0x1000; nobits_size &= 0xFFFFF000; unsigned int nobits_end = module_placement_addr+nobits_size; #if DEBUG_MODULE_MAPPING KDEBUG("Mapping NOBITS from 0x%08X to 0x%08X", module_placement_addr, nobits_end); #endif // Map the pages, and allocate memory to them for(unsigned a = module_placement_addr; a < nobits_end; a += 0x1000) { page_t *page = paging_get_page(a, true, kernel_directory); alloc_frame(page, true, true); // Zero the memory memclr((void *) a, 4096); } nobits_start = module_placement_addr; module_placement_addr += nobits_size; } else { #if DEBUG_MODULE_MAPPING KDEBUG("NOBITS section not required"); #endif } // Initialise driver module_t *driver = ((module_t* (*)(void)) init_function_addr)(); // Save locations driver->progbits_start = progbits_start; driver->map_end = module_placement_addr-1; // If there's no BSS, leave the nobits_start empty if(nobits_size) { driver->nobits_start = nobits_start; } else { driver->nobits_start = 0; } // Register them list_add(loaded_module_names, (char *) driver->name); hashmap_insert(loaded_module_map, (char *) driver->name, driver); // Drop down here when the module is all happy nextModule: ; }
/* Perform relocations of given section */ static int relocate(struct elfheader *eh, struct sheader *sh, long shrel_idx, unsigned long long virt) { struct sheader *shrel = &sh[shrel_idx]; struct sheader *shsymtab = &sh[shrel->link]; struct sheader *toreloc = &sh[shrel->info]; struct symbol *symtab = (struct symbol *)((unsigned long)shsymtab->addr); struct relo *rel = (struct relo *)((unsigned long)shrel->addr); char *section = (char *)((unsigned long)toreloc->addr); unsigned int numrel = (unsigned long)shrel->size / (unsigned long)shrel->entsize; unsigned int i; struct symbol *SysBase_sym = (void*)0; D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n", numrel, (unsigned long)(virt >> 32), (unsigned long)virt)); for (i=0; i<numrel; i++, rel++) { struct symbol *sym = &symtab[ELF32_R_SYM(rel->info)]; unsigned long *p = (unsigned long *)§ion[rel->offset]; unsigned long long s; const char * name = (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name; switch (sym->shindex) { case SHN_UNDEF: D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n", (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name, (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name)); return 0; case SHN_COMMON: D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n", (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name, (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name)); return 0; case SHN_ABS: if (SysBase_sym == (void*)0) { if (strncmp(name, "SysBase", 8) == 0) { D(kprintf("[ELF Loader] got SysBase\n")); SysBase_sym = sym; goto SysBase_yes; } else goto SysBase_no; } else if (SysBase_sym == sym) { SysBase_yes: s = SysBaseAddr; } else SysBase_no: s = sym->value; break; default: s = (unsigned long)sh[sym->shindex].addr + virt + sym->value; } s+=virt; switch (ELF32_R_TYPE(rel->info)) { case R_386_32: /* 32bit absolute */ *p += s; break; case R_386_PC32: /* 32bit PC relative */ *p += s - (unsigned int)p; break; case R_386_NONE: break; default: kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i, (unsigned int)ELF32_R_TYPE(rel->info)); return 0; } if (sym->name) D(kprintf("[ELF Loader] relocated symbol: %s->0x%x\n",name,*p)); } return 1; }
bfd_reloc_status_type pmbfd_perform_relocation(bfd *abfd, pmbfd_arelent *r, asymbol *psym, asection *input_section) { Elf32_Word pc; int64_t val, msk; int32_t oval,nval; int16_t sval; int8_t bval; int64_t llim,ulim; Elf32_Rela *rela = &r->rela32; uint8_t type = ELF32_R_TYPE(rela->r_info); struct sparc_rel_desc *dsc; if ( R_SPARC_NONE == type ) { /* No-op; BFD uses a zero dst_mask... */ return bfd_reloc_ok; } /* use R_SPARC_NONE as a dummy for 'unsupported' */ dsc = type >= sizeof(sparc_rels) ? &sparc_rels[R_SPARC_NONE] : &sparc_rels[type]; if ( 0 == dsc->nbytes ) { ERRPR("pmbfd_perform_relocation_sparc(): unsupported relocation type : %"PRIu8"\n", type); return bfd_reloc_notsupported; } if ( bfd_is_und_section(bfd_get_section(psym)) ) return bfd_reloc_undefined; pc = bfd_get_section_vma(abfd, input_section) + rela->r_offset; if ( ! dsc->unaligned && (pc & (dsc->nbytes - 1)) ) { ERRPR("pmbfd_perform_relocation_sparc(): location to relocate (0x%08"PRIx32") not properly aligned\n", pc); return bfd_reloc_other; } val = (int64_t)bfd_asymbol_value(psym) + (int64_t)rela->r_addend; if ( dsc->pc_relative ) val -= (int64_t)pc; val >>= dsc->shift; /* works also if the left shift is 32 */ msk = (1LL << dsc->width); msk--; switch ( dsc->sparc_rel_check ) { default: case sparc_rel_check_none: ulim = ~(1LL<<63); llim = ~ulim; break; case sparc_rel_check_unsg: ulim = msk; llim = 0; break; case sparc_rel_check_bits: ulim = msk; llim = ~ulim; break; case sparc_rel_check_sign: ulim = msk>>1; llim = ~ulim; break; } #if (DEBUG & DEBUG_RELOC) fprintf(stderr,"Relocating val: 0x%08"PRIx64", ulim: 0x%08"PRIx64", pc: 0x%08"PRIx32", sym: 0x%08lx\n", val, ulim, pc, bfd_asymbol_value(psym)); #endif if ( val < llim || val > ulim ) { return bfd_reloc_overflow; } if ( 1 == dsc->nbytes ) { memcpy(&bval, (void*)pc, sizeof(bval)); oval = bval; } else if ( 2 == dsc->nbytes ) { memcpy(&sval, (void*)pc, sizeof(sval)); oval = sval; } else { memcpy(&oval, (void*)pc, sizeof(oval)); } nval = ( oval & ~msk ) | (val & msk); /* patch back */ if ( 1 == dsc->nbytes ) { bval = nval; memcpy((void*)pc, &bval, sizeof(bval)); } else if ( 2 == dsc->nbytes ) { sval = nval; memcpy((void*)pc, &sval, sizeof(sval)); } else { memcpy((void*)pc, &nval, sizeof(nval)); } return bfd_reloc_ok; }
int remove_weak_relocs(struct ElfSection *pReloc, struct ElfSection *pSymbol, struct ElfSection *pString) { int iCount; int iMaxSymbol; void *pNewRel = NULL; Elf32_Rel *pInRel; Elf32_Rel *pOutRel; Elf32_Sym *pSymData = (Elf32_Sym *) pSymbol->pData; char *pStrData = NULL; int iOutput; int i; if(pString != NULL) { pStrData = (char *) pString->pData; } iMaxSymbol = pSymbol->iSize / sizeof(Elf32_Sym); iCount = pReloc->iSize / sizeof(Elf32_Rel); pNewRel = malloc(pReloc->iSize); if(pNewRel == NULL) { return 0; } pOutRel = (Elf32_Rel *) pNewRel; pInRel = (Elf32_Rel *) pReloc->pData; iOutput = 0; if(g_verbose) { fprintf(stderr, "[%s] Processing %d relocations, %d symbols\n", pReloc->szName, iCount, iMaxSymbol); } for(i = 0; i < iCount; i++) { int iSymbol; iSymbol = ELF32_R_SYM(LW(pInRel->r_info)); if(g_verbose) { fprintf(stderr, "Relocation %d - Symbol %x\n", iOutput, iSymbol); } if(iSymbol >= iMaxSymbol) { fprintf(stderr, "Warning: Ignoring relocation as cannot find matching symbol\n"); } else { if(g_verbose) { if(pStrData != NULL) { fprintf(stderr, "Symbol %d - Name %s info %x ndx %x\n", iSymbol, &pStrData[pSymData[iSymbol].st_name], pSymData[iSymbol].st_info, pSymData[iSymbol].st_shndx); } else { fprintf(stderr, "Symbol %d - Name %d info %x ndx %x\n", iSymbol, pSymData[iSymbol].st_name, pSymData[iSymbol].st_info, pSymData[iSymbol].st_shndx); } } /* Remove PC16 relocations (unsupported by PSP, and useless) */ if(LH(pSymData[iSymbol].st_shndx) == 0 || ELF32_R_TYPE(LW(pInRel->r_info)) == R_MIPS_PC16) { if(g_verbose) { fprintf(stderr, "Deleting relocation\n"); } } else { /* We are keeping this relocation, copy it across */ *pOutRel = *pInRel; pOutRel++; iOutput++; } } pInRel++; } /* If we deleted some relocations */ if(iOutput < iCount) { int iSize; iSize = iOutput * sizeof(Elf32_Rel); if(g_verbose) { fprintf(stderr, "Old relocation size %d, new %d\n", pReloc->iSize, iSize); } pReloc->iSize = iSize; /* If size is zero then delete this section */ if(iSize == 0) { pReloc->blOutput = 0; } else { /* Copy across the new relocation data */ memcpy(pReloc->pData, pNewRel, pReloc->iSize); } } free(pNewRel); return 1; }
static int relocate_rel(image_t *rootImage, image_t *image, struct Elf32_Rel *rel, int rel_len, SymbolLookupCache* cache) { int i; addr_t S; addr_t final_val; # define P ((addr_t *)(image->regions[0].delta + rel[i].r_offset)) # define A (*(P)) # define B (image->regions[0].delta) for (i = 0; i * (int)sizeof(struct Elf32_Rel) < rel_len; i++) { unsigned type = ELF32_R_TYPE(rel[i].r_info); switch (type) { case R_386_32: case R_386_PC32: case R_386_GLOB_DAT: case R_386_JMP_SLOT: case R_386_GOTOFF: { struct Elf32_Sym *sym; status_t status; sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); status = resolve_symbol(rootImage, image, sym, cache, &S); if (status < B_OK) { TRACE(("resolve symbol \"%s\" returned: %ld\n", SYMNAME(image, sym), status)); printf("resolve symbol \"%s\" returned: %ld\n", SYMNAME(image, sym), status); return status; } } } switch (type) { case R_386_NONE: continue; case R_386_32: final_val = S + A; break; case R_386_PC32: final_val = S + A - (addr_t)P; break; #if 0 case R_386_GOT32: final_val = G + A; break; case R_386_PLT32: final_val = L + A - (addr_t)P; break; #endif case R_386_COPY: /* what ? */ continue; case R_386_GLOB_DAT: final_val = S; break; case R_386_JMP_SLOT: final_val = S; break; case R_386_RELATIVE: final_val = B + A; break; #if 0 case R_386_GOTOFF: final_val = S + A - GOT; break; case R_386_GOTPC: final_val = GOT + A - P; break; #endif default: TRACE(("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info))); return B_NOT_ALLOWED; } *P = final_val; } # undef P # undef A # undef B return B_NO_ERROR; }
//------------------------------------------------------------------- static void avr_create_new_symbol_table(Elf_Data* nedata, Elf* elf, Elf* nelf, Elf32_Shdr *nshdr, uint32_t startaddr, bblklist_t* blist) { Elf32_Ehdr* ehdr; Elf32_Sym* nsym; Elf_Data* nreladata; Elf32_Rela *nerela; int numSyms, numRecs, i, txtscnndx, btxtscnfound; Elf_Scn *txtscn, *nrelascn; Elf32_Shdr *txtshdr, *nrelashdr; DEBUG("Determine .text section index ...\n"); // Get the ELF Header if ((ehdr = elf32_getehdr(elf)) == NULL){ fprintf(stderr, "avr_create_new_symbol_table: Error reading ELF header\n"); exit(EXIT_FAILURE); } txtscn = NULL; txtscnndx = 1; btxtscnfound = 0; while ((txtscn = elf_nextscn(elf, txtscn)) != NULL){ if ((txtshdr = elf32_getshdr(txtscn)) != NULL){ char* CurrSecName = NULL; CurrSecName = elf_strptr(elf, ehdr->e_shstrndx, txtshdr->sh_name); if (strcmp(CurrSecName, ".text") == 0){ btxtscnfound = 1; break; } } txtscnndx++; } if (0 == btxtscnfound){ fprintf(stderr, "avr_create_new_symbol_table: Cannot find .text section.\n"); exit(EXIT_FAILURE); } DEBUG(".text section index: %d\n", txtscnndx); // Get .rela.text section nrelascn = getELFSectionByName(nelf, ".rela.text"); nrelashdr = elf32_getshdr(nrelascn); nreladata = NULL; nreladata = elf_getdata(nrelascn, nreladata); numRecs = nreladata->d_size/nrelashdr->sh_entsize; numSyms = nedata->d_size/nshdr->sh_entsize; nsym = (Elf32_Sym*)(nedata->d_buf); for (i = 0; i < numSyms; i++){ if ((nsym->st_shndx == txtscnndx) && (ELF32_ST_TYPE(nsym->st_info) != STT_SECTION)){ if (nsym->st_value > startaddr){ uint32_t oldValue = nsym->st_value; nsym->st_value = find_updated_address(blist, oldValue); // Check if we have to further modify this symbol (if it is used as a call target value) int j; nerela = (Elf32_Rela*)nreladata->d_buf; for (j = 0; j < numRecs; j++){ if ((ELF32_R_SYM(nerela->r_info) == i) && ((ELF32_R_TYPE(nerela->r_info) == R_AVR_CALL)|| (ELF32_R_TYPE(nerela->r_info) == R_AVR_13_PCREL))){ // Check if it is indeed a call instruction before changing the symbol avr_instr_t instr; instr = find_instr_at_new_addr(blist, nerela->r_offset); if (((instr.rawVal & OP_TYPE10_MASK) == OP_CALL) || ((instr.rawVal & OP_TYPE17_MASK) == OP_RCALL)){ nsym->st_value -= sizeof(avr_instr_t) * 2; DEBUG("Call target symbol. Modify to accomodate safe stack store.\n"); } else DEBUG("Jmp target symbol. No modification to symbol required.\n"); break; } // Follwing is only for producing a more readable elf.lst if ((ELF32_ST_BIND(nsym->st_info) == STB_LOCAL) && (ELF32_ST_TYPE(nsym->st_info) == STT_FUNC) && ((ELF32_R_TYPE(nerela->r_info) == R_AVR_CALL) || (ELF32_R_TYPE(nerela->r_info) == R_AVR_13_PCREL)) && (nerela->r_addend == (nsym->st_value - (2*sizeof(avr_instr_t))))){ nsym->st_value -= sizeof(avr_instr_t) * 2; DEBUG("Call target symbol. Modified for ELF pretty print.\n"); } nerela++; } DEBUG("Entry: %d Old Value: 0x%x New Value: 0x%x\n", i, (int)oldValue, (int)nsym->st_value); } } nsym++; } return; }
static int reloc_read(const struct buffer *in, struct parsed_elf *pelf, struct xdr *xdr, int bit64) { struct buffer b; Elf64_Word i; Elf64_Ehdr *ehdr; ehdr = &pelf->ehdr; pelf->relocs = calloc(ehdr->e_shnum, sizeof(Elf64_Rela *)); /* Allocate array for each section that contains relocation entries. */ for (i = 0; i < ehdr->e_shnum; i++) { Elf64_Shdr *shdr; Elf64_Rela *rela; Elf64_Xword j; Elf64_Xword nrelocs; int is_rela; shdr = &pelf->shdr[i]; /* Only process REL and RELA sections. */ if (shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA) continue; DEBUG("Checking relocation section %u\n", i); /* Ensure the section that relocations apply is a valid. */ if (shdr->sh_info >= ehdr->e_shnum || shdr->sh_info == SHN_UNDEF) { ERROR("Relocations apply to an invalid section: %u\n", shdr[i].sh_info); return -1; } is_rela = shdr->sh_type == SHT_RELA; /* Determine the number relocations in this section. */ nrelocs = shdr->sh_size / shdr->sh_entsize; pelf->relocs[i] = calloc(nrelocs, sizeof(Elf64_Rela)); buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size); if (check_size(in, shdr->sh_offset, buffer_size(&b), "relocation section")) { ERROR("Relocation section %u failed.\n", i); return -1; } rela = pelf->relocs[i]; for (j = 0; j < nrelocs; j++) { if (bit64) { rela->r_offset = xdr->get64(&b); rela->r_info = xdr->get64(&b); if (is_rela) rela->r_addend = xdr->get64(&b); } else { uint32_t r_info; rela->r_offset = xdr->get32(&b); r_info = xdr->get32(&b); rela->r_info = ELF64_R_INFO(ELF32_R_SYM(r_info), ELF32_R_TYPE(r_info)); if (is_rela) rela->r_addend = xdr->get32(&b); } rela++; } } return 0; }
for (i = 0; i < ARRAY_SIZE (elf32_tic6x_howto_table_rel); i++) if (elf32_tic6x_howto_table_rel[i].name != NULL && strcasecmp (elf32_tic6x_howto_table_rel[i].name, r_name) == 0) return &elf32_tic6x_howto_table_rel[i]; } return NULL; } static void elf32_tic6x_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, Elf_Internal_Rela *elf_reloc) { unsigned int r_type; r_type = ELF32_R_TYPE (elf_reloc->r_info); if (r_type >= ARRAY_SIZE (elf32_tic6x_howto_table)) bfd_reloc->howto = NULL; else bfd_reloc->howto = &elf32_tic6x_howto_table[r_type]; } static void elf32_tic6x_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, Elf_Internal_Rela *elf_reloc) { unsigned int r_type; r_type = ELF32_R_TYPE (elf_reloc->r_info); if (r_type >= ARRAY_SIZE (elf32_tic6x_howto_table_rel)) bfd_reloc->howto = NULL;
/** * @param fp le fichier elf original * @param seg le segment a reloger * @param mem l'ensemble des segments * @param endianness le boutisme du programme * @param symtab la table des symbole du programme * @param symtab_libc la table des symbole de la libc (NULL si inutile) * @param fp_libc le fichier elf de la libc (NULL si inutile) * @brief Cette fonction effectue la relocation du segment passe en parametres * @brief l'ensemble des segments doit deja avoir ete charge en memoire. * * VOUS DEVEZ COMPLETER CETTE FONCTION POUR METTRE EN OEUVRE LA RELOCATION !! */ void reloc_segment(FILE* fp, segment seg, mem memory,unsigned int endianness,stab* symtable,stab* symtab_libc,FILE* fp_libc) { byte *ehdr = __elf_get_ehdr( fp ); uint32_t scnsz = 0; Elf32_Rel *rel = NULL; char* reloc_name = malloc(strlen(seg.name)+strlen(RELOC_PREFIX_STR)+1); scntab section_tab; scntab section_tab_libc; // on recompose le nom de la section memcpy(reloc_name,RELOC_PREFIX_STR,strlen(RELOC_PREFIX_STR)+1); strcat(reloc_name,seg.name); // on recupere le tableau de relocation et la table des sections rel = (Elf32_Rel *)elf_extract_scn_by_name( ehdr, fp, reloc_name, &scnsz, NULL ); elf_load_scntab(fp ,32, §ion_tab); if (symtab_libc!=NULL && fp_libc!=NULL) elf_load_scntab(fp_libc ,32, §ion_tab_libc); if (rel != NULL &&seg.content!=NULL && seg.size._32!=0) { if(verbose>0) { INFO_MSG("--------------Relocation of %s-------------------\n",seg.name) ; INFO_MSG("Number of symbol to relocate: %ld\n",scnsz/sizeof(*rel)) ; } //------------------------------------------------------ int i=0; uint sym; uint type; uint info; uint offset; //display : if(verbose>0) { //printf("scnsz=%d\n", scnsz); //print_scntab(section_tab); printf("Offset Info Type Sym.Value Sym.Name\n"); while(i<scnsz/sizeof(*rel)) { info=rel[i].r_info; offset=rel[i].r_offset; FLIP_ENDIANNESS(info) ; FLIP_ENDIANNESS(offset) ; sym=ELF32_R_SYM(info); type=ELF32_R_TYPE(info); if (type>32) { WARNING_MSG("Unknown type : %d",type); } else { printf("%08X %08X %-14s %08X %s\n",offset,info,MIPS32_REL[type],sym,(*symtable).sym[sym].name); i++; } } } i=0; //------------------------------------------------------ //Reloc : int A,V,P; //int segnum; uint32_t S; while(i<scnsz/sizeof(*rel)) { info=rel[i].r_info; offset=rel[i].r_offset; FLIP_ENDIANNESS(info) ; FLIP_ENDIANNESS(offset) ; sym=ELF32_R_SYM(info); type=ELF32_R_TYPE(info); //printf("Relocating symbol %d\n",i ); //segnum=seg_from_scnidx((*symtable).sym[sym].scnidx,(*symtable),memory); //if(segnum==-1){ // WARNING_MSG("Couldn't resolve scndix correspondance"); // break; //} //S=memory->seg[segnum].start._32+(*symtable).sym[sym].addr._32;//a verif //printf("sym=%d, symbtable size=%d\n", sym,(*symtable).size); if(addr_from_symnb(sym, (*symtable), memory,&S)==-1) { WARNING_MSG("Trying to resolve scndix correspondance in libcsymtab"); } P=seg.start._32+offset; memRead(P,1,&A); //printf("Relocation type %s\n",MIPS32_REL[type] ); switch (type) { case 2: V=S+A; //printf("V= %X,S=%X,A=%X,P=%X\n",V,S,A,P); memWrite(P,1,V); break; case 4: V=(A&0xFC00000)|((((A<<2)|((P&0xF0000000)+S))>>2)&0x3FFFFFF); //printf("V= %X,S=%X,A=%X,P=%X\n",V,S,A,P); memWrite(P,1,V); break; case 5: ; uint nexttype=rel[i+1].r_info; uint nextoffset=rel[i+1].r_offset; FLIP_ENDIANNESS(nexttype); FLIP_ENDIANNESS(nextoffset); nexttype=ELF32_R_TYPE(nexttype); if(nexttype!=6) { WARNING_MSG("R_MIPS_HI16 not followed by R_MIIPS_LO16 : %s",MIPS32_REL[nexttype]); } else { int P2=seg.start._32+nextoffset,A2; memRead(P2,1,&A2); int AHL; AHL=(A<<16)+(short)(A2); //printf("A2=%X short A2=%X\n",A2, (short)A2 ); //printf("AHL : %X\n",AHL ); //printf("Total=%X AHL+S=%X, (AHL+S)&0xFFFF=%X, diff=%X\n",((AHL+S-(short)(AHL+S))>>16),AHL+S,(AHL+S)&0xFFFF,AHL+S-(short)AHL+S) ; V=(A & 0xFFFF0000)|( ((AHL+S-(short)(AHL+S))>>16) &0xFFFF); //printf("V= %X,S=%X,A=%X,A2=%X,P=%X,P2=%X, AHL=%X\n",V,S,A,A2,P,P2,AHL); memWrite(P,1,V); } break; case 6: ; int previoustype=rel[i-1].r_info; int previousoffset=rel[i-1].r_offset; FLIP_ENDIANNESS(previoustype); FLIP_ENDIANNESS(previousoffset); previoustype=ELF32_R_TYPE(previoustype); if(previoustype!=5) { WARNING_MSG("R_MIPS_LO16 not preceded by R_MIPS_HI16 : %s",MIPS32_REL[previoustype]); } else { int32_t P2=seg.start._32+previousoffset,A2; memRead(P2,1,&A2); int32_t AHL=(A2<<16)+(short)(A); V=(A&0xFFFF0000)|((short)(AHL+S)&0xFFFF); //printf("V= %X,S=%X,A=%X,P=%X\n",V,S,A,P); memWrite(P,1,V); } break; default: if (type>32) { WARNING_MSG("Unknown type : %d, relocation impossible for element %d",type,i); } else { WARNING_MSG("Unknown type : %s(code : %d), relocation impossible for element %d",MIPS32_REL[type],type,i); } break; } i++; } //------------------------------------------------------ } del_scntab(section_tab); free( rel ); free( reloc_name ); free( ehdr ); }
static BOOL relocate(struct ElfObject *eo) { struct ELFSection *es; unsigned int shndx; for (shndx=0; shndx<(eo->nsects-1); shndx++) { if( (es = eo->sections[shndx]) != NULL ) { BOOL rela = (es->flags & ElfSecF_RELA) != 0; struct Elf32_Rela *r; int i; // kprintf("relocate(): relocating section %s " // "at 0x%08lx\n",es->name,es->address); for (i=0,r=es->relocs; i<es->nrel; i++,r++) { struct Elf32_Sym *sym = &eo->symtab[ELF32_R_SYM(r->r_info)]; long s = (long)eo->sections[sym->st_shndx]->address + sym->st_value; uint8 *p = (uint8 *)es->address + r->r_offset; switch (ELF32_R_TYPE(r->r_info)) { case R_PPC_NONE: break; case R_PPC_ADDR32: if (rela) *(long *)p = s + r->r_addend; else *(long *)p += s; break; case R_PPC_ADDR16: if (rela) *(short *)p = s + r->r_addend; else *(short *)p += s; break; case R_PPC_ADDR16_LO: if (rela) *(short *)p = (s + r->r_addend) & 0xffff; else *(short *)p = (s + *(short *)p) & 0xffff; break; case R_PPC_ADDR16_HI: if (rela) *(short *)p = (s + r->r_addend) >> 16; else *(short *)p = (s + *(short *)p) >> 16; break; case R_PPC_ADDR16_HA: if (rela) s += r->r_addend; else s += *(short *)p; *(short *)p = (s>>16) + ((s&0x8000) ? 1 : 0); break; case R_PPC_REL24: if (rela) { s = (s + r->r_addend) - (long)p; } else { if (*p & 0x02) s = (s + ((*(long *)p & 0x03fffffc) - 0x04000000)) - (long)p; else s = (s + (*(long *)p & 0x03fffffc)) - (long)p; } *(unsigned long *)p = (*(unsigned long *)p & 0xfc000003) | ((unsigned long)s & 0x03fffffc); break; case R_PPC_REL32: if (rela) *(long *)p = (s + r->r_addend) - (long)p; else *(long *)p = (s + *(long *)p) - (long)p; break; default: kprintf("Relocation type %s\nat %s+%ld referencing\n" "symbol %s+%ld\nis not supported.", reloc_name[ELF32_R_TYPE(r->r_info)],es->name,r->r_offset, eo->symnames+sym->st_name,sym->st_value); return (FALSE); } } }
int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) { unsigned int i; Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; DEBUGP("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { /* This is where to make the change */ uint32_t *loc = (uint32_t *)(sechdrs[sechdrs[relsec].sh_info].sh_addr + rela[i].r_offset); /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + ELF32_R_SYM(rela[i].r_info); uint32_t v = sym->st_value + rela[i].r_addend; switch (ELF32_R_TYPE(rela[i].r_info)) { case R_H8_DIR24R8: loc = (uint32_t *)((uint32_t)loc - 1); *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v); break; case R_H8_DIR24A8: if (ELF32_R_SYM(rela[i].r_info)) *loc += v; break; case R_H8_DIR32: case R_H8_DIR32A16: *loc += v; break; case R_H8_PCREL16: v -= (unsigned long)loc + 2; if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000) goto overflow; else *(unsigned short *)loc = v; break; case R_H8_PCREL8: v -= (unsigned long)loc + 1; if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80) goto overflow; else *(unsigned char *)loc = v; break; default: printk(KERN_ERR "module %s: Unknown relocation: %u\n", me->name, ELF32_R_TYPE(rela[i].r_info)); return -ENOEXEC; } } return 0; overflow: printk(KERN_ERR "module %s: relocation offset overflow: %08x\n", me->name, rela[i].r_offset); return -ENOEXEC; }
static BOOL scanElfSymbols(struct ElfObject *eo,struct PPCObjectInfo *info, BOOL relmode) /* Find an ELF symbol by its name or address and return all infos */ /* in the supplied PPCObjectInfo structure. Return FALSE if symbol */ /* doesn't exist. */ /* ATTENTION: PPCLibBase may be locked at that stage! */ { ULONG addr = info->Address; char *name = info->Name; //kprintf( "scanElfSymbols( 0x%08lx, 0x%08lx, %ld\n", eo, info, relmode ); if (relmode) { int i,j; struct ELFSection *es; struct Elf32_Rela *r; for (i=1; i<(eo->nsects-1); i++) { if( (es = eo->sections[i]) != NULL ) { for (j=0,r=es->relocs; j<es->nrel; j++,r++) { if (getsyminfo(eo,info,&eo->symtab[ELF32_R_SYM(r->r_info)])) { info->Address = (ULONG)es->address + r->r_offset; info->Type = PPCELFINFOTYPE_RELOC; info->SubType = (ULONG)ELF32_R_TYPE(r->r_info); if (info->Address == addr) { if (name) { if (!strcmp(name,info->Name)) return (TRUE); } else return (TRUE); } } } } } } else { struct Elf32_Sym *stab = eo->symtab; int i = eo->nsyms; while (--i) { //kprintf( "i=%ld\n", i ); if (getsyminfo(eo,info,++stab)) { if (!name) { if (info->Size) { if (addr>=info->Address && addr<(info->Address+info->Size)) return (TRUE); } else { if (addr == info->Address) return (TRUE); } } else { //kprintf( "comparing %s and %s\n", name,info->Name ); if (!strcmp(name,info->Name)) return (TRUE); } } } } return (FALSE); }
static void relocate(void * r) { ElfRelocateFunc * func; if (!relocs->file->elf64) { if (relocs->type == SHT_REL) { Elf32_Rel bf = *(Elf32_Rel *)r; if (relocs->file->byte_swap) { SWAP(bf.r_offset); SWAP(bf.r_info); } sym_index = ELF32_R_SYM(bf.r_info); reloc_type = ELF32_R_TYPE(bf.r_info); reloc_addend = 0; } else { Elf32_Rela bf = *(Elf32_Rela *)r; if (relocs->file->byte_swap) { SWAP(bf.r_offset); SWAP(bf.r_info); SWAP(bf.r_addend); } sym_index = ELF32_R_SYM(bf.r_info); reloc_type = ELF32_R_TYPE(bf.r_info); reloc_addend = bf.r_addend; } if (sym_index != STN_UNDEF) { Elf32_Sym bf = ((Elf32_Sym *)symbols->data)[sym_index]; if (symbols->file->byte_swap) { SWAP(bf.st_name); SWAP(bf.st_value); SWAP(bf.st_size); SWAP(bf.st_info); SWAP(bf.st_other); SWAP(bf.st_shndx); } switch (bf.st_shndx) { case SHN_ABS: sym_value = bf.st_value; break; case SHN_COMMON: str_exception(ERR_INV_FORMAT, "Common relocation record unsupported"); break; case SHN_UNDEF: str_exception(ERR_INV_FORMAT, "Invalid relocation record"); break; default: if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); if (symbols->file->type != ET_EXEC) { sym_value = (symbols->file->sections + bf.st_shndx)->addr + bf.st_value; } else { sym_value = bf.st_value; } *destination_section = symbols->file->sections + bf.st_shndx; break; } } } else { if (relocs->type == SHT_REL) { Elf64_Rel bf = *(Elf64_Rel *)r; if (relocs->file->byte_swap) { SWAP(bf.r_offset); SWAP(bf.r_info); } sym_index = ELF64_R_SYM(bf.r_info); reloc_type = ELF64_R_TYPE(bf.r_info); reloc_addend = 0; } else { Elf64_Rela bf = *(Elf64_Rela *)r; if (relocs->file->byte_swap) { SWAP(bf.r_offset); SWAP(bf.r_info); SWAP(bf.r_addend); } sym_index = ELF64_R_SYM(bf.r_info); reloc_type = ELF64_R_TYPE(bf.r_info); reloc_addend = bf.r_addend; } if (sym_index != STN_UNDEF) { Elf64_Sym bf = ((Elf64_Sym *)symbols->data)[sym_index]; if (symbols->file->byte_swap) { SWAP(bf.st_name); SWAP(bf.st_value); SWAP(bf.st_size); SWAP(bf.st_info); SWAP(bf.st_other); SWAP(bf.st_shndx); } switch (bf.st_shndx) { case SHN_ABS: sym_value = bf.st_value; break; case SHN_COMMON: str_exception(ERR_INV_FORMAT, "Common relocation record unsupported"); break; case SHN_UNDEF: str_exception(ERR_INV_FORMAT, "Invalid relocation record"); break; default: if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); if (symbols->file->type != ET_EXEC) { sym_value = (symbols->file->sections + bf.st_shndx)->addr + bf.st_value; } else { sym_value = bf.st_value; } *destination_section = symbols->file->sections + bf.st_shndx; break; } } } /* For executable file we don't need to apply the relocation, * all we need is destination_section */ if (section->file->type != ET_REL) return; func = elf_relocate_funcs; while (func->machine != section->file->machine) { if (func->func == NULL) str_exception(ERR_INV_FORMAT, "Unsupported ELF machine code"); func++; } func->func(); }
orl_return ElfCreateRelocs( elf_sec_handle orig_sec, elf_sec_handle reloc_sec ) { orl_return return_val; int num_relocs; int loop; unsigned char *rel; Elf32_Rel *rel32; Elf32_Rela *rela32; Elf64_Rel *rel64; Elf64_Rela *rela64; orl_reloc *o_rel; if( reloc_sec->assoc.reloc.symbol_table->assoc.sym.symbols == NULL ) { return_val = ElfCreateSymbolHandles( reloc_sec->assoc.reloc.symbol_table ); if( return_val != ORL_OKAY ) return( return_val ); } switch( reloc_sec->type ) { case ORL_SEC_TYPE_RELOCS: num_relocs = reloc_sec->size / reloc_sec->entsize; reloc_sec->assoc.reloc.relocs = (orl_reloc *)_ClientSecAlloc( reloc_sec, sizeof( orl_reloc ) * num_relocs ); if( reloc_sec->assoc.reloc.relocs == NULL ) return( ORL_OUT_OF_MEMORY ); rel = reloc_sec->contents; o_rel = (orl_reloc *)reloc_sec->assoc.reloc.relocs; for( loop = 0; loop < num_relocs; loop++ ) { o_rel->section = (orl_sec_handle)orig_sec; if( reloc_sec->elf_file_hnd->flags & ORL_FILE_FLAG_64BIT_MACHINE ) { rel64 = (Elf64_Rel *)rel; fix_rel64_byte_order( reloc_sec->elf_file_hnd, rel64 ); o_rel->symbol = (orl_symbol_handle)( reloc_sec->assoc.reloc.symbol_table->assoc.sym.symbols + rel64->r_info.u._32[I64HI32] ); o_rel->type = ElfConvertRelocType( reloc_sec->elf_file_hnd, (elf_reloc_type)rel64->r_info.u._32[I64LO32] ); o_rel->offset = (orl_sec_offset)rel64->r_offset.u._32[I64LO32]; } else { rel32 = (Elf32_Rel *)rel; fix_rel_byte_order( reloc_sec->elf_file_hnd, rel32 ); o_rel->symbol = (orl_symbol_handle)( reloc_sec->assoc.reloc.symbol_table->assoc.sym.symbols + ELF32_R_SYM( rel32->r_info ) ); o_rel->type = ElfConvertRelocType( reloc_sec->elf_file_hnd, ELF32_R_TYPE( rel32->r_info ) ); o_rel->offset = rel32->r_offset; } o_rel->addend = 0; o_rel->frame = NULL; rel += reloc_sec->entsize; o_rel++; } break; case ORL_SEC_TYPE_RELOCS_EXPADD: num_relocs = reloc_sec->size / reloc_sec->entsize; reloc_sec->assoc.reloc.relocs = (orl_reloc *)_ClientSecAlloc( reloc_sec, sizeof( orl_reloc ) * num_relocs ); if( reloc_sec->assoc.reloc.relocs == NULL ) return( ORL_OUT_OF_MEMORY ); rel = reloc_sec->contents; o_rel = (orl_reloc *)reloc_sec->assoc.reloc.relocs; for( loop = 0; loop < num_relocs; loop++ ) { o_rel->section = (orl_sec_handle)orig_sec; if( reloc_sec->elf_file_hnd->flags & ORL_FILE_FLAG_64BIT_MACHINE ) { rela64 = (Elf64_Rela *)rel; fix_rela64_byte_order( reloc_sec->elf_file_hnd, rela64 ); o_rel->symbol = (orl_symbol_handle)( reloc_sec->assoc.reloc.symbol_table->assoc.sym.symbols + rela64->r_info.u._32[I64HI32] ); o_rel->type = ElfConvertRelocType( reloc_sec->elf_file_hnd, (elf_reloc_type)rela64->r_info.u._32[I64LO32] ); o_rel->offset = (orl_sec_offset)rela64->r_offset.u._32[I64LO32]; o_rel->addend = (orl_reloc_addend)rela64->r_addend.u._32[I64LO32]; } else { rela32 = (Elf32_Rela *)rel; fix_rela_byte_order( reloc_sec->elf_file_hnd, rela32 ); o_rel->symbol = (orl_symbol_handle)( reloc_sec->assoc.reloc.symbol_table->assoc.sym.symbols + ELF32_R_SYM( rela32->r_info ) ); o_rel->type = ElfConvertRelocType( reloc_sec->elf_file_hnd, ELF32_R_TYPE( rela32->r_info ) ); o_rel->offset = rela32->r_offset; o_rel->addend = rela32->r_addend; } o_rel->frame = NULL; rel += reloc_sec->entsize; o_rel++; } break; default: break; } return( ORL_OKAY ); }
static uint64_t Elf32_r_type(Elf32_Word r_info) { return ELF32_R_TYPE(r_info); }
int updateStubs(sceScns_t *sceScns, FILE *fp, const scn_t *scns, const seg_t *segs, const char *strtab, Elf32_Sym *symtab) { union { uint8_t size; sce_libgen_mark_head head; sce_libgen_mark_stub stub; } *p; sce_libgen_mark_stub *stubMark; sceLib_stub *stubHeads; Psp2_Rela *relaFstubEnt, *relaVstubEnt, *relaStubEnt; Elf32_Off fnidOffset, fstubOffset, vnidOffset, vstubOffset; Elf32_Off offset, stubOffset; Elf32_Rel *rel, *relMarkEnt; Elf32_Sym *sym; Elf32_Word i, type, stubMarkAddr, *fnidEnt, *vnidEnt; Elf32_Half symseg; Elf32_Addr addend; int res, impFunc, impVar; if (sceScns == NULL || fp == NULL || scns == NULL || segs == NULL || strtab == NULL || symtab == NULL) { return EINVAL; } sceScns->relStub->content = malloc(sceScns->relStub->shdr.sh_size); if (sceScns->relStub->content == NULL) { perror(strtab + sceScns->relStub->shdr.sh_name); return errno; } sceScns->stub->content = malloc(sceScns->stub->shdr.sh_size); if (sceScns->stub->content == NULL) { perror(strtab + sceScns->stub->shdr.sh_name); return errno; } res = loadScn(fp, sceScns->mark, strtab + sceScns->mark->shdr.sh_name); if (res) return res; res = loadScn(fp, sceScns->relMark, strtab + sceScns->relMark->shdr.sh_name); if (res) return res; if (sceScns->fnid != NULL && sceScns->fstub != NULL && sceScns->relFstub != NULL) { impFunc = 1; sceScns->relFstub->content = malloc(sceScns->relFstub->shdr.sh_size); if (sceScns->relFstub->content == NULL) { perror(strtab + sceScns->relFstub->shdr.sh_name); return errno; } sceScns->fnid->content = malloc(sceScns->fnid->shdr.sh_size); if (sceScns->fnid->content == NULL) { perror(strtab + sceScns->fnid->shdr.sh_name); return errno; } relaFstubEnt = sceScns->relFstub->content; fnidEnt = sceScns->fnid->content; fnidOffset = sceScns->fnid->segOffset; fstubOffset = sceScns->fstub->segOffset; } else impFunc = 0; if (sceScns->vnid != NULL && sceScns->vstub != NULL && sceScns->relVstub != NULL) { impVar = 1; sceScns->relVstub->content = malloc(sceScns->relVstub->shdr.sh_size); if (sceScns->relVstub->content == NULL) { perror(strtab + sceScns->relVstub->shdr.sh_name); return errno; } sceScns->vnid->content = malloc(sceScns->vnid->shdr.sh_size); if (sceScns->vnid->content == NULL) { perror(strtab + sceScns->vnid->shdr.sh_name); return errno; } relaVstubEnt = sceScns->relVstub->content; vnidEnt = sceScns->vnid->content; vnidOffset = sceScns->vnid->segOffset; vstubOffset = sceScns->vstub->segOffset; } else impVar = 0; relaStubEnt = sceScns->relStub->content; stubHeads = sceScns->stub->content; p = sceScns->mark->content; stubOffset = sceScns->stub->segOffset; offset = 0; while (offset < sceScns->mark->shdr.sh_size) { if (p->size == sizeof(sce_libgen_mark_head)) { stubHeads->size = sizeof(sceLib_stub); stubHeads->ver = 1; stubHeads->flags = 0; stubHeads->nid = p->head.nid; // Resolve name rel = findRelByOffset(sceScns->relMark, sceScns->mark->shdr.sh_addr + offset + offsetof(sce_libgen_mark_head, name), strtab); if (rel == NULL) return errno; type = ELF32_R_TYPE(rel->r_info); sym = symtab + ELF32_R_SYM(rel->r_info); symseg = scns[sym->st_shndx].phndx; PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, symseg); PSP2_R_SET_TYPE(relaStubEnt, type); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, name)); PSP2_R_SET_ADDEND(relaStubEnt, (type == R_ARM_ABS32 || type == R_ARM_TARGET1 ? sym->st_value : p->head.name) - segs[symseg].phdr.p_vaddr); relaStubEnt++; if (impFunc) { // Resolve function NID table PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, sceScns->fnid->phndx); PSP2_R_SET_TYPE(relaStubEnt, R_ARM_ABS32); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, funcNids)); PSP2_R_SET_ADDEND(relaStubEnt, fnidOffset); relaStubEnt++; // Resolve function stub table PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, sceScns->fstub->phndx); PSP2_R_SET_TYPE(relaStubEnt, R_ARM_ABS32); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, funcStubs)); PSP2_R_SET_ADDEND(relaStubEnt, fstubOffset); relaStubEnt++; } else { stubHeads->funcNids = 0; stubHeads->funcStubs = 0; } if (impVar) { // Resolve variable NID table PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, sceScns->vnid->phndx); PSP2_R_SET_TYPE(relaStubEnt, R_ARM_ABS32); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, varNids)); PSP2_R_SET_ADDEND(relaStubEnt, vnidOffset); relaStubEnt++; // Resolve variable stub table PSP2_R_SET_SHORT(relaStubEnt, 0); PSP2_R_SET_SYMSEG(relaStubEnt, sceScns->vstub->phndx); PSP2_R_SET_TYPE(relaStubEnt, R_ARM_ABS32); PSP2_R_SET_DATSEG(relaStubEnt, sceScns->stub->phndx); PSP2_R_SET_OFFSET(relaStubEnt, stubOffset + offsetof(sceLib_stub, varStubs)); PSP2_R_SET_ADDEND(relaStubEnt, vstubOffset); relaStubEnt++; } else { stubHeads->varNids = 0; stubHeads->varStubs = 0; } // TODO: Support other types stubHeads->unkNids = 0; stubHeads->unkStubs = 0; // Resolve nids and stubs stubHeads->funcNum = 0; stubHeads->varNum = 0; stubHeads->unkNum = 0; relMarkEnt = sceScns->relMark->content; for (i = 0; i < sceScns->relMark->orgSize / sizeof(Elf32_Rel); i++) { sym = symtab + ELF32_R_SYM(relMarkEnt->r_info); type = ELF32_R_TYPE(relMarkEnt->r_info); if (type == R_ARM_ABS32 || type == R_ARM_TARGET1) { if (scns + sym->st_shndx != sceScns->mark) goto cont; addend = *(Elf32_Word *)((uintptr_t)sceScns->mark->content + relMarkEnt->r_offset - sceScns->mark->shdr.sh_addr); } else addend = sym->st_value; if (addend != sceScns->mark->shdr.sh_addr + offset) goto cont; stubMarkAddr = relMarkEnt->r_offset - offsetof(sce_libgen_mark_stub, head); stubMark = (void *)((uintptr_t)sceScns->mark->content + stubMarkAddr - sceScns->mark->shdr.sh_addr); if (impFunc && stubMark->unk[0] == 1) { res = addStub(relaFstubEnt, sceScns->fstub, fnidEnt, sceScns->relMark, sceScns->mark, fstubOffset, stubMarkAddr, stubMark, scns, segs, strtab, symtab); if (res) return res; relaFstubEnt++; fnidEnt++; fstubOffset += sizeof(Elf32_Addr); fnidOffset += sizeof(Elf32_Word); stubHeads->funcNum++; } else if (impVar) { res = addStub(relaVstubEnt, sceScns->vstub, vnidEnt, sceScns->relMark, sceScns->mark, vstubOffset, stubMarkAddr, stubMark, scns, segs, strtab, symtab); if (res) return res; relaVstubEnt++; vnidEnt++; vstubOffset += sizeof(Elf32_Addr); vnidOffset += sizeof(Elf32_Word); stubHeads->varNum++; } cont: relMarkEnt++; } stubOffset += sizeof(sceLib_stub); stubHeads++; } else if (p->size == 0) { printf("%s: Invalid mark\n", strtab + sceScns->mark->shdr.sh_name); return EILSEQ; } offset += p->size; p = (void *)((uintptr_t)p + p->size); } if (impFunc) sceScns->relFstub->shdr.sh_type = SHT_PSP2_RELA; if (impVar) sceScns->relVstub->shdr.sh_type = SHT_PSP2_RELA; sceScns->relStub->shdr.sh_type = SHT_PSP2_RELA; return 0; }
int gelf_update_rela(Elf_Data *d, int ndx, GElf_Rela *dr) { int ec; Elf *e; Elf_Scn *scn; Elf32_Rela *rela32; Elf64_Rela *rela64; size_t msz; uint32_t sh_type; if (d == NULL || ndx < 0 || dr == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } msz = _libelf_msize(ELF_T_RELA, ec, e->e_version); assert(msz > 0); if (msz * ndx >= d->d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (0); } if (ec == ELFCLASS32) { rela32 = (Elf32_Rela *) d->d_buf + ndx; LIBELF_COPY_U32(rela32, dr, r_offset); if (ELF64_R_SYM(dr->r_info) > ELF32_R_SYM(~0UL) || ELF64_R_TYPE(dr->r_info) > ELF32_R_TYPE(~0U)) { LIBELF_SET_ERROR(RANGE, 0); return (0); } rela32->r_info = ELF32_R_INFO(ELF64_R_SYM(dr->r_info), ELF64_R_TYPE(dr->r_info)); LIBELF_COPY_S32(rela32, dr, r_addend); } else { rela64 = (Elf64_Rela *) d->d_buf + ndx; *rela64 = *dr; } return (1); }
GElf_Rela * gelf_getrela(Elf_Data *ed, int ndx, GElf_Rela *dst) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; Elf32_Rela *rela32; Elf64_Rela *rela64; struct _Libelf_Data *d; d = (struct _Libelf_Data *) ed; if (d == NULL || ndx < 0 || dst == NULL || (scn = d->d_scn) == NULL || (e = scn->s_elf) == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_RELA) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_RELA, ec, e->e_version); assert(msz > 0); assert(ndx >= 0); if (msz * (size_t) ndx >= d->d_data.d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } if (ec == ELFCLASS32) { rela32 = (Elf32_Rela *) d->d_data.d_buf + ndx; dst->r_offset = (Elf64_Addr) rela32->r_offset; dst->r_info = ELF64_R_INFO( (Elf64_Xword) ELF32_R_SYM(rela32->r_info), ELF32_R_TYPE(rela32->r_info)); dst->r_addend = (Elf64_Sxword) rela32->r_addend; } else { rela64 = (Elf64_Rela *) d->d_data.d_buf + ndx; *dst = *rela64; } return (dst); }
//------------------------------------------------------------------- static void avr_create_new_rela_text_data(Elf_Data* nedata, Elf* elf, Elf32_Shdr *nshdr, uint32_t startaddr, bblklist_t* blist) { Elf_Scn* symscn; Elf32_Shdr* symshdr; Elf_Data *symdata; Elf32_Sym* sym; Elf32_Rela *nerela; int numRecs, numSyms, i, textNdx; symscn = getELFSymbolTableScn(elf); symshdr = elf32_getshdr(symscn); symdata = NULL; symdata = elf_getdata(symscn, symdata); sym = (Elf32_Sym*)symdata->d_buf; numSyms = symdata->d_size/symshdr->sh_entsize; textNdx = -1; DEBUG("Locating symbol table index for .text\n"); DEBUG("Rela Info: %d\n", (int)nshdr->sh_info); for (i = 0; i < numSyms; i++){ #ifdef DBGMODE ElfPrintSymbol(sym); DEBUG("\n"); #endif if ((sym->st_shndx == nshdr->sh_info) && (ELF32_ST_TYPE(sym->st_info) == STT_SECTION)){ textNdx = i; break; } sym++; } if (-1 == textNdx){ fprintf(stderr, "avr_create_new_rela_text_data: Could not locate .text section symbol\n"); exit(EXIT_FAILURE); } DEBUG(".text symbol table index: %d\n", textNdx); DEBUG("Fixing .rela.text entries ...\n"); nerela = (Elf32_Rela*)nedata->d_buf; numRecs = nedata->d_size/nshdr->sh_entsize; for (i = 0; i < numRecs; i++){ // Change offset field for all records .rela.text // Change addend if symbol field is .text if (nerela->r_offset > startaddr){ uint32_t oldaddr = nerela->r_offset; nerela->r_offset = find_updated_address(blist, oldaddr); DEBUG("Entry: %d Old Offset: 0x%x New Offset: 0x%x\n", i, (int)oldaddr, (int)nerela->r_offset); } if (ELF32_R_SYM(nerela->r_info) == textNdx){ if (nerela->r_addend > startaddr){ uint32_t old_addend = nerela->r_addend; nerela->r_addend = find_updated_address(blist, old_addend); // If relocation type is of R_AVR_CALL, then modify addend. // The addend should point to two words before the actual function // so as to invoke the call to the safe stack save function if (ELF32_R_TYPE(nerela->r_info) == R_AVR_CALL){ // Check if it is indeed a call instruction before changing the addend avr_instr_t instr; instr = find_instr_at_new_addr(blist, nerela->r_offset); if ((instr.rawVal & OP_TYPE10_MASK) == OP_CALL){ nerela->r_addend -= sizeof(avr_instr_t) * 2; DEBUG("Internal call target -> Modify addend to include safe stack.\n"); } else DEBUG("Internal jmp target -> No further modifications.\n"); } if (ELF32_R_TYPE(nerela->r_info) == R_AVR_13_PCREL){ // Check if it is indeed a call instruction before changing the addend avr_instr_t instr; instr = find_instr_at_new_addr(blist, nerela->r_offset); if ((instr.rawVal & OP_TYPE17_MASK) == OP_RCALL){ nerela->r_addend -= sizeof(avr_instr_t) * 2; DEBUG("Internal rcall target -> Modify addend to include safe stack.\n"); } else DEBUG("Internal rjmp target -> No further modifications.\n"); } DEBUG("Entry: %d Old Addend: 0x%x New Addend: 0x%x\n", i, (int)old_addend, nerela->r_addend); } } nerela++; } // Add new relocation records basicblk_t* cblk; Elf32_Rela *newrela; int numnewrecs; int newcalljmpflag; newrela = (Elf32_Rela*)malloc(sizeof(Elf32_Rela) * MAX_NEW_RELA); numnewrecs = 0; for (cblk = blist->blk_st; cblk != NULL; cblk = (basicblk_t*)cblk->link.next){ avr_instr_t* instr; int numinstr; uint32_t thisinstroffset; numinstr = cblk->newsize/sizeof(avr_instr_t); if (NULL == cblk->branch) continue; if ((cblk->flag & TWO_WORD_INSTR_FLAG) == 0) continue; instr = &(cblk->newinstr[numinstr - 2]); thisinstroffset = cblk->newaddr + cblk->newsize - 2 * sizeof(avr_instr_t); if (((instr->rawVal & OP_TYPE10_MASK) != OP_JMP) && ((instr->rawVal & OP_TYPE10_MASK) != OP_CALL)){ fprintf(stderr, "avr_create_new_rela_text_data: Basic block flag corrupted\n"); exit(EXIT_FAILURE); } // Check if there is a rela record with the current offset nerela = (Elf32_Rela*)nedata->d_buf; newcalljmpflag = 1; for (i = 0; i < numRecs; i++){ if (nerela->r_offset == thisinstroffset){ DEBUG("Curr New Offset: 0x%d -- Found\n", thisinstroffset); newcalljmpflag = 0; break; } nerela++; } if (newcalljmpflag == 0) continue; // Add a new relocation records // r_added = .text + branch target address newrela[numnewrecs].r_info = ELF32_R_INFO(textNdx, R_AVR_CALL); newrela[numnewrecs].r_offset = thisinstroffset; newrela[numnewrecs].r_addend = (cblk->branch)->newaddr; DEBUG("New Rela: Offset 0x%x Addend 0x%x\n", newrela[numnewrecs].r_offset, newrela[numnewrecs].r_addend); numnewrecs++; } DEBUG("New Rela Recs: %d\n", numnewrecs); uint8_t *new_d_buf, *ptr_d_buf; new_d_buf = (uint8_t*)malloc(numnewrecs * sizeof(Elf32_Rela) + nedata->d_size); memcpy(new_d_buf, nedata->d_buf, nedata->d_size); ptr_d_buf = new_d_buf + nedata->d_size; memcpy(ptr_d_buf, newrela, sizeof(Elf32_Rela)*numnewrecs); free(nedata->d_buf); free(newrela); nedata->d_buf = new_d_buf; nedata->d_size += sizeof(Elf32_Rela) * numnewrecs; return; }
/* * Dump the program and section headers. */ static void dmp_prog_sec( unsigned_32 start ) /*******************************************/ { Elf32_Phdr elf_prog; Elf32_Shdr elf_sec; unsigned_32 offset; char *string_table; int i; // grab the string table, if it exists if( Options_dmp & DEBUG_INFO ) { set_dwarf( start ); } if( Elf_head.e_shstrndx ) { offset = Elf_head.e_shoff + Elf_head.e_shstrndx * Elf_head.e_shentsize+start; Wlseek( offset ); Wread( &elf_sec, sizeof( Elf32_Shdr ) ); swap_shdr( &elf_sec ); string_table = Wmalloc( elf_sec.sh_size ); Wlseek( elf_sec.sh_offset + start ); Wread( string_table, elf_sec.sh_size ); } else { string_table = 0; } if( Elf_head.e_phnum ) { Banner( "ELF Program Header" ); offset = Elf_head.e_phoff + start; for( i = 0; i < Elf_head.e_phnum; i++ ) { Wdputs( " Program Header #" ); Putdec( i + 1 ); Wdputslc( "\n" ); if( start != 0 ) { Wdputs("File Offset:"); Puthex( offset, 8 ); Wdputslc( "\n"); } Wlseek( offset ); Wread( &elf_prog, sizeof( Elf32_Phdr ) ); swap_phdr( &elf_prog ); // elf_prog.p_offset += start; //Relocate file pos offset += sizeof( Elf32_Phdr ); Data_count++; dmp_prog_type( elf_prog.p_type ); Dump_header( &elf_prog, elf_prog_msg ); dmp_prog_flgs( elf_prog.p_flags ); if( Options_dmp & (DOS_SEG_DMP | OS2_SEG_DMP) ) { if( Segspec == 0 || Segspec == Data_count ) { Dmp_seg_data( elf_prog.p_offset + start, elf_prog.p_filesz ); } } else if( elf_prog.p_type == PT_NOTE ) { dmp_sec_note( elf_prog.p_offset + start, elf_prog.p_filesz ); } Wdputslc( "\n" ); } } if( Elf_head.e_shnum ) { Banner( "ELF Section Header" ); offset = Elf_head.e_shoff+start; for( i = 0; i < Elf_head.e_shnum; i++ ) { Wlseek( offset ); Wread( &elf_sec, sizeof( Elf32_Shdr ) ); swap_shdr( &elf_sec ); // elf_sec.sh_offset += start; // relocate file pos Wdputs( " Section Header #" ); Putdec( i ); if( string_table ) { Wdputs( " \"" ); Wdputs( &(string_table[elf_sec.sh_name]) ); Wdputs( "\"" ); } Wdputslc( "\n" ); if( start != 0 ) { Wdputs( "File Offset:" ); Puthex( offset, 8 ); Wdputslc( "\n" ); } dmp_sec_type( elf_sec.sh_type ); Dump_header( &elf_sec.sh_name, elf_sec_msg ); dmp_sec_flgs( elf_sec.sh_flags ); if( Options_dmp & FIX_DMP ) { if( elf_sec.sh_type==SHT_REL || elf_sec.sh_type==SHT_RELA ) { Elf32_Shdr rel_sec; Elf32_Rela elf_rela; int loc, ctr, rel_size; Wdputs( "relocation information for section #" ); Putdec( elf_sec.sh_info ); Wlseek( Elf_head.e_shoff + start + Elf_head.e_shentsize * elf_sec.sh_info ); Wread( &rel_sec, sizeof( Elf32_Shdr ) ); swap_shdr( &rel_sec ); if( string_table ) { Wdputs( " \"" ); Wdputs( &string_table[rel_sec.sh_name] ); Wdputs( "\"" ); } else { Wdputs( " no_name (no associated string table)" ); } Wdputslc( ":\n" ); Wdputs( "symbol index refers to section #" ); Putdec( elf_sec.sh_link ); Wdputslc( "\n" ); Wdputslc( "Offset Sym Idx Addend Type Offset Sym Idx Addend Type\n" ); rel_size = (elf_sec.sh_type == SHT_REL ? sizeof( Elf32_Rel ) : sizeof( Elf32_Rela )); for( loc = 0, ctr = 0; loc < elf_sec.sh_size; loc += rel_size, ctr++ ) { Wlseek( elf_sec.sh_offset + start + loc ); Wread( &elf_rela, rel_size ); Puthex( elf_rela.r_offset, 8 ); Wdputc( ' ' ); Puthex( ELF32_R_SYM( elf_rela.r_info ), 8 ); Wdputc( ' ' ); if( elf_sec.sh_type == SHT_RELA ) { Puthex( elf_rela.r_addend, 8 ); } else { Wdputs( "n/a " ); } Wdputc( ' ' ); Puthex( ELF32_R_TYPE( elf_rela.r_info ), 2 ); if( ctr % 2 == 1 ) { Wdputslc( "\n" ); } else { Wdputs( " " ); } } if( ctr % 2 != 0 ) { Wdputslc( "\n" ); } } } if( Options_dmp & DEBUG_INFO ) { Wdputslc( "\n" ); if( string_table ) { dmp_sec_data( &(string_table[elf_sec.sh_name]), elf_sec.sh_type, elf_sec.sh_offset+start, elf_sec.sh_size ); } else { dmp_sec_data( NULL, elf_sec.sh_type, elf_sec.sh_offset+start, elf_sec.sh_size ); } } else if( Options_dmp & OS2_SEG_DMP ) { if( elf_sec.sh_size && elf_sec.sh_type != SHT_NOBITS ) { Wdputslc( "Section dump:\n" ); Dmp_seg_data( elf_sec.sh_offset + start, elf_sec.sh_size ); } } Wdputslc( "\n" ); offset += Elf_head.e_shentsize; } } if( string_table ) { free( string_table ); } }
//--------------------------------------------------------------------- static Melf_Data* convRelaScn(Elf_Scn* relascn, symbol_map_t* symmap) { Elf32_Shdr *shdr; Elf_Data *edata; Elf32_Rela *erela; Melf_Rela *mrela; int numRecs, i; Melf_Data* mreladata; // Get the ELF Rela Section Header if ((shdr = elf32_getshdr(relascn)) == NULL){ fprintf(stderr, "Error reading rela section header.\n"); return NULL; } // Verify the ELF RELA section type if (SHT_RELA != shdr->sh_type){ fprintf(stderr, "Not a relocation section. \n"); return NULL; } // Get the ELF rela table edata = NULL; while ((edata = elf_getdata(relascn, edata)) != NULL){ if (ELF_T_RELA == edata->d_type){ erela = (Elf32_Rela*)edata->d_buf; numRecs = edata->d_size/shdr->sh_entsize; // Allocating memory for MELF rela table if ((mreladata = malloc(sizeof(Melf_Data))) == NULL){ fprintf(stderr, "Error allocating memory."); return NULL; } if ((mreladata->d_buf = malloc(sizeof(Melf_Rela) * numRecs)) == NULL){ fprintf(stderr, "Error allocating memory."); return NULL; } // Init the MELF rela table mreladata->d_numData = 0; mreladata->d_type = ELF_T_RELA; mrela = (Melf_Rela*)mreladata->d_buf; for (i = 0; i < numRecs; i++){ int esymndx; int msymndx; esymndx = ELF32_R_SYM(erela[i].r_info); // Get MELF Symbol Index if ((msymndx = addMelfSymbol(symmap, esymndx)) == -1){ fprintf(stderr, "Invalid symbol index in rela.\n"); return NULL; } // Convert ELF Rela record to MELF Rela record mrela[mreladata->d_numData].r_offset = (Melf_Addr)erela[i].r_offset; mrela[mreladata->d_numData].r_symbol = msymndx; mrela[mreladata->d_numData].r_type = (unsigned char)ELF32_R_TYPE(erela[i].r_info); mrela[mreladata->d_numData].r_addend = (Melf_Sword) erela[i].r_addend; // mreladata->d_numData++; } mreladata->d_size = mreladata->d_numData * sizeof(Melf_Rela); symmap->mreladata = mreladata; return mreladata; } } symmap->mreladata = NULL; fprintf(stderr, "Section does not contain any rela records.\n"); return NULL; }
int main(int argc, char *argv[]) { int ifd, ofd; u_int mid, flags, magic; void *image; Elf32_Ehdr *eh; Elf32_Shdr *sh; char *shstrtab; Elf32_Sym *symtab; char *strtab; int eval(Elf32_Sym *, u_int32_t *); u_int32_t *lptr; int i, l, delta; u_int8_t *rpo; u_int32_t oldaddr, addrdiff; u_int32_t tsz, dsz, bsz, trsz, drsz, entry, relver; u_int32_t pcrelsz, r32sz; int sumsize = 16; int c; u_int32_t *sect_offset; int undefsyms; uint32_t tmp32; uint16_t tmp16; progname = argv[0]; /* insert getopt here, if needed */ while ((c = getopt(argc, argv, "dFS")) != -1) switch(c) { case 'F': sumsize = 2; break; case 'S': /* Dynamically size second-stage boot */ sumsize = 0; break; case 'd': debug = 1; break; default: usage(); } argv += optind; argc -= optind; if (argc < 2) usage(); ifd = open(argv[0], O_RDONLY, 0); if (ifd < 0) err(1, "Can't open %s", argv[0]); image = mmap(0, 65536, PROT_READ, MAP_FILE|MAP_PRIVATE, ifd, 0); if (image == 0) err(1, "Can't mmap %s", argv[1]); eh = (Elf32_Ehdr *)image; /* XXX endianness */ dprintf(("%04x sections, offset %08x\n", htobe16(eh->e_shnum), htobe32(eh->e_shoff))); if (htobe16(eh->e_type) != ET_REL) errx(1, "%s isn't a relocatable file, type=%d", argv[0], htobe16(eh->e_type)); if (htobe16(eh->e_machine) != EM_68K) errx(1, "%s isn't M68K, machine=%d", argv[0], htobe16(eh->e_machine)); /* Calculate sizes from section headers. */ tsz = dsz = bsz = trsz = pcrelsz = r32sz = 0; sh = (Elf32_Shdr *)(image + htobe32(eh->e_shoff)); shstrtab = (char *)(image + htobe32(sh[htobe16(eh->e_shstrndx)].sh_offset)); symtab = NULL; /*XXX*/ strtab = NULL; /*XXX*/ dprintf((" name type flags addr offset size align\n")); for (i = 0; i < htobe16(eh->e_shnum); ++i) { u_int32_t sh_size; dprintf( ("%2d: %08x %-16s %08x %08x %08x %08x %08x %08x\n", i, htobe32(sh[i].sh_name), shstrtab + htobe32(sh[i].sh_name), htobe32(sh[i].sh_type), htobe32(sh[i].sh_flags), htobe32(sh[i].sh_addr), htobe32(sh[i].sh_offset), htobe32(sh[i].sh_size), htobe32(sh[i].sh_addralign))); sh_size = (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & -htobe32(sh[i].sh_addralign); /* If section allocates memory, add to text, data, or bss size. */ if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { if (htobe32(sh[i].sh_type) == SHT_PROGBITS) { if (htobe32(sh[i].sh_flags) & SHF_WRITE) dsz += sh_size; else tsz += sh_size; } else bsz += sh_size; /* If it's relocations, add to relocation count */ } else if (htobe32(sh[i].sh_type) == SHT_RELA) { trsz += htobe32(sh[i].sh_size); } /* Check for SHT_REL? */ /* Get symbol table location. */ else if (htobe32(sh[i].sh_type) == SHT_SYMTAB) { symtab = (Elf32_Sym *)(image + htobe32(sh[i].sh_offset)); } else if (strcmp(".strtab", shstrtab + htobe32(sh[i].sh_name)) == 0) { strtab = image + htobe32(sh[i].sh_offset); } } dprintf(("tsz = 0x%x, dsz = 0x%x, bsz = 0x%x, total 0x%x\n", tsz, dsz, bsz, tsz + dsz + bsz)); if (trsz == 0) errx(1, "%s has no relocation records.", argv[0]); dprintf(("%d relocs\n", trsz/12)); if (sumsize == 0) { /* * XXX overly cautious, but this guarantees that 16bit * pc offsets and our relocs always work. */ bbsize = 32768; if (bbsize < (tsz + dsz + bsz)) { err(1, "%s: too big.", argv[0]); } sumsize = bbsize / 512; } buffer = malloc(bbsize); relbuf = (u_int32_t *)malloc(bbsize); if (buffer == NULL || relbuf == NULL) err(1, "Unable to allocate memory\n"); /* * We have one contiguous area allocated by the ROM to us. */ if (tsz+dsz+bsz > bbsize) errx(1, "%s: resulting image too big %d+%d+%d=%d", argv[0], tsz, dsz, bsz, tsz + dsz + bsz); memset(buffer, 0, bbsize); /* Allocate and load loadable sections */ sect_offset = (u_int32_t *)malloc(htobe16(eh->e_shnum) * sizeof(u_int32_t)); for (i = 0, l = 0; i < htobe16(eh->e_shnum); ++i) { if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { dprintf(("vaddr 0x%04x size 0x%04x offset 0x%04x section %s\n", l, htobe32(sh[i].sh_size), htobe32(sh[i].sh_offset), shstrtab + htobe32(sh[i].sh_name))); if (htobe32(sh[i].sh_type) == SHT_PROGBITS) memcpy(buffer + l, image + htobe32(sh[i].sh_offset), htobe32(sh[i].sh_size)); sect_offset[i] = l; l += (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & -htobe32(sh[i].sh_addralign); } } /* * Hm. This tool REALLY should understand more than one * relocator version. For now, check that the relocator at * the image start does understand what we output. */ relver = htobe32(*(u_int32_t *)(buffer + 4)); switch (relver) { default: errx(1, "%s: unrecognized relocator version %d", argv[0], relver); /*NOTREACHED*/ case RELVER_RELATIVE_BYTES: rpo = buffer + bbsize - 1; delta = -1; break; case RELVER_RELATIVE_BYTES_FORWARD: rpo = buffer + tsz + dsz; delta = +1; *(u_int16_t *)(buffer + 14) = htobe16(tsz + dsz); break; } if (symtab == NULL) errx(1, "No symbol table found"); /* * Link sections and generate relocation data * Nasty: .text, .rodata, .data, .bss sections are not linked * Symbol table values relative to start of sections. * For each relocation entry: * Symbol value needs to be calculated: value + section offset * Image data adjusted to calculated value of symbol + addend * Add relocation table entry for 32-bit relocatable values * PC-relative entries will be absolute and don't need relocation */ undefsyms = 0; for (i = 0; i < htobe16(eh->e_shnum); ++i) { int n; Elf32_Rela *ra; u_int8_t *base; if (htobe32(sh[i].sh_type) != SHT_RELA) continue; base = NULL; if (strncmp(shstrtab + htobe32(sh[i].sh_name), ".rela", 5) != 0) err(1, "bad relocation section name %s", shstrtab + htobe32(sh[i].sh_name)); for (n = 0; n < htobe16(eh->e_shnum); ++n) { if (strcmp(shstrtab + htobe32(sh[i].sh_name) + 5, shstrtab + htobe32(sh[n].sh_name)) != 0) continue; base = buffer + sect_offset[n]; break; } if (base == NULL) errx(1, "Can't find section for reloc %s", shstrtab + htobe32(sh[i].sh_name)); ra = (Elf32_Rela *)(image + htobe32(sh[i].sh_offset)); for (n = 0; n < htobe32(sh[i].sh_size); n += sizeof(Elf32_Rela), ++ra) { Elf32_Sym *s; int value; s = &symtab[ELF32_R_SYM(htobe32(ra->r_info))]; if (s->st_shndx == ELF_SYM_UNDEFINED) { fprintf(stderr, "Undefined symbol: %s\n", strtab + s->st_name); ++undefsyms; } value = htobe32(ra->r_addend) + eval(s, sect_offset); dprintf(("reloc %04x info %04x (type %d sym %d) add 0x%x val %x\n", htobe32(ra->r_offset), htobe32(ra->r_info), ELF32_R_TYPE(htobe32(ra->r_info)), ELF32_R_SYM(htobe32(ra->r_info)), htobe32(ra->r_addend), value)); switch (ELF32_R_TYPE(htobe32(ra->r_info))) { case R_68K_32: tmp32 = htobe32(value); memcpy(base + htobe32(ra->r_offset), &tmp32, sizeof(tmp32)); relbuf[r32sz++] = (base - buffer) + htobe32(ra->r_offset); break; case R_68K_PC32: ++pcrelsz; tmp32 = htobe32(value - htobe32(ra->r_offset)); memcpy(base + htobe32(ra->r_offset), &tmp32, sizeof(tmp32)); break; case R_68K_PC16: ++pcrelsz; value -= htobe32(ra->r_offset); if (value < -0x8000 || value > 0x7fff) errx(1, "PC-relative offset out of range: %x\n", value); tmp16 = htobe16(value); memcpy(base + htobe32(ra->r_offset), &tmp16, sizeof(tmp16)); break; default: errx(1, "Relocation type %d not supported", ELF32_R_TYPE(htobe32(ra->r_info))); } } } dprintf(("%d PC-relative relocations, %d 32-bit relocations\n", pcrelsz, r32sz)); printf("%d absolute reloc%s found, ", r32sz, r32sz==1?"":"s"); i = r32sz; if (i > 1) heapsort(relbuf, r32sz, 4, intcmp); oldaddr = 0; for (--i; i>=0; --i) { dprintf(("0x%04x: ", relbuf[i])); lptr = (u_int32_t *)&buffer[relbuf[i]]; addrdiff = relbuf[i] - oldaddr; dprintf(("(0x%04x, 0x%04x): ", *lptr, addrdiff)); if (addrdiff > 255) { *rpo = 0; if (delta > 0) { ++rpo; *rpo++ = (relbuf[i] >> 8) & 0xff; *rpo++ = relbuf[i] & 0xff; dprintf(("%02x%02x%02x\n", rpo[-3], rpo[-2], rpo[-1])); } else {
static TEE_Result elf_process_rel(struct elf_load_state *state, size_t rel_sidx, vaddr_t vabase) { Elf32_Shdr *shdr = state->shdr; Elf32_Rel *rel; Elf32_Rel *rel_end; size_t sym_tab_idx; Elf32_Sym *sym_tab = NULL; size_t num_syms = 0; if (shdr[rel_sidx].sh_entsize != sizeof(Elf32_Rel)) return TEE_ERROR_BAD_FORMAT; sym_tab_idx = shdr[rel_sidx].sh_link; if (sym_tab_idx) { if (sym_tab_idx >= state->ehdr->e_shnum) return TEE_ERROR_BAD_FORMAT; if (shdr[sym_tab_idx].sh_entsize != sizeof(Elf32_Sym)) return TEE_ERROR_BAD_FORMAT; /* Check the address is inside TA memory */ if (shdr[sym_tab_idx].sh_addr > state->vasize || (shdr[sym_tab_idx].sh_addr + shdr[sym_tab_idx].sh_size) > state->vasize) return TEE_ERROR_BAD_FORMAT; sym_tab = (Elf32_Sym *)(vabase + shdr[sym_tab_idx].sh_addr); if (!TEE_ALIGNMENT_IS_OK(sym_tab, Elf32_Sym)) return TEE_ERROR_BAD_FORMAT; num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf32_Sym); } /* Check the address is inside TA memory */ if (shdr[rel_sidx].sh_addr >= state->vasize) return TEE_ERROR_BAD_FORMAT; rel = (Elf32_Rel *)(vabase + shdr[rel_sidx].sh_addr); if (!TEE_ALIGNMENT_IS_OK(rel, Elf32_Rel)) return TEE_ERROR_BAD_FORMAT; /* Check the address is inside TA memory */ if ((shdr[rel_sidx].sh_addr + shdr[rel_sidx].sh_size) >= state->vasize) return TEE_ERROR_BAD_FORMAT; rel_end = rel + shdr[rel_sidx].sh_size / sizeof(Elf32_Rel); for (; rel < rel_end; rel++) { Elf32_Addr *where; size_t sym_idx; /* Check the address is inside TA memory */ if (rel->r_offset >= state->vasize) return TEE_ERROR_BAD_FORMAT; where = (Elf32_Addr *)(vabase + rel->r_offset); if (!TEE_ALIGNMENT_IS_OK(where, Elf32_Addr)) return TEE_ERROR_BAD_FORMAT; switch (ELF32_R_TYPE(rel->r_info)) { case R_ARM_ABS32: sym_idx = ELF32_R_SYM(rel->r_info); if (sym_idx >= num_syms) return TEE_ERROR_BAD_FORMAT; *where += vabase + sym_tab[sym_idx].st_value; break; case R_ARM_RELATIVE: *where += vabase; break; default: EMSG("Unknown relocation type %d", ELF32_R_TYPE(rel->r_info)); return TEE_ERROR_BAD_FORMAT; } } return TEE_SUCCESS; }
ST_FN void pe_print_section(FILE * f, Section * s) { /* just if you'r curious */ BYTE *p, *e, b; int i, n, l, m; p = s->data; e = s->data + s->data_offset; l = e - p; fprintf(f, "section \"%s\"", s->name); if (s->link) fprintf(f, "\nlink \"%s\"", s->link->name); if (s->reloc) fprintf(f, "\nreloc \"%s\"", s->reloc->name); fprintf(f, "\nv_addr %08X", s->sh_addr); fprintf(f, "\ncontents %08X", l); fprintf(f, "\n\n"); if (s->sh_type == SHT_NOBITS) return; if (0 == l) return; if (s->sh_type == SHT_SYMTAB) m = sizeof(Elf32_Sym); if (s->sh_type == SHT_REL) m = sizeof(Elf32_Rel); else m = 16; fprintf(f, "%-8s", "offset"); for (i = 0; i < m; ++i) fprintf(f, " %02x", i); n = 56; if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_REL) { const char *fields1[] = { "name", "value", "size", "bind", "type", "other", "shndx", NULL }; const char *fields2[] = { "offs", "type", "symb", NULL }; const char **p; if (s->sh_type == SHT_SYMTAB) p = fields1, n = 106; else p = fields2, n = 58; for (i = 0; p[i]; ++i) fprintf(f, "%6s", p[i]); fprintf(f, " symbol"); } fprintf(f, "\n"); for (i = 0; i < n; ++i) fprintf(f, "-"); fprintf(f, "\n"); for (i = 0; i < l;) { fprintf(f, "%08X", i); for (n = 0; n < m; ++n) { if (n + i < l) fprintf(f, " %02X", p[i + n]); else fprintf(f, " "); } if (s->sh_type == SHT_SYMTAB) { Elf32_Sym *sym = (Elf32_Sym *) (p + i); const char *name = s->link->data + sym->st_name; fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"", sym->st_name, sym->st_value, sym->st_size, ELF32_ST_BIND(sym->st_info), ELF32_ST_TYPE(sym->st_info), sym->st_other, sym->st_shndx, name); } else if (s->sh_type == SHT_REL) { Elf32_Rel *rel = (Elf32_Rel *) (p + i); Elf32_Sym *sym = (Elf32_Sym *) s->link->data + ELF32_R_SYM(rel->r_info); const char *name = s->link->link->data + sym->st_name; fprintf(f, " %04X %02X %04X \"%s\"", rel->r_offset, ELF32_R_TYPE(rel->r_info), ELF32_R_SYM(rel->r_info), name); } else { fprintf(f, " "); for (n = 0; n < m; ++n) { if (n + i < l) { b = p[i + n]; if (b < 32 || b >= 127) b = '.'; fprintf(f, "%c", b); } } } i += m; fprintf(f, "\n"); } fprintf(f, "\n\n"); }
static int _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { int reloc_type; int symtab_index; unsigned long *reloc_addr; unsigned long symbol_addr; const Elf32_Sym *def = 0; struct symbol_ref sym_ref; struct elf_resolve *def_mod = 0; int goof = 0; reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); reloc_type = ELF32_R_TYPE(rpnt->r_info); symtab_index = ELF32_R_SYM(rpnt->r_info); symbol_addr = 0; sym_ref.sym = &symtab[symtab_index]; sym_ref.tpnt = NULL; if (symtab_index) { symbol_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name, scope, tpnt, elf_machine_type_class(reloc_type), &sym_ref); /* * We want to allow undefined references to weak symbols - this might * have been intentional. We should not be linking local symbols * here, so all bases should be covered. */ if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) && (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) { /* This may be non-fatal if called from dlopen. */ return 1; } def_mod = sym_ref.tpnt; } else { /* * Relocs against STN_UNDEF are usually treated as using a * symbol value of zero, and using the module containing the * reloc itself. */ symbol_addr = symtab[symtab_index].st_value; def_mod = tpnt; } #if defined (__SUPPORT_LD_DEBUG__) { unsigned long old_val = *reloc_addr; #endif switch (reloc_type) { case R_ARM_NONE: break; case R_ARM_ABS32: *reloc_addr += symbol_addr; break; case R_ARM_PC24: #if 0 { unsigned long addend; long newvalue, topbits; addend = *reloc_addr & 0x00ffffff; if (addend & 0x00800000) addend |= 0xff000000; newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2); topbits = newvalue & 0xfe000000; if (topbits != 0xfe000000 && topbits != 0x00000000) { newvalue = fix_bad_pc24(reloc_addr, symbol_addr) - (unsigned long)reloc_addr + (addend << 2); topbits = newvalue & 0xfe000000; if (unlikely(topbits != 0xfe000000 && topbits != 0x00000000)) { _dl_dprintf(2,"symbol '%s': R_ARM_PC24 relocation out of range.", symtab[symtab_index].st_name); _dl_exit(1); } } newvalue >>= 2; symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff); *reloc_addr = symbol_addr; break; } #else _dl_dprintf(2,"R_ARM_PC24: Compile shared libraries with -fPIC!\n"); _dl_exit(1); #endif case R_ARM_GLOB_DAT: case R_ARM_JUMP_SLOT: *reloc_addr = symbol_addr; break; case R_ARM_RELATIVE: *reloc_addr += (unsigned long) tpnt->loadaddr; break; case R_ARM_COPY: _dl_memcpy((void *) reloc_addr, (void *) symbol_addr, symtab[symtab_index].st_size); break; #if defined USE_TLS && USE_TLS case R_ARM_TLS_DTPMOD32: *reloc_addr = def_mod->l_tls_modid; break; case R_ARM_TLS_DTPOFF32: *reloc_addr += symbol_addr; break; case R_ARM_TLS_TPOFF32: CHECK_STATIC_TLS ((struct link_map *) def_mod); *reloc_addr += (symbol_addr + def_mod->l_tls_offset); break; #endif default: return -1; /*call _dl_exit(1) */ } #if defined (__SUPPORT_LD_DEBUG__) if (_dl_debug_reloc && _dl_debug_detail) _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); } #endif return goof; }
/* exec elf binarys */ static void *elf_load(void *data) { char *base; /* program base */ struct Elf32_Ehdr *hdr; /* ELF header */ struct Elf32_Shdr *shdr; /* section headers */ struct Elf32_Phdr *phdr; /* program headers */ struct Elf32_Sym *dsymtab; /* dynamic symbol table */ long entry_point; unsigned int i,j; /* tmp's */ hdr = (struct Elf32_Ehdr *) ((long) data); shdr = (struct Elf32_Shdr *) (((long) data) + hdr->e_shoff); phdr = (struct Elf32_Phdr *) (((long) data) + hdr->e_phoff); dsymtab = NULL; /* Check for proper ident in header */ if(hdr->e_ident[0] != 0x7f || hdr->e_ident[1] != 'E' || hdr->e_ident[2] != 'L' || hdr->e_ident[3] != 'F'){ printk("invalid elf header at 0x%x\n",hdr); return NULL; } //assert hdr->e_machine == 4 for 68k base = kmalloc(elf_calc_size(phdr,hdr->e_phnum)); /* load sections into memory */ for(i=0; i < hdr->e_phnum; i++, phdr++){ if(phdr->p_type == PT_LOAD){ //printk("type: %i offs: 0x%x vaddr: 0x%x memsz: %i\n", // phdr->p_type,phdr->p_offset,phdr->p_vaddr,phdr->p_memsz); //printk("0x%x -> 0x%x %i\n", // data + phdr->p_offset, base + phdr->p_vaddr, phdr->p_memsz); memcpy(base + phdr->p_vaddr, data + phdr->p_offset, phdr->p_memsz); } } /* find the dynamic symbol table */ for(i=0; i < hdr->e_shnum; i++) if(shdr[i].sh_type == SHT_DYNSYM) dsymtab = (struct Elf32_Sym *) (base + shdr[i].sh_offset); /* do the relocations */ for(i=0; i < hdr->e_shnum; i++,shdr++){ if(shdr->sh_type == SHT_RELA){ struct Elf32_Rela *rela = (struct Elf32_Rela *) (data + shdr->sh_offset); for(j=0; j < (shdr->sh_size / sizeof(struct Elf32_Rela)); j++,rela++){ /* Determine the relocation type and perform the reloaction */ switch(ELF32_R_TYPE(rela->r_info)){ #ifdef ELF_MACHINE_68K case R_68K_GLOB_DAT: *((long *)(base + rela->r_offset)) = ((long) base + dsymtab[ELF32_R_SYM(rela->r_info)].st_value); break; case R_68K_RELATIVE: *((long *)(base + rela->r_offset)) += (long) base; break; #endif /* ELF_MACHINE_68K */ default: printk("unknow relocation type %i\n",ELF32_R_TYPE(rela->r_info)); } } } } entry_point = ((long) base + hdr->e_entry); return (void *) entry_point; }
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *mod) { unsigned int i; Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; unsigned long location, value, size; pr_debug("applying relocate section %u to %u\n", mod->name, relsec, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ location = sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ sym = (Elf32_Sym *) sechdrs[symindex].sh_addr + ELF32_R_SYM(rel[i].r_info); value = sym->st_value; value += rel[i].r_addend; #ifdef CONFIG_SMP if (location >= COREB_L1_DATA_A_START) { pr_err("cannot relocate in L1: %u (SMP kernel)", mod->name, ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; } #endif pr_debug("location is %lx, value is %lx type is %d\n", mod->name, location, value, ELF32_R_TYPE(rel[i].r_info)); switch (ELF32_R_TYPE(rel[i].r_info)) { case R_BFIN_HUIMM16: value >>= 16; case R_BFIN_LUIMM16: case R_BFIN_RIMM16: size = 2; break; case R_BFIN_BYTE4_DATA: size = 4; break; case R_BFIN_PCREL24: case R_BFIN_PCREL24_JUMP_L: case R_BFIN_PCREL12_JUMP: case R_BFIN_PCREL12_JUMP_S: case R_BFIN_PCREL10: pr_err("unsupported relocation: %u (no -mlong-calls?)\n", mod->name, ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; default: pr_err("unknown relocation: %u\n", mod->name, ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; } switch (bfin_mem_access_type(location, size)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: memcpy((void *)location, &value, size); break; case BFIN_MEM_ACCESS_DMA: dma_memcpy((void *)location, &value, size); break; case BFIN_MEM_ACCESS_ITEST: isram_memcpy((void *)location, &value, size); break; default: pr_err("invalid relocation for %#lx\n", mod->name, location); return -ENOEXEC; } } return 0; }
/* There's a lot of shit in here that's not documented or very poorly documented by Intel.. I hope that this works for future compilers. */ cmd_elf_prog_t *cmd_elf_load(const char * fn) { uint8 *img, *imgout; int sz, i, j, sect; struct elf_hdr_t *hdr; struct elf_shdr_t *shdrs, *symtabhdr; struct elf_sym_t *symtab; int symtabsize; struct elf_rel_t *reltab; struct elf_rela_t *relatab; int reltabsize; char *stringtab; uint32 vma; file_t fd; cmd_elf_prog_t *out; out = malloc(sizeof(cmd_elf_prog_t)); memset(out, 0, sizeof(cmd_elf_prog_t)); /* Load the file: needs to change to just load headers */ fd = fs_open(fn, O_RDONLY); if (fd == FILEHND_INVALID) { ds_printf("DS_ERROR: Can't open input file '%s'\n", fn); return NULL; } sz = fs_total(fd); DBG(("Loading ELF file of size %d\n", sz)); img = memalign(32, sz); if (img == NULL) { ds_printf("DS_ERROR: Can't allocate %d bytes for ELF load\n", sz); fs_close(fd); return NULL; } fs_read(fd, img, sz); fs_close(fd); /* Header is at the front */ hdr = (struct elf_hdr_t *)(img+0); if (hdr->ident[0] != 0x7f || strncmp((const char*)hdr->ident+1, "ELF", 3)) { ds_printf("DS_ERROR: File is not a valid ELF file\n"); hdr->ident[4] = 0; ds_printf("DS_ERROR: hdr->ident is %d/%s\n", hdr->ident[0], hdr->ident+1); goto error1; } if (hdr->ident[4] != 1 || hdr->ident[5] != 1) { ds_printf("DS_ERROR: Invalid architecture flags in ELF file\n"); goto error1; } if (hdr->machine != ARCH_CODE) { ds_printf("DS_ERROR: Invalid architecture %02x in ELF file\n", hdr->machine); goto error1; } /* Print some debug info */ DBG(("File size is %d bytes\n", sz)); DBG((" entry point %08lx\n", hdr->entry)); DBG((" ph offset %08lx\n", hdr->phoff)); DBG((" sh offset %08lx\n", hdr->shoff)); DBG((" flags %08lx\n", hdr->flags)); DBG((" ehsize %08x\n", hdr->ehsize)); DBG((" phentsize %08x\n", hdr->phentsize)); DBG((" phnum %08x\n", hdr->phnum)); DBG((" shentsize %08x\n", hdr->shentsize)); DBG((" shnum %08x\n", hdr->shnum)); DBG((" shstrndx %08x\n", hdr->shstrndx)); /* Locate the string table; SH elf files ought to have two string tables, one for section names and one for object string names. We'll look for the latter. */ shdrs = (struct elf_shdr_t *)(img + hdr->shoff); stringtab = NULL; for (i=0; i<hdr->shnum; i++) { if (shdrs[i].type == SHT_STRTAB && i != hdr->shstrndx) { stringtab = (char*)(img + shdrs[i].offset); } } if (!stringtab) { ds_printf("DS_ERROR: ELF contains no object string table\n"); goto error1; } /* Locate the symbol table */ symtabhdr = NULL; for (i=0; i<hdr->shnum; i++) { if (shdrs[i].type == SHT_SYMTAB || shdrs[i].type == SHT_DYNSYM) { symtabhdr = shdrs+i; break; } } if (!symtabhdr) { ds_printf("DS_ERROR: ELF contains no symbol table\n"); goto error1; } symtab = (struct elf_sym_t *)(img + symtabhdr->offset); symtabsize = symtabhdr->size / sizeof(struct elf_sym_t); /* Relocate symtab entries for quick access */ for (i=0; i<symtabsize; i++) symtab[i].name = (uint32)(stringtab + symtab[i].name); /* Build the final memory image */ sz = 0; for (i=0; i<hdr->shnum; i++) { if (shdrs[i].flags & SHF_ALLOC) { shdrs[i].addr = sz; sz += shdrs[i].size; if (shdrs[i].addralign && (shdrs[i].addr % shdrs[i].addralign)) { uint32 orig = shdrs[i].addr; shdrs[i].addr = (shdrs[i].addr + shdrs[i].addralign) & ~(shdrs[i].addralign-1); sz += shdrs[i].addr - orig; } } } DBG(("Final image is %d bytes\n", sz)); out->data = imgout = malloc(sz); if (out->data == NULL) { ds_printf("DS_ERROR: Can't allocate %d bytes for ELF program data\n", sz); goto error1; } out->size = sz; vma = (uint32)imgout; for (i=0; i<hdr->shnum; i++) { if (shdrs[i].flags & SHF_ALLOC) { if (shdrs[i].type == SHT_NOBITS) { DBG((" setting %d bytes of zeros at %08x\n", shdrs[i].size, shdrs[i].addr)); memset(imgout+shdrs[i].addr, 0, shdrs[i].size); } else { DBG((" copying %d bytes from %08x to %08x\n", shdrs[i].size, shdrs[i].offset, shdrs[i].addr)); memcpy(imgout+shdrs[i].addr, img+shdrs[i].offset, shdrs[i].size); } } } /* Go through and patch in any symbols that are undefined */ for (i=1; i<symtabsize; i++) { export_sym_t * sym; /* DBG((" symbol '%s': value %04lx, size %04lx, info %02x, other %02x, shndx %04lx\n", (const char *)(symtab[i].name), symtab[i].value, symtab[i].size, symtab[i].info, symtab[i].other, symtab[i].shndx)); */ if (symtab[i].shndx != SHN_UNDEF || ELF32_ST_TYPE(symtab[i].info) == STT_SECTION) { // DBG((" symbol '%s': skipping\n", (const char *)(symtab[i].name))); continue; } /* Find the symbol in our exports */ sym = export_lookup((const char *)(symtab[i].name + ELF_SYM_PREFIX_LEN)); if (!sym/* && strcmp((symtab[i].name + ELF_SYM_PREFIX_LEN), "start")*/) { ds_printf("DS_ERROR: Function '%s' is undefined. Maybe need load module?\n", (const char *)(symtab[i].name + ELF_SYM_PREFIX_LEN)); goto error3; } /* Patch it in */ DBG((" symbol '%s' patched to 0x%lx\n", (const char *)(symtab[i].name), sym->ptr)); symtab[i].value = sym->ptr; } /* Process the relocations */ reltab = NULL; relatab = NULL; for (i=0; i<hdr->shnum; i++) { if (shdrs[i].type != SHT_REL && shdrs[i].type != SHT_RELA) continue; sect = shdrs[i].info; DBG(("Relocating (%s) on section %d\n", shdrs[i].type == SHT_REL ? "SHT_REL" : "SHT_RELA", sect)); switch (shdrs[i].type) { case SHT_RELA: relatab = (struct elf_rela_t *)(img + shdrs[i].offset); reltabsize = shdrs[i].size / sizeof(struct elf_rela_t); for (j=0; j<reltabsize; j++) { int sym; // XXX Does non-sh ever use RELA? if (ELF32_R_TYPE(relatab[j].info) != R_SH_DIR32) { dbglog(DBG_ERROR, "cmd_elf_load: ELF contains unknown RELA type %02x\n", ELF32_R_TYPE(relatab[j].info)); goto error3; } sym = ELF32_R_SYM(relatab[j].info); if (symtab[sym].shndx == SHN_UNDEF) { DBG((" Writing undefined RELA %08x(%08lx+%08lx) -> %08x\n", symtab[sym].value + relatab[j].addend, symtab[sym].value, relatab[j].addend, vma + shdrs[sect].addr + relatab[j].offset)); *((uint32 *)(imgout + shdrs[sect].addr + relatab[j].offset)) = symtab[sym].value + relatab[j].addend; } else { DBG((" Writing RELA %08x(%08x+%08x+%08x+%08x) -> %08x\n", vma + shdrs[symtab[sym].shndx].addr + symtab[sym].value + relatab[j].addend, vma, shdrs[symtab[sym].shndx].addr, symtab[sym].value, relatab[j].addend, vma + shdrs[sect].addr + relatab[j].offset)); *((uint32*)(imgout + shdrs[sect].addr /* assuming 1 == .text */ + relatab[j].offset)) += vma + shdrs[symtab[sym].shndx].addr + symtab[sym].value + relatab[j].addend; } } break; case SHT_REL: reltab = (struct elf_rel_t *)(img + shdrs[i].offset); reltabsize = shdrs[i].size / sizeof(struct elf_rel_t); for (j=0; j<reltabsize; j++) { int sym, info, pcrel; // XXX Does non-ia32 ever use REL? info = ELF32_R_TYPE(reltab[j].info); if (info != R_386_32 && info != R_386_PC32) { ds_printf("DS_ERROR: ELF contains unknown REL type %02x\n", info); goto error3; } pcrel = (info == R_386_PC32); sym = ELF32_R_SYM(reltab[j].info); if (symtab[sym].shndx == SHN_UNDEF) { uint32 value = symtab[sym].value; if (sect == 1 && j < 5) { DBG((" Writing undefined %s %08x -> %08x", pcrel ? "PCREL" : "ABSREL", value, vma + shdrs[sect].addr + reltab[j].offset)); } if (pcrel) value -= vma + shdrs[sect].addr + reltab[j].offset; *((uint32 *)(imgout + shdrs[sect].addr + reltab[j].offset)) += value; if (sect == 1 && j < 5) { DBG(("(%08x)\n", *((uint32 *)(imgout + shdrs[sect].addr + reltab[j].offset)))); } } else { uint32 value = vma + shdrs[symtab[sym].shndx].addr + symtab[sym].value; if (sect == 1 && j < 5) { DBG((" Writing %s %08x(%08x+%08x+%08x) -> %08x", pcrel ? "PCREL" : "ABSREL", value, vma, shdrs[symtab[sym].shndx].addr, symtab[sym].value, vma + shdrs[sect].addr + reltab[j].offset)); } if (pcrel) value -= vma + shdrs[sect].addr + reltab[j].offset; *((uint32*)(imgout + shdrs[sect].addr + reltab[j].offset)) += value; if (sect == 1 && j < 5) { DBG(("(%08x)\n", *((uint32 *)(imgout + shdrs[sect].addr + reltab[j].offset)))); } } } break; } } if (reltab == NULL && relatab == NULL) { ds_printf("DS_WARNING: found no REL(A) sections; did you forget -r?\n"); } /* Look for the program entry points and deal with that */ { int sym; #define DO_ONE(symname, outp) \ sym = find_sym(ELF_SYM_PREFIX symname, symtab, symtabsize); \ if (sym < 0) { \ ds_printf("DS_ERROR: ELF contains no %s()\n", symname); \ goto error3; \ } \ \ out->outp = (vma + shdrs[symtab[sym].shndx].addr \ + symtab[sym].value); DO_ONE("main", main); #undef DO_ONE } free(img); DBG(("elf_load final ELF stats: memory image at %p, size %08lx\n\tentry pt %p\n", out->data, out->size, out->start)); /* Flush the icache for that zone */ icache_flush_range((uint32)out->data, out->size); return out; error3: free(out->data); error1: free(img); return NULL; }
unsigned addElfHook(const char* soName, const char* symbol, void* replaceFunc) { struct SoInfo *si = NULL; Elf32_Rel *rel = NULL; Elf32_Sym *s = NULL; unsigned int sym_offset = 0; size_t i; // since we know the module is already loaded and mostly // we DO NOT want its constructors to be called again, // ise RTLD_NOLOAD to just get its soinfo address. si = (struct SoInfo *)dlopen( soName, RTLD_GLOBAL/* RTLD_NOLOAD */ ); if( !si ){ LOGE( "dlopen error: %s.", dlerror() ); return 0; } s = soInfoElfLookUp( si, elfHash(symbol), symbol ); if( !s ){ return 0; } sym_offset = s - si->symtab; LOGD("the sym offset is %d", sym_offset); // loop reloc table to find the symbol by index for( i = 0, rel = si->plt_rel; i < si->plt_rel_count; ++i, ++rel ) { unsigned type = ELF32_R_TYPE(rel->r_info); unsigned sym = ELF32_R_SYM(rel->r_info); unsigned reloc = (unsigned)(rel->r_offset + si->base); if( sym_offset == sym ) { switch(type) { case R_ARM_JUMP_SLOT: return patchAddress( reloc, replaceFunc ); default: LOGE( "Expected R_ARM_JUMP_SLOT, found 0x%X", type ); } } } unsigned original = 0; // loop dyn reloc table for( i = 0, rel = si->rel; i < si->rel_count; ++i, ++rel ) { unsigned type = ELF32_R_TYPE(rel->r_info); unsigned sym = ELF32_R_SYM(rel->r_info); unsigned reloc = (unsigned)(rel->r_offset + si->base); if( sym_offset == sym ) { switch(type) { case R_ARM_ABS32: case R_ARM_GLOB_DAT: original = patchAddress( reloc, replaceFunc ); default: LOGE( "Expected R_ARM_ABS32 or R_ARM_GLOB_DAT, found 0x%X", type ); } } } if( original == 0 ){ LOGE( "Unable to find symbol in the reloc tables ( plt_rel_count=%u - rel_count=%u ).", si->plt_rel_count, si->rel_count ); } return original; }
int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relindex, struct module *module) { Elf32_Shdr *symsec = sechdrs + symindex; Elf32_Shdr *relsec = sechdrs + relindex; Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; Elf32_Rel *rel = (void *)relsec->sh_addr; unsigned int i; for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { unsigned long loc; Elf32_Sym *sym; s32 offset; offset = ELF32_R_SYM(rel->r_info); if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { printk(KERN_ERR "%s: bad relocation, " "section %d reloc %d\n", module->name, relindex, i); return -ENOEXEC; } sym = ((Elf32_Sym *)symsec->sh_addr) + offset; if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { printk(KERN_ERR "%s: out of bounds relocation, " "section %d reloc %d offset %d size %d\n", module->name, relindex, i, rel->r_offset, dstsec->sh_size); return -ENOEXEC; } loc = dstsec->sh_addr + rel->r_offset; switch (ELF32_R_TYPE(rel->r_info)) { case R_UNICORE_NONE: break; case R_UNICORE_ABS32: *(u32 *)loc += sym->st_value; break; case R_UNICORE_PC24: case R_UNICORE_CALL: case R_UNICORE_JUMP24: offset = (*(u32 *)loc & 0x00ffffff) << 2; if (offset & 0x02000000) offset -= 0x04000000; offset += sym->st_value - loc; if (offset & 3 || offset <= (s32)0xfe000000 || offset >= (s32)0x02000000) { printk(KERN_ERR "%s: relocation out of range, section " "%d reloc %d sym '%s'\n", module->name, relindex, i, strtab + sym->st_name); return -ENOEXEC; } offset >>= 2; *(u32 *)loc &= 0xff000000; *(u32 *)loc |= offset & 0x00ffffff; break; default: printk(KERN_ERR "%s: unknown relocation: %u\n", module->name, ELF32_R_TYPE(rel->r_info)); return -ENOEXEC; } } return 0; }