Example #1
0
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",
		relsec, sechdrs[relsec].sh_info);

	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
		/*                                  */
		location = sechdrs[sechdrs[relsec].sh_info].sh_addr +
		           rel[i].r_offset;

		/*                                                     
                                           */
		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)\n",
				ELF32_R_TYPE(rel[i].r_info));
			return -ENOEXEC;
		}
#endif

		pr_debug("location is %lx, value is %lx type is %d\n",
			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",
				ELF32_R_TYPE(rel[i].r_info));
			return -ENOEXEC;

		default:
			pr_err("unknown relocation: %u\n",
				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", location);
			return -ENOEXEC;
		}
	}

	return 0;
}
Example #2
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;
}
Example #3
0
static int
_dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
	      ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
{
	int reloc_type;
	int symtab_index;
	char *symname;
	unsigned long *reloc_addr;
	unsigned long symbol_addr;
	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;
	symname = strtab + symtab[symtab_index].st_name;

	if (symtab_index) {
		symbol_addr = _dl_find_hash(symname, 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;

		}
		if (_dl_trace_prelink)
			_dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
					&sym_ref, elf_machine_type_class(reloc_type));
		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;
}
bfd_boolean
_bfd_elf_discard_section_eh_frame
   (bfd *abfd, struct bfd_link_info *info, asection *sec,
    bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *),
    struct elf_reloc_cookie *cookie)
{
#define REQUIRE(COND)					\
  do							\
    if (!(COND))					\
      goto free_no_table;				\
  while (0)

  bfd_byte *ehbuf = NULL, *buf;
  bfd_byte *last_cie, *last_fde;
  struct eh_cie_fde *ent, *last_cie_inf, *this_inf;
  struct cie_header hdr;
  struct cie cie;
  struct elf_link_hash_table *htab;
  struct eh_frame_hdr_info *hdr_info;
  struct eh_frame_sec_info *sec_info = NULL;
  unsigned int cie_usage_count, offset;
  unsigned int ptr_size;

  if (sec->size == 0)
    {
      /* This file does not contain .eh_frame information.  */
      return FALSE;
    }

  if (bfd_is_abs_section (sec->output_section))
    {
      /* At least one of the sections is being discarded from the
	 link, so we should just ignore them.  */
      return FALSE;
    }

  htab = elf_hash_table (info);
  hdr_info = &htab->eh_info;

  /* Read the frame unwind information from abfd.  */

  REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));

  if (sec->size >= 4
      && bfd_get_32 (abfd, ehbuf) == 0
      && cookie->rel == cookie->relend)
    {
      /* Empty .eh_frame section.  */
      free (ehbuf);
      return FALSE;
    }

  /* If .eh_frame section size doesn't fit into int, we cannot handle
     it (it would need to use 64-bit .eh_frame format anyway).  */
  REQUIRE (sec->size == (unsigned int) sec->size);

  ptr_size = (get_elf_backend_data (abfd)
	      ->elf_backend_eh_frame_address_size (abfd, sec));
  REQUIRE (ptr_size != 0);

  buf = ehbuf;
  last_cie = NULL;
  last_cie_inf = NULL;
  memset (&cie, 0, sizeof (cie));
  cie_usage_count = 0;
  sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
			  + 99 * sizeof (struct eh_cie_fde));
  REQUIRE (sec_info);

  sec_info->alloced = 100;

#define ENSURE_NO_RELOCS(buf)				\
  REQUIRE (!(cookie->rel < cookie->relend		\
	     && (cookie->rel->r_offset			\
		 < (bfd_size_type) ((buf) - ehbuf))	\
	     && cookie->rel->r_info != 0))

#define SKIP_RELOCS(buf)				\
  while (cookie->rel < cookie->relend			\
	 && (cookie->rel->r_offset			\
	     < (bfd_size_type) ((buf) - ehbuf)))	\
    cookie->rel++

