예제 #1
0
파일: module.c 프로젝트: UIKit0/TSOS
/*
 * 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 = &sections[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 = &sections[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 = &sections[symbol->st_shndx];
				compilerInfo = elf + section->sh_offset + symbol->st_address;
			} else if(!strcmp(name, "supported_kernel")) {
				elf_section_entry_t *section = &sections[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 = &sections[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 = &sections[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: ;
}
예제 #2
0
/* 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 *)&section[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;
}
예제 #3
0
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;
}
예제 #4
0
파일: psp-prxgen.c 프로젝트: CDragu/pspsdk
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;
}
예제 #6
0
//-------------------------------------------------------------------
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;
}
예제 #7
0
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;
}
예제 #8
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;
예제 #9
0
파일: emul.c 프로젝트: Benz0X/Emul-MIPS
/**
 * @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, &section_tab);

    if (symtab_libc!=NULL && fp_libc!=NULL)
        elf_load_scntab(fp_libc ,32, &section_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 );

}
예제 #10
0
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);
        }
      }
    }
예제 #11
0
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;
}
예제 #12
0
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);
}
예제 #13
0
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();
}
예제 #14
0
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 );
}
예제 #15
0
static uint64_t
Elf32_r_type(Elf32_Word r_info)
{
  return ELF32_R_TYPE(r_info);
}
예제 #16
0
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;
}
예제 #17
0
파일: gelf_rela.c 프로젝트: Bhudipta/minix
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);
}
예제 #18
0
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);
}
예제 #19
0
//-------------------------------------------------------------------
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;
}
예제 #20
0
/*
 * 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 );
    }
}
예제 #21
0
파일: elftomini.c 프로젝트: nesl/sos-2x
//---------------------------------------------------------------------
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;
}
예제 #22
0
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 {
예제 #23
0
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;
}
예제 #24
0
파일: tccpe.c 프로젝트: AbdelghaniDr/mirror
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");
}
예제 #25
0
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;
}
예제 #26
0
파일: exec.c 프로젝트: kylelutz/link-os
/* 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;
}
예제 #27
0
파일: module.c 프로젝트: pthomas/linux-2.6
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;
}
예제 #28
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;
}
예제 #29
0
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;
}
예제 #30
0
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;
}