mirror of
https://github.com/openbsd/src.git
synced 2026-04-29 08:36:22 +00:00
Fix relocation handling for PLT entries with a r_addend
On sparc64 the first 32768 PLT entries use a direct form of relocation while all other entires afterwards use a PC relative pointer that initally points at PLT0 and is then fixed up to point at the function. These entries use the r_addend. This relocation mode was broken in two ways: - kbind only modified 32bit of the 64bit pointer - the offset calculation used the wrong base pointer. It used the address of the PLT0 entry instead of the object base address. Introduce a simple _dl_reloc_addend() wrapper which does the calculation in both the _dl_bind and _dl_md_reloc_all_plt case. Adjust the kbind calls to update two Elf_Word values so the pointer is swapped by the kernel. There is still an issue that kbind(2) does not update this 64bit value in an atomic operation. This fixes the stage1 gcc15 cc1 and cc1plus binaries that have over 60'000 PLT entries. With and OK miod@ jca@
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: rtld_machine.c,v 1.70 2024/03/30 08:44:20 miod Exp $ */
|
||||
/* $OpenBSD: rtld_machine.c,v 1.71 2025/09/09 08:41:48 claudio Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Dale Rahn
|
||||
@@ -198,8 +198,10 @@ static const long reloc_target_bitmask[] = {
|
||||
};
|
||||
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
|
||||
|
||||
int _dl_reloc_plt(Elf_Word *where1, Elf_Word *where2, Elf_Word *pltaddr,
|
||||
Elf_Addr value);
|
||||
static int _dl_reloc_plt(Elf_Word *where1, Elf_Word *where2, Elf_Word *pltaddr,
|
||||
Elf_Addr value);
|
||||
static int _dl_reloc_addend(Elf_Word *where, Elf_Addr value,
|
||||
Elf64_Sxword addend, Elf_Addr base);
|
||||
void _dl_install_plt(Elf_Word *pltgot, Elf_Addr proc);
|
||||
|
||||
int
|
||||
@@ -363,7 +365,7 @@ resolve_failed:
|
||||
#define HIVAL(v, s) (((v) >> (s)) & 0x003fffff)
|
||||
#define LOVAL(v) ((v) & 0x000003ff)
|
||||
|
||||
int
|
||||
static int
|
||||
_dl_reloc_plt(Elf_Word *where1, Elf_Word *where2, Elf_Word *pltaddr,
|
||||
Elf_Addr value)
|
||||
{
|
||||
@@ -552,6 +554,22 @@ _dl_reloc_plt(Elf_Word *where1, Elf_Word *where2, Elf_Word *pltaddr,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_dl_reloc_addend(Elf_Word *where, Elf_Addr value, Elf64_Sxword addend,
|
||||
Elf_Addr base)
|
||||
{
|
||||
/*
|
||||
* This entry is >32768. The relocation points to a
|
||||
* PC-relative pointer to the _dl_bind_start_0 stub at
|
||||
* the top of the PLT section. Update it to point to
|
||||
* the target function.
|
||||
* Since this updates a 64bit address the where pointer
|
||||
* needs to be 64bit aligned to work.
|
||||
*/
|
||||
*((Elf_Addr *)where) = value + addend - base;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve a symbol at run-time.
|
||||
*/
|
||||
@@ -627,9 +645,9 @@ _dl_bind(elf_object_t *object, int index)
|
||||
* | """ | | """ |
|
||||
* | kbind.size | | kbind.size |
|
||||
* | """ | | """ |
|
||||
* | word 2 | | word |
|
||||
* | word 3 | +------------+
|
||||
* | word 4 |
|
||||
* | word 2 | | word 1 |
|
||||
* | word 3 | | (word 2) |
|
||||
* | word 4 | +------------+
|
||||
* | word 5 |
|
||||
* | word 1 |
|
||||
* +------------+
|
||||
@@ -643,18 +661,14 @@ _dl_bind(elf_object_t *object, int index)
|
||||
addr = (Elf_Word *)(object->obj_base + rela->r_offset);
|
||||
_dl_memset(&buf, 0, sizeof(buf));
|
||||
if (__predict_false(rela->r_addend)) {
|
||||
/*
|
||||
* This entry is >32768. The relocation points to a
|
||||
* PC-relative pointer to the _dl_bind_start_0 stub at
|
||||
* the top of the PLT section. Update it to point to
|
||||
* the target function.
|
||||
*/
|
||||
buf.newval[0] = rela->r_addend + newvalue
|
||||
- object->Dyn.info[DT_PLTGOT];
|
||||
i = _dl_reloc_addend(&buf.newval[0], newvalue,
|
||||
rela->r_addend, object->obj_base);
|
||||
|
||||
/* fill in the __kbind structure */
|
||||
buf.param[1].kb_addr = addr;
|
||||
buf.param[1].kb_size = sizeof(buf.newval[0]);
|
||||
buf.param[1].kb_size = i * sizeof(buf.newval[0]);
|
||||
param = &buf.param[1];
|
||||
psize = sizeof(struct __kbind) + sizeof(buf.newval[0]);
|
||||
psize = sizeof(struct __kbind) + i * sizeof(buf.newval[0]);
|
||||
} else {
|
||||
Elf_Word first;
|
||||
|
||||
@@ -779,14 +793,8 @@ _dl_md_reloc_all_plt(elf_object_t *object)
|
||||
value = sr.obj->obj_base + sr.sym->st_value;
|
||||
|
||||
if (__predict_false(relas->r_addend)) {
|
||||
/*
|
||||
* This entry is >32768. The relocation points to a
|
||||
* PC-relative pointer to the _dl_bind_start_0 stub at
|
||||
* the top of the PLT section. Update it to point to
|
||||
* the target function.
|
||||
*/
|
||||
*(Elf_Addr *)where = relas->r_addend + value -
|
||||
object->Dyn.info[DT_PLTGOT];
|
||||
_dl_reloc_addend(&where[0], value,
|
||||
relas->r_addend, object->obj_base);
|
||||
} else
|
||||
_dl_reloc_plt(&where[1], &where[2], where, value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user