#define GET_RELOC(buf)					\
  ((cookie->rel < cookie->relend			\
    && (cookie->rel->r_offset				\
	== (bfd_size_type) ((buf) - ehbuf)))		\
   ? cookie->rel : NULL)

  for (;;)
    {
      char *aug;
      bfd_byte *start, *end, *insns, *insns_end;
      bfd_size_type length;
      unsigned int set_loc_count;

      if (sec_info->count == sec_info->alloced)
	{
	  struct eh_cie_fde *old_entry = sec_info->entry;
	  sec_info = bfd_realloc (sec_info,
				  sizeof (struct eh_frame_sec_info)
				  + ((sec_info->alloced + 99)
				     * sizeof (struct eh_cie_fde)));
	  REQUIRE (sec_info);

	  memset (&sec_info->entry[sec_info->alloced], 0,
		  100 * sizeof (struct eh_cie_fde));
	  sec_info->alloced += 100;

	  /* Now fix any pointers into the array.  */
	  if (last_cie_inf >= old_entry
	      && last_cie_inf < old_entry + sec_info->count)
	    last_cie_inf = sec_info->entry + (last_cie_inf - old_entry);
	}

      this_inf = sec_info->entry + sec_info->count;
      last_fde = buf;
      /* If we are at the end of the section, we still need to decide
	 on whether to output or discard last encountered CIE (if any).  */
      if ((bfd_size_type) (buf - ehbuf) == sec->size)
	{
	  hdr.length = 0;
	  hdr.id = (unsigned int) -1;
	  end = buf;
	}
      else
	{
	  /* Read the length of the entry.  */
	  REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
	  hdr.length = bfd_get_32 (abfd, buf - 4);

	  /* 64-bit .eh_frame is not supported.  */
	  REQUIRE (hdr.length != 0xffffffff);

	  /* The CIE/FDE must be fully contained in this input section.  */
	  REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr.length <= sec->size);
	  end = buf + hdr.length;

	  this_inf->offset = last_fde - ehbuf;
	  this_inf->size = 4 + hdr.length;

	  if (hdr.length == 0)
	    {
	      /* A zero-length CIE should only be found at the end of
		 the section.  */
	      REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
	      ENSURE_NO_RELOCS (buf);
	      sec_info->count++;
	      /* Now just finish last encountered CIE processing and break
		 the loop.  */
	      hdr.id = (unsigned int) -1;
	    }
	  else
	    {
	      REQUIRE (skip_bytes (&buf, end, 4));
	      hdr.id = bfd_get_32 (abfd, buf - 4);
	      REQUIRE (hdr.id != (unsigned int) -1);
	    }
	}

      if (hdr.id == 0 || hdr.id == (unsigned int) -1)
	{
	  unsigned int initial_insn_length;

	  /* CIE  */
	  if (last_cie != NULL)
	    {
	      /* Now check if this CIE is identical to the last CIE,
		 in which case we can remove it provided we adjust
		 all FDEs.  Also, it can be removed if we have removed
		 all FDEs using it.  */
	      if ((!info->relocatable
		   && hdr_info->last_cie_sec
		   && (sec->output_section
		       == hdr_info->last_cie_sec->output_section)
		   && cie_compare (&cie, &hdr_info->last_cie) == 0)
		  || cie_usage_count == 0)
		last_cie_inf->removed = 1;
	      else
		{
		  hdr_info->last_cie = cie;
		  hdr_info->last_cie_sec = sec;
		  last_cie_inf->make_relative = cie.make_relative;
		  last_cie_inf->make_lsda_relative = cie.make_lsda_relative;
		  last_cie_inf->per_encoding_relative
		    = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
		}
	    }

	  if (hdr.id == (unsigned int) -1)
	    break;

	  last_cie_inf = this_inf;
	  this_inf->cie = 1;

	  cie_usage_count = 0;
	  memset (&cie, 0, sizeof (cie));
	  cie.hdr = hdr;
	  start = buf;
	  REQUIRE (read_byte (&buf, end, &cie.version));

	  /* Cannot handle unknown versions.  */
	  REQUIRE (cie.version == 1 || cie.version == 3);
	  REQUIRE (strlen ((char *) buf) < sizeof (cie.augmentation));

	  strcpy (cie.augmentation, (char *) buf);
	  buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1;
	  ENSURE_NO_RELOCS (buf);
	  if (buf[0] == 'e' && buf[1] == 'h')
	    {
	      /* GCC < 3.0 .eh_frame CIE */
	      /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
		 is private to each CIE, so we don't need it for anything.
		 Just skip it.  */
	      REQUIRE (skip_bytes (&buf, end, ptr_size));
	      SKIP_RELOCS (buf);
	    }
	  REQUIRE (read_uleb128 (&buf, end, &cie.code_align));
	  REQUIRE (read_sleb128 (&buf, end, &cie.data_align));
	  if (cie.version == 1)
	    {
	      REQUIRE (buf < end);
	      cie.ra_column = *buf++;
	    }
	  else
	    REQUIRE (read_uleb128 (&buf, end, &cie.ra_column));
	  ENSURE_NO_RELOCS (buf);
	  cie.lsda_encoding = DW_EH_PE_omit;
	  cie.fde_encoding = DW_EH_PE_omit;
	  cie.per_encoding = DW_EH_PE_omit;
	  aug = cie.augmentation;
	  if (aug[0] != 'e' || aug[1] != 'h')
	    {
	      if (*aug == 'z')
		{
		  aug++;
		  REQUIRE (read_uleb128 (&buf, end, &cie.augmentation_size));
	  	  ENSURE_NO_RELOCS (buf);
		}

	      while (*aug != '\0')
		switch (*aug++)
		  {
		  case 'L':
		    REQUIRE (read_byte (&buf, end, &cie.lsda_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size));
		    break;
		  case 'R':
		    REQUIRE (read_byte (&buf, end, &cie.fde_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie.fde_encoding, ptr_size));
		    break;
		  case 'S':
		    break;
		  case 'P':
		    {
		      int per_width;

		      REQUIRE (read_byte (&buf, end, &cie.per_encoding));
		      per_width = get_DW_EH_PE_width (cie.per_encoding,
						      ptr_size);
		      REQUIRE (per_width);
		      if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned)
			{
			  length = -(buf - ehbuf) & (per_width - 1);
			  REQUIRE (skip_bytes (&buf, end, length));
			}
		      ENSURE_NO_RELOCS (buf);
		      /* Ensure we have a reloc here, against
			 a global symbol.  */
		      if (GET_RELOC (buf) != NULL)
			{
			  unsigned long r_symndx;

#ifdef BFD64
			  if (ptr_size == 8)
			    r_symndx = ELF64_R_SYM (cookie->rel->r_info);
			  else
#endif
			    r_symndx = ELF32_R_SYM (cookie->rel->r_info);
			  if (r_symndx >= cookie->locsymcount)
			    {
			      struct elf_link_hash_entry *h;

			      r_symndx -= cookie->extsymoff;
			      h = cookie->sym_hashes[r_symndx];

			      while (h->root.type == bfd_link_hash_indirect
				     || h->root.type == bfd_link_hash_warning)
				h = (struct elf_link_hash_entry *)
				    h->root.u.i.link;

			      cie.personality = h;
			    }
			  /* Cope with MIPS-style composite relocations.  */
			  do
			    cookie->rel++;
			  while (GET_RELOC (buf) != NULL);
			}
		      REQUIRE (skip_bytes (&buf, end, per_width));
		    }
		    break;
		  default:
		    /* Unrecognized augmentation. Better bail out.  */
		    goto free_no_table;
		  }
	    }

	  /* For shared libraries, try to get rid of as many RELATIVE relocs
	     as possible.  */
	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_relative_eh_frame
		  (abfd, info, sec)))
	    {
	      if ((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr)
		cie.make_relative = 1;
	      /* If the CIE doesn't already have an 'R' entry, it's fairly
		 easy to add one, provided that there's no aligned data
		 after the augmentation string.  */
	      else if (cie.fde_encoding == DW_EH_PE_omit
		       && (cie.per_encoding & 0xf0) != DW_EH_PE_aligned)
		{
		  if (*cie.augmentation == 0)
		    this_inf->add_augmentation_size = 1;
		  this_inf->add_fde_encoding = 1;
		  cie.make_relative = 1;
		}
	    }

	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_lsda_relative_eh_frame
		  (abfd, info, sec))
	      && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr)
	    cie.make_lsda_relative = 1;

	  /* If FDE encoding was not specified, it defaults to
	     DW_EH_absptr.  */
	  if (cie.fde_encoding == DW_EH_PE_omit)
	    cie.fde_encoding = DW_EH_PE_absptr;

	  initial_insn_length = end - buf;
	  if (initial_insn_length <= 50)
	    {
	      cie.initial_insn_length = initial_insn_length;
	      memcpy (cie.initial_instructions, buf, initial_insn_length);
	    }
	  insns = buf;
	  buf += initial_insn_length;
	  ENSURE_NO_RELOCS (buf);
	  last_cie = last_fde;
	}
      else
	{
	  /* Ensure this FDE uses the last CIE encountered.  */
	  REQUIRE (last_cie);
	  REQUIRE (hdr.id == (unsigned int) (buf - 4 - last_cie));

	  ENSURE_NO_RELOCS (buf);
	  REQUIRE (GET_RELOC (buf));

	  if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
	    /* This is a FDE against a discarded section.  It should
	       be deleted.  */
	    this_inf->removed = 1;
	  else
	    {
	      if (info->shared
		  && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr
		       && cie.make_relative == 0)
		      || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned))
		{
		  /* If a shared library uses absolute pointers
		     which we cannot turn into PC relative,
		     don't create the binary search table,
		     since it is affected by runtime relocations.  */
		  hdr_info->table = FALSE;
		}
	      cie_usage_count++;
	      hdr_info->fde_count++;
	    }
	  /* Skip the initial location and address range.  */
	  start = buf;
	  length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size);
	  REQUIRE (skip_bytes (&buf, end, 2 * length));

	  /* Skip the augmentation size, if present.  */
	  if (cie.augmentation[0] == 'z')
	    REQUIRE (read_uleb128 (&buf, end, &length));
	  else
	    length = 0;

	  /* Of the supported augmentation characters above, only 'L'
	     adds augmentation data to the FDE.  This code would need to
	     be adjusted if any future augmentations do the same thing.  */
	  if (cie.lsda_encoding != DW_EH_PE_omit)
	    {
	      this_inf->lsda_offset = buf - start;
	      /* If there's no 'z' augmentation, we don't know where the
		 CFA insns begin.  Assume no padding.  */
	      if (cie.augmentation[0] != 'z')
		length = end - buf;
	    }

	  /* Skip over the augmentation data.  */
	  REQUIRE (skip_bytes (&buf, end, length));
	  insns = buf;

	  buf = last_fde + 4 + hdr.length;
	  SKIP_RELOCS (buf);
	}

      /* Try to interpret the CFA instructions and find the first
	 padding nop.  Shrink this_inf's size so that it doesn't
	 include the padding.  */
      length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size);
      set_loc_count = 0;
      insns_end = skip_non_nops (insns, end, length, &set_loc_count);
      /* If we don't understand the CFA instructions, we can't know
	 what needs to be adjusted there.  */
      if (insns_end == NULL
	  /* For the time being we don't support DW_CFA_set_loc in
	     CIE instructions.  */
	  || (set_loc_count && this_inf->cie))
	goto free_no_table;
      this_inf->size -= end - insns_end;
      if (set_loc_count
	  && ((cie.fde_encoding & 0xf0) == DW_EH_PE_pcrel
	      || cie.make_relative))
	{
	  unsigned int cnt;
	  bfd_byte *p;

	  this_inf->set_loc = bfd_malloc ((set_loc_count + 1)
					  * sizeof (unsigned int));
	  REQUIRE (this_inf->set_loc);
	  this_inf->set_loc[0] = set_loc_count;
	  p = insns;
	  cnt = 0;
	  while (p < end)
	    {
	      if (*p == DW_CFA_set_loc)
		this_inf->set_loc[++cnt] = p + 1 - start;
	      REQUIRE (skip_cfa_op (&p, end, length));
	    }
	}

      this_inf->fde_encoding = cie.fde_encoding;
      this_inf->lsda_encoding = cie.lsda_encoding;
      sec_info->count++;
    }

  elf_section_data (sec)->sec_info = sec_info;
  sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;

  /* Ok, now we can assign new offsets.  */
  offset = 0;
  last_cie_inf = hdr_info->last_cie_inf;
  for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
    if (!ent->removed)
      {
	if (ent->cie)
	  last_cie_inf = ent;
	else
	  ent->cie_inf = last_cie_inf;
	ent->new_offset = offset;
	offset += size_of_output_cie_fde (ent, ptr_size);
      }
  hdr_info->last_cie_inf = last_cie_inf;

  /* Resize the sec as needed.  */
  sec->rawsize = sec->size;
  sec->size = offset;
  if (sec->size == 0)
    sec->flags |= SEC_EXCLUDE;

  free (ehbuf);
  return offset != sec->rawsize;

