Message ID | 20090731233828.GF26333@bombadil.infradead.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
On Fri, Jul 31, 2009 at 7:38 PM, Kyle McMartin<kyle@mcmartin.ca> wrote: > Is it as simple as: > > diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c > index ef5caf2..0502fab 100644 > --- a/arch/parisc/kernel/module.c > +++ b/arch/parisc/kernel/module.c > @@ -82,13 +82,6 @@ >         return -ENOEXEC;             \ >     } > > -/* Maximum number of GOT entries. We use a long displacement ldd from > - * 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 > - >  /* three functions to determine where in the module core >  * or init pieces the location is */ >  static inline int in_init(struct module *me, void *loc) > @@ -126,6 +119,14 @@ struct stub_entry { >  }; >  #endif > > +/* Maximum number of GOT entries. We use a long displacement ldd from > + * the bottom of the table, which has 16-bit signed displacement from > + * %dp. Because we only use the forward direction, we're limited to > + * 15-bits - 1, and because each GOT entry is 8-bytes wide, we're limited > + * to 4095 entries. > + */ > +#define MAX_GOTS    (((1 << 15) - 1) / sizeof(struct got_entry)) > + OK >  /* Field selection types defined by hppa */ >  #define rnd(x)         (((x)+0x1000)&~0x1fff) >  /* fsel: full 32 bits */ > @@ -151,6 +152,15 @@ static inline int reassemble_14(int as14) >         ((as14 & 0x2000) >> 13)); >  } > > +/* Unusual 16-bit encoding, for wide mode only.  */ > +static inline int reassemble_16a(int as16) > +{ > +    int s, t; > +    t = (as16 << 1) & 0xffff; > +    s = (as16 & 0x8000); > +    return (t ^ s ^ (s >> 1)) | (s >> 15); > +} > + OK >  static inline int reassemble_17(int as17) >  { >     return (((as17 & 0x10000) >> 16) | > @@ -460,12 +470,16 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, >  */ >     switch (stub_type) { >     case ELF_STUB_GOT: > +        unsigned int d = get_got(me, value, addend) & 0x7fff; > + >         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); > +        if (d > 15) > +            stub->insns[0] |= reassemble_16a(d); > + You need to rewrite stub->insn[0[, the long format 3 ldd is a different opcode, see the PA 2.0 manual, it will no longer be 0x537b0000. You also still need a <= 15 byte case which uses the old short format 5 ldd with a 14-bit immediate. >         break; >     case ELF_STUB_MILLI: >         stub->insns[0] = 0x20200000;   /* ldil 0,%r1      */ > > I don't think we need to worry about the initial 15-bytes displacement, > since they're all within the first got_entry? (The resulting assembly > looks alright from a 64-bit toolchain: No, we still have to worry about the initial 15-bytes. Within the first 15-bytes you have one GOT entry (%dp + 0) and thus you need to add the case for the short format 3 ldd. Thanks for hacking this up! Cheers, Carlos. -- To unsubscribe from this list: send the line "unsubscribe linux-parisc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index ef5caf2..0502fab 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -82,13 +82,6 @@ return -ENOEXEC; \ } -/* Maximum number of GOT entries. We use a long displacement ldd from - * 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 - /* three functions to determine where in the module core * or init pieces the location is */ static inline int in_init(struct module *me, void *loc) @@ -126,6 +119,14 @@ struct stub_entry { }; #endif +/* Maximum number of GOT entries. We use a long displacement ldd from + * the bottom of the table, which has 16-bit signed displacement from + * %dp. Because we only use the forward direction, we're limited to + * 15-bits - 1, and because each GOT entry is 8-bytes wide, we're limited + * to 4095 entries. + */ +#define MAX_GOTS (((1 << 15) - 1) / sizeof(struct got_entry)) + /* Field selection types defined by hppa */ #define rnd(x) (((x)+0x1000)&~0x1fff) /* fsel: full 32 bits */ @@ -151,6 +152,15 @@ static inline int reassemble_14(int as14) ((as14 & 0x2000) >> 13)); } +/* Unusual 16-bit encoding, for wide mode only. */ +static inline int reassemble_16a(int as16) +{ + int s, t; + 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) | @@ -460,12 +470,16 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, */ switch (stub_type) { case ELF_STUB_GOT: + unsigned int d = get_got(me, value, addend) & 0x7fff; + 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); + if (d > 15) + stub->insns[0] |= reassemble_16a(d); + break; case ELF_STUB_MILLI: stub->insns[0] = 0x20200000; /* ldil 0,%r1 */