summaryrefslogtreecommitdiff
path: root/libexec/ld.so/sparc64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-04-24 18:12:30 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-04-24 18:12:30 +0000
commit824c0ae01a78b8cb968cd05489febb9b375cfcdd (patch)
treeb0f1ec97858fb48bb9fcecf2473a0060f580c822 /libexec/ld.so/sparc64
parent7aec5b0f6ddc48947940a5488c79b478d0550c24 (diff)
Fix handling of more than 32768 PLT entries. Mostly from NetBSD.
eyeballed by deraadt@ and drahn@
Diffstat (limited to 'libexec/ld.so/sparc64')
-rw-r--r--libexec/ld.so/sparc64/ldasm.S20
-rw-r--r--libexec/ld.so/sparc64/rtld_machine.c19
2 files changed, 24 insertions, 15 deletions
diff --git a/libexec/ld.so/sparc64/ldasm.S b/libexec/ld.so/sparc64/ldasm.S
index 332bc13ebd8..7b9f8d72210 100644
--- a/libexec/ld.so/sparc64/ldasm.S
+++ b/libexec/ld.so/sparc64/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.24 2006/05/03 16:10:52 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.25 2010/04/24 18:12:29 kettenis Exp $ */
/* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */
/*
@@ -157,7 +157,7 @@ _ENTRY(_dl_start)
*
* and _dl_bind_start_0(x, y) does:
*
- * i = x - y + 1048596;
+ * i = x - y + 8 - 32768*32;
* n = 32768 + (i/5120)*160 + (i%5120)/24;
*
* Neither routine needs to issue a save since it's already been
@@ -167,17 +167,21 @@ _ENTRY(_dl_start)
/* NOTE: _dl_bind_start_0 is untested. Hence the debug stuff */
_ENTRY(_dl_bind_start_0) # (x, y)
- sethi %hi(1048596), %l1
+ sethi %hi(32768*32-8), %l1
sub %o0, %o1, %l0 /* x - y */
- or %l1, %lo(1048596), %l1
- add %l0, %l1, %l0 /* x - y + 1048596 */
+ or %l1, %lo(32768*32-8), %l1
+ sub %l0, %l1, %l0 /* x - y + 8 - 32768*32 */
- sdivx %l0, 5120, %l1 /* Calculate i/5120 */
+ sethi %hi(5120), %l1
+ sdivx %l0, %l1, %l1 /* Calculate i/5120 */
ldx [%o1 + (10*4)], %o0 /* Load object pointer from PLT2 */
- sub %l0, %l1, %l2 /* And i%5120 */
+ sllx %l1, 2, %l2
+ add %l1, %l2, %l2
+ sllx %l2, 10, %l2
+ sub %l0, %l2, %l2 /* And i%5120 */
/* Let the division churn for a bit. */
- sdivx %l2, 14, %l4 /* (i%5120)/24 */
+ sdivx %l2, 24, %l4 /* (i%5120)/24 */
/* 160 is (32 * 5) or (32 * (4 + 1)) */
sllx %l1, 2, %l3 /* 4 * (i/5120) */
diff --git a/libexec/ld.so/sparc64/rtld_machine.c b/libexec/ld.so/sparc64/rtld_machine.c
index 4fa524db1d4..0776204ba71 100644
--- a/libexec/ld.so/sparc64/rtld_machine.c
+++ b/libexec/ld.so/sparc64/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.43 2008/07/16 20:33:42 drahn Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.44 2010/04/24 18:12:29 kettenis Exp $ */
/*
* Copyright (c) 1999 Dale Rahn
@@ -197,7 +197,8 @@ static long reloc_target_bitmask[] = {
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
-void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rela);
+void _dl_reloc_plt(elf_object_t *object, Elf_Word *where, Elf_Addr value,
+ Elf_RelA *rela);
void _dl_install_plt(Elf_Word *pltgot, Elf_Addr proc);
int
@@ -279,7 +280,7 @@ resolve_failed:
}
if (type == R_TYPE(JMP_SLOT)) {
- _dl_reloc_plt((Elf_Word *)where, value, relas);
+ _dl_reloc_plt(object, (Elf_Word *)where, value, relas);
continue;
}
@@ -374,7 +375,8 @@ resolve_failed:
#define LOVAL(v) ((v) & 0x000003ff)
void
-_dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rela)
+_dl_reloc_plt(elf_object_t *object, Elf_Word *where, Elf_Addr value,
+ Elf_RelA *rela)
{
Elf_Addr offset;
@@ -408,9 +410,12 @@ _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rela)
if (rela->r_addend) {
Elf_Addr *ptr = (Elf_Addr *)where;
/*
- * This entry is >32768. Just replace the pointer.
+ * 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.
*/
- ptr[0] = value;
+ ptr[0] += value - object->Dyn.info[DT_PLTGOT];
} else if (offset <= (1L<<20) && offset >= -(1L<<20)) {
/*
@@ -645,7 +650,7 @@ _dl_bind(elf_object_t *object, int index)
PROT_READ|PROT_WRITE|PROT_EXEC);
}
- _dl_reloc_plt(addr, ooff + this->st_value, rela);
+ _dl_reloc_plt(object, addr, ooff + this->st_value, rela);
/* if PLT is (to be protected), change back to RO/X */
if (object->plt_size != 0) {