📄 insmod.c
字号:
static unsigned long obj_elf_hash_n(const char *, unsigned long len);static struct obj_symbol *obj_find_symbol (struct obj_file *f, const char *name);static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, struct obj_symbol *sym);#ifdef BB_FEATURE_INSMOD_VERSION_CHECKINGstatic void obj_set_symbol_compare(struct obj_file *f, int (*cmp)(const char *, const char *), unsigned long (*hash)(const char *));#endifstatic struct obj_section *obj_find_section (struct obj_file *f, const char *name);static void obj_insert_section_load_order (struct obj_file *f, struct obj_section *sec);static struct obj_section *obj_create_alloced_section (struct obj_file *f, const char *name, unsigned long align, unsigned long size);static struct obj_section *obj_create_alloced_section_first (struct obj_file *f, const char *name, unsigned long align, unsigned long size);static void *obj_extend_section (struct obj_section *sec, unsigned long more);static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, const char *string);static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, struct obj_symbol *sym);static int obj_check_undefineds(struct obj_file *f);static void obj_allocate_commons(struct obj_file *f);static unsigned long obj_load_size (struct obj_file *f);static int obj_relocate (struct obj_file *f, ElfW(Addr) base);static struct obj_file *obj_load(FILE *f, int loadprogbits);static int obj_create_image (struct obj_file *f, char *image);/* Architecture specific manipulation routines. */static struct obj_file *arch_new_file (void);static struct obj_section *arch_new_section (void);static struct obj_symbol *arch_new_symbol (void);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);static int arch_create_got (struct obj_file *f);static int arch_init_module (struct obj_file *f, struct new_module *);#endif /* obj.h *///----------------------------------------------------------------------------//--------end of modutils obj.h//----------------------------------------------------------------------------#define _PATH_MODULES "/lib/modules"static const int STRVERSIONLEN = 32;/*======================================================================*/static int flag_force_load = 0;static int flag_autoclean = 0;static int flag_verbose = 0;static int flag_export = 1;/*======================================================================*//* previously, these were named i386_* but since we could be compiling for the sh, I've renamed them to the more general arch_* These structures are the same between the x86 and SH, and we can't support anything else right now anyway. In the future maybe they should be #if defined'd *//* Done ;-) */#if defined(BB_USE_PLT_ENTRIES)struct arch_plt_entry{ int offset; int allocated:1; int inited:1; /* has been set up */};#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;};#endifstruct arch_file { struct obj_file root;#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(BB_USE_PLT_ENTRIES) struct arch_plt_entry pltent;#endif#if defined(BB_USE_GOT_ENTRIES) struct arch_got_entry gotent;#endif};struct external_module { const char *name; ElfW(Addr) addr; int used; size_t nsyms; struct new_module_symbol *syms;};static struct new_module_symbol *ksyms;static size_t nksyms;static struct external_module *ext_modules;static int n_ext_modules;static int n_ext_modules_used;extern int delete_module(const char *);static char m_filename[FILENAME_MAX + 1];static char m_fullName[FILENAME_MAX + 1];/*======================================================================*/static int check_module_name_match(const char *filename, struct stat *statbuf, void *userdata){ char *fullname = (char *) userdata; if (fullname[0] == '\0') return (FALSE); else { 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 */ safe_strncpy(m_filename, filename, sizeof(m_filename)); return (TRUE); } free(tmp1); } return (FALSE);}/*======================================================================*/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;}static struct obj_section *arch_new_section(void){ return xmalloc(sizeof(struct obj_section));}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;}static enum obj_relocarch_apply_relocation(struct obj_file *f, struct obj_section *targsec, struct obj_section *symsec, struct obj_symbol *sym, 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;#endif#if defined(BB_USE_PLT_ENTRIES) ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; struct arch_plt_entry *pe; unsigned long *ip;#endif enum obj_reloc ret = obj_reloc_ok; switch (ELF32_R_TYPE(rel->r_info)) {/* even though these constants seem to be the same for the i386 and the sh, we "#if define" them for clarity and in case that ever changes */#if defined(__sh__) case R_SH_NONE:#elif defined(__arm__) 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;#if defined(__sh__) case R_SH_DIR32:#elif defined(__arm__) case R_ARM_ABS32:#elif defined(__i386__) 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__) case R_SH_REL32: *loc += v - dot; break;#elif defined(__i386__) case R_386_PLT32: 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(__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 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; } /* relative distance to target */ v -= dot; /* if the target is too far away.... */ if ((int)v < -0x02000000 || (int)v >= 0x02000000) { /* go via the plt */ v = plt + pe->offset - dot; } if (v & 3) ret = obj_reloc_dangerous; /* merge the offset into the instruction. */#if defined(__arm__) /* Convert to words. */ v >>= 2; *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);#endif#if defined(__powerpc__) *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);#endif break;#endif /* BB_USE_PLT_ENTRIES */#if defined(__arm__)#elif defined(__sh__) case R_SH_GLOB_DAT: case R_SH_JMP_SLOT: *loc = v; break;#elif defined(__i386__) case R_386_GLOB_DAT: 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__)#elif defined(__sh__) case R_SH_RELATIVE: *loc += f->baseaddr + rel->r_addend; break;#elif defined(__i386__) 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__) case R_ARM_GOTPC:#elif defined(__i386__) case R_386_GOTPC:#endif assert(got != 0);#if defined(__sh__)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -