Apply a patch from Magnus Damm <damm@opensource.se> to support

powerpc with busybox insmod
 -Erik
This commit is contained in:
Eric Andersen 2001-02-20 20:47:08 +00:00
parent 477aedd77f
commit 90fe7fea10
2 changed files with 326 additions and 80 deletions

203
insmod.c
View File

@ -14,6 +14,12 @@
* very minor changes required to also work with StrongArm and presumably * very minor changes required to also work with StrongArm and presumably
* all ARM based systems. * all ARM based systems.
* *
* Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
* PowerPC specific code stolen from modutils-2.3.16,
* written by Paul Mackerras, Copyright 1996, 1997 Linux International.
* I've only tested the code on mpc8xx platforms in big-endian mode.
* Did some cleanup and added BB_USE_xxx_ENTRIES...
*
* Based almost entirely on the Linux modutils-2.3.11 implementation. * Based almost entirely on the Linux modutils-2.3.11 implementation.
* Copyright 1996, 1997 Linux International. * Copyright 1996, 1997 Linux International.
* New implementation contributed by Richard Henderson <rth@tamu.edu> * New implementation contributed by Richard Henderson <rth@tamu.edu>
@ -52,6 +58,28 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include "busybox.h" #include "busybox.h"
#if defined(__powerpc__)
#define BB_USE_PLT_ENTRIES
#define BB_PLT_ENTRY_SIZE 16
#endif
#if defined(__arm__)
#define BB_USE_PLT_ENTRIES
#define BB_PLT_ENTRY_SIZE 8
#define BB_USE_GOT_ENTRIES
#define BB_GOT_ENTRY_SIZE 8
#endif
#if defined(__sh__)
#define BB_USE_GOT_ENTRIES
#define BB_GOT_ENTRY_SIZE 4
#endif
#if defined(__i386__)
#define BB_USE_GOT_ENTRIES
#define BB_GOT_ENTRY_SIZE 4
#endif
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
//--------modutils module.h, lines 45-242 //--------modutils module.h, lines 45-242
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -81,7 +109,7 @@
#ifndef MODUTILS_MODULE_H #ifndef MODUTILS_MODULE_H
static const int MODUTILS_MODULE_H = 1; static const int MODUTILS_MODULE_H = 1;
#ident "$Id: insmod.c,v 1.48 2001/02/20 06:14:07 andersen Exp $" #ident "$Id: insmod.c,v 1.49 2001/02/20 20:47:08 andersen Exp $"
/* This file contains the structures used by the 2.0 and 2.1 kernels. /* This file contains the structures used by the 2.0 and 2.1 kernels.
We do not use the kernel headers directly because we do not wish We do not use the kernel headers directly because we do not wish
@ -287,7 +315,7 @@ int delete_module(const char *);
#ifndef MODUTILS_OBJ_H #ifndef MODUTILS_OBJ_H
static const int MODUTILS_OBJ_H = 1; static const int MODUTILS_OBJ_H = 1;
#ident "$Id: insmod.c,v 1.48 2001/02/20 06:14:07 andersen Exp $" #ident "$Id: insmod.c,v 1.49 2001/02/20 20:47:08 andersen Exp $"
/* The relocatable object is manipulated using elfin types. */ /* The relocatable object is manipulated using elfin types. */
@ -311,21 +339,27 @@ static const int MODUTILS_OBJ_H = 1;
#endif #endif
#define ELFCLASSM ELFCLASS32 #define ELFCLASSM ELFCLASS32
#define ELFDATAM ELFDATA2LSB
#if defined(__sh__) #if defined(__sh__)
#define MATCH_MACHINE(x) (x == EM_SH) #define MATCH_MACHINE(x) (x == EM_SH)
#define SHT_RELM SHT_RELA #define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela #define Elf32_RelM Elf32_Rela
#define ELFDATAM ELFDATA2LSB
#elif defined(__arm__) #elif defined(__arm__)
#define MATCH_MACHINE(x) (x == EM_ARM) #define MATCH_MACHINE(x) (x == EM_ARM)
#define SHT_RELM SHT_REL #define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel #define Elf32_RelM Elf32_Rel
#define ELFDATAM ELFDATA2LSB
#elif defined(__powerpc__)
#define MATCH_MACHINE(x) (x == EM_PPC)
#define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela
#define ELFDATAM ELFDATA2MSB
#elif defined(__i386__) #elif defined(__i386__)
@ -340,6 +374,7 @@ static const int MODUTILS_OBJ_H = 1;
#define SHT_RELM SHT_REL #define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel #define Elf32_RelM Elf32_Rel
#define ELFDATAM ELFDATA2LSB
#else #else
#error Sorry, but insmod.c does not yet support this architecture... #error Sorry, but insmod.c does not yet support this architecture...
@ -540,8 +575,10 @@ int flag_export = 1;
/* Done ;-) */ /* Done ;-) */
#if defined(__arm__)
struct arm_plt_entry
#if defined(BB_USE_PLT_ENTRIES)
struct arch_plt_entry
{ {
int offset; int offset;
int allocated:1; int allocated:1;
@ -549,26 +586,32 @@ struct arm_plt_entry
}; };
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
struct arch_got_entry { struct arch_got_entry {
int offset; int offset;
unsigned offset_done:1; unsigned offset_done:1;
unsigned reloc_done:1; unsigned reloc_done:1;
}; };
#endif
struct arch_file { struct arch_file {
struct obj_file root; struct obj_file root;
#if defined(__arm__) #if defined(BB_USE_PLT_ENTRIES)
struct obj_section *plt; struct obj_section *plt;
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
struct obj_section *got; struct obj_section *got;
#endif
}; };
struct arch_symbol { struct arch_symbol {
struct obj_symbol root; struct obj_symbol root;
#if defined(__arm__) #if defined(BB_USE_PLT_ENTRIES)
struct arm_plt_entry pltent; struct arch_plt_entry pltent;
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
struct arch_got_entry gotent; struct arch_got_entry gotent;
#endif
}; };
@ -618,7 +661,8 @@ extern int delete_module(const char *);
_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks) _syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks)
#endif #endif
#if defined(__i386__) || defined(__m68k__) || defined(__arm__) #if defined(__i386__) || defined(__m68k__) || defined(__arm__) \
|| defined(__powerpc__)
/* Jump through hoops to fixup error return codes */ /* Jump through hoops to fixup error return codes */
#define __NR__create_module __NR_create_module #define __NR__create_module __NR_create_module
static inline _syscall2(long, _create_module, const char *, name, size_t, static inline _syscall2(long, _create_module, const char *, name, size_t,
@ -673,7 +717,14 @@ struct obj_file *arch_new_file(void)
{ {
struct arch_file *f; struct arch_file *f;
f = xmalloc(sizeof(*f)); f = xmalloc(sizeof(*f));
#if defined(BB_USE_PLT_ENTRIES)
f->plt = NULL;
#endif
#if defined(BB_USE_GOT_ENTRIES)
f->got = NULL; f->got = NULL;
#endif
return &f->root; return &f->root;
} }
@ -686,7 +737,14 @@ struct obj_symbol *arch_new_symbol(void)
{ {
struct arch_symbol *sym; struct arch_symbol *sym;
sym = xmalloc(sizeof(*sym)); sym = xmalloc(sizeof(*sym));
#if defined(BB_USE_PLT_ENTRIES)
memset(&sym->pltent, 0, sizeof(sym->pltent));
#endif
#if defined(BB_USE_GOT_ENTRIES)
memset(&sym->gotent, 0, sizeof(sym->gotent)); memset(&sym->gotent, 0, sizeof(sym->gotent));
#endif
return &sym->root; return &sym->root;
} }
@ -702,14 +760,14 @@ arch_apply_relocation(struct obj_file *f,
ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
#if defined(BB_USE_GOT_ENTRIES)
ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
#if defined(__arm__) #endif
#if defined(BB_USE_PLT_ENTRIES)
ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
struct arch_plt_entry *pe;
struct arm_plt_entry *pe;
unsigned long *ip; unsigned long *ip;
#endif #endif
enum obj_reloc ret = obj_reloc_ok; enum obj_reloc ret = obj_reloc_ok;
switch (ELF32_R_TYPE(rel->r_info)) { switch (ELF32_R_TYPE(rel->r_info)) {
@ -723,6 +781,8 @@ arch_apply_relocation(struct obj_file *f,
case R_ARM_NONE: case R_ARM_NONE:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_NONE: case R_386_NONE:
#elif defined(__powerpc__)
case R_PPC_NONE:
#endif #endif
break; break;
@ -731,11 +791,27 @@ arch_apply_relocation(struct obj_file *f,
#elif defined(__arm__) #elif defined(__arm__)
case R_ARM_ABS32: case R_ARM_ABS32:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_32: case R_386_32:
#elif defined(__powerpc__)
case R_PPC_ADDR32:
#endif #endif
*loc += v; *loc += v;
break; break;
#if defined(__powerpc__)
case R_PPC_ADDR16_HA:
*(unsigned short *)loc = (v + 0x8000) >> 16;
break;
case R_PPC_ADDR16_HI:
*(unsigned short *)loc = v >> 16;
break;
case R_PPC_ADDR16_LO:
*(unsigned short *)loc = v;
break;
#endif
#if defined(__arm__) #if defined(__arm__)
#elif defined(__sh__) #elif defined(__sh__)
case R_SH_REL32: case R_SH_REL32:
@ -746,22 +822,48 @@ arch_apply_relocation(struct obj_file *f,
case R_386_PC32: case R_386_PC32:
*loc += v - dot; *loc += v - dot;
break; break;
#elif defined(__powerpc__)
case R_PPC_REL32:
*loc = v - dot;
break;
#endif #endif
#if defined(__sh__) #if defined(__sh__)
case R_SH_PLT32: case R_SH_PLT32:
*loc = v - dot; *loc = v - dot;
break; break;
#elif defined(__arm__) #elif defined(__i386__)
#endif
#if defined(BB_USE_PLT_ENTRIES)
#if defined(__arm__)
case R_ARM_PC24: case R_ARM_PC24:
case R_ARM_PLT32: case R_ARM_PLT32:
#endif
#if defined(__powerpc__)
case R_PPC_REL24:
#endif
/* find the plt entry and initialize it if necessary */ /* find the plt entry and initialize it if necessary */
assert(isym != NULL); assert(isym != NULL);
pe = (struct arm_plt_entry*) &isym->pltent;
pe = (struct arch_plt_entry*) &isym->pltent;
if (! pe->inited) { if (! pe->inited) {
ip = (unsigned long *) (ifile->plt->contents + pe->offset); ip = (unsigned long *) (ifile->plt->contents + pe->offset);
/* generate some machine code */
#if defined(__arm__)
ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
ip[1] = v; /* sym@ */ ip[1] = v; /* sym@ */
#endif
#if defined(__powerpc__)
ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
ip[2] = 0x7d6903a6; /* mtctr r11 */
ip[3] = 0x4e800420; /* bctr */
#endif
pe->inited = 1; pe->inited = 1;
} }
@ -775,15 +877,18 @@ arch_apply_relocation(struct obj_file *f,
if (v & 3) if (v & 3)
ret = obj_reloc_dangerous; ret = obj_reloc_dangerous;
/* merge the offset into the instruction. */
#if defined(__arm__)
/* Convert to words. */ /* Convert to words. */
v >>= 2; v >>= 2;
/* merge the offset into the instruction. */
*loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
break;
#elif defined(__i386__)
#endif #endif
#if defined(__powerpc__)
*loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
#endif
break;
#endif /* BB_USE_PLT_ENTRIES */
#if defined(__arm__) #if defined(__arm__)
#elif defined(__sh__) #elif defined(__sh__)
@ -809,6 +914,8 @@ arch_apply_relocation(struct obj_file *f,
break; break;
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTPC: case R_SH_GOTPC:
#elif defined(__arm__) #elif defined(__arm__)
@ -827,7 +934,7 @@ arch_apply_relocation(struct obj_file *f,
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
#elif defined(__arm__) #elif defined(__arm__)
case R_ARM_GOT32: case R_ARM_GOT32:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_GOT32: case R_386_GOT32:
#endif #endif
@ -849,7 +956,7 @@ arch_apply_relocation(struct obj_file *f,
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTOFF: case R_SH_GOTOFF:
#elif defined(__arm__) #elif defined(__arm__)
case R_ARM_GOTOFF: case R_ARM_GOTOFF:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_GOTOFF: case R_386_GOTOFF:
#endif #endif
@ -857,6 +964,8 @@ arch_apply_relocation(struct obj_file *f,
*loc += v - got; *loc += v - got;
break; break;
#endif /* BB_USE_GOT_ENTRIES */
default: default:
printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
ret = obj_reloc_unhandled; ret = obj_reloc_unhandled;
@ -869,8 +978,11 @@ arch_apply_relocation(struct obj_file *f,
int arch_create_got(struct obj_file *f) int arch_create_got(struct obj_file *f)
{ {
struct arch_file *ifile = (struct arch_file *) f; struct arch_file *ifile = (struct arch_file *) f;
int i, got_offset = 0, gotneeded = 0; int i;
#if defined(__arm__) #if defined(BB_USE_GOT_ENTRIES)
int got_offset = 0, gotneeded = 0;
#endif
#if defined(BB_USE_PLT_ENTRIES)
int plt_offset = 0, pltneeded = 0; int plt_offset = 0, pltneeded = 0;
#endif #endif
struct obj_section *relsec, *symsec, *strsec; struct obj_section *relsec, *symsec, *strsec;
@ -898,12 +1010,20 @@ int arch_create_got(struct obj_file *f)
switch (ELF32_R_TYPE(rel->r_info)) { switch (ELF32_R_TYPE(rel->r_info)) {
#if defined(__arm__) #if defined(__arm__)
case R_ARM_GOT32: case R_ARM_GOT32:
break;
#elif defined(__sh__) #elif defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
break;
#elif defined(__i386__) #elif defined(__i386__)
case R_386_GOT32: case R_386_GOT32:
#endif
break; break;
#endif
#if defined(__powerpc__)
case R_PPC_REL24:
pltneeded = 1;
break;
#endif
#if defined(__arm__) #if defined(__arm__)
case R_ARM_PC24: case R_ARM_PC24:
@ -936,17 +1056,18 @@ int arch_create_got(struct obj_file *f)
name = f->sections[extsym->st_shndx]->name; name = f->sections[extsym->st_shndx]->name;
} }
intsym = (struct arch_symbol *) obj_find_symbol(f, name); intsym = (struct arch_symbol *) obj_find_symbol(f, name);
#if defined(BB_USE_GOT_ENTRIES)
if (!intsym->gotent.offset_done) { if (!intsym->gotent.offset_done) {
intsym->gotent.offset_done = 1; intsym->gotent.offset_done = 1;
intsym->gotent.offset = got_offset; intsym->gotent.offset = got_offset;
got_offset += 4; got_offset += BB_GOT_ENTRY_SIZE;
} }
#if defined(__arm__) #endif
#if defined(BB_USE_PLT_ENTRIES)
if (pltneeded && intsym->pltent.allocated == 0) { if (pltneeded && intsym->pltent.allocated == 0) {
intsym->pltent.allocated = 1; intsym->pltent.allocated = 1;
intsym->pltent.offset = plt_offset; intsym->pltent.offset = plt_offset;
plt_offset += 8; plt_offset += BB_PLT_ENTRY_SIZE;
intsym->pltent.inited = 0; intsym->pltent.inited = 0;
pltneeded = 0; pltneeded = 0;
} }
@ -954,27 +1075,29 @@ int arch_create_got(struct obj_file *f)
} }
} }
#if defined(__arm__) #if defined(BB_USE_GOT_ENTRIES)
if (got_offset) { if (got_offset) {
struct obj_section* relsec = obj_find_section(f, ".got"); struct obj_section* relsec = obj_find_section(f, ".got");
if (relsec) { if (relsec) {
obj_extend_section(relsec, got_offset); obj_extend_section(relsec, got_offset);
} else { } else {
relsec = obj_create_alloced_section(f, ".got", 8, got_offset); relsec = obj_create_alloced_section(f, ".got",
BB_GOT_ENTRY_SIZE,
got_offset);
assert(relsec); assert(relsec);
} }
ifile->got = relsec; ifile->got = relsec;
} }
if (plt_offset)
ifile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset);
#else
if (got_offset > 0 || gotneeded)
ifile->got = obj_create_alloced_section(f, ".got", 4, got_offset);
#endif #endif
#if defined(BB_USE_PLT_ENTRIES)
if (plt_offset)
ifile->plt = obj_create_alloced_section(f, ".plt",
BB_PLT_ENTRY_SIZE,
plt_offset);
#endif
return 1; return 1;
} }

View File

@ -14,6 +14,12 @@
* very minor changes required to also work with StrongArm and presumably * very minor changes required to also work with StrongArm and presumably
* all ARM based systems. * all ARM based systems.
* *
* Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
* PowerPC specific code stolen from modutils-2.3.16,
* written by Paul Mackerras, Copyright 1996, 1997 Linux International.
* I've only tested the code on mpc8xx platforms in big-endian mode.
* Did some cleanup and added BB_USE_xxx_ENTRIES...
*
* Based almost entirely on the Linux modutils-2.3.11 implementation. * Based almost entirely on the Linux modutils-2.3.11 implementation.
* Copyright 1996, 1997 Linux International. * Copyright 1996, 1997 Linux International.
* New implementation contributed by Richard Henderson <rth@tamu.edu> * New implementation contributed by Richard Henderson <rth@tamu.edu>
@ -52,6 +58,28 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include "busybox.h" #include "busybox.h"
#if defined(__powerpc__)
#define BB_USE_PLT_ENTRIES
#define BB_PLT_ENTRY_SIZE 16
#endif
#if defined(__arm__)
#define BB_USE_PLT_ENTRIES
#define BB_PLT_ENTRY_SIZE 8
#define BB_USE_GOT_ENTRIES
#define BB_GOT_ENTRY_SIZE 8
#endif
#if defined(__sh__)
#define BB_USE_GOT_ENTRIES
#define BB_GOT_ENTRY_SIZE 4
#endif
#if defined(__i386__)
#define BB_USE_GOT_ENTRIES
#define BB_GOT_ENTRY_SIZE 4
#endif
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
//--------modutils module.h, lines 45-242 //--------modutils module.h, lines 45-242
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -81,7 +109,7 @@
#ifndef MODUTILS_MODULE_H #ifndef MODUTILS_MODULE_H
static const int MODUTILS_MODULE_H = 1; static const int MODUTILS_MODULE_H = 1;
#ident "$Id: insmod.c,v 1.48 2001/02/20 06:14:07 andersen Exp $" #ident "$Id: insmod.c,v 1.49 2001/02/20 20:47:08 andersen Exp $"
/* This file contains the structures used by the 2.0 and 2.1 kernels. /* This file contains the structures used by the 2.0 and 2.1 kernels.
We do not use the kernel headers directly because we do not wish We do not use the kernel headers directly because we do not wish
@ -287,7 +315,7 @@ int delete_module(const char *);
#ifndef MODUTILS_OBJ_H #ifndef MODUTILS_OBJ_H
static const int MODUTILS_OBJ_H = 1; static const int MODUTILS_OBJ_H = 1;
#ident "$Id: insmod.c,v 1.48 2001/02/20 06:14:07 andersen Exp $" #ident "$Id: insmod.c,v 1.49 2001/02/20 20:47:08 andersen Exp $"
/* The relocatable object is manipulated using elfin types. */ /* The relocatable object is manipulated using elfin types. */
@ -311,21 +339,27 @@ static const int MODUTILS_OBJ_H = 1;
#endif #endif
#define ELFCLASSM ELFCLASS32 #define ELFCLASSM ELFCLASS32
#define ELFDATAM ELFDATA2LSB
#if defined(__sh__) #if defined(__sh__)
#define MATCH_MACHINE(x) (x == EM_SH) #define MATCH_MACHINE(x) (x == EM_SH)
#define SHT_RELM SHT_RELA #define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela #define Elf32_RelM Elf32_Rela
#define ELFDATAM ELFDATA2LSB
#elif defined(__arm__) #elif defined(__arm__)
#define MATCH_MACHINE(x) (x == EM_ARM) #define MATCH_MACHINE(x) (x == EM_ARM)
#define SHT_RELM SHT_REL #define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel #define Elf32_RelM Elf32_Rel
#define ELFDATAM ELFDATA2LSB
#elif defined(__powerpc__)
#define MATCH_MACHINE(x) (x == EM_PPC)
#define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela
#define ELFDATAM ELFDATA2MSB
#elif defined(__i386__) #elif defined(__i386__)
@ -340,6 +374,7 @@ static const int MODUTILS_OBJ_H = 1;
#define SHT_RELM SHT_REL #define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel #define Elf32_RelM Elf32_Rel
#define ELFDATAM ELFDATA2LSB
#else #else
#error Sorry, but insmod.c does not yet support this architecture... #error Sorry, but insmod.c does not yet support this architecture...
@ -540,8 +575,10 @@ int flag_export = 1;
/* Done ;-) */ /* Done ;-) */
#if defined(__arm__)
struct arm_plt_entry
#if defined(BB_USE_PLT_ENTRIES)
struct arch_plt_entry
{ {
int offset; int offset;
int allocated:1; int allocated:1;
@ -549,26 +586,32 @@ struct arm_plt_entry
}; };
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
struct arch_got_entry { struct arch_got_entry {
int offset; int offset;
unsigned offset_done:1; unsigned offset_done:1;
unsigned reloc_done:1; unsigned reloc_done:1;
}; };
#endif
struct arch_file { struct arch_file {
struct obj_file root; struct obj_file root;
#if defined(__arm__) #if defined(BB_USE_PLT_ENTRIES)
struct obj_section *plt; struct obj_section *plt;
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
struct obj_section *got; struct obj_section *got;
#endif
}; };
struct arch_symbol { struct arch_symbol {
struct obj_symbol root; struct obj_symbol root;
#if defined(__arm__) #if defined(BB_USE_PLT_ENTRIES)
struct arm_plt_entry pltent; struct arch_plt_entry pltent;
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
struct arch_got_entry gotent; struct arch_got_entry gotent;
#endif
}; };
@ -618,7 +661,8 @@ extern int delete_module(const char *);
_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks) _syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks)
#endif #endif
#if defined(__i386__) || defined(__m68k__) || defined(__arm__) #if defined(__i386__) || defined(__m68k__) || defined(__arm__) \
|| defined(__powerpc__)
/* Jump through hoops to fixup error return codes */ /* Jump through hoops to fixup error return codes */
#define __NR__create_module __NR_create_module #define __NR__create_module __NR_create_module
static inline _syscall2(long, _create_module, const char *, name, size_t, static inline _syscall2(long, _create_module, const char *, name, size_t,
@ -673,7 +717,14 @@ struct obj_file *arch_new_file(void)
{ {
struct arch_file *f; struct arch_file *f;
f = xmalloc(sizeof(*f)); f = xmalloc(sizeof(*f));
#if defined(BB_USE_PLT_ENTRIES)
f->plt = NULL;
#endif
#if defined(BB_USE_GOT_ENTRIES)
f->got = NULL; f->got = NULL;
#endif
return &f->root; return &f->root;
} }
@ -686,7 +737,14 @@ struct obj_symbol *arch_new_symbol(void)
{ {
struct arch_symbol *sym; struct arch_symbol *sym;
sym = xmalloc(sizeof(*sym)); sym = xmalloc(sizeof(*sym));
#if defined(BB_USE_PLT_ENTRIES)
memset(&sym->pltent, 0, sizeof(sym->pltent));
#endif
#if defined(BB_USE_GOT_ENTRIES)
memset(&sym->gotent, 0, sizeof(sym->gotent)); memset(&sym->gotent, 0, sizeof(sym->gotent));
#endif
return &sym->root; return &sym->root;
} }
@ -702,14 +760,14 @@ arch_apply_relocation(struct obj_file *f,
ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
#if defined(BB_USE_GOT_ENTRIES)
ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
#if defined(__arm__) #endif
#if defined(BB_USE_PLT_ENTRIES)
ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
struct arch_plt_entry *pe;
struct arm_plt_entry *pe;
unsigned long *ip; unsigned long *ip;
#endif #endif
enum obj_reloc ret = obj_reloc_ok; enum obj_reloc ret = obj_reloc_ok;
switch (ELF32_R_TYPE(rel->r_info)) { switch (ELF32_R_TYPE(rel->r_info)) {
@ -723,6 +781,8 @@ arch_apply_relocation(struct obj_file *f,
case R_ARM_NONE: case R_ARM_NONE:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_NONE: case R_386_NONE:
#elif defined(__powerpc__)
case R_PPC_NONE:
#endif #endif
break; break;
@ -731,11 +791,27 @@ arch_apply_relocation(struct obj_file *f,
#elif defined(__arm__) #elif defined(__arm__)
case R_ARM_ABS32: case R_ARM_ABS32:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_32: case R_386_32:
#elif defined(__powerpc__)
case R_PPC_ADDR32:
#endif #endif
*loc += v; *loc += v;
break; break;
#if defined(__powerpc__)
case R_PPC_ADDR16_HA:
*(unsigned short *)loc = (v + 0x8000) >> 16;
break;
case R_PPC_ADDR16_HI:
*(unsigned short *)loc = v >> 16;
break;
case R_PPC_ADDR16_LO:
*(unsigned short *)loc = v;
break;
#endif
#if defined(__arm__) #if defined(__arm__)
#elif defined(__sh__) #elif defined(__sh__)
case R_SH_REL32: case R_SH_REL32:
@ -746,22 +822,48 @@ arch_apply_relocation(struct obj_file *f,
case R_386_PC32: case R_386_PC32:
*loc += v - dot; *loc += v - dot;
break; break;
#elif defined(__powerpc__)
case R_PPC_REL32:
*loc = v - dot;
break;
#endif #endif
#if defined(__sh__) #if defined(__sh__)
case R_SH_PLT32: case R_SH_PLT32:
*loc = v - dot; *loc = v - dot;
break; break;
#elif defined(__arm__) #elif defined(__i386__)
#endif
#if defined(BB_USE_PLT_ENTRIES)
#if defined(__arm__)
case R_ARM_PC24: case R_ARM_PC24:
case R_ARM_PLT32: case R_ARM_PLT32:
#endif
#if defined(__powerpc__)
case R_PPC_REL24:
#endif
/* find the plt entry and initialize it if necessary */ /* find the plt entry and initialize it if necessary */
assert(isym != NULL); assert(isym != NULL);
pe = (struct arm_plt_entry*) &isym->pltent;
pe = (struct arch_plt_entry*) &isym->pltent;
if (! pe->inited) { if (! pe->inited) {
ip = (unsigned long *) (ifile->plt->contents + pe->offset); ip = (unsigned long *) (ifile->plt->contents + pe->offset);
/* generate some machine code */
#if defined(__arm__)
ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
ip[1] = v; /* sym@ */ ip[1] = v; /* sym@ */
#endif
#if defined(__powerpc__)
ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
ip[2] = 0x7d6903a6; /* mtctr r11 */
ip[3] = 0x4e800420; /* bctr */
#endif
pe->inited = 1; pe->inited = 1;
} }
@ -775,15 +877,18 @@ arch_apply_relocation(struct obj_file *f,
if (v & 3) if (v & 3)
ret = obj_reloc_dangerous; ret = obj_reloc_dangerous;
/* merge the offset into the instruction. */
#if defined(__arm__)
/* Convert to words. */ /* Convert to words. */
v >>= 2; v >>= 2;
/* merge the offset into the instruction. */
*loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
break;
#elif defined(__i386__)
#endif #endif
#if defined(__powerpc__)
*loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
#endif
break;
#endif /* BB_USE_PLT_ENTRIES */
#if defined(__arm__) #if defined(__arm__)
#elif defined(__sh__) #elif defined(__sh__)
@ -809,6 +914,8 @@ arch_apply_relocation(struct obj_file *f,
break; break;
#endif #endif
#if defined(BB_USE_GOT_ENTRIES)
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTPC: case R_SH_GOTPC:
#elif defined(__arm__) #elif defined(__arm__)
@ -827,7 +934,7 @@ arch_apply_relocation(struct obj_file *f,
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
#elif defined(__arm__) #elif defined(__arm__)
case R_ARM_GOT32: case R_ARM_GOT32:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_GOT32: case R_386_GOT32:
#endif #endif
@ -849,7 +956,7 @@ arch_apply_relocation(struct obj_file *f,
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTOFF: case R_SH_GOTOFF:
#elif defined(__arm__) #elif defined(__arm__)
case R_ARM_GOTOFF: case R_ARM_GOTOFF:
#elif defined(__i386__) #elif defined(__i386__)
case R_386_GOTOFF: case R_386_GOTOFF:
#endif #endif
@ -857,6 +964,8 @@ arch_apply_relocation(struct obj_file *f,
*loc += v - got; *loc += v - got;
break; break;
#endif /* BB_USE_GOT_ENTRIES */
default: default:
printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));
ret = obj_reloc_unhandled; ret = obj_reloc_unhandled;
@ -869,8 +978,11 @@ arch_apply_relocation(struct obj_file *f,
int arch_create_got(struct obj_file *f) int arch_create_got(struct obj_file *f)
{ {
struct arch_file *ifile = (struct arch_file *) f; struct arch_file *ifile = (struct arch_file *) f;
int i, got_offset = 0, gotneeded = 0; int i;
#if defined(__arm__) #if defined(BB_USE_GOT_ENTRIES)
int got_offset = 0, gotneeded = 0;
#endif
#if defined(BB_USE_PLT_ENTRIES)
int plt_offset = 0, pltneeded = 0; int plt_offset = 0, pltneeded = 0;
#endif #endif
struct obj_section *relsec, *symsec, *strsec; struct obj_section *relsec, *symsec, *strsec;
@ -898,12 +1010,20 @@ int arch_create_got(struct obj_file *f)
switch (ELF32_R_TYPE(rel->r_info)) { switch (ELF32_R_TYPE(rel->r_info)) {
#if defined(__arm__) #if defined(__arm__)
case R_ARM_GOT32: case R_ARM_GOT32:
break;
#elif defined(__sh__) #elif defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
break;
#elif defined(__i386__) #elif defined(__i386__)
case R_386_GOT32: case R_386_GOT32:
#endif
break; break;
#endif
#if defined(__powerpc__)
case R_PPC_REL24:
pltneeded = 1;
break;
#endif
#if defined(__arm__) #if defined(__arm__)
case R_ARM_PC24: case R_ARM_PC24:
@ -936,17 +1056,18 @@ int arch_create_got(struct obj_file *f)
name = f->sections[extsym->st_shndx]->name; name = f->sections[extsym->st_shndx]->name;
} }
intsym = (struct arch_symbol *) obj_find_symbol(f, name); intsym = (struct arch_symbol *) obj_find_symbol(f, name);
#if defined(BB_USE_GOT_ENTRIES)
if (!intsym->gotent.offset_done) { if (!intsym->gotent.offset_done) {
intsym->gotent.offset_done = 1; intsym->gotent.offset_done = 1;
intsym->gotent.offset = got_offset; intsym->gotent.offset = got_offset;
got_offset += 4; got_offset += BB_GOT_ENTRY_SIZE;
} }
#if defined(__arm__) #endif
#if defined(BB_USE_PLT_ENTRIES)
if (pltneeded && intsym->pltent.allocated == 0) { if (pltneeded && intsym->pltent.allocated == 0) {
intsym->pltent.allocated = 1; intsym->pltent.allocated = 1;
intsym->pltent.offset = plt_offset; intsym->pltent.offset = plt_offset;
plt_offset += 8; plt_offset += BB_PLT_ENTRY_SIZE;
intsym->pltent.inited = 0; intsym->pltent.inited = 0;
pltneeded = 0; pltneeded = 0;
} }
@ -954,27 +1075,29 @@ int arch_create_got(struct obj_file *f)
} }
} }
#if defined(__arm__) #if defined(BB_USE_GOT_ENTRIES)
if (got_offset) { if (got_offset) {
struct obj_section* relsec = obj_find_section(f, ".got"); struct obj_section* relsec = obj_find_section(f, ".got");
if (relsec) { if (relsec) {
obj_extend_section(relsec, got_offset); obj_extend_section(relsec, got_offset);
} else { } else {
relsec = obj_create_alloced_section(f, ".got", 8, got_offset); relsec = obj_create_alloced_section(f, ".got",
BB_GOT_ENTRY_SIZE,
got_offset);
assert(relsec); assert(relsec);
} }
ifile->got = relsec; ifile->got = relsec;
} }
if (plt_offset)
ifile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset);
#else
if (got_offset > 0 || gotneeded)
ifile->got = obj_create_alloced_section(f, ".got", 4, got_offset);
#endif #endif
#if defined(BB_USE_PLT_ENTRIES)
if (plt_offset)
ifile->plt = obj_create_alloced_section(f, ".plt",
BB_PLT_ENTRY_SIZE,
plt_offset);
#endif
return 1; return 1;
} }