diff options
| author | John David Anglin <dave.anglin@nrc-cnrc.gc.ca> | 2009-08-02 06:34:08 -0400 |
|---|---|---|
| committer | Helge Deller <deller@gmx.de> | 2009-08-02 06:34:08 -0400 |
| commit | b4f2e2ad5348063ef94aa623f6f09b52ecaf0990 (patch) | |
| tree | c725f839326292875f26fe2bd08cebac0e24b2ee | |
| parent | ed680c4ad478d0fee9740f7d029087f181346564 (diff) | |
parisc: Fix GOT overflow during module load on 64bit kernel
Signed-off-by: John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
Signed-off-by: Helge Deller <deller@gmx.de>
| -rw-r--r-- | arch/parisc/kernel/module.c | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index ef5caf2e6ed0..61ee0eec4e69 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c | |||
| @@ -86,8 +86,12 @@ | |||
| 86 | * the bottom of the table, which has a maximum signed displacement of | 86 | * the bottom of the table, which has a maximum signed displacement of |
| 87 | * 0x3fff; however, since we're only going forward, this becomes | 87 | * 0x3fff; however, since we're only going forward, this becomes |
| 88 | * 0x1fff, and thus, since each GOT entry is 8 bytes long we can have | 88 | * 0x1fff, and thus, since each GOT entry is 8 bytes long we can have |
| 89 | * at most 1023 entries */ | 89 | * at most 1023 entries. |
| 90 | #define MAX_GOTS 1023 | 90 | * To overcome this 14bit displacement with some kernel modules, we'll |
| 91 | * use instead the unusal 16bit displacement method (see reassemble_16a) | ||
| 92 | * which gives us a maximum positive displacement of 0x7fff, and as such | ||
| 93 | * allows us to allocate up to 4095 GOT entries. */ | ||
| 94 | #define MAX_GOTS 4095 | ||
| 91 | 95 | ||
| 92 | /* three functions to determine where in the module core | 96 | /* three functions to determine where in the module core |
| 93 | * or init pieces the location is */ | 97 | * or init pieces the location is */ |
| @@ -145,12 +149,40 @@ struct stub_entry { | |||
| 145 | /* The reassemble_* functions prepare an immediate value for | 149 | /* The reassemble_* functions prepare an immediate value for |
| 146 | insertion into an opcode. pa-risc uses all sorts of weird bitfields | 150 | insertion into an opcode. pa-risc uses all sorts of weird bitfields |
| 147 | in the instruction to hold the value. */ | 151 | in the instruction to hold the value. */ |
| 152 | static inline int sign_unext(int x, int len) | ||
| 153 | { | ||
| 154 | int len_ones; | ||
| 155 | |||
| 156 | len_ones = (1 << len) - 1; | ||
| 157 | return x & len_ones; | ||
| 158 | } | ||
| 159 | |||
| 160 | static inline int low_sign_unext(int x, int len) | ||
| 161 | { | ||
| 162 | int sign, temp; | ||
| 163 | |||
| 164 | sign = (x >> (len-1)) & 1; | ||
| 165 | temp = sign_unext(x, len-1); | ||
| 166 | return (temp << 1) | sign; | ||
| 167 | } | ||
| 168 | |||
| 148 | static inline int reassemble_14(int as14) | 169 | static inline int reassemble_14(int as14) |
| 149 | { | 170 | { |
| 150 | return (((as14 & 0x1fff) << 1) | | 171 | return (((as14 & 0x1fff) << 1) | |
| 151 | ((as14 & 0x2000) >> 13)); | 172 | ((as14 & 0x2000) >> 13)); |
| 152 | } | 173 | } |
| 153 | 174 | ||
| 175 | static inline int reassemble_16a(int as16) | ||
| 176 | { | ||
| 177 | int s, t; | ||
| 178 | |||
| 179 | /* Unusual 16-bit encoding, for wide mode only. */ | ||
| 180 | t = (as16 << 1) & 0xffff; | ||
| 181 | s = (as16 & 0x8000); | ||
| 182 | return (t ^ s ^ (s >> 1)) | (s >> 15); | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 154 | static inline int reassemble_17(int as17) | 186 | static inline int reassemble_17(int as17) |
| 155 | { | 187 | { |
| 156 | return (((as17 & 0x10000) >> 16) | | 188 | return (((as17 & 0x10000) >> 16) | |
| @@ -407,6 +439,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, | |||
| 407 | enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec) | 439 | enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec) |
| 408 | { | 440 | { |
| 409 | struct stub_entry *stub; | 441 | struct stub_entry *stub; |
| 442 | int __maybe_unused d; | ||
| 410 | 443 | ||
| 411 | /* initialize stub_offset to point in front of the section */ | 444 | /* initialize stub_offset to point in front of the section */ |
| 412 | if (!me->arch.section[targetsec].stub_offset) { | 445 | if (!me->arch.section[targetsec].stub_offset) { |
| @@ -460,12 +493,19 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, | |||
| 460 | */ | 493 | */ |
| 461 | switch (stub_type) { | 494 | switch (stub_type) { |
| 462 | case ELF_STUB_GOT: | 495 | case ELF_STUB_GOT: |
| 463 | stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ | 496 | d = get_got(me, value, addend); |
| 497 | if (d <= 15) { | ||
| 498 | /* Format 5 */ | ||
| 499 | stub->insns[0] = 0x0f6010db; /* ldd 0(%dp),%dp */ | ||
| 500 | stub->insns[0] |= low_sign_unext(d, 5) << 16; | ||
| 501 | } else { | ||
| 502 | /* Format 3 */ | ||
| 503 | stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ | ||
| 504 | stub->insns[0] |= reassemble_16a(d); | ||
| 505 | } | ||
| 464 | stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */ | 506 | stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */ |
| 465 | stub->insns[2] = 0xe820d000; /* bve (%r1) */ | 507 | stub->insns[2] = 0xe820d000; /* bve (%r1) */ |
| 466 | stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */ | 508 | stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */ |
| 467 | |||
| 468 | stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff); | ||
| 469 | break; | 509 | break; |
| 470 | case ELF_STUB_MILLI: | 510 | case ELF_STUB_MILLI: |
| 471 | stub->insns[0] = 0x20200000; /* ldil 0,%r1 */ | 511 | stub->insns[0] = 0x20200000; /* ldil 0,%r1 */ |
