📄 insmod.c
字号:
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 (__v850e__) case R_V850_NONE: break; case R_V850_32: /* We write two shorts instead of a long because even 32-bit insns only need half-word alignment, but 32-bit data needs to be long-word aligned. */ v += ((unsigned short *)loc)[0]; v += ((unsigned short *)loc)[1] << 16; ((unsigned short *)loc)[0] = v & 0xffff; ((unsigned short *)loc)[1] = (v >> 16) & 0xffff; break; case R_V850_22_PCREL: goto bb_use_plt;#endif#if defined(CONFIG_USE_PLT_ENTRIES) bb_use_plt: /* find the plt entry and initialize it if necessary */ assert(isym != NULL);#if defined(CONFIG_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 */#endif#if defined (__v850e__) /* We have to trash a register, so we assume that any control transfer more than 21-bits away must be a function call (so we can use a call-clobbered register). */ ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */ ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */#endif pe->inited = 1; } /* relative distance to target */ v -= dot; /* if the target is too far away.... */#if defined (__arm__) || defined (__powerpc__) if ((int)v < -0x02000000 || (int)v >= 0x02000000) #elif defined (__v850e__) if ((Elf32_Sword)v > 0x1fffff || (Elf32_Sword)v < (Elf32_Sword)-0x200000)#endif /* go via the plt */ v = plt + pe->offset - dot;#if defined (__v850e__) if (v & 1)#else if (v & 3)#endif 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#if defined (__v850e__) /* We write two shorts instead of a long because even 32-bit insns only need half-word alignment, but the 32-bit data write needs to be long-word aligned. */ ((unsigned short *)loc)[0] = (*(unsigned short *)loc & 0xffc0) /* opcode + reg */ | ((v >> 16) & 0x3f); /* offs high part */ ((unsigned short *)loc)[1] = (v & 0xffff); /* offs low part */#endif break;#endif /* CONFIG_USE_PLT_ENTRIES */#if defined(CONFIG_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 /* CONFIG_USE_GOT_ENTRIES */ } return ret;}#if defined(CONFIG_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(CONFIG_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(CONFIG_USE_GOT_ENTRIES) || defined(CONFIG_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(CONFIG_USE_GOT_ENTRIES) || defined(CONFIG_USE_PLT_ENTRIES) struct arch_file *ifile = (struct arch_file *) f; int i;#if defined(CONFIG_USE_GOT_ENTRIES) int got_offset = 0, got_needed = 0, got_allocate;#endif#if defined(CONFIG_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(CONFIG_USE_GOT_ENTRIES) got_allocate = 0;#endif#if defined(CONFIG_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;#elif defined (__v850e__) case R_V850_22_PCREL: plt_needed = 1; break;#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(CONFIG_USE_GOT_ENTRIES) if (got_allocate) { got_offset += arch_single_init( rel, &intsym->gotent, got_offset, CONFIG_GOT_ENTRY_SIZE); got_needed = 1; }#endif#if defined(CONFIG_USE_PLT_ENTRIES) if (plt_allocate) {#if defined(CONFIG_USE_PLT_LIST) plt_offset += arch_list_add( rel, &intsym->pltent, plt_offset, CONFIG_PLT_ENTRY_SIZE);#else plt_offset += arch_single_init( rel, &intsym->pltent, plt_offset, CONFIG_PLT_ENTRY_SIZE);#endif plt_needed = 1; }#endif } }#if defined(CONFIG_USE_GOT_ENTRIES) if (got_needed) { ifile->got = arch_xsect_init(f, ".got", got_offset, CONFIG_GOT_ENTRY_SIZE); }#endif#if defined(CONFIG_USE_PLT_ENTRIES) if (plt_needed) { ifile->plt = arch_xsect_init(f, ".plt", plt_offset, CONFIG_PLT_ENTRY_SIZE); }#endif#endif /* defined(CONFIG_USE_GOT_ENTRIES) || defined(CONFIG_USE_PLT_ENTRIES) */}#ifdef CONFIG_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 CONFIG_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 /* CONFIG_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){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -