Handle non-plt IRELATIVE relocations, at least for x86.
lld 10.0 seems to generate this relocation for rdtsc_mb() ifunc in our libc. Reported, reviewed, and tested by: dim (amd64, previous version) Discussed with: emaste Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D23652
This commit is contained in:
parent
751fae1eff
commit
c5ca0d1132
@ -258,27 +258,52 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
reloc_iresolve_one(Obj_Entry *obj, const Elf_Rela *rela,
|
||||
RtldLockState *lockstate)
|
||||
{
|
||||
Elf_Addr *where, target, *ptr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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)
|
||||
reloc_iresolve_one(obj, rela, lockstate);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
|
||||
{
|
||||
const Elf_Rela *relalim;
|
||||
const Elf_Rela *rela;
|
||||
|
||||
if (!obj->irelative_nonplt)
|
||||
return (0);
|
||||
obj->irelative_nonplt = false;
|
||||
relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
|
||||
for (rela = obj->rela; rela < relalim; rela++) {
|
||||
if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE)
|
||||
reloc_iresolve_one(obj, rela, lockstate);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -498,6 +523,9 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
||||
break;
|
||||
case R_AARCH64_NONE:
|
||||
break;
|
||||
case R_AARCH64_IRELATIVE:
|
||||
obj->irelative_nonplt = true;
|
||||
break;
|
||||
default:
|
||||
rtld_printf("%s: Unhandled relocation %lu\n",
|
||||
obj->path, ELF_R_TYPE(rela->r_info));
|
||||
|
@ -303,6 +303,10 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
||||
case R_X86_64_RELATIVE:
|
||||
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
|
||||
break;
|
||||
case R_X86_64_IRELATIVE:
|
||||
obj->irelative_nonplt = true;
|
||||
break;
|
||||
|
||||
/*
|
||||
* missing:
|
||||
* R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16,
|
||||
@ -410,34 +414,53 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
|
||||
return (target);
|
||||
}
|
||||
|
||||
static void
|
||||
reloc_iresolve_one(Obj_Entry *obj, const Elf_Rela *rela,
|
||||
RtldLockState *lockstate)
|
||||
{
|
||||
Elf_Addr *where, target, *ptr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
|
||||
{
|
||||
const Elf_Rela *relalim;
|
||||
const Elf_Rela *rela;
|
||||
const Elf_Rela *relalim;
|
||||
const Elf_Rela *rela;
|
||||
|
||||
if (!obj->irelative)
|
||||
return (0);
|
||||
relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
|
||||
for (rela = obj->pltrela; rela < relalim; rela++) {
|
||||
Elf_Addr *where, target, *ptr;
|
||||
|
||||
switch (ELF_R_TYPE(rela->r_info)) {
|
||||
case R_X86_64_JMP_SLOT:
|
||||
break;
|
||||
|
||||
case R_X86_64_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;
|
||||
break;
|
||||
if (!obj->irelative)
|
||||
return (0);
|
||||
obj->irelative = false;
|
||||
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_X86_64_IRELATIVE)
|
||||
reloc_iresolve_one(obj, rela, lockstate);
|
||||
}
|
||||
}
|
||||
obj->irelative = false;
|
||||
return (0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj, RtldLockState *lockstate)
|
||||
{
|
||||
const Elf_Rela *relalim;
|
||||
const Elf_Rela *rela;
|
||||
|
||||
if (!obj->irelative_nonplt)
|
||||
return (0);
|
||||
obj->irelative_nonplt = false;
|
||||
relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
|
||||
for (rela = obj->rela; rela < relalim; rela++) {
|
||||
if (ELF_R_TYPE(rela->r_info) == R_X86_64_IRELATIVE)
|
||||
reloc_iresolve_one(obj, rela, lockstate);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -451,6 +451,15 @@ reloc_iresolve(Obj_Entry *obj __unused,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
{
|
||||
|
||||
/* XXX not implemented */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
|
@ -263,6 +263,9 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
||||
case R_386_TLS_DTPOFF32:
|
||||
*where += (Elf_Addr) def->st_value;
|
||||
break;
|
||||
case R_386_IRELATIVE:
|
||||
obj->irelative_nonplt = true;
|
||||
break;
|
||||
default:
|
||||
_rtld_error("%s: Unsupported relocation type %d"
|
||||
" in non-PLT relocations\n", obj->path,
|
||||
@ -365,29 +368,51 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
|
||||
return (target);
|
||||
}
|
||||
|
||||
static void
|
||||
reloc_iresolve_one(Obj_Entry *obj, const Elf_Rel *rel,
|
||||
RtldLockState *lockstate)
|
||||
{
|
||||
Elf_Addr *where, target;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
|
||||
{
|
||||
const Elf_Rel *rellim;
|
||||
const Elf_Rel *rel;
|
||||
Elf_Addr *where, target;
|
||||
const Elf_Rel *rellim;
|
||||
const Elf_Rel *rel;
|
||||
|
||||
if (!obj->irelative)
|
||||
return (0);
|
||||
rellim = (const Elf_Rel *)((const 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;
|
||||
if (!obj->irelative)
|
||||
return (0);
|
||||
obj->irelative = false;
|
||||
rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
|
||||
for (rel = obj->pltrel; rel < rellim; rel++) {
|
||||
if (ELF_R_TYPE(rel->r_info) == R_386_RELATIVE)
|
||||
reloc_iresolve_one(obj, rel, lockstate);
|
||||
}
|
||||
}
|
||||
obj->irelative = false;
|
||||
return (0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj, RtldLockState *lockstate)
|
||||
{
|
||||
const Elf_Rel *rellim;
|
||||
const Elf_Rel *rel;
|
||||
|
||||
if (!obj->irelative_nonplt)
|
||||
return (0);
|
||||
obj->irelative_nonplt = false;
|
||||
rellim = (const Elf_Rel *)((const char *)obj->rel + obj->relsize);
|
||||
for (rel = obj->rel; rel < rellim; rel++) {
|
||||
if (ELF_R_TYPE(rel->r_info) == R_386_IRELATIVE)
|
||||
reloc_iresolve_one(obj, rel, lockstate);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -722,6 +722,15 @@ reloc_iresolve(Obj_Entry *obj __unused,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
{
|
||||
|
||||
/* XXX not implemented */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
|
@ -652,6 +652,13 @@ reloc_iresolve(Obj_Entry *obj,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
|
@ -652,6 +652,13 @@ reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
init_pltgot(Obj_Entry *obj)
|
||||
{
|
||||
|
@ -211,6 +211,15 @@ reloc_iresolve(Obj_Entry *obj __unused,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
{
|
||||
|
||||
/* XXX not implemented */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
|
@ -3034,10 +3034,13 @@ resolve_object_ifunc(Obj_Entry *obj, bool bind_now, int flags,
|
||||
if (obj->ifuncs_resolved)
|
||||
return (0);
|
||||
obj->ifuncs_resolved = true;
|
||||
if (!obj->irelative && !((obj->bind_now || bind_now) && obj->gnu_ifunc))
|
||||
if (!obj->irelative && !obj->irelative_nonplt &&
|
||||
!((obj->bind_now || bind_now) && obj->gnu_ifunc))
|
||||
return (0);
|
||||
if (obj_disable_relro(obj) == -1 ||
|
||||
(obj->irelative && reloc_iresolve(obj, lockstate) == -1) ||
|
||||
(obj->irelative_nonplt && reloc_iresolve_nonplt(obj,
|
||||
lockstate) == -1) ||
|
||||
((obj->bind_now || bind_now) && obj->gnu_ifunc &&
|
||||
reloc_gnu_ifunc(obj, flags, lockstate) == -1) ||
|
||||
obj_enforce_relro(obj) == -1)
|
||||
|
@ -264,6 +264,7 @@ typedef struct Struct_Obj_Entry {
|
||||
bool dag_inited : 1; /* Object has its DAG initialized. */
|
||||
bool filtees_loaded : 1; /* Filtees loaded */
|
||||
bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */
|
||||
bool irelative_nonplt : 1; /* Object has R_MACHDEP_IRELATIVE non-plt relocs */
|
||||
bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */
|
||||
bool non_plt_gnu_ifunc : 1; /* Object has non-plt IFUNC references */
|
||||
bool ifuncs_resolved : 1; /* Object ifuncs were already resolved */
|
||||
@ -406,6 +407,7 @@ int reloc_non_plt(Obj_Entry *, Obj_Entry *, int flags,
|
||||
int reloc_plt(Obj_Entry *, int flags, struct Struct_RtldLockState *);
|
||||
int reloc_jmpslots(Obj_Entry *, int flags, struct Struct_RtldLockState *);
|
||||
int reloc_iresolve(Obj_Entry *, struct Struct_RtldLockState *);
|
||||
int reloc_iresolve_nonplt(Obj_Entry *, struct Struct_RtldLockState *);
|
||||
int reloc_gnu_ifunc(Obj_Entry *, int flags, struct Struct_RtldLockState *);
|
||||
void ifunc_init(Elf_Auxinfo[__min_size(AT_COUNT)]);
|
||||
void pre_init(void);
|
||||
|
@ -569,6 +569,15 @@ reloc_iresolve(Obj_Entry *obj __unused,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
{
|
||||
|
||||
/* XXX not implemented */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
|
||||
struct Struct_RtldLockState *lockstate __unused)
|
||||
|
Loading…
x
Reference in New Issue
Block a user