X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=insmod.c;h=1a63ecb2ac0cb7a2bf417a65ec8cbe31eeb47ca3;hb=deba6dea0340465af76624f9ef3a0bbe28130d8a;hp=e52da91e447466a5eb87c0493bd0e54e235f8ff9;hpb=f5d5e77321ad32b3952dcdf21d14fd0ef3d4c1a9;p=oweals%2Fbusybox.git diff --git a/insmod.c b/insmod.c index e52da91e4..1a63ecb2a 100644 --- a/insmod.c +++ b/insmod.c @@ -2,7 +2,11 @@ /* * Mini insmod implementation for busybox * - * Copyright (C) 1999,2000 by Lineo, inc. + * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, + * and MIPS. + * + * + * Copyright (C) 1999,2000,2001 by Lineo, inc. * Written by Erik Andersen * and Ron Alder * @@ -14,6 +18,18 @@ * very minor changes required to also work with StrongArm and presumably * all ARM based systems. * + * Magnus Damm 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... + * + * Quinn Jensen added MIPS support 23-Feb-2001. + * based on modutils-2.4.2 + * MIPS specific support for Elf loading and relocation. + * Copyright 1996, 1997 Linux International. + * Contributed by Ralf Baechle + * * Based almost entirely on the Linux modutils-2.3.11 implementation. * Copyright 1996, 1997 Linux International. * New implementation contributed by Richard Henderson @@ -37,7 +53,6 @@ * */ -#include "busybox.h" #include #include #include @@ -46,8 +61,48 @@ #include #include #include +#include #include #include +#include "busybox.h" + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE +# define new_sys_init_module init_module +#else +# define old_sys_init_module init_module +#endif + +#ifdef BB_FEATURE_INSMOD_LOADINKMEM +#define LOADBITS 0 +#else +#define LOADBITS 1 +#endif + +#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 + +#if defined(__mips__) +// neither used +#endif //---------------------------------------------------------------------------- //--------modutils module.h, lines 45-242 @@ -78,7 +133,7 @@ #ifndef MODUTILS_MODULE_H static const int MODUTILS_MODULE_H = 1; -#ident "$Id: insmod.c,v 1.38 2001/01/24 23:34:48 andersen Exp $" +#ident "$Id: insmod.c,v 1.70 2001/07/31 22:51:49 andersen Exp $" /* 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 @@ -211,8 +266,19 @@ struct new_module unsigned tgt_long persist_end; unsigned tgt_long can_unload; unsigned tgt_long runsize; +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE + const char *kallsyms_start; /* All symbols for kernel debugging */ + const char *kallsyms_end; + const char *archdata_start; /* arch specific data for module */ + const char *archdata_end; + const char *kernel_data; /* Reserved for kernel internal use */ +#endif }; +#define ARCHDATA_SEC_NAME "__archdata" +#define KALLSYMS_SEC_NAME "__kallsyms" + + struct new_module_info { unsigned long addr; @@ -284,7 +350,7 @@ int delete_module(const char *); #ifndef MODUTILS_OBJ_H static const int MODUTILS_OBJ_H = 1; -#ident "$Id: insmod.c,v 1.38 2001/01/24 23:34:48 andersen Exp $" +#ident "$Id: insmod.c,v 1.70 2001/07/31 22:51:49 andersen Exp $" /* The relocatable object is manipulated using elfin types. */ @@ -308,7 +374,10 @@ static const int MODUTILS_OBJ_H = 1; #endif #define ELFCLASSM ELFCLASS32 -#define ELFDATAM ELFDATA2LSB + +#if (defined(__mc68000__)) +#define ELFDATAM ELFDATA2MSB +#endif @@ -317,12 +386,42 @@ static const int MODUTILS_OBJ_H = 1; #define MATCH_MACHINE(x) (x == EM_SH) #define SHT_RELM SHT_RELA #define Elf32_RelM Elf32_Rela +#define ELFDATAM ELFDATA2LSB #elif defined(__arm__) #define MATCH_MACHINE(x) (x == EM_ARM) #define SHT_RELM SHT_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(__mips__) + +/* Account for ELF spec changes. */ +#ifndef EM_MIPS_RS3_LE +#ifdef EM_MIPS_RS4_BE +#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE +#else +#define EM_MIPS_RS3_LE 10 +#endif +#endif /* !EM_MIPS_RS3_LE */ + +#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE) +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#ifdef __MIPSEB__ +#define ELFDATAM ELFDATA2MSB +#endif +#ifdef __MIPSEL__ +#define ELFDATAM ELFDATA2LSB +#endif #elif defined(__i386__) @@ -337,9 +436,16 @@ static const int MODUTILS_OBJ_H = 1; #define SHT_RELM SHT_REL #define Elf32_RelM Elf32_Rel +#define ELFDATAM ELFDATA2LSB + +#elif defined(__mc68000__) + +#define MATCH_MACHINE(x) (x == EM_68K) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela #else -#error insmod.c no platform specified +#error Sorry, but insmod.c does not yet support this architecture... #endif #ifndef ElfW @@ -434,78 +540,75 @@ struct obj_symbol_patch /* Generic object manipulation routines. */ -unsigned long obj_elf_hash(const char *); +static unsigned long obj_elf_hash(const char *); -unsigned long obj_elf_hash_n(const char *, unsigned long len); +static unsigned long obj_elf_hash_n(const char *, unsigned long len); -struct obj_symbol *obj_add_symbol (struct obj_file *f, const char *name, - unsigned long symidx, int info, int secidx, - ElfW(Addr) value, unsigned long size); - -struct obj_symbol *obj_find_symbol (struct obj_file *f, +static struct obj_symbol *obj_find_symbol (struct obj_file *f, const char *name); -ElfW(Addr) obj_symbol_final_value(struct obj_file *f, +static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, struct obj_symbol *sym); -void obj_set_symbol_compare(struct obj_file *f, +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING +static void obj_set_symbol_compare(struct obj_file *f, int (*cmp)(const char *, const char *), unsigned long (*hash)(const char *)); +#endif -struct obj_section *obj_find_section (struct obj_file *f, +static struct obj_section *obj_find_section (struct obj_file *f, const char *name); -void obj_insert_section_load_order (struct obj_file *f, +static void obj_insert_section_load_order (struct obj_file *f, struct obj_section *sec); -struct obj_section *obj_create_alloced_section (struct obj_file *f, +static struct obj_section *obj_create_alloced_section (struct obj_file *f, const char *name, unsigned long align, unsigned long size); -struct obj_section *obj_create_alloced_section_first (struct obj_file *f, +static struct obj_section *obj_create_alloced_section_first (struct obj_file *f, const char *name, unsigned long align, unsigned long size); -void *obj_extend_section (struct obj_section *sec, unsigned long more); +static void *obj_extend_section (struct obj_section *sec, unsigned long more); -int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, +static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, const char *string); -int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, +static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, struct obj_symbol *sym); -int obj_check_undefineds(struct obj_file *f); +static int obj_check_undefineds(struct obj_file *f); -void obj_allocate_commons(struct obj_file *f); +static void obj_allocate_commons(struct obj_file *f); -unsigned long obj_load_size (struct obj_file *f); +static unsigned long obj_load_size (struct obj_file *f); -int obj_relocate (struct obj_file *f, ElfW(Addr) base); +static int obj_relocate (struct obj_file *f, ElfW(Addr) base); -struct obj_file *obj_load(FILE *f); +static struct obj_file *obj_load(FILE *f, int loadprogbits); -int obj_create_image (struct obj_file *f, char *image); +static int obj_create_image (struct obj_file *f, char *image); /* Architecture specific manipulation routines. */ -struct obj_file *arch_new_file (void); +static struct obj_file *arch_new_file (void); -struct obj_section *arch_new_section (void); +static struct obj_section *arch_new_section (void); -struct obj_symbol *arch_new_symbol (void); +static struct obj_symbol *arch_new_symbol (void); -enum obj_reloc arch_apply_relocation (struct obj_file *f, +static enum obj_reloc arch_apply_relocation (struct obj_file *f, struct obj_section *targsec, struct obj_section *symsec, struct obj_symbol *sym, ElfW(RelM) *rel, ElfW(Addr) value); -int arch_create_got (struct obj_file *f); +static int arch_create_got (struct obj_file *f); -struct new_module; -int arch_init_module (struct obj_file *f, struct new_module *); +static int arch_init_module (struct obj_file *f, struct new_module *); #endif /* obj.h */ //---------------------------------------------------------------------------- @@ -521,10 +624,10 @@ static const int STRVERSIONLEN = 32; /*======================================================================*/ -int flag_force_load = 0; -int flag_autoclean = 0; -int flag_verbose = 0; -int flag_export = 1; +static int flag_force_load = 0; +static int flag_autoclean = 0; +static int flag_verbose = 0; +static int flag_export = 1; /*======================================================================*/ @@ -537,8 +640,10 @@ int flag_export = 1; /* Done ;-) */ -#if defined(__arm__) -struct arm_plt_entry + + +#if defined(BB_USE_PLT_ENTRIES) +struct arch_plt_entry { int offset; int allocated:1; @@ -546,26 +651,44 @@ struct arm_plt_entry }; #endif +#if defined(BB_USE_GOT_ENTRIES) struct arch_got_entry { int offset; unsigned offset_done:1; unsigned reloc_done:1; }; +#endif + +#if defined(__mips__) +struct mips_hi16 +{ + struct mips_hi16 *next; + Elf32_Addr *addr; + Elf32_Addr value; +}; +#endif struct arch_file { struct obj_file root; -#if defined(__arm__) - struct obj_section *plt; +#if defined(BB_USE_PLT_ENTRIES) + struct obj_section *plt; #endif +#if defined(BB_USE_GOT_ENTRIES) struct obj_section *got; +#endif +#if defined(__mips__) + struct mips_hi16 *mips_hi16_list; +#endif }; struct arch_symbol { struct obj_symbol root; -#if defined(__arm__) - struct arm_plt_entry pltent; +#if defined(BB_USE_PLT_ENTRIES) + struct arch_plt_entry pltent; #endif +#if defined(BB_USE_GOT_ENTRIES) struct arch_got_entry gotent; +#endif }; @@ -577,117 +700,85 @@ struct external_module { struct new_module_symbol *syms; }; -struct new_module_symbol *ksyms; -size_t nksyms; +static struct new_module_symbol *ksyms; +static size_t nksyms; -struct external_module *ext_modules; -int n_ext_modules; -int n_ext_modules_used; - - - -/* Some firendly syscalls to cheer everyone's day... */ -#define __NR_new_sys_init_module __NR_init_module -_syscall2(int, new_sys_init_module, const char *, name, - const struct new_module *, info) -#define __NR_old_sys_init_module __NR_init_module -_syscall5(int, old_sys_init_module, const char *, name, char *, code, - unsigned, codesize, struct old_mod_routines *, routines, - struct old_symbol_table *, symtab) -#ifndef BB_RMMOD -_syscall1(int, delete_module, const char *, name) -#else +static struct external_module *ext_modules; +static int n_ext_modules; +static int n_ext_modules_used; extern int delete_module(const char *); -#endif -/* This is kind of troublesome. See, we don't actually support - the m68k or the arm the same way we support i386 and (now) - sh. In doing my SH patch, I just assumed that whatever works - for i386 also works for m68k and arm since currently insmod.c - does nothing special for them. If this isn't true, the below - line is rather misleading IMHO, and someone should either - change it or add more proper architecture-dependent support - for these boys. +static char m_filename[FILENAME_MAX + 1]; +static char m_fullName[FILENAME_MAX + 1]; - -- Bryan Rittmeyer */ -#ifdef BB_FEATURE_OLD_MODULE_INTERFACE -_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks) -#endif - -#if defined(__i386__) || defined(__m68k__) || defined(__arm__) -/* Jump through hoops to fixup error return codes */ -#define __NR__create_module __NR_create_module -static inline _syscall2(long, _create_module, const char *, name, size_t, - size) -unsigned long create_module(const char *name, size_t size) -{ - long ret = _create_module(name, size); - - if (ret == -1 && errno > 125) { - ret = -errno; - errno = 0; - } - return ret; -} -#else -_syscall2(unsigned long, create_module, const char *, name, size_t, size) -#endif -static char m_filename[BUFSIZ + 1] = "\0"; -static char m_fullName[BUFSIZ + 1] = "\0"; /*======================================================================*/ -static int findNamedModule(const char *fileName, struct stat *statbuf, - void *userDate) +static int check_module_name_match(const char *filename, struct stat *statbuf, + void *userdata) { - char *fullName = (char *) userDate; + char *fullname = (char *) userdata; - - if (fullName[0] == '\0') + if (fullname[0] == '\0') return (FALSE); else { - char *tmp = strrchr((char *) fileName, '/'); - - if (tmp == NULL) - tmp = (char *) fileName; - else - tmp++; - if (check_wildcard_match(tmp, fullName) == TRUE) { + char *tmp, *tmp1 = strdup(filename); + tmp = get_last_path_component(tmp1); + if (strcmp(tmp, fullname) == 0) { + free(tmp1); /* Stop searching if we find a match */ - memcpy(m_filename, fileName, strlen(fileName)+1); - return (FALSE); + safe_strncpy(m_filename, filename, sizeof(m_filename)); + return (TRUE); } + free(tmp1); } - return (TRUE); + return (FALSE); } /*======================================================================*/ -struct obj_file *arch_new_file(void) +static struct obj_file *arch_new_file(void) { struct arch_file *f; f = xmalloc(sizeof(*f)); + +#if defined(BB_USE_PLT_ENTRIES) + f->plt = NULL; +#endif +#if defined(BB_USE_GOT_ENTRIES) f->got = NULL; +#endif +#if defined(__mips__) + f->mips_hi16_list = NULL; +#endif + return &f->root; } -struct obj_section *arch_new_section(void) +static struct obj_section *arch_new_section(void) { return xmalloc(sizeof(struct obj_section)); } -struct obj_symbol *arch_new_symbol(void) +static struct obj_symbol *arch_new_symbol(void) { struct arch_symbol *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)); +#endif + return &sym->root; } -enum obj_reloc +static enum obj_reloc arch_apply_relocation(struct obj_file *f, struct obj_section *targsec, struct obj_section *symsec, @@ -695,18 +786,20 @@ arch_apply_relocation(struct obj_file *f, ElfW(RelM) *rel, ElfW(Addr) v) { struct arch_file *ifile = (struct arch_file *) f; +#if !(defined(__mips__)) struct arch_symbol *isym = (struct arch_symbol *) sym; +#endif ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + 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; -#if defined(__arm__) +#endif +#if defined(BB_USE_PLT_ENTRIES) ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; - - struct arm_plt_entry *pe; + struct arch_plt_entry *pe; unsigned long *ip; #endif - enum obj_reloc ret = obj_reloc_ok; switch (ELF32_R_TYPE(rel->r_info)) { @@ -720,6 +813,12 @@ arch_apply_relocation(struct obj_file *f, case R_ARM_NONE: #elif defined(__i386__) case R_386_NONE: +#elif defined(__mc68000__) + case R_68K_NONE: +#elif defined(__powerpc__) + case R_PPC_NONE: +#elif defined(__mips__) + case R_MIPS_NONE: #endif break; @@ -728,10 +827,122 @@ arch_apply_relocation(struct obj_file *f, #elif defined(__arm__) case R_ARM_ABS32: #elif defined(__i386__) - case R_386_32: + case R_386_32: +#elif defined(__mc68000__) + case R_68K_32: +#elif defined(__powerpc__) + case R_PPC_ADDR32: +#elif defined(__mips__) + case R_MIPS_32: #endif *loc += v; break; +#if defined(__mc68000__) + case R_68K_8: + if (v > 0xff) + ret = obj_reloc_overflow; + *(char *)loc = v; + break; + case R_68K_16: + if (v > 0xffff) + ret = obj_reloc_overflow; + *(short *)loc = v; + break; +#endif /* __mc68000__ */ + +#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(__mips__) + case R_MIPS_26: + if (v % 4) + ret = obj_reloc_dangerous; + if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000)) + ret = obj_reloc_overflow; + *loc = + (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & + 0x03ffffff); + break; + + case R_MIPS_HI16: + { + struct mips_hi16 *n; + + /* 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 *) xmalloc(sizeof *n); + n->addr = loc; + n->value = v; + n->next = ifile->mips_hi16_list; + ifile->mips_hi16_list = n; + break; + } + + case R_MIPS_LO16: + { + unsigned long insnlo = *loc; + Elf32_Addr val, vallo; + + /* Sign extend the addend we extract from the lo insn. */ + vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; + + if (ifile->mips_hi16_list != NULL) { + struct mips_hi16 *l; + + l = ifile->mips_hi16_list; + while (l != NULL) { + struct mips_hi16 *next; + unsigned long insn; + + /* The value for the HI16 had best be the same. */ + assert(v == l->value); + + /* 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; + free(l); + l = next; + } + + ifile->mips_hi16_list = NULL; + } + + /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */ + val = v + vallo; + insnlo = (insnlo & ~0xffff) | (val & 0xffff); + *loc = insnlo; + break; + } +#endif #if defined(__arm__) #elif defined(__sh__) @@ -743,22 +954,64 @@ arch_apply_relocation(struct obj_file *f, case R_386_PC32: *loc += v - dot; break; +#elif defined(__mc68000__) + case R_68K_PC8: + v -= dot; + if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80) + ret = obj_reloc_overflow; + *(char *)loc = v; + break; + case R_68K_PC16: + v -= dot; + if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000) + ret = obj_reloc_overflow; + *(short *)loc = v; + break; + case R_68K_PC32: + *(int *)loc = v - dot; + break; +#elif defined(__powerpc__) + case R_PPC_REL32: + *loc = v - dot; + break; #endif #if defined(__sh__) case R_SH_PLT32: *loc = v - dot; break; -#elif defined(__arm__) +#elif defined(__i386__) +#endif + +#if defined(BB_USE_PLT_ENTRIES) + +#if defined(__arm__) case R_ARM_PC24: case R_ARM_PLT32: +#endif +#if defined(__powerpc__) + case R_PPC_REL24: +#endif /* find the plt entry and initialize it if necessary */ assert(isym != NULL); - pe = (struct arm_plt_entry*) &isym->pltent; + + pe = (struct arch_plt_entry*) &isym->pltent; + if (! pe->inited) { ip = (unsigned long *) (ifile->plt->contents + pe->offset); + + /* generate some machine code */ + +#if defined(__arm__) ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ 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; } @@ -772,15 +1025,18 @@ arch_apply_relocation(struct obj_file *f, if (v & 3) ret = obj_reloc_dangerous; + /* merge the offset into the instruction. */ +#if defined(__arm__) /* Convert to words. */ v >>= 2; - /* merge the offset into the instruction. */ *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); - break; -#elif defined(__i386__) #endif - +#if defined(__powerpc__) + *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); +#endif + break; +#endif /* BB_USE_PLT_ENTRIES */ #if defined(__arm__) #elif defined(__sh__) @@ -793,6 +1049,11 @@ arch_apply_relocation(struct obj_file *f, case R_386_JMP_SLOT: *loc = v; break; +#elif defined(__mc68000__) + case R_68K_GLOB_DAT: + case R_68K_JMP_SLOT: + *loc = v; + break; #endif #if defined(__arm__) @@ -804,8 +1065,15 @@ arch_apply_relocation(struct obj_file *f, case R_386_RELATIVE: *loc += f->baseaddr; break; +#elif defined(__mc68000__) + case R_68K_RELATIVE: + *(int *)loc += f->baseaddr; + break; #endif +#if defined(BB_USE_GOT_ENTRIES) + +#if !defined(__68k__) #if defined(__sh__) case R_SH_GOTPC: #elif defined(__arm__) @@ -816,17 +1084,20 @@ arch_apply_relocation(struct obj_file *f, assert(got != 0); #if defined(__sh__) *loc += got - dot + rel->r_addend;; -#elif defined(__i386__) || defined(__arm__) +#elif defined(__i386__) || defined(__arm__) || defined(__m68k_) *loc += got - dot; #endif break; +#endif // __68k__ #if defined(__sh__) case R_SH_GOT32: #elif defined(__arm__) - case R_ARM_GOT32: + case R_ARM_GOT32: #elif defined(__i386__) case R_386_GOT32: +#elif defined(__mc68000__) + case R_68K_GOT32: #endif assert(isym != NULL); /* needs an entry in the .got: set it, once */ @@ -837,22 +1108,28 @@ arch_apply_relocation(struct obj_file *f, /* make the reloc with_respect_to_.got */ #if defined(__sh__) *loc += isym->gotent.offset + rel->r_addend; -#elif defined(__i386__) || defined(__arm__) +#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) *loc += isym->gotent.offset; #endif break; /* address relative to the got */ +#if !defined(__mc68000__) #if defined(__sh__) case R_SH_GOTOFF: #elif defined(__arm__) - case R_ARM_GOTOFF: + case R_ARM_GOTOFF: #elif defined(__i386__) case R_386_GOTOFF: +#elif defined(__mc68000__) + case R_68K_GOTOFF: #endif assert(got != 0); *loc += v - got; break; +#endif // __mc68000__ + +#endif /* BB_USE_GOT_ENTRIES */ default: printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); @@ -863,11 +1140,15 @@ arch_apply_relocation(struct obj_file *f, return ret; } -int arch_create_got(struct obj_file *f) +static int arch_create_got(struct obj_file *f) { +#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) struct arch_file *ifile = (struct arch_file *) f; - int i, got_offset = 0, gotneeded = 0; -#if defined(__arm__) + int i; +#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; #endif struct obj_section *relsec, *symsec, *strsec; @@ -895,12 +1176,23 @@ int arch_create_got(struct obj_file *f) switch (ELF32_R_TYPE(rel->r_info)) { #if defined(__arm__) case R_ARM_GOT32: + break; #elif defined(__sh__) case R_SH_GOT32: + break; #elif defined(__i386__) case R_386_GOT32: + break; +#elif defined(__mc68000__) + case R_68K_GOT32: + break; #endif + +#if defined(__powerpc__) + case R_PPC_REL24: + pltneeded = 1; break; +#endif #if defined(__arm__) case R_ARM_PC24: @@ -933,17 +1225,18 @@ int arch_create_got(struct obj_file *f) name = f->sections[extsym->st_shndx]->name; } intsym = (struct arch_symbol *) obj_find_symbol(f, name); - +#if defined(BB_USE_GOT_ENTRIES) if (!intsym->gotent.offset_done) { intsym->gotent.offset_done = 1; 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) { intsym->pltent.allocated = 1; intsym->pltent.offset = plt_offset; - plt_offset += 8; + plt_offset += BB_PLT_ENTRY_SIZE; intsym->pltent.inited = 0; pltneeded = 0; } @@ -951,31 +1244,34 @@ int arch_create_got(struct obj_file *f) } } -#if defined(__arm__) +#if defined(BB_USE_GOT_ENTRIES) if (got_offset) { - struct obj_section* relsec = obj_find_section(f, ".got"); + struct obj_section* myrelsec = obj_find_section(f, ".got"); - if (relsec) { - obj_extend_section(relsec, got_offset); + if (myrelsec) { + obj_extend_section(myrelsec, got_offset); } else { - relsec = obj_create_alloced_section(f, ".got", 8, got_offset); - assert(relsec); + myrelsec = obj_create_alloced_section(f, ".got", + BB_GOT_ENTRY_SIZE, + got_offset); + assert(myrelsec); } - ifile->got = relsec; + ifile->got = myrelsec; } +#endif +#if defined(BB_USE_PLT_ENTRIES) 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); + ifile->plt = obj_create_alloced_section(f, ".plt", + BB_PLT_ENTRY_SIZE, + plt_offset); +#endif #endif - return 1; } -int arch_init_module(struct obj_file *f, struct new_module *mod) +static int arch_init_module(struct obj_file *f, struct new_module *mod) { return 1; } @@ -984,7 +1280,7 @@ int arch_init_module(struct obj_file *f, struct new_module *mod) /*======================================================================*/ /* Standard ELF hash function. */ -inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) +static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) { unsigned long h = 0; unsigned long g; @@ -1002,7 +1298,7 @@ inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) return h; } -unsigned long obj_elf_hash(const char *name) +static unsigned long obj_elf_hash(const char *name) { return obj_elf_hash_n(name, strlen(name)); } @@ -1013,25 +1309,15 @@ unsigned long obj_elf_hash(const char *name) static int get_kernel_version(char str[STRVERSIONLEN]) { struct utsname uts_info; - char *p, *q; - int a, b, c; + int kv; if (uname(&uts_info) < 0) return -1; strncpy(str, uts_info.release, STRVERSIONLEN); - p = uts_info.release; - a = strtoul(p, &p, 10); - if (*p != '.') + kv = get_kernel_revision(); + if(kv==0) return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; } /* String comparison for non-co-versioned kernel and module. */ @@ -1059,7 +1345,7 @@ static unsigned long ncv_symbol_hash(const char *str) return obj_elf_hash_n(str, len); } -void +static void obj_set_symbol_compare(struct obj_file *f, int (*cmp) (const char *, const char *), unsigned long (*hash) (const char *)) @@ -1087,8 +1373,8 @@ obj_set_symbol_compare(struct obj_file *f, #endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - -struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name, +static struct obj_symbol * +obj_add_symbol(struct obj_file *f, const char *name, unsigned long symidx, int info, int secidx, ElfW(Addr) value, unsigned long size) @@ -1153,7 +1439,7 @@ struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name, /* Don't report an error if the symbol is coming from the kernel or some external module. */ if (secidx <= SHN_HIRESERVE) - error_msg("%s multiply defined\n", name); + error_msg("%s multiply defined", name); return sym; } } @@ -1164,8 +1450,13 @@ struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name, f->symtab[hash] = sym; sym->ksymidx = -1; - if (ELFW(ST_BIND) (info) == STB_LOCAL) - f->local_symtab[symidx] = sym; + if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) { + if (symidx >= f->local_symtab_size) + error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", + name, (long) symidx, (long) f->local_symtab_size); + else + f->local_symtab[symidx] = sym; + } found: sym->name = name; @@ -1177,7 +1468,8 @@ struct obj_symbol *obj_add_symbol(struct obj_file *f, const char *name, return sym; } -struct obj_symbol *obj_find_symbol(struct obj_file *f, const char *name) +static struct obj_symbol * +obj_find_symbol(struct obj_file *f, const char *name) { struct obj_symbol *sym; unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; @@ -1189,7 +1481,7 @@ struct obj_symbol *obj_find_symbol(struct obj_file *f, const char *name) return NULL; } -ElfW(Addr) +static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) { if (sym) { @@ -1203,7 +1495,7 @@ ElfW(Addr) } } -struct obj_section *obj_find_section(struct obj_file *f, const char *name) +static struct obj_section *obj_find_section(struct obj_file *f, const char *name) { int i, n = f->header.e_shnum; @@ -1236,7 +1528,7 @@ static int obj_load_order_prio(struct obj_section *a) return ac; } -void +static void obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) { struct obj_section **p; @@ -1248,7 +1540,7 @@ obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) *p = sec; } -struct obj_section *obj_create_alloced_section(struct obj_file *f, +static struct obj_section *obj_create_alloced_section(struct obj_file *f, const char *name, unsigned long align, unsigned long size) @@ -1274,7 +1566,7 @@ struct obj_section *obj_create_alloced_section(struct obj_file *f, return sec; } -struct obj_section *obj_create_alloced_section_first(struct obj_file *f, +static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, const char *name, unsigned long align, unsigned long size) @@ -1303,15 +1595,16 @@ struct obj_section *obj_create_alloced_section_first(struct obj_file *f, return sec; } -void *obj_extend_section(struct obj_section *sec, unsigned long more) +static void *obj_extend_section(struct obj_section *sec, unsigned long more) { unsigned long oldsize = sec->header.sh_size; - sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); + if (more) { + sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); + } return sec->contents + oldsize; } - /* Conditionally add the symbols from the given symbol set to the new module. */ @@ -1416,7 +1709,7 @@ old_process_module_arguments(struct obj_file *f, int argc, char **argv) /* Also check that the parameter was not resolved from the kernel. */ if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - error_msg("symbol for parameter %s not found\n", p); + error_msg("symbol for parameter %s not found", p); return 0; } @@ -1429,7 +1722,7 @@ old_process_module_arguments(struct obj_file *f, int argc, char **argv) str = alloca(strlen(q)); for (r = str, q++; *q != '"'; ++q, ++r) { if (*q == '\0') { - error_msg("improperly terminated string argument for %s\n", p); + error_msg("improperly terminated string argument for %s", p); return 0; } else if (*q == '\\') switch (*++q) { @@ -1488,19 +1781,19 @@ old_process_module_arguments(struct obj_file *f, int argc, char **argv) while (*q++ == ','); } else { char *contents = f->sections[sym->secidx]->contents; - char *loc = contents + sym->value; + char *myloc = contents + sym->value; char *r; /* To search for commas */ /* Break the string with comas */ while ((r = strchr(q, ',')) != (char *) NULL) { *r++ = '\0'; - obj_string_patch(f, sym->secidx, loc - contents, q); - loc += sizeof(char *); + obj_string_patch(f, sym->secidx, myloc - contents, q); + myloc += sizeof(char *); q = r; } /* last part */ - obj_string_patch(f, sym->secidx, loc - contents, q); + obj_string_patch(f, sym->secidx, myloc - contents, q); } argc--, argv++; @@ -1557,8 +1850,11 @@ static int old_get_kernel_symbols(const char *m_name) int nks, nms, nmod, i; nks = get_kernel_syms(NULL); - if (nks < 0) { - perror_msg("get_kernel_syms: %s", m_name); + if (nks <= 0) { + if (nks) + perror_msg("get_kernel_syms: %s", m_name); + else + error_msg("No kernel symbols"); return 0; } @@ -1578,7 +1874,6 @@ static int old_get_kernel_symbols(const char *m_name) while (k->name[0] == '#' && k->name[1]) { struct old_kernel_sym *k2; - struct new_module_symbol *s; /* Find out how many symbols this module has. */ for (k2 = k + 1; k2->name[0] != '#'; ++k2) @@ -1783,7 +2078,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) p = get_modinfo_value(f, key); key += 5; if (p == NULL) { - error_msg("invalid parameter %s\n", key); + error_msg("invalid parameter %s", key); return 0; } @@ -1791,7 +2086,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) /* Also check that the parameter was not resolved from the kernel. */ if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - error_msg("symbol for parameter %s not found\n", key); + error_msg("symbol for parameter %s not found", key); return 0; } @@ -1819,7 +2114,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) str = alloca(strlen(q)); for (r = str, q++; *q != '"'; ++q, ++r) { if (*q == '\0') { - error_msg("improperly terminated string argument for %s\n", + error_msg("improperly terminated string argument for %s", key); return 0; } else if (*q == '\\') @@ -1914,14 +2209,14 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) /* Probably we should do that outside the loop ? */ if (!isdigit(*(p + 1))) { error_msg("parameter type 'c' for %s must be followed by" - " the maximum size\n", key); + " the maximum size", key); return 0; } charssize = strtoul(p + 1, (char **) NULL, 10); /* Check length */ if (strlen(str) >= charssize) { - error_msg("string too long for %s (max %ld)\n", key, + error_msg("string too long for %s (max %ld)", key, charssize - 1); return 0; } @@ -1950,7 +2245,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) break; default: - error_msg("unknown parameter type '%c' for %s\n", *p, key); + error_msg("unknown parameter type '%c' for %s", *p, key); return 0; } } @@ -1969,21 +2264,21 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) case ',': if (++n > max) { - error_msg("too many values for %s (max %d)\n", key, max); + error_msg("too many values for %s (max %d)", key, max); return 0; } ++q; break; default: - error_msg("invalid argument syntax for %s\n", key); + error_msg("invalid argument syntax for %s", key); return 0; } } end_of_arg: if (n < min) { - error_msg("too few values for %s (min %d)\n", key, min); + error_msg("too few values for %s (min %d)", key, min); return 0; } @@ -2048,7 +2343,7 @@ static int new_get_kernel_symbols(void) module_names = xmalloc(bufsize = 256); retry_modules_load: if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { - if (errno == ENOSPC) { + if (errno == ENOSPC && bufsize < ret) { module_names = xrealloc(module_names, bufsize = ret); goto retry_modules_load; } @@ -2057,48 +2352,50 @@ static int new_get_kernel_symbols(void) } n_ext_modules = nmod = ret; - ext_modules = modules = xmalloc(nmod * sizeof(*modules)); - memset(modules, 0, nmod * sizeof(*modules)); /* Collect the modules' symbols. */ - for (i = 0, mn = module_names, m = modules; - i < nmod; ++i, ++m, mn += strlen(mn) + 1) { - struct new_module_info info; - - if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - perror_msg("query_module: QM_INFO: %s", mn); - return 0; - } - - syms = xmalloc(bufsize = 1024); - retry_mod_sym_load: - if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { - switch (errno) { - case ENOSPC: - syms = xrealloc(syms, bufsize = ret); - goto retry_mod_sym_load; - case ENOENT: - /* The module was removed out from underneath us. */ - continue; - default: - perror_msg("query_module: QM_SYMBOLS: %s", mn); + if (nmod){ + ext_modules = modules = xmalloc(nmod * sizeof(*modules)); + memset(modules, 0, nmod * sizeof(*modules)); + for (i = 0, mn = module_names, m = modules; + i < nmod; ++i, ++m, mn += strlen(mn) + 1) { + struct new_module_info info; + + if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + perror_msg("query_module: QM_INFO: %s", mn); return 0; } - } - nsyms = ret; - - m->name = mn; - m->addr = info.addr; - m->nsyms = nsyms; - m->syms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; + + syms = xmalloc(bufsize = 1024); + retry_mod_sym_load: + if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { + switch (errno) { + case ENOSPC: + syms = xrealloc(syms, bufsize = ret); + goto retry_mod_sym_load; + case ENOENT: + /* The module was removed out from underneath us. */ + continue; + default: + perror_msg("query_module: QM_SYMBOLS: %s", mn); + return 0; + } + } + nsyms = ret; + + m->name = mn; + m->addr = info.addr; + m->nsyms = nsyms; + m->syms = syms; + + for (j = 0, s = syms; j < nsyms; ++j, ++s) { + s->name += (unsigned long) syms; + } } } @@ -2107,7 +2404,7 @@ static int new_get_kernel_symbols(void) syms = xmalloc(bufsize = 16 * 1024); retry_kern_sym_load: if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { - if (errno == ENOSPC) { + if (errno == ENOSPC && bufsize < ret) { syms = xrealloc(syms, bufsize = ret); goto retry_kern_sym_load; } @@ -2240,6 +2537,9 @@ new_init_module(const char *m_name, struct obj_file *f, tgt_long m_addr; sec = obj_find_section(f, ".this"); + if (!sec || !sec->contents) { + perror_msg_and_die("corrupt module %s?",m_name); + } module = (struct new_module *) sec->contents; m_addr = sec->header.sh_addr; @@ -2280,6 +2580,16 @@ new_init_module(const char *m_name, struct obj_file *f, module->runsize > sec->header.sh_addr - m_addr) module->runsize = sec->header.sh_addr - m_addr; } + sec = obj_find_section(f, ARCHDATA_SEC_NAME); + if (sec && sec->header.sh_size) { + module->archdata_start = (void*)sec->header.sh_addr; + module->archdata_end = module->archdata_start + sec->header.sh_size; + } + sec = obj_find_section(f, KALLSYMS_SEC_NAME); + if (sec && sec->header.sh_size) { + module->kallsyms_start = (void*)sec->header.sh_addr; + module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; + } if (!arch_init_module(f, module)) return 0; @@ -2311,7 +2621,7 @@ new_init_module(const char *m_name, struct obj_file *f, /*======================================================================*/ -int +static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, const char *string) { @@ -2340,7 +2650,7 @@ obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, return 1; } -int +static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, struct obj_symbol *sym) { @@ -2356,7 +2666,7 @@ obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, return 1; } -int obj_check_undefineds(struct obj_file *f) +static int obj_check_undefineds(struct obj_file *f) { unsigned long i; int ret = 1; @@ -2369,7 +2679,7 @@ int obj_check_undefineds(struct obj_file *f) sym->secidx = SHN_ABS; sym->value = 0; } else { - error_msg("unresolved symbol %s\n", sym->name); + error_msg("unresolved symbol %s", sym->name); ret = 0; } } @@ -2378,7 +2688,7 @@ int obj_check_undefineds(struct obj_file *f) return ret; } -void obj_allocate_commons(struct obj_file *f) +static void obj_allocate_commons(struct obj_file *f) { struct common_entry { struct common_entry *next; @@ -2487,7 +2797,7 @@ void obj_allocate_commons(struct obj_file *f) } } -unsigned long obj_load_size(struct obj_file *f) +static unsigned long obj_load_size(struct obj_file *f) { unsigned long dot = 0; struct obj_section *sec; @@ -2508,7 +2818,7 @@ unsigned long obj_load_size(struct obj_file *f) return dot; } -int obj_relocate(struct obj_file *f, ElfW(Addr) base) +static int obj_relocate(struct obj_file *f, ElfW(Addr) base) { int i, n = f->header.e_shnum; int ret = 1; @@ -2596,11 +2906,11 @@ int obj_relocate(struct obj_file *f, ElfW(Addr) base) errmsg = "Unhandled relocation"; bad_reloc: if (extsym) { - error_msg("%s of type %ld for %s\n", errmsg, + error_msg("%s of type %ld for %s", errmsg, (long) ELFW(R_TYPE) (rel->r_info), strtab + extsym->st_name); } else { - error_msg("%s of type %ld\n", errmsg, + error_msg("%s of type %ld", errmsg, (long) ELFW(R_TYPE) (rel->r_info)); } ret = 0; @@ -2638,7 +2948,7 @@ int obj_relocate(struct obj_file *f, ElfW(Addr) base) return ret; } -int obj_create_image(struct obj_file *f, char *image) +static int obj_create_image(struct obj_file *f, char *image) { struct obj_section *sec; ElfW(Addr) base = f->baseaddr; @@ -2646,7 +2956,7 @@ int obj_create_image(struct obj_file *f, char *image) for (sec = f->load_order; sec; sec = sec->load_next) { char *secimg; - if (sec->header.sh_size == 0) + if (sec->contents == 0 || sec->header.sh_size == 0) continue; secimg = image + (sec->header.sh_addr - base); @@ -2660,7 +2970,7 @@ int obj_create_image(struct obj_file *f, char *image) /*======================================================================*/ -struct obj_file *obj_load(FILE * fp) +static struct obj_file *obj_load(FILE * fp, int loadprogbits) { struct obj_file *f; ElfW(Shdr) * section_headers; @@ -2685,25 +2995,25 @@ struct obj_file *obj_load(FILE * fp) || f->header.e_ident[EI_MAG1] != ELFMAG1 || f->header.e_ident[EI_MAG2] != ELFMAG2 || f->header.e_ident[EI_MAG3] != ELFMAG3) { - error_msg("not an ELF file\n"); + error_msg("not an ELF file"); return NULL; } if (f->header.e_ident[EI_CLASS] != ELFCLASSM || f->header.e_ident[EI_DATA] != ELFDATAM || f->header.e_ident[EI_VERSION] != EV_CURRENT || !MATCH_MACHINE(f->header.e_machine)) { - error_msg("ELF file not for this architecture\n"); + error_msg("ELF file not for this architecture"); return NULL; } if (f->header.e_type != ET_REL) { - error_msg("ELF file not a relocatable object\n"); + error_msg("ELF file not a relocatable object"); return NULL; } /* Read the section headers. */ if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { - error_msg("section header size mismatch: %lu != %lu\n", + error_msg("section header size mismatch: %lu != %lu", (unsigned long) f->header.e_shentsize, (unsigned long) sizeof(ElfW(Shdr))); return NULL; @@ -2731,7 +3041,7 @@ struct obj_file *obj_load(FILE * fp) sec->header = section_headers[i]; sec->idx = i; - switch (sec->header.sh_type) { + if(sec->header.sh_size) switch (sec->header.sh_type) { case SHT_NULL: case SHT_NOTE: case SHT_NOBITS: @@ -2739,6 +3049,12 @@ struct obj_file *obj_load(FILE * fp) break; case SHT_PROGBITS: +#if LOADBITS + if (!loadprogbits) { + sec->contents = NULL; + break; + } +#endif case SHT_SYMTAB: case SHT_STRTAB: case SHT_RELM: @@ -2756,11 +3072,11 @@ struct obj_file *obj_load(FILE * fp) #if SHT_RELM == SHT_REL case SHT_RELA: - error_msg("RELA relocations not supported on this architecture\n"); + error_msg("RELA relocations not supported on this architecture"); return NULL; #else case SHT_REL: - error_msg("REL relocations not supported on this architecture\n"); + error_msg("REL relocations not supported on this architecture"); return NULL; #endif @@ -2773,7 +3089,7 @@ struct obj_file *obj_load(FILE * fp) break; } - error_msg("can't handle sections of type %ld\n", + error_msg("can't handle sections of type %ld", (long) sec->header.sh_type); return NULL; } @@ -2791,6 +3107,12 @@ struct obj_file *obj_load(FILE * fp) for (i = 0; i < shnum; ++i) { struct obj_section *sec = f->sections[i]; + /* .modinfo should be contents only but gcc has no attribute for that. + * The kernel may have marked .modinfo as ALLOC, ignore this bit. + */ + if (strcmp(sec->name, ".modinfo") == 0) + sec->header.sh_flags &= ~SHF_ALLOC; + if (sec->header.sh_flags & SHF_ALLOC) obj_insert_section_load_order(f, sec); @@ -2802,7 +3124,7 @@ struct obj_file *obj_load(FILE * fp) ElfW(Sym) * sym; if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { - error_msg("symbol size mismatch: %lu != %lu\n", + error_msg("symbol size mismatch: %lu != %lu", (unsigned long) sec->header.sh_entsize, (unsigned long) sizeof(ElfW(Sym))); return NULL; @@ -2814,38 +3136,73 @@ struct obj_file *obj_load(FILE * fp) /* Allocate space for a table of local symbols. */ j = f->local_symtab_size = sec->header.sh_info; - f->local_symtab = xmalloc(j *= - sizeof(struct obj_symbol *)); - memset(f->local_symtab, 0, j); + f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *)); /* Insert all symbols into the hash table. */ for (j = 1, ++sym; j < nsym; ++j, ++sym) { const char *name; if (sym->st_name) name = strtab + sym->st_name; - else + else name = f->sections[sym->st_shndx]->name; obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, sym->st_value, sym->st_size); - } - } + } + } break; case SHT_RELM: if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { - error_msg("relocation entry size mismatch: %lu != %lu\n", + error_msg("relocation entry size mismatch: %lu != %lu", (unsigned long) sec->header.sh_entsize, (unsigned long) sizeof(ElfW(RelM))); return NULL; } break; + /* XXX Relocation code from modutils-2.3.19 is not here. + * Why? That's about 20 lines of code from obj/obj_load.c, + * which gets done in a second pass through the sections. + * This BusyBox insmod does similar work in obj_relocate(). */ } } return f; } +#ifdef BB_FEATURE_INSMOD_LOADINKMEM +/* + * load the unloaded sections directly into the memory allocated by + * kernel for the module + */ + +static int obj_load_progbits(FILE * fp, struct obj_file* f) +{ + char* imagebase = (char*) f->imagebase; + ElfW(Addr) base = f->baseaddr; + struct obj_section* sec; + + for (sec = f->load_order; sec; sec = sec->load_next) { + + /* section already loaded? */ + if (sec->contents != NULL) + continue; + + if (sec->header.sh_size == 0) + continue; + + sec->contents = imagebase + (sec->header.sh_addr - base); + fseek(fp, sec->header.sh_offset, SEEK_SET); + if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { + errorMsg("error reading ELF section data: %s\n", strerror(errno)); + return 0; + } + + } + return 1; +} +#endif + static void hide_special_symbols(struct obj_file *f) { static const char *const specials[] = { @@ -2877,7 +3234,8 @@ extern int insmod_main( int argc, char **argv) ElfW(Addr) m_addr; FILE *fp; struct obj_file *f; - char m_name[BUFSIZ + 1] = "\0"; + struct stat st; + char m_name[FILENAME_MAX + 1] = "\0"; int exit_status = EXIT_FAILURE; int m_has_modinfo; #ifdef BB_FEATURE_INSMOD_VERSION_CHECKING @@ -2889,7 +3247,7 @@ extern int insmod_main( int argc, char **argv) #endif /* Parse any options */ - while ((opt = getopt(argc, argv, "fkvxL")) > 0) { + while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) { switch (opt) { case 'f': /* force loading */ flag_force_load = 1; @@ -2903,6 +3261,9 @@ extern int insmod_main( int argc, char **argv) case 'x': /* do not export externs */ flag_export = 0; break; + case 'o': /* name the output module */ + strncpy(m_name, optarg, FILENAME_MAX); + break; case 'L': /* Stub warning */ /* This is needed for compatibility with modprobe. * In theory, this does locking, but we don't do @@ -2910,12 +3271,12 @@ extern int insmod_main( int argc, char **argv) * loading the same module 50 times concurrently. */ break; default: - usage(insmod_usage); + show_usage(); } } if (argv[optind] == NULL) { - usage(insmod_usage); + show_usage(); } /* Grab the module name */ @@ -2928,29 +3289,62 @@ extern int insmod_main( int argc, char **argv) if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') len -= 2; - memcpy(m_name, tmp, len); - strcpy(m_fullName, m_name); + memcpy(m_fullName, tmp, len); + m_fullName[len]='\0'; + if (*m_name == '\0') { + strcpy(m_name, m_fullName); + } strcat(m_fullName, ".o"); - /* Get a filedesc for the module */ - if ((fp = fopen(argv[optind], "r")) == NULL) { - /* Hmpf. Could not open it. Search through _PATH_MODULES to find a module named m_name */ - if (recursive_action(_PATH_MODULES, TRUE, FALSE, FALSE, - findNamedModule, 0, m_fullName) == FALSE) + /* Get a filedesc for the module. Check we we have a complete path */ + if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) || + (fp = fopen(argv[optind], "r")) == NULL) { + struct utsname myuname; + + /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, + * but do not error out yet if we fail to find it... */ + if (uname(&myuname) == 0) { + char module_dir[FILENAME_MAX]; + char real_module_dir[FILENAME_MAX]; + snprintf (module_dir, sizeof(module_dir), "%s/%s", + _PATH_MODULES, myuname.release); + /* Jump through hoops in case /lib/modules/`uname -r` + * is a symlink. We do not want recursive_action to + * follow symlinks, but we do want to follow the + * /lib/modules/`uname -r` dir, So resolve it ourselves + * if it is a link... */ + if (realpath (module_dir, real_module_dir) == NULL) + strcpy(real_module_dir, module_dir); + recursive_action(real_module_dir, TRUE, FALSE, FALSE, + check_module_name_match, 0, m_fullName); + } + + /* Check if we have found anything yet */ + if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) { - if (m_filename[0] == '\0' - || ((fp = fopen(m_filename, "r")) == NULL)) + char module_dir[FILENAME_MAX]; + if (realpath (_PATH_MODULES, module_dir) == NULL) + strcpy(module_dir, _PATH_MODULES); + /* No module found under /lib/modules/`uname -r`, this + * time cast the net a bit wider. Search /lib/modules/ */ + if (recursive_action(module_dir, TRUE, FALSE, FALSE, + check_module_name_match, 0, m_fullName) == FALSE) { - error_msg("No module named '%s' found in '%s'\n", m_fullName, _PATH_MODULES); - return EXIT_FAILURE; - } - } else - error_msg_and_die("No module named '%s' found in '%s'\n", m_fullName, _PATH_MODULES); - } else - memcpy(m_filename, argv[optind], strlen(argv[optind])); + if (m_filename[0] == '\0' + || ((fp = fopen(m_filename, "r")) == NULL)) + { + error_msg("%s: no module by that name found", m_fullName); + return EXIT_FAILURE; + } + } else + error_msg_and_die("%s: no module by that name found", m_fullName); + } + } else + safe_strncpy(m_filename, argv[optind], sizeof(m_filename)); + printf("Using %s\n", m_filename); - if ((f = obj_load(fp)) == NULL) + if ((f = obj_load(fp, LOADBITS)) == NULL) perror_msg_and_die("Could not load the module"); if (get_modinfo_value(f, "kernel_version") == NULL) @@ -2968,7 +3362,7 @@ extern int insmod_main( int argc, char **argv) m_version = old_get_module_version(f, m_strversion); if (m_version == -1) { error_msg("couldn't find the kernel version the module was " - "compiled for\n"); + "compiled for"); goto out; } } @@ -2977,12 +3371,12 @@ extern int insmod_main( int argc, char **argv) if (flag_force_load) { error_msg("Warning: kernel-module version mismatch\n" "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s\n", + "\twhile this kernel is version %s", m_filename, m_strversion, k_strversion); } else { error_msg("kernel-module version mismatch\n" "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s.\n", + "\twhile this kernel is version %s.", m_filename, m_strversion, k_strversion); goto out; } @@ -2998,7 +3392,7 @@ extern int insmod_main( int argc, char **argv) goto out; k_crcs = new_is_kernel_checksummed(); #else - error_msg("Not configured to support new kernels\n"); + error_msg("Not configured to support new kernels"); goto out; #endif } else { @@ -3007,7 +3401,7 @@ extern int insmod_main( int argc, char **argv) goto out; k_crcs = old_is_kernel_checksummed(); #else - error_msg("Not configured to support old kernels\n"); + error_msg("Not configured to support old kernels"); goto out; #endif } @@ -3039,6 +3433,9 @@ extern int insmod_main( int argc, char **argv) } obj_allocate_commons(f); + /* done with the module name, on to the optional var=value arguments */ + ++optind; + if (optind < argc) { if (m_has_modinfo ? !new_process_module_arguments(f, argc - optind, argv + optind) @@ -3058,16 +3455,13 @@ extern int insmod_main( int argc, char **argv) m_size = obj_load_size(f); - errno = 0; m_addr = create_module(m_name, m_size); - switch (errno) { - case 0: - break; + if (m_addr==-1) switch (errno) { case EEXIST: - error_msg("A module named %s already exists\n", m_name); + error_msg("A module named %s already exists", m_name); goto out; case ENOMEM: - error_msg("Can't allocate kernel memory for module; needed %lu bytes\n", + error_msg("Can't allocate kernel memory for module; needed %lu bytes", m_size); goto out; default: @@ -3075,6 +3469,19 @@ extern int insmod_main( int argc, char **argv) goto out; } +#if !LOADBITS + /* + * the PROGBITS section was not loaded by the obj_load + * now we can load them directly into the kernel memory + */ + // f->imagebase = (char*) m_addr; + f->imagebase = (ElfW(Addr)) m_addr; + if (!obj_load_progbits(fp, f)) { + delete_module(m_name); + goto out; + } +#endif + if (!obj_relocate(f, m_addr)) { delete_module(m_name); goto out;