From patchwork Sat Aug 1 19:07:13 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John David Anglin X-Patchwork-Id: 38682 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n71J7SNF004887 for ; Sat, 1 Aug 2009 19:07:29 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752045AbZHATHZ (ORCPT ); Sat, 1 Aug 2009 15:07:25 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752046AbZHATHZ (ORCPT ); Sat, 1 Aug 2009 15:07:25 -0400 Received: from hiauly1.hia.nrc.ca ([132.246.100.193]:2225 "EHLO hiauly1.hia.nrc.ca" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752045AbZHATHY (ORCPT ); Sat, 1 Aug 2009 15:07:24 -0400 Received: by hiauly1.hia.nrc.ca (Postfix, from userid 1000) id 0929A500B; Sat, 1 Aug 2009 15:07:14 -0400 (EDT) Subject: Re: Bug#539378: [hppa]: fails to load nfs module: Global Offset Table To: dave@hiauly1.hia.nrc.ca (John David Anglin) Date: Sat, 1 Aug 2009 15:07:13 -0400 (EDT) From: "John David Anglin" Cc: deller@gmx.de, kyle@mcmartin.ca, carlos@systemhalted.org, elendil@planet.nl, 539378@bugs.debian.org, debian-hppa@lists.debian.org, linux-parisc@vger.kernel.org, randolph@tausq.org, submit@bugs.debian.org In-Reply-To: <20090801003740.8BBDE5160@hiauly1.hia.nrc.ca> from "John David Anglin" at Jul 31, 2009 08:37:39 pm X-Mailer: ELM [version 2.4 PL25] MIME-Version: 1.0 Message-Id: <20090801190715.0929A500B@hiauly1.hia.nrc.ca> Sender: linux-parisc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-parisc@vger.kernel.org > > case ELF_STUB_GOT: > > - stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ > > + stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ > > stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */ > > stub->insns[2] = 0xe820d000; /* bve (%r1) */ > > stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */ > > > > - stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff); > > + d = get_got(me, value, addend); > > + if (d <= 15) > > + stub->insns[0] |= reassemble_14(d); > > reassemble_14 is wrong for ldd format 3. Need format 5 and im5 insertion. Since I complained about not using format 5 for small displacements, here's an updated patch for review. Seems to work: dave@mx3210:/usr/src/D$ lsmod Module Size Used by dm_snapshot 45680 0 dm_mirror 27480 0 dm_region_hash 17408 1 dm_mirror dm_log 18968 2 dm_mirror,dm_region_hash dm_mod 111200 3 dm_snapshot,dm_mirror,dm_log ext2 99648 2 sd_mod 63792 4 crc_t10dif 2368 1 sd_mod tg3 196428 0 sym53c8xx 127568 3 libphy 39280 1 tg3 scsi_transport_spi 43528 1 sym53c8xx scsi_mod 261104 3 sd_mod,sym53c8xx,scsi_transport_spi Dave diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index ecd1c50..88989cb 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -86,8 +86,12 @@ * the bottom of the table, which has a maximum signed displacement of * 0x3fff; however, since we're only going forward, this becomes * 0x1fff, and thus, since each GOT entry is 8 bytes long we can have - * at most 1023 entries */ -#define MAX_GOTS 1023 + * at most 1023 entries. + * To overcome this 14bit displacement with some kernel modules, we'll + * use instead the unusal 16bit displacement method (see reassemble_16a) + * which gives us a maximum positive displacement of 0x7fff, and as such + * allows us to allocate up to 4095 GOT entries. */ +#define MAX_GOTS 4095 /* three functions to determine where in the module core * or init pieces the location is */ @@ -145,12 +149,40 @@ struct stub_entry { /* The reassemble_* functions prepare an immediate value for insertion into an opcode. pa-risc uses all sorts of weird bitfields in the instruction to hold the value. */ +static inline int sign_unext (int x, int len) +{ + int len_ones; + + len_ones = (1 << len) - 1; + return x & len_ones; +} + +static inline int low_sign_unext(int x, int len) +{ + int sign, temp; + + sign = (x >> (len-1)) & 1; + temp = sign_unext (x, len-1); + return (temp << 1) | sign; +} + static inline int reassemble_14(int as14) { return (((as14 & 0x1fff) << 1) | ((as14 & 0x2000) >> 13)); } +static inline int reassemble_16a(int as16) +{ + int s, t; + + /* Unusual 16-bit encoding, for wide mode only. */ + t = (as16 << 1) & 0xffff; + s = (as16 & 0x8000); + return (t ^ s ^ (s >> 1)) | (s >> 15); +} + + static inline int reassemble_17(int as17) { return (((as17 & 0x10000) >> 16) | @@ -409,6 +441,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec) { struct stub_entry *stub; + int d; /* initialize stub_offset to point in front of the section */ if (!me->arch.section[targetsec].stub_offset) { @@ -462,12 +495,19 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, */ switch (stub_type) { case ELF_STUB_GOT: - stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ + d = get_got(me, value, addend); + if (d <= 15) { + /* Format 5 */ + stub->insns[0] = 0x0f6010db; /* ldd 0(%dp),%dp */ + stub->insns[0] |= low_sign_unext(d, 5) << 16; + } else { + /* Format 3 */ + stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ + stub->insns[0] |= reassemble_16a(d); + } stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */ stub->insns[2] = 0xe820d000; /* bve (%r1) */ stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */ - - stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff); break; case ELF_STUB_MILLI: stub->insns[0] = 0x20200000; /* ldil 0,%r1 */