insmod.c

来自「手机嵌入式Linux下可用的busybox源码」· C语言 代码 · 共 2,778 行 · 第 1/5 页

C
2,778
字号
					   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);#ifdef BB_FEATURE_NEW_MODULE_INTERFACEstatic int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,		     struct obj_symbol *sym);#endifstatic 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 void arch_create_got (struct obj_file *f);#ifdef BB_FEATURE_NEW_MODULE_INTERFACEstatic int arch_init_module (struct obj_file *f, struct new_module *);#endif#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_quiet = 0;static int flag_export = 1;/*======================================================================*/#if defined(BB_USE_LIST)struct arch_list_entry{	struct arch_list_entry *next;	BB_LIST_ARCHTYPE addend;	int offset;	int inited : 1;};#endif#if defined(BB_USE_SINGLE)struct arch_single_entry{	int offset;	int inited : 1;	int allocated : 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)#if defined(BB_USE_PLT_LIST)	struct arch_list_entry *pltent;#else	struct arch_single_entry pltent;#endif#endif#if defined(BB_USE_GOT_ENTRIES)	struct arch_single_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];static char m_fullName[FILENAME_MAX];/*======================================================================*/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));	memset(f, 0, sizeof(*f));	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));	memset(sym, 0, sizeof(*sym));	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;	enum obj_reloc ret = obj_reloc_ok;	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) || defined(BB_USE_PLT_ENTRIES)	struct arch_symbol *isym = (struct arch_symbol *) sym;#endif#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;	unsigned long *ip;#if defined(BB_USE_PLT_LIST)	struct arch_list_entry *pe;#else	struct arch_single_entry *pe;#endif#endif	switch (ELF32_R_TYPE(rel->r_info)) {#if defined(__arm__)	case R_ARM_NONE:		break;	case R_ARM_ABS32:		*loc += v;		break;			case R_ARM_GOT32:		goto bb_use_got;	case R_ARM_GOTPC:		/* relative reloc, always to _GLOBAL_OFFSET_TABLE_ 		 * (which is .got) similar to branch, 		 * but is full 32 bits relative */		assert(got);		*loc += got - dot;		break;	case R_ARM_PC24:	case R_ARM_PLT32:		goto bb_use_plt;	case R_ARM_GOTOFF: /* address relative to the got */		assert(got);		*loc += v - got;		break;#elif defined(__i386__)	case R_386_NONE:		break;	case R_386_32:		*loc += v;		break;	case R_386_PLT32:	case R_386_PC32:		*loc += v - dot;		break;	case R_386_GLOB_DAT:	case R_386_JMP_SLOT:		*loc = v;		break;	case R_386_RELATIVE:		*loc += f->baseaddr;		break;	case R_386_GOTPC:		assert(got != 0);		*loc += got - dot;		break;	case R_386_GOT32:		goto bb_use_got;	case R_386_GOTOFF:		assert(got != 0);		*loc += v - got;		break;#elif defined(__mc68000__)	case R_68K_NONE:		break;	case R_68K_32:		*loc += v;		break;	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;	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;	case R_68K_GLOB_DAT:	case R_68K_JMP_SLOT:		*loc = v;		break;	case R_68K_RELATIVE:		*(int *)loc += f->baseaddr;		break;	case R_68K_GOT32:		goto bb_use_got;	case R_68K_GOTOFF:		assert(got != 0);		*loc += v - got;		break;#elif defined(__mips__)	case R_MIPS_NONE:		break;	case R_MIPS_32:		*loc += v;		break;	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;		}#elif 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;	case R_PPC_REL24:		goto bb_use_plt;	case R_PPC_REL32:		*loc = v - dot;		break;	case R_PPC_ADDR32:		*loc = v;		break;#elif defined(__sh__)	case R_SH_NONE:		break;	case R_SH_DIR32:		*loc += v;		break;	case R_SH_REL32:		*loc += v - dot;		break;			case R_SH_PLT32:		*loc = v - dot;		break;	case R_SH_GLOB_DAT:	case R_SH_JMP_SLOT:		*loc = v;		break;	case R_SH_RELATIVE:		*loc = f->baseaddr + rel->r_addend;		break;	case R_SH_GOTPC:		assert(got != 0);		*loc = got - dot + rel->r_addend;		break;	case R_SH_GOT32:		goto bb_use_got;	case R_SH_GOTOFF:		assert(got != 0);		*loc = v - got;		break;#endif	default:        printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info));		ret = obj_reloc_unhandled;		break;#if defined(BB_USE_PLT_ENTRIES)	  bb_use_plt:      /* find the plt entry and initialize it if necessary */      assert(isym != NULL);#if defined(BB_USE_PLT_LIST)      for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;)	pe = pe->next;      assert(pe != NULL);#else      pe = &isym->pltent;#endif      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 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?