free_no_table:
  if (ehbuf)
    free (ehbuf);
  if (sec_info)
    free (sec_info);
  hdr_info->table = FALSE;
  hdr_info->last_cie.hdr.length = 0;
  return FALSE;

#undef REQUIRE
}
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;
}
Example #6
0
/**
 * @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 );

}
Example #7
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);
}
Example #8
0
/*---------------------------------------------------------------------------*/
static int
relocate_section(int fd,
                 unsigned int section, unsigned short size,
                 unsigned int sectionaddr,
                 char *sectionbase,
                 unsigned int strs,
                 unsigned int strtab,
                 unsigned int symtab, unsigned short symtabsize,
                 unsigned char using_relas)
{
    /* sectionbase added; runtime start address of current section */
    struct elf32_rela rela; /* Now used both for rel and rela data! */
    int rel_size = 0;
    struct elf32_sym s;
    unsigned int a;
    char name[30];
    char *addr;
    struct relevant_section *sect;

    /* determine correct relocation entry sizes */
    if(using_relas)
    {
        rel_size = sizeof(struct elf32_rela);
    }
    else
    {
        rel_size = sizeof(struct elf32_rel);
    }

    for(a = section; a < section + size; a += rel_size)
    {
        seek_read(fd, a, (char *)&rela, rel_size);
        seek_read(fd,
                  symtab + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info),
                  (char *)&s, sizeof(s));
        if(s.st_name != 0)
        {
            seek_read(fd, strtab + s.st_name, name, sizeof(name));
            PRINTF("name: %s\n", name);
            addr = (char *)symtab_lookup(name);
            /* ADDED */
            if(addr == NULL)
            {
                PRINTF("name not found in global: %s\n", name);
                addr = find_local_symbol(fd, name, symtab, symtabsize, strtab);
                PRINTF("found address %p\n", addr);
            }
            if(addr == NULL)
            {
                if(s.st_shndx == bss.number)
                {
                    sect = &bss;
                }
                else if(s.st_shndx == data.number)
                {
                    sect = &data;
                }
                else if(s.st_shndx == rodata.number)
                {
                    sect = &rodata;
                }
                else if(s.st_shndx == text.number)
                {
                    sect = &text;
                }
                else
                {
                    PRINTF("elfloader unknown name: '%30s'\n", name);
                    memcpy(elfloader_unknown, name, sizeof(elfloader_unknown));
                    elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0;
                    return ELFLOADER_SYMBOL_NOT_FOUND;
                }
                addr = sect->address;
            }
        }
        else
        {
            if(s.st_shndx == bss.number)
            {
                sect = &bss;
            }
            else if(s.st_shndx == data.number)
            {
                sect = &data;
            }
            else if(s.st_shndx == rodata.number)
            {
                sect = &rodata;
            }
            else if(s.st_shndx == text.number)
            {
                sect = &text;
            }
            else
            {
                return ELFLOADER_SEGMENT_NOT_FOUND;
            }

            addr = sect->address;
        }

        if(!using_relas)
        {
            /* copy addend to rela structure */
            seek_read(fd, sectionaddr + rela.r_offset, (char *)&rela.r_addend, 4);
        }

        elfloader_arch_relocate(fd, sectionaddr, sectionbase, &rela, addr);
    }
    return ELFLOADER_OK;
}
Example #9
0
static int
relocate_rel(image_t *rootImage, image_t *image, struct Elf32_Rel *rel,
	int rel_len)
{
	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, &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;
}
Example #10
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;
}
Example #11
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();
}
Example #12
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 );
}
Example #13
0
File: module.c Project: 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: ;
}
Example #14
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);
}
Example #15
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);
        }
      }
    }
