32bit module support
PATCH 1/1 32bit module support
I have not done extensive tests yet, but this patch appears to be working. I'd appreciate people giving it a try and let me know how it goes.
There is one worrisome "FIXME" in that file, which is not clear to me. Ralf?
Jun
arch/mips/kernel/module-elf32.c renamed from arch/mips/kernel/module-elf32.c.orig +59 -76
@@ -23,14 +23,11 @@#include <linux/string.h> #include <linux/kernel.h> -struct mips_hi16 { -struct mips_hi16 *next; +struct mips_hilo16 {Elf32_Addr *addr;Elf32_Addr value; }; -static struct mips_hi16 *mips_hi16_list; -#if 0 #define DEBUGP printk#else
@@ -78,6 +75,35 @@return 0 ; } +/* +* For the hi16, we should set ((AHL+S) - (short)(AHL+S)) >> 16 +* For the lo16, we should set (AHL+S) & 0xffff +* where +* AHL = (AHI << 16 ) + (short)ALO +* whereis +* AHI = *(hi16 instr loc) & 0xffff // before reloc +* ALO = *(lo16 instr loc) & 0xffff // before reloc +*/ +#define U32_TO_SHORT (x) (((x & 0xffff) ^ 0x8000) - 0x8000) +static void relocate_hilo16 (struct mips_hilo16 *hi,struct mips_hilo16 *lo) +{ +u32 AHI ,ALO ,AHL_S , res_hi, res_lo; + +AHI = *(hi->addr) &0xffff ; +ALO = *(lo->addr) &0xffff ; +AHL_S = (AHI <<16 ) +U32_TO_SHORT (ALO ) + hi->value; + + res_lo =AHL_S &0xffff ; + res_hi = (AHL_S >>16 ) + ((res_lo &0x8000 )==0 ?0 :1 ); + res_hi &=0xffff ; + + *hi->addr = (*hi->addr & ~0xffff ) | res_hi; + *lo->addr = (*lo->addr & ~0xffff ) | res_lo; +} + +#undef KERN_ERR +#define KERN_ERR + int apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
@@ -85,19 +111,20 @@ struct module *me) {unsigned int i; -Elf32_Rel *rel = (void *)sechdrs[relsec].sh_offset; +Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;Elf32_Sym *sym;uint32_t *location;Elf32_Addr v; +struct mips_hilo16 hi16, lo16;DEBUGP ("Applying relocate section %u to %u\n" , relsec, sechdrs[relsec].sh_info);for (i =0 ; i < sechdrs[relsec].sh_size /sizeof (*rel); i++) {/* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset;/* This is the symbol it is referring to */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_offset + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr +ELF32_R_SYM (rel[i].r_info);if (!sym->st_value) { printk(KERN_WARNING "%s: Unknown symbol %s\n",
@@ -116,99 +143,52 @@break ;case R_MIPS_26 : -if (v %4 ) +if (v %4 ) {printk (KERN_ERR "module %s: dangerous relocation\n" , me->name);return -ENOEXEC ; + }if ((v &0xf0000000 ) != - (((unsigned long )location +4 ) &0xf0000000 )) + (((unsigned long )location +4 ) &0xf0000000 )) {printk (KERN_ERR "module %s: relocation overflow\n" , me->name);return -ENOEXEC ; + } *location = (*location & ~0x03ffffff ) | ((*location + (v >>2 )) &0x03ffffff );break ; -case R_MIPS_HI16 : { -struct mips_hi16 *n; - +case R_MIPS_HI16 :/* * We cannot relocate this one now because we don't * know the value of the carry we need to add. Save * the information, and let LO16 do the actual * relocation. */ - n = (struct mips_hi16 *)kmalloc (sizeof *n,GFP_KERNEL ); - n->addr = location; - n->value = v; - n->next = mips_hi16_list; - mips_hi16_list = n; + hi16.addr = location; + hi16.value = v;break ; - } - -case R_MIPS_LO16 : { -unsigned long insnlo = *location; -Elf32_Addr val, vallo; - -/* Sign extend the addend we extract from the lo insn. */ - vallo = ((insnlo &0xffff ) ^0x8000 ) -0x8000 ; - -if (mips_hi16_list !=NULL ) { -struct mips_hi16 *l; - - l = mips_hi16_list; -while (l !=NULL ) { -struct mips_hi16 *next; -unsigned long insn; - -/* -* The value for the HI16 had best be -* the same. -*/ -printk (KERN_ERR "module %s: dangerous " -"relocation\n" , me->name); -return -ENOEXEC ; - -/* -* Do the HI16 relocation. Note that -* we actually don't need to know -* anything about the LO16 itself, -* except where to find the low 16 bits -* of the addend needed by the LO16. -*/ - insn = *l->addr; - val = ((insn &0xffff ) <<16 ) + vallo; - val += v; - -/* -* Account for the sign extension that -* will happen in the low bits. -*/ - val = ((val >>16 ) + ((val &0x8000 ) != -0 )) &0xffff ; - - insn = (insn & ~0xffff ) | val; - *l->addr = insn; - - next = l->next; -kfree (l); - l = next; - } - - mips_hi16_list =NULL ; - } +case R_MIPS_LO16 :/* -* Ok, we're done with the HI16 relocs. Now deal with -* the LO16. +* This lo16 entry must have the same value as +* the preceeding or last hi16 entry. */ - val = v + vallo; - insnlo = (insnlo & ~0xffff ) | (val &0xffff ); - *location = insnlo; +if (v != hi16.value) { +printk (KERN_ERR "module %s: HI16/LO16 value mistmatch : %08x vs %08x\n" , + me->name, + hi16.value, + v); +return -ENOEXEC ; + } + + lo16.addr = location; + lo16.value = v; + +relocate_hilo16 (&hi16, &lo16);break ; - }default : printk(KERN_ERR "module %s: Unknown relocation: %u\n",
@@ -225,6 +205,9 @@ unsigned int relsec, struct module *me) { + if (sechdrs[relsec].sh_size == 0) + return 0; + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name);return -ENOEXEC ;
Quoted 2 lines · Jun Sun
There is one worrisome "FIXME" in that file, which is not clear to me. Ralf?
That comment was copied over from i386. It it works for them it must be good for us ;-)
Ralf
Quoted 6 lines · Jun Sun
I have not done extensive tests yet, but this patch appears to be working. I'd appreciate people giving it a try and let me know how it goes.
There is one worrisome "FIXME" in that file, which is not clear to me. Ralf?
Your code removed handling for a GNU extension. Anyway, I already had a fairly similar patch and I commited it last night. I don't normally announce patches I commit to the list but thought this one is noteworthy as it solves the last big problem with 2.6.
What still needs to be done is adding module supprt for 64-bit also - but that's not functional in 2.4 either and I have no plans to implement 64-bit modules in 2.4.
Ralf
Quoted 3 lines · Ralf Baechle
What still needs to be done is adding module supprt for 64-bit also - but that's not functional in 2.4 either and I have no plans to implement 64-bit modules in 2.4.
AFAIK, what would be needed for 2.4 is an update to modutils, not the
kernel itself. It can be done any time provided the interested party writes appropriate code.
Signature · 3 lines
+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
Quoted 7 lines · Maciej W. Rozycki
Quoted 3 lines
What still needs to be done is adding module supprt for 64-bit also - but that's not functional in 2.4 either and I have no plans to implement 64-bit modules in 2.4.
AFAIK, what would be needed for 2.4 is an update to modutils, not the
kernel itself. It can be done any time provided the interested party writes appropriate code.
You're right, for 2.4 modutils would need to be updated since the entire relocation is done in userspace. The work that needs to be done on userspace rsp. kernel utilities is similar though - 80% of the relocation code in 2.6 were taken from the old modutils; the remaining 20% were needed rewriting since the kernel environment for the relocation code is different than in modutils. In short, once 64-bit modules are working for the one kernel version it's going to be easy to support the other also.
Ralf