insmod.c
来自「手机嵌入式Linux下可用的busybox源码」· C语言 代码 · 共 2,778 行 · 第 1/5 页
C
2,778 行
#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(BB_USE_GOT_ENTRIES) bb_use_got: assert(isym != NULL); /* needs an entry in the .got: set it, once */ if (!isym->gotent.inited) { isym->gotent.inited = 1; *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; } /* make the reloc with_respect_to_.got */#if defined(__sh__) *loc += isym->gotent.offset + rel->r_addend;#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) *loc += isym->gotent.offset;#endif break;#endif /* BB_USE_GOT_ENTRIES */ } return ret;}#if defined(BB_USE_LIST) static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list, int offset, int size){ struct arch_list_entry *pe; for (pe = *list; pe != NULL; pe = pe->next) { if (pe->addend == rel->r_addend) { break; } } if (pe == NULL) { pe = xmalloc(sizeof(struct arch_list_entry)); pe->next = *list; pe->addend = rel->r_addend; pe->offset = offset; pe->inited = 0; *list = pe; return size; } return 0;}#endif#if defined(BB_USE_SINGLE) static int arch_single_init(ElfW(RelM) *rel, struct arch_single_entry *single, int offset, int size){ if (single->allocated == 0) { single->allocated = 1; single->offset = offset; single->inited = 0; return size; } return 0;}#endif#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES)static struct obj_section *arch_xsect_init(struct obj_file *f, char *name, int offset, int size){ struct obj_section *myrelsec = obj_find_section(f, name); if (offset == 0) { offset += size; } if (myrelsec) { obj_extend_section(myrelsec, offset); } else { myrelsec = obj_create_alloced_section(f, name, size, offset); assert(myrelsec); } return myrelsec;}#endifstatic void 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;#if defined(BB_USE_GOT_ENTRIES) int got_offset = 0, got_needed = 0, got_allocate;#endif#if defined(BB_USE_PLT_ENTRIES) int plt_offset = 0, plt_needed = 0, plt_allocate;#endif struct obj_section *relsec, *symsec, *strsec; ElfW(RelM) *rel, *relend; ElfW(Sym) *symtab, *extsym; const char *strtab, *name; struct arch_symbol *intsym; for (i = 0; i < f->header.e_shnum; ++i) { relsec = f->sections[i]; if (relsec->header.sh_type != SHT_RELM) continue; symsec = f->sections[relsec->header.sh_link]; strsec = f->sections[symsec->header.sh_link]; rel = (ElfW(RelM) *) relsec->contents; relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); symtab = (ElfW(Sym) *) symsec->contents; strtab = (const char *) strsec->contents; for (; rel < relend; ++rel) { extsym = &symtab[ELF32_R_SYM(rel->r_info)]; #if defined(BB_USE_GOT_ENTRIES) got_allocate = 0;#endif#if defined(BB_USE_PLT_ENTRIES) plt_allocate = 0;#endif switch (ELF32_R_TYPE(rel->r_info)) {#if defined(__arm__) case R_ARM_PC24: case R_ARM_PLT32: plt_allocate = 1; break; case R_ARM_GOTOFF: case R_ARM_GOTPC: got_needed = 1; continue; case R_ARM_GOT32: got_allocate = 1; break;#elif defined(__i386__) case R_386_GOTPC: case R_386_GOTOFF: got_needed = 1; continue; case R_386_GOT32: got_allocate = 1; break;#elif defined(__powerpc__) case R_PPC_REL24: plt_allocate = 1; break;#elif defined(__mc68000__) case R_68K_GOT32: got_allocate = 1; break; case R_68K_GOTOFF: got_needed = 1; continue;#elif defined(__sh__) case R_SH_GOT32: got_allocate = 1; break; case R_SH_GOTPC: case R_SH_GOTOFF: got_needed = 1; continue;#endif default: continue; } if (extsym->st_name != 0) { name = strtab + extsym->st_name; } else { name = f->sections[extsym->st_shndx]->name; } intsym = (struct arch_symbol *) obj_find_symbol(f, name);#if defined(BB_USE_GOT_ENTRIES) if (got_allocate) { got_offset += arch_single_init( rel, &intsym->gotent, got_offset, BB_GOT_ENTRY_SIZE); got_needed = 1; }#endif#if defined(BB_USE_PLT_ENTRIES) if (plt_allocate) {#if defined(BB_USE_PLT_LIST) plt_offset += arch_list_add( rel, &intsym->pltent, plt_offset, BB_PLT_ENTRY_SIZE);#else plt_offset += arch_single_init( rel, &intsym->pltent, plt_offset, BB_PLT_ENTRY_SIZE);#endif plt_needed = 1; }#endif } }#if defined(BB_USE_GOT_ENTRIES) if (got_needed) { ifile->got = arch_xsect_init(f, ".got", got_offset, BB_GOT_ENTRY_SIZE); }#endif#if defined(BB_USE_PLT_ENTRIES) if (plt_needed) { ifile->plt = arch_xsect_init(f, ".plt", plt_offset, BB_PLT_ENTRY_SIZE); }#endif#endif /* defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) */}#ifdef BB_FEATURE_NEW_MODULE_INTERFACEstatic int arch_init_module(struct obj_file *f, struct new_module *mod){ return 1;}#endif/*======================================================================*//* Standard ELF hash function. */static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n){ unsigned long h = 0; unsigned long g; unsigned char ch; while (n > 0) { ch = *name++; h = (h << 4) + ch; if ((g = (h & 0xf0000000)) != 0) { h ^= g >> 24; h &= ~g; } n--; } return h;}static unsigned long obj_elf_hash(const char *name){ return obj_elf_hash_n(name, strlen(name));}#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING/* String comparison for non-co-versioned kernel and module. */static int ncv_strcmp(const char *a, const char *b){ size_t alen = strlen(a), blen = strlen(b); if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') return strncmp(a, b, alen); else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') return strncmp(a, b, blen); else return strcmp(a, b);}/* String hashing for non-co-versioned kernel and module. Here we are simply forced to drop the crc from the hash. */static unsigned long ncv_symbol_hash(const char *str){ size_t len = strlen(str); if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') len -= 10; return obj_elf_hash_n(str, len);}static voidobj_set_symbol_compare(struct obj_file *f, int (*cmp) (const char *, const char *), unsigned long (*hash) (const char *)){ if (cmp) f->symbol_cmp = cmp; if (hash) { struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; int i; f->symbol_hash = hash; memcpy(tmptab, f->symtab, sizeof(tmptab)); memset(f->symtab, 0, sizeof(f->symtab)); for (i = 0; i < HASH_BUCKETS; ++i) for (sym = tmptab[i]; sym; sym = next) { unsigned long h = hash(sym->name) % HASH_BUCKETS; next = sym->next; sym->next = f->symtab[h]; f->symtab[h] = sym; } }}#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */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){ struct obj_symbol *sym; unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; int n_type = ELFW(ST_TYPE) (info); int n_binding = ELFW(ST_BIND) (info); for (sym = f->symtab[hash]; sym; sym = sym->next) if (f->symbol_cmp(sym->name, name) == 0) { int o_secidx = sym->secidx; int o_info = sym->info; int o_type = ELFW(ST_TYPE) (o_info); int o_binding = ELFW(ST_BIND) (o_info); /* A redefinition! Is it legal? */ if (secidx == SHN_UNDEF) return sym; else if (o_secidx == SHN_UNDEF) goto found; else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { /* Cope with local and global symbols of the same name in the same object file, as might have been created by ld -r. The only reason locals are now seen at this level at all is so that we can do semi-sensible things with parameters. */ struct obj_symbol *nsym, **p; nsym = arch_new_symbol(); nsym->next = sym->next; nsym->ksymidx = -1; /* Excise the old (local) symbol from the hash chain. */ for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) continue; *p = sym = nsym; goto found; } else if (n_binding == STB_LOCAL) { /* Another symbol of the same name has already been defined. Just add this to the local table. */ sym = arch_new_symbol(); sym->next = NULL; sym->ksymidx = -1; f->local_symtab[symidx] = sym; goto found; } else if (n_binding == STB_WEAK) return sym; else if (o_binding == STB_WEAK) goto found; /* Don't unify COMMON symbols with object types the programmer doesn't expect. */ else if (secidx == SHN_COMMON && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) return sym; else if (o_secidx == SHN_COMMON && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) goto found; else { /* 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", name); return sym; } } /* Completely new symbol. */ sym = arch_new_symbol(); sym->next = f->symtab[hash]; f->symtab[hash] = sym; sym->ksymidx = -1; 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; sym->value = value; sym->size = size; sym->secidx = secidx; sym->info = info; return sym;}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; for (sym = f->symtab[hash]; sym; sym = sym->next) if (f->symbol_cmp(sym->name, name) == 0) return sym; return NULL;}static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym){ if (sym) { if (sym->secidx >= SHN_LORESERVE) return sym->value; return sym->value + f->sections[sym->secidx]->header.sh_addr; } else { /* As a special case, a NULL sym has value zero. */ return 0; }}static struct obj_section *obj_find_section(struct obj_file *f, const char *name){ int i, n = f->header.e_shnum; for (i = 0; i < n; ++i) if (strcmp(f->sections[i]->name, name) == 0) return f->sections[i]; return NULL;}static int obj_load_order_prio(struct obj_section *a){ unsigned long af, ac; af = a->header.sh_flags; ac = 0; if (a->name[0] != '.' || strlen(a->name) != 10 || strcmp(a->name + 5, ".init")) ac |= 32; if (af & SHF_ALLOC) ac |= 16; if (!(af & SHF_WRITE)) ac |= 8; if (af & SHF_EXECINSTR) ac |= 4; if (a->header.sh_type != SHT_NOBITS) ac |= 2; return ac;}static voidobj_insert_section_load_order(struct obj_file *f, struct obj_section *sec){ struct obj_section **p; int prio = obj_load_order_prio(sec); for (p = f->load_order_search_start; *p; p = &(*p)->load_next) if (obj_load_order_prio(*p) < prio) break; sec->load_next = *p; *p = sec;}static struct obj_section *obj_create_alloced_section(struct obj_file *f, const char *name, unsigned long align, unsigned long size){ int newidx = f->header.e_shnum++; struct obj_section *sec; f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); f->sections[newidx] = sec = arch_new_section(); memset(sec, 0, sizeof(*sec)); sec->header.sh_type = SHT_PROGBITS; sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; sec->header.sh_size = size; sec->header.sh_addralign = align; sec->name = name; sec->idx = newidx; if (size) sec->contents = xmalloc(size); obj_insert_section_load_order(f, sec); return sec;}static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, const char *name, unsigned long align, unsigned long size){ int newidx = f->header.e_shnum++; struct obj_section *sec;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?