示例#1
0
static void check_rela(Elf_Rela *rela, struct module *me)
{
	struct mod_arch_syminfo *info;

	info = me->arch.syminfo + ELF_R_SYM (rela->r_info);
	switch (ELF_R_TYPE (rela->r_info)) {
	case R_390_GOT12:	/* 12 bit GOT offset.  */
	case R_390_GOT16:	/* 16 bit GOT offset.  */
	case R_390_GOT20:	/* 20 bit GOT offset.  */
	case R_390_GOT32:	/* 32 bit GOT offset.  */
	case R_390_GOT64:	/* 64 bit GOT offset.  */
	case R_390_GOTENT:	/* 32 bit PC rel. to GOT entry shifted by 1. */
	case R_390_GOTPLT12:	/* 12 bit offset to jump slot.	*/
	case R_390_GOTPLT16:	/* 16 bit offset to jump slot.  */
	case R_390_GOTPLT20:	/* 20 bit offset to jump slot.  */
	case R_390_GOTPLT32:	/* 32 bit offset to jump slot.  */
	case R_390_GOTPLT64:	/* 64 bit offset to jump slot.	*/
	case R_390_GOTPLTENT:	/* 32 bit rel. offset to jump slot >> 1. */
		if (info->got_offset == -1UL) {
			info->got_offset = me->arch.got_size;
			me->arch.got_size += sizeof(void*);
		}
		break;
	case R_390_PLT16DBL:	/* 16 bit PC rel. PLT shifted by 1.  */
	case R_390_PLT32DBL:	/* 32 bit PC rel. PLT shifted by 1.  */
	case R_390_PLT32:	/* 32 bit PC relative PLT address.  */
	case R_390_PLT64:	/* 64 bit PC relative PLT address.  */
	case R_390_PLTOFF16:	/* 16 bit offset from GOT to PLT. */
	case R_390_PLTOFF32:	/* 32 bit offset from GOT to PLT. */
	case R_390_PLTOFF64:	/* 16 bit offset from GOT to PLT. */
		if (info->plt_offset == -1UL) {
			info->plt_offset = me->arch.plt_size;
			me->arch.plt_size += PLT_ENTRY_SIZE;
		}
		break;
	case R_390_COPY:
	case R_390_GLOB_DAT:
	case R_390_JMP_SLOT:
	case R_390_RELATIVE:
		/* Only needed if we want to support loading of 
		   modules linked with -shared. */
		break;
	}
}
示例#2
0
文件: mdreloc.c 项目: ryo/netbsd-src
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{

    if (!obj->relocbase)
        return 0;

    for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) {
        Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);

        assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT));

        /* Just relocate the GOT slots pointing into the PLT */
        *where += (Elf_Addr)obj->relocbase;
        rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
    }

    return 0;
}
示例#3
0
/*
 *  * Process the PLT relocations.
 *   */
int
reloc_plt(Obj_Entry *obj)
{
	const Elf_Rel *rellim;
	const Elf_Rel *rel;
		
	rellim = (const Elf_Rel *)((char *)obj->pltrel +
	    obj->pltrelsize);
	for (rel = obj->pltrel;  rel < rellim;  rel++) {
		Elf_Addr *where;

		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
		
		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
		*where += (Elf_Addr )obj->relocbase;
	}
	
	return (0);
}
示例#4
0
文件: reloc.c 项目: dzavalishin/oskit
/*
 * Process the special R_386_COPY relocations in the main program.  These
 * copy data from a shared object into a region in the main program's BSS
 * segment.
 *
 * Returns 0 on success, -1 on failure.
 */
int
do_copy_relocations(Obj_Entry *dstobj)
{
    const Elf_Rel *rellim;
    const Elf_Rel *rel;

    assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */

    rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
    for (rel = dstobj->rel;  rel < rellim;  rel++) {
	if (ELF_R_TYPE(rel->r_info) == R_386_COPY) {
	    void *dstaddr;
	    const Elf_Sym *dstsym;
	    const char *name;
	    unsigned long hash;
	    size_t size;
	    const void *srcaddr;
	    const Elf_Sym *srcsym;
	    Obj_Entry *srcobj;

	    dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
	    dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
	    name = dstobj->strtab + dstsym->st_name;
	    hash = elf_hash(name);
	    size = dstsym->st_size;

	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
		if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
		    break;

	    if (srcobj == NULL) {
		_rtld_error("Undefined symbol \"%s\" referenced from COPY"
		  " relocation in %s", name, dstobj->path);
		return -1;
	    }

	    srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
	    memcpy(dstaddr, srcaddr, size);
	}
    }

    return 0;
}
示例#5
0
el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)
{
    uint64_t *p = (uint64_t*) (rel->r_offset + ctx->base_load_vaddr);
    uint32_t type = ELF_R_TYPE(rel->r_info);
    uint32_t sym  = ELF_R_SYM(rel->r_info);

    switch (type) {
        case R_AMD64_NONE: break;
        case R_AMD64_RELATIVE:
            EL_DEBUG("Applying R_AMD64_RELATIVE reloc @%p\n", p);
            *p = rel->r_addend + ctx->base_load_vaddr;
            break;
        default:
            EL_DEBUG("Bad relocation %u\n", type);
            return EL_BADREL;

    }

    return EL_OK;
}
示例#6
0
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
	const Elf_Rela *rela;

	if (!obj->relocbase)
		return 0;

	for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);

		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));

		/* Just relocate the GOT slots pointing into the PLT */
		*where += (Elf_Addr)obj->relocbase;
		rdbg(("lazy fixup pltgot %p in %s --> %p", where, obj->path,
		    (void *)*where));
	}

	return 0;
}
示例#7
0
文件: dl.c 项目: Arvian/GRUB2
void
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
				 grub_size_t *got)
{
  const Elf_Ehdr *e = ehdr;
  const Elf_Shdr *s;
  unsigned i;

  *tramp = 0;
  *got = 0;

  /* Find a symbol table.  */
  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
       i < e->e_shnum;
       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
    if (s->sh_type == SHT_SYMTAB)
      break;

  if (i == e->e_shnum)
    return;

  for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
       i < e->e_shnum;
       i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
    if (s->sh_type == SHT_RELA)
      {
	const Elf_Rela *rel, *max;
	
	for (rel = (const Elf_Rela *) ((const char *) e + s->sh_offset),
	       max = rel + s->sh_size / s->sh_entsize;
	     rel < max;
	     rel++)
	  if (ELF_R_TYPE (rel->r_info) == GRUB_ELF_R_PPC_REL24)
	    (*tramp)++;
	
      }

  return;
}
示例#8
0
/* ARGSUSED3 */
void
undo_reloc(void *vrel, uchar_t *oaddr, uchar_t *iaddr, Reloc *reloc)
{
	Rela		*rel = vrel;
	const Rel_entry	*rep;
	Xword		rtype = ELF_R_TYPE(rel->r_info, M_MACH);
	ulong_t		*_oaddr;
	ulong_t		*_iaddr;

	switch (rtype) {
	case R_SPARC_NONE:
		break;
	case R_SPARC_COPY:
		(void) memset((void *)oaddr, 0, (size_t)reloc->r_size);
		break;
	case R_SPARC_JMP_SLOT:
		/* LINTED */
		_oaddr = (unsigned long *)oaddr;
		/* LINTED */
		_iaddr = (unsigned long *)iaddr;

		if (_iaddr) {
			*_oaddr++ = *_iaddr++;
			*_oaddr++ = *_iaddr++;
			*_oaddr = *_iaddr;
		} else {
			*_oaddr++ = 0;
			*_oaddr++ = 0;
			*_oaddr = 0;
		}
		break;
	default:
		rep = &reloc_table[rtype];
		if (iaddr)
			(void) memcpy(oaddr, iaddr, rep->re_fsize);
		else
			(void) memset(oaddr, 0, rep->re_fsize);
	}
}
示例#9
0
/* ARGSUSED3 */
void
inc_reloc(void *vnrel, void *vorel, Reloc *reloc, uchar_t *oaddr,
    uchar_t *iaddr)
{
	Rela	*nrel = vnrel;
	Rela	*orel = vorel;

	if (ELF_R_TYPE(nrel->r_info, M_MACH) == R_AMD64_JUMP_SLOT) {
		/* LINTED */
		ulong_t	*_oaddr = (ulong_t *)oaddr;
		/* LINTED */
		ulong_t	*_iaddr = (ulong_t *)iaddr;

		if (_iaddr)
			*_oaddr = *_iaddr + reloc->r_value;
		else
			*_oaddr = reloc->r_value;
	}

	*nrel = *orel;
	nrel->r_offset += reloc->r_value;
}
示例#10
0
int
reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
{
	const Elf_Rela *relalim;
	const Elf_Rela *rela;
	Elf_Addr *where, target, *ptr;

	if (!obj->irelative)
		return (0);
	relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
	for (rela = obj->pltrela;  rela < relalim;  rela++) {
		if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE) {
			ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
			lock_release(rtld_bind_lock, lockstate);
			target = call_ifunc_resolver(ptr);
			wlock_acquire(rtld_bind_lock, lockstate);
			*where = target;
		}
	}
	obj->irelative = false;
	return (0);
}
示例#11
0
static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
	Elf_Addr *tp)
{
	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
	Elf_Addr new_value;
	const Elf_Sym  *def;
	const Obj_Entry *defobj;
	unsigned long info = rel->r_info;

	assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));

	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
	if (__predict_false(def == NULL))
		return -1;
	if (__predict_false(def == &_rtld_sym_zero))
		return 0;

	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
		if (tp == NULL)
			return 0;
		new_value = _rtld_resolve_ifunc(defobj, def);
	} else {
		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
	}
	/* Set the Thumb bit, if needed.  */
	if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
		new_value |= 1;
	rdbg(("bind now/fixup in %s --> old=%p new=%p",
	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
	if (*where != new_value)
		*where = new_value;
	if (tp)
		*tp = new_value;

	return 0;
}
示例#12
0
/*
 * LD_BIND_NOW was set - force relocation for all jump slots
 */
int
reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
{
	const Obj_Entry *defobj;
	const Elf_Rela *relalim;
	const Elf_Rela *rela;
	const Elf_Sym *def;

	if (obj->jmpslots_done)
		return (0);

	relalim = (const Elf_Rela *)((const char *)obj->pltrela +
	    obj->pltrelasize);
	for (rela = obj->pltrela; rela < relalim; rela++) {
		Elf_Addr *where, target;

		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
		switch(ELF_R_TYPE(rela->r_info)) {
		case R_AARCH64_JUMP_SLOT:
			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
			    &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
			if (def == NULL)
				return (-1);
			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
				obj->gnu_ifunc = true;
				continue;
			}
			target = (Elf_Addr)(defobj->relocbase + def->st_value);
			reloc_jmpslot(where, target, defobj, obj,
			    (const Elf_Rel *)rela);
			break;
		}
	}
	obj->jmpslots_done = true;

	return (0);
}
示例#13
0
int
reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
{
    const Elf_Rel *rellim;
    const Elf_Rel *rel;
    Elf_Addr *where, target;

    if (!obj->irelative)
	return (0);
    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
    for (rel = obj->pltrel;  rel < rellim;  rel++) {
	switch (ELF_R_TYPE(rel->r_info)) {
	case R_386_IRELATIVE:
	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
	  lock_release(rtld_bind_lock, lockstate);
	  target = call_ifunc_resolver(obj->relocbase + *where);
	  wlock_acquire(rtld_bind_lock, lockstate);
	  *where = target;
	  break;
	}
    }
    obj->irelative = false;
    return (0);
}
bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela,
                                    const ElfSymbols* symbols,
                                    SymbolResolver* resolver,
                                    Error* error) {
  const ELF::Word rel_type = ELF_R_TYPE(rela->r_info);
  const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info);

  ELF::Addr sym_addr = 0;
  ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
  RLOG("  reloc=%p offset=%p type=%d symbol=%d\n",
       reloc,
       rela->r_offset,
       rel_type,
       rel_symbol);

  if (rel_type == 0)
    return true;

  bool resolved = false;

  // If this is a symbolic relocation, compute the symbol's address.
  if (__builtin_expect(rel_symbol != 0, 0)) {
    if (!ResolveSymbol(rel_type,
                       rel_symbol,
                       symbols,
                       resolver,
                       reloc,
                       &sym_addr,
                       error)) {
      return false;
    }
    resolved = true;
  }

  return ApplyResolvedRelaReloc(rela, sym_addr, resolved, error);
}
示例#15
0
/* ARGSUSED3 */
void
undo_reloc(void *vrel, uchar_t *oaddr, uchar_t *iaddr, Reloc *reloc)
{
	Rela		*rel = vrel;
	Xword		rtype = ELF_R_TYPE(rel->r_info, M_MACH);

	switch (rtype) {
	case R_AMD64_NONE:
		break;
	case R_AMD64_COPY:
		(void) memset((void *)oaddr, 0, (size_t)reloc->r_size);
		break;
	case R_AMD64_JUMP_SLOT:
		{
			/* LINTED */
			ulong_t *_oaddr = (ulong_t *)oaddr;
			/* LINTED */
			ulong_t *_iaddr = (ulong_t *)iaddr;

			if (_iaddr)
				*_oaddr = *_iaddr + reloc->r_value;
			else
				*_oaddr = reloc->r_value;
		}
		break;
	default:
		{
			size_t re_fsize = reloc_table[rtype].re_fsize;

			if (iaddr)
				(void) memcpy(oaddr, iaddr, re_fsize);
			else
				(void) memset(oaddr, 0, re_fsize);
		}
	}
}
示例#16
0
/*
 * Read and process the relocations for one link object, we assume all
 * relocation sections for loadable segments are stored contiguously in
 * the file.
 */
int
elf_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel)
{
	ulong_t		relbgn, relend, relsiz, basebgn, pltbgn, pltend;
	ulong_t		_pltbgn, _pltend;
	ulong_t		dsymndx, roffset, rsymndx, psymndx = 0;
	uchar_t		rtype;
	long		value, pvalue;
	Sym		*symref, *psymref, *symdef, *psymdef;
	Syminfo		*sip;
	char		*name, *pname;
	Rt_map		*_lmp, *plmp;
	int		ret = 1, noplt = 0;
	int		relacount = RELACOUNT(lmp), plthint = 0;
	Rel		*rel;
	uint_t		binfo, pbinfo;
	APlist		*bound = NULL;

	/*
	 * Although only necessary for lazy binding, initialize the first
	 * global offset entry to go to elf_rtbndr().  dbx(1) seems
	 * to find this useful.
	 */
	if ((plt == 0) && PLTGOT(lmp)) {
		mmapobj_result_t	*mpp;

		/*
		 * Make sure the segment is writable.
		 */
		if ((((mpp =
		    find_segment((caddr_t)PLTGOT(lmp), lmp)) != NULL) &&
		    ((mpp->mr_prot & PROT_WRITE) == 0)) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL)))
			return (0);

		elf_plt_init(PLTGOT(lmp), (caddr_t)lmp);
	}

	/*
	 * Initialize the plt start and end addresses.
	 */
	if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0)
		pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp));

	relsiz = (ulong_t)(RELENT(lmp));
	basebgn = ADDR(lmp);

	if (PLTRELSZ(lmp))
		plthint = PLTRELSZ(lmp) / relsiz;

	/*
	 * If we've been called upon to promote an RTLD_LAZY object to an
	 * RTLD_NOW then we're only interested in scaning the .plt table.
	 * An uninitialized .plt is the case where the associated got entry
	 * points back to the plt itself.  Determine the range of the real .plt
	 * entries using the _PROCEDURE_LINKAGE_TABLE_ symbol.
	 */
	if (plt) {
		Slookup	sl;
		Sresult	sr;

		relbgn = pltbgn;
		relend = pltend;
		if (!relbgn || (relbgn == relend))
			return (1);

		/*
		 * Initialize the symbol lookup, and symbol result, data
		 * structures.
		 */
		SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_PLT), lmp, lmp, ld_entry_cnt,
		    elf_hash(MSG_ORIG(MSG_SYM_PLT)), 0, 0, 0, LKUP_DEFT);
		SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_PLT));

		if (elf_find_sym(&sl, &sr, &binfo, NULL) == 0)
			return (1);

		symdef = sr.sr_sym;
		_pltbgn = symdef->st_value;
		if (!(FLAGS(lmp) & FLG_RT_FIXED) &&
		    (symdef->st_shndx != SHN_ABS))
			_pltbgn += basebgn;
		_pltend = _pltbgn + (((PLTRELSZ(lmp) / relsiz)) *
		    M_PLT_ENTSIZE) + M_PLT_RESERVSZ;

	} else {
		/*
		 * The relocation sections appear to the run-time linker as a
		 * single table.  Determine the address of the beginning and end
		 * of this table.  There are two different interpretations of
		 * the ABI at this point:
		 *
		 *   o	The REL table and its associated RELSZ indicate the
		 *	concatenation of *all* relocation sections (this is the
		 *	model our link-editor constructs).
		 *
		 *   o	The REL table and its associated RELSZ indicate the
		 *	concatenation of all *but* the .plt relocations.  These
		 *	relocations are specified individually by the JMPREL and
		 *	PLTRELSZ entries.
		 *
		 * Determine from our knowledege of the relocation range and
		 * .plt range, the range of the total relocation table.  Note
		 * that one other ABI assumption seems to be that the .plt
		 * relocations always follow any other relocations, the
		 * following range checking drops that assumption.
		 */
		relbgn = (ulong_t)(REL(lmp));
		relend = relbgn + (ulong_t)(RELSZ(lmp));
		if (pltbgn) {
			if (!relbgn || (relbgn > pltbgn))
				relbgn = pltbgn;
			if (!relbgn || (relend < pltend))
				relend = pltend;
		}
	}
	if (!relbgn || (relbgn == relend)) {
		DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE));
		return (1);
	}
	DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START));

	/*
	 * If we're processing a dynamic executable in lazy mode there is no
	 * need to scan the .rel.plt table, however if we're processing a shared
	 * object in lazy mode the .got addresses associated to each .plt must
	 * be relocated to reflect the location of the shared object.
	 */
	if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0) &&
	    (FLAGS(lmp) & FLG_RT_FIXED))
		noplt = 1;

	sip = SYMINFO(lmp);
	/*
	 * Loop through relocations.
	 */
	while (relbgn < relend) {
		mmapobj_result_t	*mpp;
		uint_t			sb_flags = 0;

		rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH);

		/*
		 * If this is a RELATIVE relocation in a shared object (the
		 * common case), and if we are not debugging, then jump into a
		 * tighter relocation loop (elf_reloc_relative).
		 */
		if ((rtype == R_386_RELATIVE) &&
		    ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) {
			if (relacount) {
				relbgn = elf_reloc_relative_count(relbgn,
				    relacount, relsiz, basebgn, lmp,
				    textrel, 0);
				relacount = 0;
			} else {
				relbgn = elf_reloc_relative(relbgn, relend,
				    relsiz, basebgn, lmp, textrel, 0);
			}
			if (relbgn >= relend)
				break;
			rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH);
		}

		roffset = ((Rel *)relbgn)->r_offset;

		/*
		 * If this is a shared object, add the base address to offset.
		 */
		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
			/*
			 * If we're processing lazy bindings, we have to step
			 * through the plt entries and add the base address
			 * to the corresponding got entry.
			 */
			if (plthint && (plt == 0) &&
			    (rtype == R_386_JMP_SLOT) &&
			    ((MODE(lmp) & RTLD_NOW) == 0)) {
				relbgn = elf_reloc_relative_count(relbgn,
				    plthint, relsiz, basebgn, lmp, textrel, 0);
				plthint = 0;
				continue;
			}
			roffset += basebgn;
		}

		rsymndx = ELF_R_SYM(((Rel *)relbgn)->r_info);
		rel = (Rel *)relbgn;
		relbgn += relsiz;

		/*
		 * Optimizations.
		 */
		if (rtype == R_386_NONE)
			continue;
		if (noplt && ((ulong_t)rel >= pltbgn) &&
		    ((ulong_t)rel < pltend)) {
			relbgn = pltend;
			continue;
		}

		/*
		 * If we're promoting plts, determine if this one has already
		 * been written.
		 */
		if (plt && ((*(ulong_t *)roffset < _pltbgn) ||
		    (*(ulong_t *)roffset > _pltend)))
			continue;

		/*
		 * If this relocation is not against part of the image
		 * mapped into memory we skip it.
		 */
		if ((mpp = find_segment((caddr_t)roffset, lmp)) == NULL) {
			elf_reloc_bad(lmp, (void *)rel, rtype, roffset,
			    rsymndx);
			continue;
		}

		binfo = 0;
		/*
		 * If a symbol index is specified then get the symbol table
		 * entry, locate the symbol definition, and determine its
		 * address.
		 */
		if (rsymndx) {
			/*
			 * If a Syminfo section is provided, determine if this
			 * symbol is deferred, and if so, skip this relocation.
			 */
			if (sip && is_sym_deferred((ulong_t)rel, basebgn, lmp,
			    textrel, sip, rsymndx))
				continue;

			/*
			 * Get the local symbol table entry.
			 */
			symref = (Sym *)((ulong_t)SYMTAB(lmp) +
			    (rsymndx * SYMENT(lmp)));

			/*
			 * If this is a local symbol, just use the base address.
			 * (we should have no local relocations in the
			 * executable).
			 */
			if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) {
				value = basebgn;
				name = NULL;

				/*
				 * Special case TLS relocations.
				 */
				if (rtype == R_386_TLS_DTPMOD32) {
					/*
					 * Use the TLS modid.
					 */
					value = TLSMODID(lmp);

				} else if (rtype == R_386_TLS_TPOFF) {
					if ((value = elf_static_tls(lmp, symref,
					    rel, rtype, 0, roffset, 0)) == 0) {
						ret = 0;
						break;
					}
				}
			} else {
				/*
				 * If the symbol index is equal to the previous
				 * symbol index relocation we processed then
				 * reuse the previous values. (Note that there
				 * have been cases where a relocation exists
				 * against a copy relocation symbol, our ld(1)
				 * should optimize this away, but make sure we
				 * don't use the same symbol information should
				 * this case exist).
				 */
				if ((rsymndx == psymndx) &&
				    (rtype != R_386_COPY)) {
					/* LINTED */
					if (psymdef == 0) {
						DBG_CALL(Dbg_bind_weak(lmp,
						    (Addr)roffset, (Addr)
						    (roffset - basebgn), name));
						continue;
					}
					/* LINTED */
					value = pvalue;
					/* LINTED */
					name = pname;
					/* LINTED */
					symdef = psymdef;
					/* LINTED */
					symref = psymref;
					/* LINTED */
					_lmp = plmp;
					/* LINTED */
					binfo = pbinfo;

					if ((LIST(_lmp)->lm_tflags |
					    AFLAGS(_lmp)) &
					    LML_TFLG_AUD_SYMBIND) {
						value = audit_symbind(lmp, _lmp,
						    /* LINTED */
						    symdef, dsymndx, value,
						    &sb_flags);
					}
				} else {
					Slookup		sl;
					Sresult		sr;

					/*
					 * Lookup the symbol definition.
					 * Initialize the symbol lookup, and
					 * symbol result, data structures.
					 */
					name = (char *)(STRTAB(lmp) +
					    symref->st_name);

					SLOOKUP_INIT(sl, name, lmp, 0,
					    ld_entry_cnt, 0, rsymndx, symref,
					    rtype, LKUP_STDRELOC);
					SRESULT_INIT(sr, name);
					symdef = NULL;

					if (lookup_sym(&sl, &sr, &binfo,
					    in_nfavl)) {
						name = (char *)sr.sr_name;
						_lmp = sr.sr_dmap;
						symdef = sr.sr_sym;
					}

					/*
					 * If the symbol is not found and the
					 * reference was not to a weak symbol,
					 * report an error.  Weak references
					 * may be unresolved.
					 */
					/* BEGIN CSTYLED */
					if (symdef == 0) {
					    if (sl.sl_bind != STB_WEAK) {
						if (elf_reloc_error(lmp, name,
						    rel, binfo))
							continue;

					   	ret = 0;
						break;

					    } else {
						psymndx = rsymndx;
						psymdef = 0;

						DBG_CALL(Dbg_bind_weak(lmp,
						    (Addr)roffset, (Addr)
						    (roffset - basebgn), name));
						continue;
					    }
					}
					/* END CSTYLED */

					/*
					 * If symbol was found in an object
					 * other than the referencing object
					 * then record the binding.
					 */
					if ((lmp != _lmp) && ((FLAGS1(_lmp) &
					    FL1_RT_NOINIFIN) == 0)) {
						if (aplist_test(&bound, _lmp,
						    AL_CNT_RELBIND) == 0) {
							ret = 0;
							break;
						}
					}

					/*
					 * Calculate the location of definition;
					 * symbol value plus base address of
					 * containing shared object.
					 */
					if (IS_SIZE(rtype))
						value = symdef->st_size;
					else
						value = symdef->st_value;

					if (!(FLAGS(_lmp) & FLG_RT_FIXED) &&
					    !(IS_SIZE(rtype)) &&
					    (symdef->st_shndx != SHN_ABS) &&
					    (ELF_ST_TYPE(symdef->st_info) !=
					    STT_TLS))
						value += ADDR(_lmp);

					/*
					 * Retain this symbol index and the
					 * value in case it can be used for the
					 * subsequent relocations.
					 */
					if (rtype != R_386_COPY) {
						psymndx = rsymndx;
						pvalue = value;
						pname = name;
						psymdef = symdef;
						psymref = symref;
						plmp = _lmp;
						pbinfo = binfo;
					}
					if ((LIST(_lmp)->lm_tflags |
					    AFLAGS(_lmp)) &
					    LML_TFLG_AUD_SYMBIND) {
						dsymndx = (((uintptr_t)symdef -
						    (uintptr_t)SYMTAB(_lmp)) /
						    SYMENT(_lmp));
						value = audit_symbind(lmp, _lmp,
						    symdef, dsymndx, value,
						    &sb_flags);
					}
				}

				/*
				 * If relocation is PC-relative, subtract
				 * offset address.
				 */
				if (IS_PC_RELATIVE(rtype))
					value -= roffset;

				/*
				 * Special case TLS relocations.
				 */
				if (rtype == R_386_TLS_DTPMOD32) {
					/*
					 * Relocation value is the TLS modid.
					 */
					value = TLSMODID(_lmp);

				} else if (rtype == R_386_TLS_TPOFF) {
					if ((value = elf_static_tls(_lmp,
					    symdef, rel, rtype, name, roffset,
					    value)) == 0) {
						ret = 0;
						break;
					}
				}
			}
		} else {
			/*
			 * Special cases.
			 */
			if (rtype == R_386_TLS_DTPMOD32) {
				/*
				 * TLS relocation value is the TLS modid.
				 */
				value = TLSMODID(lmp);
			} else
				value = basebgn;

			name = NULL;
		}

		DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH,
		    M_REL_SHT_TYPE, rel, NULL, 0, name));

		/*
		 * Make sure the segment is writable.
		 */
		if (((mpp->mr_prot & PROT_WRITE) == 0) &&
		    ((set_prot(lmp, mpp, 1) == 0) ||
		    (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) {
			ret = 0;
			break;
		}

		/*
		 * Call relocation routine to perform required relocation.
		 */
		switch (rtype) {
		case R_386_COPY:
			if (elf_copy_reloc(name, symref, lmp, (void *)roffset,
			    symdef, _lmp, (const void *)value) == 0)
				ret = 0;
			break;
		case R_386_JMP_SLOT:
			if (((LIST(lmp)->lm_tflags | AFLAGS(lmp)) &
			    (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) &&
			    AUDINFO(lmp)->ai_dynplts) {
				int	fail = 0;
				int	pltndx = (((ulong_t)rel -
				    (uintptr_t)JMPREL(lmp)) / relsiz);
				int	symndx = (((uintptr_t)symdef -
				    (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp));

				(void) elf_plt_trace_write(roffset, lmp, _lmp,
				    symdef, symndx, pltndx, (caddr_t)value,
				    sb_flags, &fail);
				if (fail)
					ret = 0;
			} else {
				/*
				 * Write standard PLT entry to jump directly
				 * to newly bound function.
				 */
				DBG_CALL(Dbg_reloc_apply_val(LIST(lmp),
				    ELF_DBG_RTLD, (Xword)roffset,
				    (Xword)value));
				*(ulong_t *)roffset = value;
			}
			break;
		default:
			/*
			 * Write the relocation out.
			 */
			if (do_reloc_rtld(rtype, (uchar_t *)roffset,
			    (Word *)&value, name, NAME(lmp), LIST(lmp)) == 0)
				ret = 0;

			DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD,
			    (Xword)roffset, (Xword)value));
		}

		if ((ret == 0) &&
		    ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0))
			break;

		if (binfo) {
			DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset,
			    (Off)(roffset - basebgn), (Xword)(-1), PLT_T_FULL,
			    _lmp, (Addr)value, symdef->st_value, name, binfo));
		}
	}

	return (relocate_finish(lmp, bound, ret));
}
示例#17
0
/* Process the non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
    RtldLockState *lockstate)
{
	const Elf_Rela *relalim;
	const Elf_Rela *rela;
	SymCache *cache;
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Elf_Addr *where, symval;
	Elf32_Addr *where32;
	int r;

	r = -1;
	/*
	 * The dynamic loader may be called from a thread, we have
	 * limited amounts of stack available so we cannot use alloca().
	 */
	if (obj != obj_rtld) {
		cache = calloc(obj->dynsymcount, sizeof(SymCache));
		/* No need to check for NULL here */
	} else
		cache = NULL;

	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
	for (rela = obj->rela;  rela < relalim;  rela++) {
		/*
		 * First, resolve symbol for relocations which
		 * reference symbols.
		 */
		switch (ELF_R_TYPE(rela->r_info)) {
		case R_X86_64_64:
		case R_X86_64_PC32:
		case R_X86_64_GLOB_DAT:
		case R_X86_64_TPOFF64:
		case R_X86_64_TPOFF32:
		case R_X86_64_DTPMOD64:
		case R_X86_64_DTPOFF64:
		case R_X86_64_DTPOFF32:
			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
			    &defobj, flags, cache, lockstate);
			if (def == NULL)
				goto done;
			/*
			 * If symbol is IFUNC, only perform relocation
			 * when caller allowed it by passing
			 * SYMLOOK_IFUNC flag.  Skip the relocations
			 * otherwise.
			 *
			 * Also error out in case IFUNC relocations
			 * are specified for TLS, which cannot be
			 * usefully interpreted.
			 */
			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
				switch (ELF_R_TYPE(rela->r_info)) {
				case R_X86_64_64:
				case R_X86_64_PC32:
				case R_X86_64_GLOB_DAT:
					if ((flags & SYMLOOK_IFUNC) == 0) {
						obj->non_plt_gnu_ifunc = true;
						continue;
					}
					symval = (Elf_Addr)rtld_resolve_ifunc(
					    defobj, def);
					break;
				case R_X86_64_TPOFF64:
				case R_X86_64_TPOFF32:
				case R_X86_64_DTPMOD64:
				case R_X86_64_DTPOFF64:
				case R_X86_64_DTPOFF32:
					_rtld_error("%s: IFUNC for TLS reloc",
					    obj->path);
					goto done;
				}
			} else {
				if ((flags & SYMLOOK_IFUNC) != 0)
					continue;
				symval = (Elf_Addr)defobj->relocbase +
				    def->st_value;
			}
			break;
		default:
			if ((flags & SYMLOOK_IFUNC) != 0)
				continue;
			break;
		}
		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
		where32 = (Elf32_Addr *)where;

		switch (ELF_R_TYPE(rela->r_info)) {
		case R_X86_64_NONE:
			break;
		case R_X86_64_64:
			*where = symval + rela->r_addend;
			break;
		case R_X86_64_PC32:
			/*
			 * I don't think the dynamic linker should
			 * ever see this type of relocation.  But the
			 * binutils-2.6 tools sometimes generate it.
			 */
			*where32 = (Elf32_Addr)(unsigned long)(symval +
		            rela->r_addend - (Elf_Addr)where);
			break;
		/* missing: R_X86_64_GOT32 R_X86_64_PLT32 */
		case R_X86_64_COPY:
			/*
			 * These are deferred until all other relocations have
			 * been done.  All we do here is make sure that the COPY
			 * relocation is not in a shared library.  They are
			 * allowed only in executable files.
			 */
			if (!obj->mainprog) {
				_rtld_error("%s: Unexpected R_X86_64_COPY "
				    "relocation in shared library", obj->path);
				goto done;
			}
			break;
		case R_X86_64_GLOB_DAT:
			*where = symval;
			break;
		case R_X86_64_TPOFF64:
			/*
			 * We lazily allocate offsets for static TLS
			 * as we see the first relocation that
			 * references the TLS block. This allows us to
			 * support (small amounts of) static TLS in
			 * dynamically loaded modules. If we run out
			 * of space, we generate an error.
			 */
			if (!defobj->tls_done) {
				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
					_rtld_error("%s: No space available "
					    "for static Thread Local Storage",
					    obj->path);
					goto done;
				}
			}
			*where = (Elf_Addr)(def->st_value - defobj->tlsoffset +
			    rela->r_addend);
			break;
		case R_X86_64_TPOFF32:
			/*
			 * We lazily allocate offsets for static TLS
			 * as we see the first relocation that
			 * references the TLS block. This allows us to
			 * support (small amounts of) static TLS in
			 * dynamically loaded modules. If we run out
			 * of space, we generate an error.
			 */
			if (!defobj->tls_done) {
				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
					_rtld_error("%s: No space available "
					    "for static Thread Local Storage",
					    obj->path);
					goto done;
				}
			}
			*where32 = (Elf32_Addr)(def->st_value -
			    defobj->tlsoffset + rela->r_addend);
			break;
		case R_X86_64_DTPMOD64:
			*where += (Elf_Addr)defobj->tlsindex;
			break;
		case R_X86_64_DTPOFF64:
			*where += (Elf_Addr)(def->st_value + rela->r_addend);
			break;
		case R_X86_64_DTPOFF32:
			*where32 += (Elf32_Addr)(def->st_value +
			    rela->r_addend);
			break;
		case R_X86_64_RELATIVE:
			*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
			break;
		/*
		 * missing:
		 * R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16,
		 * R_X86_64_PC16, R_X86_64_8, R_X86_64_PC8
		 */
		default:
			_rtld_error("%s: Unsupported relocation type %u"
			    " in non-PLT relocations\n", obj->path,
			    (unsigned int)ELF_R_TYPE(rela->r_info));
			goto done;
		}
	}
	r = 0;
done:
	free(cache);
	return (r);
}
示例#18
0
/*
 * 1. _gp_disp symbol are not considered in this file.
 * 2. There is a local/external column;
 * local corresponds to (STB_LOCAL & STT_SECTION) and
 * all others are external. Because if the type of a
 * symbol is STT_SECTION, it must be STB_LOCAL. Thus
 * just consider symtype here.
 */
bool
rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
                            const Elf_Rel*              rel,
                            const rtems_rtl_obj_sect_t* sect,
                            const char*                 symname,
                            const Elf_Byte              syminfo,
                            const Elf_Word              symvalue)
{
  Elf_Addr *where;
  Elf_Word  tmp;
  Elf_Word addend = (Elf_Word)0;
  Elf_Word local = 0;
  uint32_t t;


  static Elf_Addr *where_hi16;
  static Elf_Addr ahl;

  where = (Elf_Addr *)(sect->base + rel->r_offset);
  addend = *where;

  if (syminfo == STT_SECTION)
    local = 1;

  switch (ELF_R_TYPE(rel->r_info)) {
    case R_TYPE(NONE):
      break;

    case R_TYPE(16):
      tmp = addend & 0xffff;
      if ((tmp & 0x8000) == 0x8000)
        tmp |= 0xffff0000; /* Sign extend */
      tmp = symvalue + (int)tmp;
      if ((tmp & 0xffff0000) != 0) {
        printf("R_MIPS_16 Overflow\n");
        return false;
      }

      *where = (tmp & 0xffff) | (*where & 0xffff0000);

      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: R_MIPS_16 %p @ %p in %s\n",
                (void *)*(where), where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(32):
      tmp = symvalue + addend;
      if (addend != tmp)
        *where = tmp;

      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: R_MIPS_32 %p @ %p in %s\n",
                (void *)*(where), where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(26):

        addend &= 0x03ffffff;
        addend <<= 2;

      if (local == 1) { /* STB_LOCAL and STT_SECTION */
        tmp = symvalue + (((Elf_Addr)where & 0xf0000000) | addend);
        tmp >>= 2;

      } else { /* external */
示例#19
0
static int extract_elf_rel(struct module_verify_data *mvdata,
			   int secix,
			   const Elf_Rel *reltab, size_t nrels,
			   const char *sh_name)
{
	struct {
#if defined(MODULES_ARE_ELF32)
		uint32_t	r_offset;
		uint32_t	st_value;
		uint32_t	st_size;
		uint16_t	st_shndx;
		uint8_t		r_type;
		uint8_t		st_info;
		uint8_t		st_other;
#elif defined(MODULES_ARE_ELF64)
		uint64_t	r_offset;
		uint64_t	st_value;
		uint64_t	st_size;
		uint32_t	r_type;
		uint16_t	st_shndx;
		uint8_t		st_info;
		uint8_t		st_other;
#else
#error unsupported module type
#endif
	} __attribute__((packed)) relocation;

	const Elf_Rel *reloc;
	const Elf_Sym *symbol;
	size_t loop;

	/* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
	for (loop = 0; loop < nrels; loop++) {
		int st_shndx;

		reloc = &reltab[loop];

		/* decode the relocation */
		relocation.r_offset = reloc->r_offset;
		relocation.r_type = ELF_R_TYPE(reloc->r_info);

		/* decode the symbol referenced by the relocation */
		symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)];
		relocation.st_info = symbol->st_info;
		relocation.st_other = symbol->st_other;
		relocation.st_value = symbol->st_value;
		relocation.st_size = symbol->st_size;
		relocation.st_shndx = symbol->st_shndx;
		st_shndx = symbol->st_shndx;

		/* canonicalise the section used by the symbol */
		if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects)
			relocation.st_shndx = mvdata->canonmap[st_shndx];

		crypto_digest_update_val(mvdata, relocation);

		/* undefined symbols must be named if referenced */
		if (st_shndx == SHN_UNDEF) {
			const char *name = mvdata->strings + symbol->st_name;
			crypto_digest_update_data(mvdata,
						  name, strlen(name) + 1);
		}
	}

	_debug("%08zx %02x digested the %s section, nrels %zu\n",
	       mvdata->signed_size, mvdata->csum, sh_name, nrels);

	return 0;
} /* end extract_elf_rel() */
示例#20
0
文件: mdreloc.c 项目: ryo/netbsd-src
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{

    for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) {
        Elf_Addr        *where;
        const Elf_Sym   *def;
        const Obj_Entry *defobj;
        unsigned long	 symnum;
        Elf_Addr	 addend;

        where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
        symnum = ELF_R_SYM(rela->r_info);
        addend = rela->r_addend;

        switch (ELF_R_TYPE(rela->r_info)) {
        case R_TYPE(NONE):
            break;

        case R_TYPE(ABS64):	/* word B + S + A */
        case R_TYPE(GLOB_DAT):	/* word B + S */
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;
            *where = addend + (Elf_Addr)defobj->relocbase +
                     def->st_value;
            rdbg(("ABS64/GLOB_DAT %s in %s --> %p @ %p in %s",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp, where, defobj->path));
            break;

        case R_TYPE(RELATIVE):	/* word B + A */
            *where = addend + (Elf_Addr)obj->relocbase;
            rdbg(("RELATIVE in %s --> %p", obj->path,
                  (void *)tmp));
            break;

        case R_TYPE(COPY):
            /*
             * These are deferred until all other relocations have
             * been done.  All we do here is make sure that the
             * COPY relocation is not in a shared library.  They
             * are allowed only in executable files.
             */
            if (obj->isdynamic) {
                _rtld_error(
                    "%s: Unexpected R_COPY relocation in shared library",
                    obj->path);
                return -1;
            }
            rdbg(("COPY (avoid in main)"));
            break;

        case R_TLS_TYPE(TLS_DTPREL):
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;

            *where = addend + (Elf_Addr)(def->st_value);

            rdbg(("TLS_DTPOFF32 %s in %s --> %p",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp));

            break;
        case R_TLS_TYPE(TLS_DTPMOD):
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;

            *where = (Elf_Addr)(defobj->tlsindex);

            rdbg(("TLS_DTPMOD %s in %s --> %p",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp));

            break;

        case R_TLS_TYPE(TLS_TPREL):
            def = _rtld_find_symdef(symnum, obj, &defobj, false);
            if (def == NULL)
                return -1;

            if (!defobj->tls_done &&
                    _rtld_tls_offset_allocate(obj))
                return -1;

            *where = (Elf_Addr)def->st_value + defobj->tlsoffset +
                     sizeof(struct tls_tcb);
            rdbg(("TLS_TPOFF32 %s in %s --> %p",
                  obj->strtab + obj->symtab[symnum].st_name,
                  obj->path, (void *)tmp));
            break;

        default:
            rdbg(("sym = %lu, type = %lu, offset = %p, "
                  "contents = %p, symbol = %s",
                  symnum, (u_long)ELF_R_TYPE(rela->r_info),
                  (void *)rela->r_offset, *where,
                  obj->strtab + obj->symtab[symnum].st_name));
            _rtld_error("%s: Unsupported relocation type %ld "
                        "in non-PLT relocations",
                        obj->path, (u_long) ELF_R_TYPE(rela->r_info));
            return -1;
        }
    }
    return 0;
}
示例#21
0
/* Process the non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
    RtldLockState *lockstate)
{
	const Elf_Rel *rellim;
	const Elf_Rel *rel;
	SymCache *cache;
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Elf_Addr *where, symval, add;
	int r;

	r = -1;
	/*
	 * The dynamic loader may be called from a thread, we have
	 * limited amounts of stack available so we cannot use alloca().
	 */
	if (obj != obj_rtld) {
		cache = calloc(obj->dynsymcount, sizeof(SymCache));
		/* No need to check for NULL here */
	} else
		cache = NULL;

	rellim = (const Elf_Rel *)((caddr_t) obj->rel + obj->relsize);
	for (rel = obj->rel;  rel < rellim;  rel++) {
		switch (ELF_R_TYPE(rel->r_info)) {
		case R_386_32:
		case R_386_PC32:
		case R_386_GLOB_DAT:
		case R_386_TLS_TPOFF:
		case R_386_TLS_TPOFF32:
		case R_386_TLS_DTPMOD32:
		case R_386_TLS_DTPOFF32:
			def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
			    flags, cache, lockstate);
			if (def == NULL)
				goto done;
			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
				switch (ELF_R_TYPE(rel->r_info)) {
				case R_386_32:
				case R_386_PC32:
				case R_386_GLOB_DAT:
					if ((flags & SYMLOOK_IFUNC) == 0) {
						obj->non_plt_gnu_ifunc = true;
						continue;
					}
					symval = (Elf_Addr)rtld_resolve_ifunc(
					    defobj, def);
					break;
				case R_386_TLS_TPOFF:
				case R_386_TLS_TPOFF32:
				case R_386_TLS_DTPMOD32:
				case R_386_TLS_DTPOFF32:
					_rtld_error("%s: IFUNC for TLS reloc",
					    obj->path);
					goto done;
				}
			} else {
				if ((flags & SYMLOOK_IFUNC) != 0)
					continue;
				symval = (Elf_Addr)defobj->relocbase +
				    def->st_value;
			}
			break;
		default:
			if ((flags & SYMLOOK_IFUNC) != 0)
				continue;
			break;
		}
		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);

		switch (ELF_R_TYPE(rel->r_info)) {
		case R_386_NONE:
			break;
		case R_386_32:
			*where += symval;
			break;
		case R_386_PC32:
		    /*
		     * I don't think the dynamic linker should ever
		     * see this type of relocation.  But the
		     * binutils-2.6 tools sometimes generate it.
		     */
		    *where += symval - (Elf_Addr)where;
		    break;
		case R_386_COPY:
			/*
			 * These are deferred until all other
			 * relocations have been done.  All we do here
			 * is make sure that the COPY relocation is
			 * not in a shared library.  They are allowed
			 * only in executable files.
			 */
			if (!obj->mainprog) {
				_rtld_error("%s: Unexpected R_386_COPY "
				    "relocation in shared library", obj->path);
				goto done;
			}
			break;
		case R_386_GLOB_DAT:
			*where = symval;
			break;
		case R_386_RELATIVE:
			*where += (Elf_Addr)obj->relocbase;
			break;
		case R_386_TLS_TPOFF:
		case R_386_TLS_TPOFF32:
			/*
			 * We lazily allocate offsets for static TLS
			 * as we see the first relocation that
			 * references the TLS block. This allows us to
			 * support (small amounts of) static TLS in
			 * dynamically loaded modules. If we run out
			 * of space, we generate an error.
			 */
			if (!defobj->tls_done) {
				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
					_rtld_error("%s: No space available "
					    "for static Thread Local Storage",
					    obj->path);
					goto done;
				}
			}
			add = (Elf_Addr)(def->st_value - defobj->tlsoffset);
			if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF)
				*where += add;
			else
				*where -= add;
			break;
		case R_386_TLS_DTPMOD32:
			*where += (Elf_Addr)defobj->tlsindex;
			break;
		case R_386_TLS_DTPOFF32:
			*where += (Elf_Addr) def->st_value;
			break;
		default:
			_rtld_error("%s: Unsupported relocation type %d"
			    " in non-PLT relocations\n", obj->path,
			    ELF_R_TYPE(rel->r_info));
			goto done;
		}
	}
	r = 0;
done:
	free(cache);
	return (r);
}
示例#22
0
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
    int type, int local, elf_lookup_fn lookup)
{
	Elf64_Addr *where, val;
	Elf32_Addr *where32, val32;
	Elf_Addr addr;
	Elf_Addr addend;
	Elf_Size rtype, symidx;
	const Elf_Rel *rel;
	const Elf_Rela *rela;

	switch (type) {
	case ELF_RELOC_REL:
		rel = (const Elf_Rel *)data;
		where = (Elf_Addr *) (relocbase + rel->r_offset);
		rtype = ELF_R_TYPE(rel->r_info);
		symidx = ELF_R_SYM(rel->r_info);
		/* Addend is 32 bit on 32 bit relocs */
		switch (rtype) {
		case R_X86_64_PC32:
		case R_X86_64_32S:
			addend = *(Elf32_Addr *)where;
			break;
		default:
			addend = *where;
			break;
		}
		break;
	case ELF_RELOC_RELA:
		rela = (const Elf_Rela *)data;
		where = (Elf_Addr *) (relocbase + rela->r_offset);
		addend = rela->r_addend;
		rtype = ELF_R_TYPE(rela->r_info);
		symidx = ELF_R_SYM(rela->r_info);
		break;
	default:
		panic("unknown reloc type %d\n", type);
	}

	switch (rtype) {

		case R_X86_64_NONE:	/* none */
			break;

		case R_X86_64_64:		/* S + A */
			addr = lookup(lf, symidx, 1);
			val = addr + addend;
			if (addr == 0)
				return -1;
			if (*where != val)
				*where = val;
			break;

		case R_X86_64_PC32:	/* S + A - P */
			addr = lookup(lf, symidx, 1);
			where32 = (Elf32_Addr *)where;
			val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where);
			if (addr == 0)
				return -1;
			if (*where32 != val32)
				*where32 = val32;
			break;

		case R_X86_64_32S:	/* S + A sign extend */
			addr = lookup(lf, symidx, 1);
			val32 = (Elf32_Addr)(addr + addend);
			where32 = (Elf32_Addr *)where;
			if (addr == 0)
				return -1;
			if (*where32 != val32)
				*where32 = val32;
			break;

		case R_X86_64_COPY:	/* none */
			/*
			 * There shouldn't be copy relocations in kernel
			 * objects.
			 */
			printf("kldload: unexpected R_COPY relocation\n");
			return -1;
			break;

		case R_X86_64_GLOB_DAT:	/* S */
		case R_X86_64_JMP_SLOT:	/* XXX need addend + offset */
			addr = lookup(lf, symidx, 1);
			if (addr == 0)
				return -1;
			if (*where != addr)
				*where = addr;
			break;

		case R_X86_64_RELATIVE:	/* B + A */
			addr = relocbase + addend;
			val = addr;
			if (*where != val)
				*where = val;
			break;

		default:
			printf("kldload: unexpected relocation type %ld\n",
			       rtype);
			return -1;
	}
	return(0);
}
示例#23
0
int
_dl_md_reloc(elf_object_t *object, int rel, int relasz)
{
	long	i;
	long	numrela;
	int	fails = 0;
	Elf64_Addr loff;
	Elf64_Rela  *relas;
	struct load_list *llist;

	loff = object->obj_base;
	numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela);
	relas = (Elf64_Rela *)(object->Dyn.info[rel]);

	if (relas == NULL)
		return(0);

	/*
	 * unprotect some segments if we need it.
	 * XXX - we unprotect way to much. only the text can have cow
	 * relocations.
	 */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE)) {
				_dl_mprotect(llist->start, llist->size,
				    llist->prot|PROT_WRITE);
			}
		}
	}

	for (i = 0; i < numrela; i++, relas++) {
		Elf64_Addr *r_addr;
		Elf64_Addr ooff;
		const Elf64_Sym *sym, *this;
		const char *symn;

		r_addr = (Elf64_Addr *)(relas->r_offset + loff);

		if (ELF64_R_SYM(relas->r_info) == 0xffffffff)
			continue;


		sym = object->dyn.symtab;
		sym += ELF64_R_SYM(relas->r_info);
		symn = object->dyn.strtab + sym->st_name;

		this = NULL;
		switch (ELF64_R_TYPE(relas->r_info)) {
		case R_TYPE(REFQUAD):
			ooff =  _dl_find_symbol_bysym(object,
			    ELF64_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr += ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(RELATIVE):
			/*
			 * There is a lot of unaligned RELATIVE
			 * relocs generated by gcc in the exception handlers.
			 */
			if ((((Elf_Addr) r_addr) & 0x7) != 0) {
				Elf_Addr tmp;
#if 0
_dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
    ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
#endif
				_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
				tmp += loff;
				_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
			} else
				*r_addr += loff;
			break;
		case R_TYPE(JMP_SLOT):
			ooff = _dl_find_symbol(symn, &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
			    sym, object, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr = ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(GLOB_DAT):
			ooff =  _dl_find_symbol_bysym(object,
			    ELF64_R_SYM(relas->r_info), &this,
			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
			    sym, NULL);
			if (this == NULL)
				goto resolve_failed;
			*r_addr = ooff + this->st_value + relas->r_addend;
			break;
		case R_TYPE(NONE):
			break;
		default:
			_dl_printf("%s:"
			    " %s: unsupported relocation '%s' %d at %lx\n",
			    _dl_progname, object->load_name, symn,
			    ELF64_R_TYPE(relas->r_info), r_addr );
			_dl_exit(1);
		}
		continue;
resolve_failed:
		if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
			fails++;
	}
	__asm __volatile("imb" : : : "memory");

	/* reprotect the unprotected segments */
	if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) {
		for (llist = object->load_list; llist != NULL; llist = llist->next) {
			if (!(llist->prot & PROT_WRITE))
				_dl_mprotect(llist->start, llist->size,
				    llist->prot);
		}
	}
	return (fails);
}
示例#24
0
文件: reloc.c 项目: Alkzndr/freebsd
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
	const Elf_Rel *rel = 0, *rellim;
	Elf_Addr relsz = 0;
	const Elf_Sym *symtab = NULL, *sym;
	Elf_Addr *where;
	Elf_Addr *got = NULL;
	Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
	size_t i;

	for (; dynp->d_tag != DT_NULL; dynp++) {
		switch (dynp->d_tag) {
		case DT_REL:
			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
			break;
		case DT_SYMTAB:
			symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_PLTGOT:
			got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_MIPS_LOCAL_GOTNO:
			local_gotno = dynp->d_un.d_val;
			break;
		case DT_MIPS_SYMTABNO:
			symtabno = dynp->d_un.d_val;
			break;
		case DT_MIPS_GOTSYM:
			gotsym = dynp->d_un.d_val;
			break;
		}
	}

	i = (got[1] & GOT1_MASK) ? 2 : 1;
	/* Relocate the local GOT entries */
	got += i;
	for (; i < local_gotno; i++) {
		*got++ += relocbase;
	}

	sym = symtab + gotsym;
	/* Now do the global GOT entries */
	for (i = gotsym; i < symtabno; i++) {
		*got = sym->st_value + relocbase;
		++sym;
		++got;
	}

	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
	for (; rel < rellim; rel++) {
		Elf_Word r_symndx, r_type;

		where = (void *)(relocbase + rel->r_offset);

		r_symndx = ELF_R_SYM(rel->r_info);
		r_type = ELF_R_TYPE(rel->r_info);

		switch (r_type & 0xff) {
		case R_TYPE(REL32): {
			const size_t rlen =
			    ELF_R_NXTTYPE_64_P(r_type)
				? sizeof(Elf_Sxword)
				: sizeof(Elf_Sword);
			Elf_Sxword old = load_ptr(where, rlen);
			Elf_Sxword val = old;
#ifdef __mips_n64
			assert(r_type == R_TYPE(REL32)
			    || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
#endif
			assert(r_symndx < gotsym);
			sym = symtab + r_symndx;
			assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
			val += relocbase;
			store_ptr(where, val, sizeof(Elf_Sword));
			dbg("REL32/L(%p) %p -> %p in <self>",
			    where, (void *)old, (void *)val);
			store_ptr(where, val, rlen);
			break;
		}

		case R_TYPE(GPREL32):
		case R_TYPE(NONE):
			break;


		default:
			abort();
			break;
		}
	}
}
示例#25
0
文件: reloc.c 项目: Alkzndr/freebsd
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
    RtldLockState *lockstate)
{
	const Elf_Rel *rel;
	const Elf_Rel *rellim;
	Elf_Addr *got = obj->pltgot;
	const Elf_Sym *sym, *def;
	const Obj_Entry *defobj;
	Elf_Word i;
#ifdef SUPPORT_OLD_BROKEN_LD
	int broken;
#endif

	/* The relocation for the dynamic loader has already been done. */
	if (obj == obj_rtld)
		return (0);

	if ((flags & SYMLOOK_IFUNC) != 0)
		/* XXX not implemented */
		return (0);

#ifdef SUPPORT_OLD_BROKEN_LD
	broken = 0;
	sym = obj->symtab;
	for (i = 1; i < 12; i++)
		if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE))
			broken = 1;
	dbg("%s: broken=%d", obj->path, broken);
#endif

	i = (got[1] & GOT1_MASK) ? 2 : 1;

	/* Relocate the local GOT entries */
	got += i;
	dbg("got:%p for %d entries adding %p",
	    got, obj->local_gotno, obj->relocbase);
	for (; i < obj->local_gotno; i++) {
		*got += (Elf_Addr)obj->relocbase;
		got++;
	}
	sym = obj->symtab + obj->gotsym;

	dbg("got:%p for %d entries",
	    got, obj->symtabno);
	/* Now do the global GOT entries */
	for (i = obj->gotsym; i < obj->symtabno; i++) {
		dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
		    sym->st_name + obj->strtab, (u_long) *got);

#ifdef SUPPORT_OLD_BROKEN_LD
		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
		    broken && sym->st_shndx == SHN_UNDEF) {
			/*
			 * XXX DANGER WILL ROBINSON!
			 * You might think this is stupid, as it intentionally
			 * defeats lazy binding -- and you'd be right.
			 * Unfortunately, for lazy binding to work right, we
			 * need to a way to force the GOT slots used for
			 * function pointers to be resolved immediately.  This
			 * is supposed to be done automatically by the linker,
			 * by not outputting a PLT slot and setting st_value
			 * to 0 if there are non-PLT references, but older
			 * versions of GNU ld do not do this.
			 */
			def = find_symdef(i, obj, &defobj, flags, NULL,
			    lockstate);
			if (def == NULL)
				return -1;
			*got = def->st_value + (Elf_Addr)defobj->relocbase;
		} else
