Re: Bug#539378: [hppa]: fails to load nfs module: Global Offset Table
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.
Reply to: