📄 insmod.c
字号:
*loc += got - dot + rel->r_addend;;#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:#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 */ if (!isym->gotent.reloc_done) { isym->gotent.reloc_done = 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; /* address relative to the got */#if !defined(__mc68000__)#if defined(__sh__) case R_SH_GOTOFF:#elif defined(__arm__) 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)); ret = obj_reloc_unhandled; break; } return ret;}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;#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; 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)]; 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: case R_ARM_PLT32: pltneeded = 1; break; case R_ARM_GOTPC: case R_ARM_GOTOFF: gotneeded = 1; if (got_offset == 0) got_offset = 4;#elif defined(__sh__) case R_SH_GOTPC: case R_SH_GOTOFF: gotneeded = 1;#elif defined(__i386__) case R_386_GOTPC: case R_386_GOTOFF: gotneeded = 1;#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 (!intsym->gotent.offset_done) { intsym->gotent.offset_done = 1; intsym->gotent.offset = got_offset; got_offset += BB_GOT_ENTRY_SIZE; }#endif#if defined(BB_USE_PLT_ENTRIES) if (pltneeded && intsym->pltent.allocated == 0) { intsym->pltent.allocated = 1; intsym->pltent.offset = plt_offset; plt_offset += BB_PLT_ENTRY_SIZE; intsym->pltent.inited = 0; pltneeded = 0; }#endif } }#if defined(BB_USE_GOT_ENTRIES) if (got_offset) { struct obj_section* myrelsec = obj_find_section(f, ".got"); if (myrelsec) { obj_extend_section(myrelsec, got_offset); } else { myrelsec = obj_create_alloced_section(f, ".got", BB_GOT_ENTRY_SIZE, got_offset); assert(myrelsec); } ifile->got = myrelsec; }#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#endif return 1;}static int arch_init_module(struct obj_file *f, struct new_module *mod){ return 1;}/*======================================================================*//* 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; 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); sec->load_next = f->load_order; f->load_order = sec; if (f->load_order_search_start == &f->load_order) f->load_order_search_start = &sec->load_next; return sec;}static void *obj_extend_section(struct obj_section *sec, unsigned long more){ unsigned long oldsize = sec->header.sh_size; 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. */static intadd_symbols_from( struct obj_file *f, int idx, struct new_module_symbol *syms, size_t nsyms){ struct new_module_symbol *s; size_t i; int used = 0; for (i = 0, s = syms; i < nsyms; ++i, ++s) { /* Only add symbols that are already marked external. If we override locals we may cause problems for argument initialization. We will also create a false dependency on the module. */ struct obj_symbol *sym; sym = obj_find_symbol(f, (char *) s->name); if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { sym = obj_add_symbol(f, (char *) s->name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), idx, s->value, 0); /* Did our symbol just get installed? If so, mark the module as "used". */ if (sym->secidx == idx) used = 1; } } return used;}static void add_kernel_symbols(struct obj_file *f)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -