Example #1
0
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
    elf_lookup_fn lookup)
{
	const Elf_Rela *rela;
	Elf_Word *where32;
	Elf_Addr *where;
	Elf_Size rtype, symidx;
	Elf_Addr value;
	Elf_Addr mask;
	Elf_Addr addr;
	int error;

	if (type != ELF_RELOC_RELA)
		return (-1);

	rela = (const Elf_Rela *)data;
	where = (Elf_Addr *)(relocbase + rela->r_offset);
	where32 = (Elf_Word *)where;
	rtype = ELF64_R_TYPE_ID(rela->r_info);
	symidx = ELF_R_SYM(rela->r_info);

	if (rtype == R_SPARC_NONE || rtype == R_SPARC_RELATIVE)
		return (0);

	if (rtype == R_SPARC_JMP_SLOT || rtype == R_SPARC_COPY ||
	    rtype >= nitems(reloc_target_bitmask)) {
		printf("kldload: unexpected relocation type %ld\n", rtype);
		return (-1);
	}

	if (RELOC_UNALIGNED(rtype)) {
		printf("kldload: unaligned relocation type %ld\n", rtype);
		return (-1);
	}

	value = rela->r_addend;

	if (RELOC_RESOLVE_SYMBOL(rtype)) {
		error = lookup(lf, symidx, 1, &addr);
		if (error != 0)
			return (-1);
		value += addr;
		if (RELOC_BARE_SYMBOL(rtype))
			value = elf_relocaddr(lf, value);
	}

	if (rtype == R_SPARC_OLO10)
		value = (value & 0x3ff) + ELF64_R_TYPE_DATA(rela->r_info);

	if (rtype == R_SPARC_HIX22)
		value ^= 0xffffffffffffffff;

	if (RELOC_PC_RELATIVE(rtype))
		value -= (Elf_Addr)where;

	if (RELOC_BASE_RELATIVE(rtype))
		value = elf_relocaddr(lf, value + relocbase);

	mask = RELOC_VALUE_BITMASK(rtype);
	value >>= RELOC_VALUE_RIGHTSHIFT(rtype);
	value &= mask;

	if (rtype == R_SPARC_LOX10)
		value |= 0x1c00;

	if (RELOC_TARGET_SIZE(rtype) > 32) {
		*where &= ~mask;
		*where |= value;
	} else {
		*where32 &= ~mask;
		*where32 |= value;
	}

	return (0);
}
Example #2
0
/* Process one elf relocation with addend. */
int
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
    elf_lookup_fn lookup)
{
	const Elf_Rela *rela;
	Elf_Word *where32;
	Elf_Addr *where;
	Elf_Size rtype, symidx;
	Elf_Addr value;
	Elf_Addr mask;
	Elf_Addr addr;

	if (type != ELF_RELOC_RELA)
		return (-1);

	rela = (const Elf_Rela *)data;
	where = (Elf_Addr *)(relocbase + rela->r_offset);
	where32 = (Elf_Word *)where;
	rtype = ELF64_R_TYPE_ID(rela->r_info);
	symidx = ELF_R_SYM(rela->r_info);

	if (rtype == R_SPARC_NONE || rtype == R_SPARC_RELATIVE)
		return (0);

	if (rtype == R_SPARC_JMP_SLOT || rtype == R_SPARC_COPY ||
	    rtype >= sizeof(reloc_target_bitmask) /
	    sizeof(*reloc_target_bitmask))
		return (-1);

	if (RELOC_UNALIGNED(rtype))
		return (-1);

	value = rela->r_addend;

	if (RELOC_RESOLVE_SYMBOL(rtype)) {
		addr = lookup(lf, symidx, 1);
		if (addr == 0)
			return (-1);
		value += addr;
	}

	if (rtype == R_SPARC_OLO10)
		value = (value & 0x3ff) + ELF64_R_TYPE_DATA(rela->r_info);

	if (RELOC_PC_RELATIVE(rtype))
		value -= (Elf_Addr)where;

	if (RELOC_BASE_RELATIVE(rtype)) {
		value = elf_relocaddr(lf, value + relocbase);
	}

	mask = RELOC_VALUE_BITMASK(rtype);
	value >>= RELOC_VALUE_RIGHTSHIFT(rtype);
	value &= mask;

	if (RELOC_TARGET_SIZE(rtype) > 32) {
		*where &= ~mask;
		*where |= value;
	} else {
		*where32 &= ~mask;
		*where32 |= value;
	}

	return (0);
}