Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/elf_machdep.c
Show First 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | |||||
bool | bool | ||||
elf_is_ifunc_reloc(Elf_Size r_info __unused) | elf_is_ifunc_reloc(Elf_Size r_info __unused) | ||||
{ | { | ||||
return (ELF_R_TYPE(r_info) == R_AARCH64_IRELATIVE); | return (ELF_R_TYPE(r_info) == R_AARCH64_IRELATIVE); | ||||
} | } | ||||
static int | static int | ||||
reloc_instr_imm(Elf32_Addr *where, Elf_Addr val, u_int msb, u_int lsb) | |||||
{ | |||||
/* Check bounds: upper bits must be all ones or all zeros. */ | |||||
if ((uint64_t)((int64_t)val >> (msb + 1)) + 1 > 1) | |||||
return (-1); | |||||
val >>= lsb; | |||||
val &= (1 << (msb - lsb + 1)) - 1; | |||||
*where |= (Elf32_Addr)val; | |||||
return (0); | |||||
} | |||||
/* | |||||
* Process a relocation. Support for some static relocations is required | |||||
* in order for the -zifunc-noplt optimization to work. Unfortunately, this | |||||
* means that our kernel and modules may not comply with the AArch64 ABI. | |||||
*/ | |||||
static int | |||||
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, | elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, | ||||
int type, int local, elf_lookup_fn lookup) | int type, int local, elf_lookup_fn lookup) | ||||
{ | { | ||||
Elf_Addr *where, addr, addend, val; | Elf_Addr *where, addr, addend, val; | ||||
Elf_Word rtype, symidx; | Elf_Word rtype, symidx; | ||||
const Elf_Rel *rel; | const Elf_Rel *rel; | ||||
const Elf_Rela *rela; | const Elf_Rela *rela; | ||||
int error; | int error; | ||||
Show All 18 Lines | elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, | ||||
} | } | ||||
if (local) { | if (local) { | ||||
if (rtype == R_AARCH64_RELATIVE) | if (rtype == R_AARCH64_RELATIVE) | ||||
*where = elf_relocaddr(lf, relocbase + addend); | *where = elf_relocaddr(lf, relocbase + addend); | ||||
return (0); | return (0); | ||||
} | } | ||||
error = 0; | |||||
switch (rtype) { | switch (rtype) { | ||||
case R_AARCH64_NONE: | case R_AARCH64_NONE: | ||||
case R_AARCH64_RELATIVE: | case R_AARCH64_RELATIVE: | ||||
break; | break; | ||||
case R_AARCH64_TSTBR14: | |||||
error = lookup(lf, symidx, 1, &addr); | |||||
if (error != 0) | |||||
return (-1); | |||||
error = reloc_instr_imm((Elf32_Addr *)where, | |||||
addr + addend - (Elf_Addr)where, 15, 2); | |||||
break; | |||||
case R_AARCH64_CONDBR19: | |||||
error = lookup(lf, symidx, 1, &addr); | |||||
if (error != 0) | |||||
return (-1); | |||||
error = reloc_instr_imm((Elf32_Addr *)where, | |||||
addr + addend - (Elf_Addr)where, 20, 2); | |||||
break; | |||||
case R_AARCH64_JUMP26: | |||||
case R_AARCH64_CALL26: | |||||
error = lookup(lf, symidx, 1, &addr); | |||||
if (error != 0) | |||||
return (-1); | |||||
error = reloc_instr_imm((Elf32_Addr *)where, | |||||
addr + addend - (Elf_Addr)where, 27, 2); | |||||
break; | |||||
case R_AARCH64_ABS64: | case R_AARCH64_ABS64: | ||||
case R_AARCH64_GLOB_DAT: | case R_AARCH64_GLOB_DAT: | ||||
case R_AARCH64_JUMP_SLOT: | case R_AARCH64_JUMP_SLOT: | ||||
error = lookup(lf, symidx, 1, &addr); | error = lookup(lf, symidx, 1, &addr); | ||||
if (error != 0) | if (error != 0) | ||||
return (-1); | return (-1); | ||||
*where = addr + addend; | *where = addr + addend; | ||||
break; | break; | ||||
case R_AARCH64_IRELATIVE: | case R_AARCH64_IRELATIVE: | ||||
addr = relocbase + addend; | addr = relocbase + addend; | ||||
val = ((Elf64_Addr (*)(void))addr)(); | val = ((Elf64_Addr (*)(void))addr)(); | ||||
if (*where != val) | if (*where != val) | ||||
*where = val; | *where = val; | ||||
break; | break; | ||||
default: | default: | ||||
printf("kldload: unexpected relocation type %d\n", rtype); | printf("kldload: unexpected relocation type %d\n", rtype); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | return (error); | ||||
} | } | ||||
int | int | ||||
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, | elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, | ||||
int type, elf_lookup_fn lookup) | int type, elf_lookup_fn lookup) | ||||
{ | { | ||||
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); | return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); | ||||
Show All 26 Lines |