Example #16
0
int
gelf_update_rela(Elf_Data *ed, int ndx, GElf_Rela *dr)
{
	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 || 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);
	assert(ndx >= 0);

	if (msz * (size_t) ndx >= d->d_data.d_size) {
		LIBELF_SET_ERROR(ARGUMENT, 0);
		return (0);
	}

	if (ec == ELFCLASS32) {
		rela32 = (Elf32_Rela *) d->d_data.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(
			(Elf32_Word) ELF64_R_SYM(dr->r_info),
			(Elf32_Word) ELF64_R_TYPE(dr->r_info));

		LIBELF_COPY_S32(rela32, dr, r_addend);
	} else {
		rela64 = (Elf64_Rela *) d->d_data.d_buf + ndx;

		*rela64 = *dr;
	}

	return (1);
}
Example #17
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;
}
Example #18
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 );
    }
}
Example #19
0
unsigned libhook_addhook( const char *soname, const char *symbol, unsigned newval ) {
    struct soinfo *si = NULL;
    Elf32_Rel *rel = NULL;
    Elf32_Sym *s = NULL;
    unsigned int sym_offset = 0;
    size_t i;

//    HOOKLOG( "dlopen(%s)", soname );

    // 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, 4 /* RTLD_NOLOAD */ );
//    si = (struct soinfo *)dlopen( soname, 0 /* RTLD_NOLOAD */ );
    if( !si ){
        HOOKLOG( "dlopen error: %s.", dlerror() );
        return 0;
    }

//    HOOKLOG( "libhook_addhook dlopen success [0x%X], soinfo_elf_lookup...",(unsigned int)si);

    s = soinfo_elf_lookup( si, elfhash(symbol), symbol );
    if( !s ){
        return 0;
    }

  //  HOOKLOG( "soinfo_elf_lookup = [0x%X]", (unsigned int)s);

    sym_offset = s - si->symtab;

//    HOOKLOG( "sym_offset = [0x%X]", 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);

//        HOOKLOG( "[%i] type/reloc/sym = [0x%X/0x%X/0x%X]", i, type, reloc, sym);

        if( sym_offset == sym ) {
            switch(type) {
                case R_ARM_JUMP_SLOT:

//                    HOOKLOG( "found R_ARM_JUMP_SLOT at [0x%X]", reloc);

                    return libhook_patch_address( reloc, newval );

                default:

                    HOOKLOG( "Expected R_ARM_JUMP_SLOT, found 0x%X", type );
            }
        }
    }

//    HOOKLOG( "find by index finished %i", 0);

    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 = libhook_patch_address( reloc, newval );

                default:

                    HOOKLOG( "Expected R_ARM_ABS32 or R_ARM_GLOB_DAT, found 0x%X", type );
            }
        }
    }

    if( original == 0 ){
        HOOKLOG( "Unable to find symbol in the reloc tables ( plt_rel_count=%u - rel_count=%u ).", si->plt_rel_count, si->rel_count );
    }

    return original;
}