#endif
		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
		    sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
			/*
			 * If there are non-PLT references to the function,
			 * st_value should be 0, forcing us to resolve the
			 * address immediately.
			 *
			 * XXX DANGER WILL ROBINSON!
			 * The linker is not outputting PLT slots for calls to
			 * functions that are defined in the same shared
			 * library.  This is a bug, because it can screw up
			 * link ordering rules if the symbol is defined in
			 * more than one module.  For now, if there is a
			 * definition, we fail the test above and force a full
			 * symbol lookup.  This means that all intra-module
			 * calls are bound immediately.  - mycroft, 2003/09/24
			 */
			*got = sym->st_value + (Elf_Addr)obj->relocbase;
			if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
				dbg("Warning2, i:%d maps to relocbase address:%p",
				    i, obj->relocbase);
			}

		} else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
			/* Symbols with index SHN_ABS are not relocated. */
			if (sym->st_shndx != SHN_ABS) {
				*got = sym->st_value +
				    (Elf_Addr)obj->relocbase;
				if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
					dbg("Warning3, i:%d maps to relocbase address:%p",
					    i, obj->relocbase);
				}
			}
		} else {
			/* TODO: add cache here */
			def = find_symdef(i, obj, &defobj, flags, NULL,
			    lockstate);
			if (def == NULL) {
				dbg("Warning4, can't find symbole %d", i);
				return -1;
			}
			*got = def->st_value + (Elf_Addr)defobj->relocbase;
			if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
				dbg("Warning4, i:%d maps to relocbase address:%p",
				    i, obj->relocbase);
				dbg("via first obj symbol %s",
				    obj->strtab + obj->symtab[i].st_name);
				dbg("found in obj %p:%s",
				    defobj, defobj->path);
			}
		}

		dbg("  --> now %lx", (u_long) *got);
		++sym;
		++got;
	}

	got = obj->pltgot;
	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
	for (rel = obj->rel; rel < rellim; rel++) {
		Elf_Word	r_symndx, r_type;
		void		*where;

		where = obj->relocbase + rel->r_offset;
		r_symndx = ELF_R_SYM(rel->r_info);
		r_type = ELF_R_TYPE(rel->r_info);

		switch (r_type & 0xff) {
		case R_TYPE(NONE):
			break;

		case R_TYPE(REL32): {
			/* 32-bit PC-relative reference */
			const size_t rlen =
			    ELF_R_NXTTYPE_64_P(r_type)
				? sizeof(Elf_Sxword)
				: sizeof(Elf_Sword);
			Elf_Sxword old = load_ptr(where, rlen);
			Elf_Sxword val = old;

			def = obj->symtab + r_symndx;

			if (r_symndx >= obj->gotsym) {
				val += got[obj->local_gotno + r_symndx - obj->gotsym];
				dbg("REL32/G(%p) %p --> %p (%s) in %s",
				    where, (void *)old, (void *)val,
				    obj->strtab + def->st_name,
				    obj->path);
			} else {
				/*
				 * XXX: ABI DIFFERENCE!
				 *
				 * Old NetBSD binutils would generate shared
				 * libs with section-relative relocations being
				 * already adjusted for the start address of
				 * the section.
				 *
				 * New binutils, OTOH, generate shared libs
				 * with the same relocations being based at
				 * zero, so we need to add in the start address
				 * of the section.
				 *
				 * --rkb, Oct 6, 2001
				 */

				if (def->st_info ==
				    ELF_ST_INFO(STB_LOCAL, STT_SECTION)
#ifdef SUPPORT_OLD_BROKEN_LD
				    && !broken
#endif
				    )
					val += (Elf_Addr)def->st_value;

				val += (Elf_Addr)obj->relocbase;

				dbg("REL32/L(%p) %p -> %p (%s) in %s",
				    where, (void *)old, (void *)val,
				    obj->strtab + def->st_name, obj->path);
			}
			store_ptr(where, val, rlen);
			break;
		}

#ifdef __mips_n64
		case R_TYPE(TLS_DTPMOD64):
#else
		case R_TYPE(TLS_DTPMOD32): 
#endif
		{

			const size_t rlen = sizeof(Elf_Addr);
			Elf_Addr old = load_ptr(where, rlen);
			Elf_Addr val = old;

        		def = find_symdef(r_symndx, obj, &defobj, flags, NULL,
	    			lockstate);
			if (def == NULL)
				return -1;

			val += (Elf_Addr)defobj->tlsindex;

			store_ptr(where, val, rlen);
			dbg("DTPMOD %s in %s %p --> %p in %s",
			    obj->strtab + obj->symtab[r_symndx].st_name,
			    obj->path, (void *)old, (void*)val, defobj->path);
			break;
		}

#ifdef __mips_n64
		case R_TYPE(TLS_DTPREL64):
#else
		case R_TYPE(TLS_DTPREL32):
#endif
		{
			const size_t rlen = sizeof(Elf_Addr);
			Elf_Addr old = load_ptr(where, rlen);
			Elf_Addr val = old;

        		def = find_symdef(r_symndx, obj, &defobj, flags, NULL,
	    			lockstate);
			if (def == NULL)
				return -1;

			if (!defobj->tls_done && allocate_tls_offset(obj))
				return -1;

			val += (Elf_Addr)def->st_value - TLS_DTP_OFFSET;
			store_ptr(where, val, rlen);

			dbg("DTPREL %s in %s %p --> %p in %s",
			    obj->strtab + obj->symtab[r_symndx].st_name,
			    obj->path, (void*)old, (void *)val, defobj->path);
			break;
		}

#ifdef __mips_n64
		case R_TYPE(TLS_TPREL64):
#else
		case R_TYPE(TLS_TPREL32):
#endif
		{
			const size_t rlen = sizeof(Elf_Addr);
			Elf_Addr old = load_ptr(where, rlen);
			Elf_Addr val = old;

        		def = find_symdef(r_symndx, obj, &defobj, flags, NULL,
	    			lockstate);

			if (def == NULL)
				return -1;

			if (!defobj->tls_done && allocate_tls_offset(obj))
				return -1;

			val += (Elf_Addr)(def->st_value + defobj->tlsoffset
			    - TLS_TP_OFFSET - TLS_TCB_SIZE);
			store_ptr(where, val, rlen);

			dbg("TPREL %s in %s %p --> %p in %s",
			    obj->strtab + obj->symtab[r_symndx].st_name,
			    obj->path, (void*)old, (void *)val, defobj->path);
			break;
		}



		default:
			dbg("sym = %lu, type = %lu, offset = %p, "
			    "contents = %p, symbol = %s",
			    (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
			    (void *)rel->r_offset,
			    (void *)load_ptr(where, sizeof(Elf_Sword)),
			    obj->strtab + obj->symtab[r_symndx].st_name);
			_rtld_error("%s: Unsupported relocation type %ld "
			    "in non-PLT relocations",
			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
			return -1;
		}
	}

	return 0;
}
示例#26
0
/* Relocate a non-PLT object with addend. */
static int
reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
    SymCache *cache, int flags, RtldLockState *lockstate)
{
	struct fptr **fptrs;
	Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);

	switch (ELF_R_TYPE(rela->r_info)) {
	case R_IA_64_REL64LSB:
		/*
		 * We handle rtld's relocations in rtld_start.S
		 */
		if (obj != obj_rtld)
			store64(where,
				load64(where) + (Elf_Addr) obj->relocbase);
		break;

	case R_IA_64_DIR64LSB: {
		const Elf_Sym *def;
		const Obj_Entry *defobj;
		Elf_Addr target;

		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags, cache, lockstate);
		if (def == NULL)
			return -1;

		target = (def->st_shndx != SHN_UNDEF)
		    ? (Elf_Addr)(defobj->relocbase + def->st_value) : 0;
		store64(where, target + rela->r_addend);
		break;
	}

	case R_IA_64_FPTR64LSB: {
		/*
		 * We have to make sure that all @fptr references to
		 * the same function are identical so that code can
		 * compare function pointers.
		 */
		const Elf_Sym *def;
		const Obj_Entry *defobj;
		struct fptr *fptr = 0;
		Elf_Addr target, gp;
		int sym_index;

		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    SYMLOOK_IN_PLT | flags, cache, lockstate);
		if (def == NULL) {
			/*
			 * XXX r_debug_state is problematic and find_symdef()
			 * returns NULL for it. This probably has something to
			 * do with symbol versioning (r_debug_state is in the
			 * symbol map). If we return -1 in that case we abort
			 * relocating rtld, which typically is fatal. So, for
			 * now just skip the symbol when we're relocating
			 * rtld. We don't care about r_debug_state unless we
			 * are being debugged.
			 */
			if (obj != obj_rtld)
				return -1;
			break;
		}

		if (def->st_shndx != SHN_UNDEF) {
			target = (Elf_Addr)(defobj->relocbase + def->st_value);
			gp = (Elf_Addr)defobj->pltgot;

			/* rtld is allowed to reference itself only */
			assert(!obj->rtld || obj == defobj);
			fptrs = defobj->priv;
			if (fptrs == NULL)
				fptrs = alloc_fptrs((Obj_Entry *) defobj, 
				    obj->rtld);

			sym_index = def - defobj->symtab;

			/*
			 * Find the @fptr, using fptrs as a helper.
			 */
			if (fptrs)
				fptr = fptrs[sym_index];
			if (!fptr) {
				fptr = alloc_fptr(target, gp);
				if (fptrs)
					fptrs[sym_index] = fptr;
			}
		} else
			fptr = NULL;

		store64(where, (Elf_Addr)fptr);
		break;
	}

	case R_IA_64_IPLTLSB: {
		/*
		 * Relocation typically used to populate C++ virtual function
		 * tables. It creates a 128-bit function descriptor at the
		 * specified memory address.
		 */
		const Elf_Sym *def;
		const Obj_Entry *defobj;
		struct fptr *fptr;
		Elf_Addr target, gp;

		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags, cache, lockstate);
		if (def == NULL)
			return -1;

		if (def->st_shndx != SHN_UNDEF) {
			target = (Elf_Addr)(defobj->relocbase + def->st_value);
			gp = (Elf_Addr)defobj->pltgot;
		} else {
			target = 0;
			gp = 0;
		}

		fptr = (void*)where;
		store64(&fptr->target, target);
		store64(&fptr->gp, gp);
		break;
	}

	case R_IA_64_DTPMOD64LSB: {
		const Elf_Sym *def;
		const Obj_Entry *defobj;

		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags, cache, lockstate);
		if (def == NULL)
			return -1;

		store64(where, defobj->tlsindex);
		break;
	}

	case R_IA_64_DTPREL64LSB: {
		const Elf_Sym *def;
		const Obj_Entry *defobj;

		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags, cache, lockstate);
		if (def == NULL)
			return -1;

		store64(where, def->st_value + rela->r_addend);
		break;
	}

	case R_IA_64_TPREL64LSB: {
		const Elf_Sym *def;
		const Obj_Entry *defobj;

		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags, cache, lockstate);
		if (def == NULL)
			return -1;

		/*
		 * We lazily allocate offsets for static TLS as we
		 * see the first relocation that references the
		 * TLS block. This allows us to support (small
		 * amounts of) static TLS in dynamically loaded
		 * modules. If we run out of space, we generate an
		 * error.
		 */
		if (!defobj->tls_done) {
			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
				_rtld_error("%s: No space available for static "
				    "Thread Local Storage", obj->path);
				return -1;
			}
		}

		store64(where, defobj->tlsoffset + def->st_value + rela->r_addend);
		break;
	}

	case R_IA_64_NONE:
		break;

	default:
		_rtld_error("%s: Unsupported relocation type %u"
			    " in non-PLT relocations\n", obj->path,
			    (unsigned int)ELF_R_TYPE(rela->r_info));
		return -1;
	}

	return(0);
}
示例#27
0
文件: elf.c 项目: archiecobbs/jcvm
/*
 * Resolve a symbol in an ELF object. There are two cases here.
 *
 * If 'resolver' is NULL, only symbols resolvable internally are
 * resolved, and exceptions are stored, not posted. Otherwise,
 * only symbols resolvable externally are resolved, 'resolver' is
 * used to resolve them, and exceptions are posted.
 */
