From 2997d64776d8596004bed5410963cdc5dcdeb739 Mon Sep 17 00:00:00 2001 From: mycroft Date: Wed, 25 Sep 2002 21:11:18 +0000 Subject: [PATCH] Make this work with PLTs larger than 8192 entries (64KB). Not tested exhaustively, but it works in some simple cases. --- libexec/ld.elf_so/arch/powerpc/ppc_reloc.c | 61 ++++++++++++++-------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c b/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c index 9c5fbdb358fc..66cd3f4d6a83 100644 --- a/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c +++ b/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c @@ -1,4 +1,4 @@ -/* $NetBSD: ppc_reloc.c,v 1.27 2002/09/25 07:27:53 mycroft Exp $ */ +/* $NetBSD: ppc_reloc.c,v 1.28 2002/09/25 21:11:18 mycroft Exp $ */ /*- * Copyright (C) 1998 Tsubai Masanari @@ -63,10 +63,14 @@ _rtld_setup_pltgot(obj) Elf_Word *jmptab; int N = obj->pltrelalim - obj->pltrela; + /* Entries beyond 8192 take twice as much space. */ + if (N > 8192) + N += N-8192; + pltcall = obj->pltgot; + jmptab = pltcall + 18 + N * 2; memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); - jmptab = pltcall + 18 + N * 2; pltcall[1] |= ha(jmptab); pltcall[2] |= l(jmptab); @@ -192,27 +196,30 @@ _rtld_relocate_plt_lazy(obj) const Obj_Entry *obj; { const Elf_Rela *rela; + int reloff; - for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { + for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) { Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); int distance; Elf_Addr *pltresolve; - int reloff = rela - obj->pltrela; assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT)); - if (reloff < 0 || reloff >= 0x8000) - return (-1); - pltresolve = obj->pltgot + 8; - distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); - - /* li r11,reloff */ - /* b pltresolve */ - where[0] = 0x39600000 | reloff; - where[1] = 0x48000000 | (distance & 0x03fffffc); - /* __syncicache(where, 8); */ + if (reloff < 32768) { + /* li r11,reloff */ + *where++ = 0x39600000 | reloff; + } else { + /* lis r11,ha(reloff) */ + /* addi r11,l(reloff) */ + *where++ = 0x3d600000 | ha(reloff); + *where++ = 0x396b0000 | l(reloff); + } + /* b pltresolve */ + distance = (Elf_Addr)pltresolve - (Elf_Addr)where; + *where++ = 0x48000000 | (distance & 0x03fffffc); + /* __syncicache(where - 12, 12); */ } return 0; @@ -247,18 +254,28 @@ _rtld_bind(obj, reloff) Elf_Addr *pltcall, *jmptab; int N = obj->pltrelalim - obj->pltrela; + /* Entries beyond 8192 take twice as much space. */ + if (N > 8192) + N += N-8192; + pltcall = obj->pltgot; - jmptab = pltcall + 18 + N * 2; + jmptab[reloff] = value; - distance = (Elf_Addr)pltcall - (Elf_Addr)(where + 1); - - /* li r11,reloff */ - /* b pltcall # use pltcall routine */ - where[0] = 0x39600000 | reloff; - where[1] = 0x48000000 | (distance & 0x03fffffc); - __syncicache(where, 8); + if (reloff < 32768) { + /* li r11,reloff */ + *where++ = 0x39600000 | reloff; + } else { + /* lis r11,ha(reloff) */ + /* addi r11,l(reloff) */ + *where++ = 0x3d600000 | ha(reloff); + *where++ = 0x396b0000 | l(reloff); + } + /* b pltcall */ + distance = (Elf_Addr)pltcall - (Elf_Addr)where; + *where++ = 0x48000000 | (distance & 0x03fffffc); + __syncicache(where - 12, 12); } return (caddr_t)value;