static inline jint
_jc_elf_resolve_sym(_jc_env *env, _jc_elf *elf, _jc_elf_loadable *loadable,
	const Elf_Rela *rela, _jc_elf_resolver *resolver, void *arg)
{
	const Elf_Word type = ELF_R_TYPE(rela->r_info);
	_jc_elf_info *const info = elf->info;
	const Elf_Sym *const sym = &info->symbols[ELF_R_SYM(rela->r_info)];
	const char *name = info->strings + sym->st_name;

	switch (sym->st_shndx) {
	case SHN_ABS:
		if (resolver != NULL)
			break;
		if (_jc_elf_arch_reloc(env, elf->pathname,
		    loadable->vaddr, rela->r_offset, type,
		    sym->st_value, rela->r_addend) != JNI_OK)
			return JNI_ERR;
		break;
	case SHN_UNDEF:
	    {
		Elf_Addr value;

		if (resolver == NULL)
			break;
		if ((*resolver)(env, arg,
		    info->strings + sym->st_name, &value) != JNI_OK)
			return JNI_ERR;
		if (_jc_elf_arch_reloc(env, elf->pathname, loadable->vaddr,
		    rela->r_offset, type, value, rela->r_addend) != JNI_OK) {
			_jc_post_exception_info(env);
			return JNI_ERR;
		}
		break;
	    }
	case SHN_COMMON:
		_JC_ASSERT(resolver == NULL);
		_JC_EX_STORE(env, LinkageError,
		    "%s: ELF symbol `%s' is common (not supported)",
		    elf->pathname, name);
		return JNI_ERR;
	default:
	    {
		const _jc_elf_loadable *sym_section;

		/* Skip if only resolving externals */
		if (resolver != NULL)
			break;

		/* Sanity check the symbol's section */
		if (sym->st_shndx >= info->ehdr->e_shnum
		    || (sym_section
		      = info->shdr2section[sym->st_shndx]) == NULL) {
			_JC_EX_STORE(env, LinkageError,
			    "%s: invalid section index %d for symbol `%s'",
			    elf->pathname, sym->st_shndx, name);
			return JNI_ERR;
		}

		/* Apply relocation */
		if (_jc_elf_arch_reloc(env, elf->pathname,
		    loadable->vaddr, rela->r_offset, type,
		    (Elf_Addr)(sym_section->vaddr + sym->st_value),
		    rela->r_addend) != JNI_OK)
			return JNI_ERR;
		break;
	    }
	}

	/* Done */
	return JNI_OK;
}
int
kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data,
	   bool isrela, bool local)
{
	Elf64_Addr *where, val;
	Elf32_Addr *where32, val32;
	Elf64_Addr addr;
	Elf64_Addr addend;
	uintptr_t rtype, symidx;
	const Elf_Rel *rel;
	const Elf_Rela *rela;

	if (isrela) {
		rela = (const Elf_Rela *)data;
		where = (Elf64_Addr *)(relocbase + rela->r_offset);
		addend = rela->r_addend;
		rtype = ELF_R_TYPE(rela->r_info);
		symidx = ELF_R_SYM(rela->r_info);
	} else {
		rel = (const Elf_Rel *)data;
		where = (Elf64_Addr *)(relocbase + rel->r_offset);
		rtype = ELF_R_TYPE(rel->r_info);
		symidx = ELF_R_SYM(rel->r_info);
		/* Addend is 32 bit on 32 bit relocs */
		switch (rtype) {
		case R_X86_64_PC32:
		case R_X86_64_32:
		case R_X86_64_32S:
			addend = *(Elf32_Addr *)where;
			break;
		default:
			addend = *where;
			break;
		}
	}

	switch (rtype) {
	case R_X86_64_NONE:	/* none */
		break;

	case R_X86_64_64:		/* S + A */
		addr = kobj_sym_lookup(ko, symidx);
		if (addr == 0)
			return -1;
		val = addr + addend;
		*where = val;
		break;

	case R_X86_64_PC32:	/* S + A - P */
		addr = kobj_sym_lookup(ko, symidx);
		if (addr == 0)
			return -1;
		where32 = (Elf32_Addr *)where;
		val32 = (Elf32_Addr)(addr + addend - (Elf64_Addr)where);
		*where32 = val32;
		break;

	case R_X86_64_32:	/* S + A */
	case R_X86_64_32S:	/* S + A sign extend */
		addr = kobj_sym_lookup(ko, symidx);
		if (addr == 0)
			return -1;
		val32 = (Elf32_Addr)(addr + addend);
		where32 = (Elf32_Addr *)where;
		*where32 = val32;
		break;

	case R_X86_64_GLOB_DAT:	/* S */
	case R_X86_64_JUMP_SLOT:/* XXX need addend + offset */
		addr = kobj_sym_lookup(ko, symidx);
		if (addr == 0)
			return -1;
		*where = addr;
		break;

	case R_X86_64_RELATIVE:	/* B + A */
		addr = relocbase + addend;
		val = addr;
		*where = val;
		break;

	default:
		printf("kobj_reloc: unexpected relocation type %ld\n", rtype);
		return -1;
	}

	return 0;
}
示例#29
0
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
    int type, int local, elf_lookup_fn lookup)
{
	Elf_Addr *where;
	Elf_Addr addr;
	Elf_Addr addend;
	Elf_Word rtype, symidx;
	const Elf_Rel *rel;
	const Elf_Rela *rela;
	int error;

	switch (type) {
	case ELF_RELOC_REL:
		rel = (const Elf_Rel *)data;
		where = (Elf_Addr *) (relocbase + rel->r_offset);
		addend = load_ptr(where);
		rtype = ELF_R_TYPE(rel->r_info);
		symidx = ELF_R_SYM(rel->r_info);
		break;
	case ELF_RELOC_RELA:
		rela = (const Elf_Rela *)data;
		where = (Elf_Addr *) (relocbase + rela->r_offset);
		addend = rela->r_addend;
		rtype = ELF_R_TYPE(rela->r_info);
		symidx = ELF_R_SYM(rela->r_info);
		break;
	default:
		panic("unknown reloc type %d\n", type);
	}

	if (local) {
		if (rtype == R_ARM_RELATIVE) {	/* A + B */
			addr = elf_relocaddr(lf, relocbase + addend);
			if (load_ptr(where) != addr)
				store_ptr(where, addr);
		}
		return (0);
	}

	switch (rtype) {

		case R_ARM_NONE:	/* none */
			break;

		case R_ARM_ABS32:
			error = lookup(lf, symidx, 1, &addr);
			if (error != 0)
				return -1;
			store_ptr(where, addr + load_ptr(where));
			break;

		case R_ARM_COPY:	/* none */
			/*
			 * There shouldn't be copy relocations in kernel
			 * objects.
			 */
			printf("kldload: unexpected R_COPY relocation\n");
			return -1;
			break;

		case R_ARM_JUMP_SLOT:
			error = lookup(lf, symidx, 1, &addr);
			if (error == 0) {
				store_ptr(where, addr);
				return (0);
			}
			return (-1);
		case R_ARM_RELATIVE:
			break;

		default:
			printf("kldload: unexpected relocation type %d\n",
			       rtype);
			return -1;
	}
	return(0);
}
示例#30
0
STATIC
BOOLEAN
WriteSections32 (
  SECTION_FILTER_TYPES  FilterType
  )
{
  UINT32      Idx;
  Elf_Shdr    *SecShdr;
  UINT32      SecOffset;
  BOOLEAN     (*Filter)(Elf_Shdr *);

  //
  // Initialize filter pointer
  //
  switch (FilterType) {
    case SECTION_TEXT:
      Filter = IsTextShdr;
      break;
    case SECTION_HII:
      Filter = IsHiiRsrcShdr;
      break;
    case SECTION_DATA:
      Filter = IsDataShdr;
      break;
    default:
      return FALSE;
  }

  //
  // First: copy sections.
  //
  for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
    Elf_Shdr *Shdr = GetShdrByIndex(Idx);
    if ((*Filter)(Shdr)) {
      switch (Shdr->sh_type) {
      case SHT_PROGBITS:
        /* Copy.  */
        memcpy(mCoffFile + mCoffSectionsOffset[Idx],
              (UINT8*)mEhdr + Shdr->sh_offset,
              Shdr->sh_size);
        break;

      case SHT_NOBITS:
        memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size);
        break;

      default:
        //
        //  Ignore for unkown section type.
        //
        VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);
        break;
      }
    }
  }

  //
  // Second: apply relocations.
  //
  for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
    //
    // Determine if this is a relocation section.
    //
    Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
    if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
      continue;
    }
    
    //
    // Relocation section found.  Now extract section information that the relocations
    // apply to in the ELF data and the new COFF data.
    //
    SecShdr = GetShdrByIndex(RelShdr->sh_info);
    SecOffset = mCoffSectionsOffset[RelShdr->sh_info];
    
    //
    // Only process relocations for the current filter type.
    //
    if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
      UINT32 RelOffset;
      
      //
      // Determine the symbol table referenced by the relocation data.
      //
      Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
      UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;

      //
      // Process all relocation entries for this section.
      //
      for (RelOffset = 0; RelOffset < RelShdr->sh_size; RelOffset += RelShdr->sh_entsize) {
        //
        // Set pointer to relocation entry
        //
        Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelOffset);
        
        //
        // Set pointer to symbol table entry associated with the relocation entry.
        //
        Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
        
        Elf_Shdr *SymShdr;
        UINT8 *Targ;
        UINT16 Address;

        //
        // Check section header index found in symbol table and get the section 
        // header location.
        //
        if (Sym->st_shndx == SHN_UNDEF
            || Sym->st_shndx == SHN_ABS
            || Sym->st_shndx > mEhdr->e_shnum) {
          Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);
        }
        SymShdr = GetShdrByIndex(Sym->st_shndx);

        //
        // Convert the relocation data to a pointer into the coff file.
        //
        // Note: 
        //   r_offset is the virtual address of the storage unit to be relocated.
        //   sh_addr is the virtual address for the base of the section.
        //
        Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);

        //
        // Determine how to handle each relocation type based on the machine type.
        //
        if (mEhdr->e_machine == EM_386) {
          switch (ELF_R_TYPE(Rel->r_info)) {
          case R_386_NONE:
            break;
          case R_386_32:
            //
            // Absolute relocation.
            //  Converts Targ from a absolute virtual address to the absolute
            //  COFF address.
            //
            *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
              + mCoffSectionsOffset[Sym->st_shndx];
            break;
          case R_386_PC32:
            //
            // Relative relocation: Symbol - Ip + Addend
            //
            *(UINT32 *)Targ = *(UINT32 *)Targ
              + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
              - (SecOffset - SecShdr->sh_addr);
            break;
          default:
            Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
          }
        } else if (mEhdr->e_machine == EM_ARM) {
          switch (ELF32_R_TYPE(Rel->r_info)) {
          case R_ARM_RBASE:
            // No relocation - no action required
            // break skipped

          case R_ARM_PC24:
          case R_ARM_XPC25:
          case R_ARM_THM_PC22:
          case R_ARM_THM_JUMP19:
          case R_ARM_CALL:
          case R_ARM_JMP24:
          case R_ARM_THM_JUMP24:  
          case R_ARM_PREL31:  
          case R_ARM_MOVW_PREL_NC:  
          case R_ARM_MOVT_PREL:
          case R_ARM_THM_MOVW_PREL_NC:
          case R_ARM_THM_MOVT_PREL:
          case R_ARM_THM_JMP6:
          case R_ARM_THM_ALU_PREL_11_0:
          case R_ARM_THM_PC12:
          case R_ARM_REL32_NOI:
          case R_ARM_ALU_PC_G0_NC:
          case R_ARM_ALU_PC_G0:
          case R_ARM_ALU_PC_G1_NC:
          case R_ARM_ALU_PC_G1:
          case R_ARM_ALU_PC_G2:
          case R_ARM_LDR_PC_G1:
          case R_ARM_LDR_PC_G2:
          case R_ARM_LDRS_PC_G0:
          case R_ARM_LDRS_PC_G1:
          case R_ARM_LDRS_PC_G2:
          case R_ARM_LDC_PC_G0:
          case R_ARM_LDC_PC_G1:
          case R_ARM_LDC_PC_G2:
          case R_ARM_GOT_PREL:
          case R_ARM_THM_JUMP11:
          case R_ARM_THM_JUMP8:
          case R_ARM_TLS_GD32:
          case R_ARM_TLS_LDM32:
          case R_ARM_TLS_IE32:
            // Thease are all PC-relative relocations and don't require modification
            // GCC does not seem to have the concept of a application that just needs to get relocated.
            break;

          case R_ARM_THM_MOVW_ABS_NC:
            // MOVW is only lower 16-bits of the addres
            Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
            ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
            break;

          case R_ARM_THM_MOVT_ABS:
            // MOVT is only upper 16-bits of the addres
            Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16);
            ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
            break;

          case R_ARM_ABS32:
          case R_ARM_RABS32:
            //
            // Absolute relocation.
            //
            *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
            break;

          default:
            Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
          }
        }
      }
    }
  }