⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 module.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	mod->arch.core_plt->sh_type = SHT_NOBITS;	mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;	mod->arch.core_plt->sh_addralign = 16;	mod->arch.core_plt->sh_size = core_plts * sizeof(struct plt_entry);	mod->arch.init_plt->sh_type = SHT_NOBITS;	mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;	mod->arch.init_plt->sh_addralign = 16;	mod->arch.init_plt->sh_size = init_plts * sizeof(struct plt_entry);	mod->arch.got->sh_type = SHT_NOBITS;	mod->arch.got->sh_flags = ARCH_SHF_SMALL | SHF_ALLOC;	mod->arch.got->sh_addralign = 8;	mod->arch.got->sh_size = gots * sizeof(struct got_entry);	mod->arch.opd->sh_type = SHT_NOBITS;	mod->arch.opd->sh_flags = SHF_ALLOC;	mod->arch.opd->sh_addralign = 8;	mod->arch.opd->sh_size = fdescs * sizeof(struct fdesc);	DEBUGP("%s: core.plt=%lx, init.plt=%lx, got=%lx, fdesc=%lx\n",	       __FUNCTION__, mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size,	       mod->arch.got->sh_size, mod->arch.opd->sh_size);	return 0;}static inline intin_init (const struct module *mod, uint64_t addr){	return addr - (uint64_t) mod->module_init < mod->init_size;}static inline intin_core (const struct module *mod, uint64_t addr){	return addr - (uint64_t) mod->module_core < mod->core_size;}static inline intis_internal (const struct module *mod, uint64_t value){	return in_init(mod, value) || in_core(mod, value);}/* * Get gp-relative offset for the linkage-table entry of VALUE. */static uint64_tget_ltoff (struct module *mod, uint64_t value, int *okp){	struct got_entry *got, *e;	if (!*okp)		return 0;	got = (void *) mod->arch.got->sh_addr;	for (e = got; e < got + mod->arch.next_got_entry; ++e)		if (e->val == value)			goto found;	/* Not enough GOT entries? */	if (e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size))		BUG();	e->val = value;	++mod->arch.next_got_entry;  found:	return (uint64_t) e - mod->arch.gp;}static inline intgp_addressable (struct module *mod, uint64_t value){	return value - mod->arch.gp + MAX_LTOFF/2 < MAX_LTOFF;}/* Get PC-relative PLT entry for this value.  Returns 0 on failure. */static uint64_tget_plt (struct module *mod, const struct insn *insn, uint64_t value, int *okp){	struct plt_entry *plt, *plt_end;	uint64_t target_ip, target_gp;	if (!*okp)		return 0;	if (in_init(mod, (uint64_t) insn)) {		plt = (void *) mod->arch.init_plt->sh_addr;		plt_end = (void *) plt + mod->arch.init_plt->sh_size;	} else {		plt = (void *) mod->arch.core_plt->sh_addr;		plt_end = (void *) plt + mod->arch.core_plt->sh_size;	}	/* "value" is a pointer to a function-descriptor; fetch the target ip/gp from it: */	target_ip = ((uint64_t *) value)[0];	target_gp = ((uint64_t *) value)[1];	/* Look for existing PLT entry. */	while (plt->bundle[0][0]) {		if (plt_target(plt) == target_ip)			goto found;		if (++plt >= plt_end)			BUG();	}	*plt = ia64_plt_template;	if (!patch_plt(mod, plt, target_ip, target_gp)) {		*okp = 0;		return 0;	}#if ARCH_MODULE_DEBUG	if (plt_target(plt) != target_ip) {		printk("%s: mistargeted PLT: wanted %lx, got %lx\n",		       __FUNCTION__, target_ip, plt_target(plt));		*okp = 0;		return 0;	}#endif  found:	return (uint64_t) plt;}/* Get function descriptor for VALUE. */static uint64_tget_fdesc (struct module *mod, uint64_t value, int *okp){	struct fdesc *fdesc = (void *) mod->arch.opd->sh_addr;	if (!*okp)		return 0;	if (!value) {		printk(KERN_ERR "%s: fdesc for zero requested!\n", mod->name);		return 0;	}	if (!is_internal(mod, value))		/*		 * If it's not a module-local entry-point, "value" already points to a		 * function-descriptor.		 */		return value;	/* Look for existing function descriptor. */	while (fdesc->ip) {		if (fdesc->ip == value)			return (uint64_t)fdesc;		if ((uint64_t) ++fdesc >= mod->arch.opd->sh_addr + mod->arch.opd->sh_size)			BUG();	}	/* Create new one */	fdesc->ip = value;	fdesc->gp = mod->arch.gp;	return (uint64_t) fdesc;}static inline intdo_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,	  Elf64_Shdr *sec, void *location){	enum reloc_target_format format = (r_type >> FORMAT_SHIFT) & FORMAT_MASK;	enum reloc_value_formula formula = (r_type >> VALUE_SHIFT) & VALUE_MASK;	uint64_t val;	int ok = 1;	val = sym->st_value + addend;	switch (formula) {	      case RV_SEGREL:	/* segment base is arbitrarily chosen to be 0 for kernel modules */	      case RV_DIRECT:		break;	      case RV_GPREL:	  val -= mod->arch.gp; break;	      case RV_LTREL:	  val = get_ltoff(mod, val, &ok); break;	      case RV_PLTREL:	  val = get_plt(mod, location, val, &ok); break;	      case RV_FPTR:	  val = get_fdesc(mod, val, &ok); break;	      case RV_SECREL:	  val -= sec->sh_addr; break;	      case RV_LTREL_FPTR: val = get_ltoff(mod, get_fdesc(mod, val, &ok), &ok); break;	      case RV_PCREL:		switch (r_type) {		      case R_IA64_PCREL21B:			if ((in_init(mod, val) && in_core(mod, (uint64_t)location)) ||			    (in_core(mod, val) && in_init(mod, (uint64_t)location))) {				/*				 * Init section may have been allocated far away from core,				 * if the branch won't reach, then allocate a plt for it.				 */				uint64_t delta = ((int64_t)val - (int64_t)location) / 16;				if (delta + (1 << 20) >= (1 << 21)) {					val = get_fdesc(mod, val, &ok);					val = get_plt(mod, location, val, &ok);				}			} else if (!is_internal(mod, val))				val = get_plt(mod, location, val, &ok);			/* FALL THROUGH */		      default:			val -= bundle(location);			break;		      case R_IA64_PCREL32MSB:		      case R_IA64_PCREL32LSB:		      case R_IA64_PCREL64MSB:		      case R_IA64_PCREL64LSB:			val -= (uint64_t) location;			break;		}		switch (r_type) {		      case R_IA64_PCREL60B: format = RF_INSN60; break;		      case R_IA64_PCREL21B: format = RF_INSN21B; break;		      case R_IA64_PCREL21M: format = RF_INSN21M; break;		      case R_IA64_PCREL21F: format = RF_INSN21F; break;		      default: break;		}		break;	      case RV_BDREL:		val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core);		break;	      case RV_LTV:		/* can link-time value relocs happen here?  */		BUG();		break;	      case RV_PCREL2:		if (r_type == R_IA64_PCREL21BI) {			if (!is_internal(mod, val)) {				printk(KERN_ERR "%s: %s reloc against non-local symbol (%lx)\n",				       __FUNCTION__, reloc_name[r_type], val);				return -ENOEXEC;			}			format = RF_INSN21B;		}		val -= bundle(location);		break;	      case RV_SPECIAL:		switch (r_type) {		      case R_IA64_IPLTMSB:		      case R_IA64_IPLTLSB:			val = get_fdesc(mod, get_plt(mod, location, val, &ok), &ok);			format = RF_64LSB;			if (r_type == R_IA64_IPLTMSB)				format = RF_64MSB;			break;		      case R_IA64_SUB:			val = addend - sym->st_value;			format = RF_INSN64;			break;		      case R_IA64_LTOFF22X:			if (gp_addressable(mod, val))				val -= mod->arch.gp;			else				val = get_ltoff(mod, val, &ok);			format = RF_INSN22;			break;		      case R_IA64_LDXMOV:			if (gp_addressable(mod, val)) {				/* turn "ld8" into "mov": */				DEBUGP("%s: patching ld8 at %p to mov\n", __FUNCTION__, location);				ia64_patch((u64) location, 0x1fff80fe000UL, 0x10000000000UL);			}			return 0;		      default:			if (reloc_name[r_type])				printk(KERN_ERR "%s: special reloc %s not supported",				       mod->name, reloc_name[r_type]);			else				printk(KERN_ERR "%s: unknown special reloc %x\n",				       mod->name, r_type);			return -ENOEXEC;		}		break;	      case RV_TPREL:	      case RV_LTREL_TPREL:	      case RV_DTPMOD:	      case RV_LTREL_DTPMOD:	      case RV_DTPREL:	      case RV_LTREL_DTPREL:		printk(KERN_ERR "%s: %s reloc not supported\n",		       mod->name, reloc_name[r_type] ? reloc_name[r_type] : "?");		return -ENOEXEC;	      default:		printk(KERN_ERR "%s: unknown reloc %x\n", mod->name, r_type);		return -ENOEXEC;	}	if (!ok)		return -ENOEXEC;	DEBUGP("%s: [%p]<-%016lx = %s(%lx)\n", __FUNCTION__, location, val,	       reloc_name[r_type] ? reloc_name[r_type] : "?", sym->st_value + addend);	switch (format) {	      case RF_INSN21B:	ok = apply_imm21b(mod, location, (int64_t) val / 16); break;	      case RF_INSN22:	ok = apply_imm22(mod, location, val); break;	      case RF_INSN64:	ok = apply_imm64(mod, location, val); break;	      case RF_INSN60:	ok = apply_imm60(mod, location, (int64_t) val / 16); break;	      case RF_32LSB:	put_unaligned(val, (uint32_t *) location); break;	      case RF_64LSB:	put_unaligned(val, (uint64_t *) location); break;	      case RF_32MSB:	/* ia64 Linux is little-endian... */	      case RF_64MSB:	/* ia64 Linux is little-endian... */	      case RF_INSN14:	/* must be within-module, i.e., resolved by "ld -r" */	      case RF_INSN21M:	/* must be within-module, i.e., resolved by "ld -r" */	      case RF_INSN21F:	/* must be within-module, i.e., resolved by "ld -r" */		printk(KERN_ERR "%s: format %u needed by %s reloc is not supported\n",		       mod->name, format, reloc_name[r_type] ? reloc_name[r_type] : "?");		return -ENOEXEC;	      default:		printk(KERN_ERR "%s: relocation %s resulted in unknown format %u\n",		       mod->name, reloc_name[r_type] ? reloc_name[r_type] : "?", format);		return -ENOEXEC;	}	return ok ? 0 : -ENOEXEC;}intapply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,		    unsigned int relsec, struct module *mod){	unsigned int i, n = sechdrs[relsec].sh_size / sizeof(Elf64_Rela);	Elf64_Rela *rela = (void *) sechdrs[relsec].sh_addr;	Elf64_Shdr *target_sec;	int ret;	DEBUGP("%s: applying section %u (%u relocs) to %u\n", __FUNCTION__,	       relsec, n, sechdrs[relsec].sh_info);	target_sec = sechdrs + sechdrs[relsec].sh_info;	if (target_sec->sh_entsize == ~0UL)		/*		 * If target section wasn't allocated, we don't need to relocate it.		 * Happens, e.g., for debug sections.		 */		return 0;	if (!mod->arch.gp) {		/*		 * XXX Should have an arch-hook for running this after final section		 *     addresses have been selected...		 */		uint64_t gp;		if (mod->core_size > MAX_LTOFF)			/*			 * This takes advantage of fact that SHF_ARCH_SMALL gets allocated			 * at the end of the module.			 */			gp = mod->core_size - MAX_LTOFF / 2;		else			gp = mod->core_size / 2;		gp = (uint64_t) mod->module_core + ((gp + 7) & -8);		mod->arch.gp = gp;		DEBUGP("%s: placing gp at 0x%lx\n", __FUNCTION__, gp);	}	for (i = 0; i < n; i++) {		ret = do_reloc(mod, ELF64_R_TYPE(rela[i].r_info),			       ((Elf64_Sym *) sechdrs[symindex].sh_addr				+ ELF64_R_SYM(rela[i].r_info)),			       rela[i].r_addend, target_sec,			       (void *) target_sec->sh_addr + rela[i].r_offset);		if (ret < 0)			return ret;	}	return 0;}intapply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,		unsigned int relsec, struct module *mod){	printk(KERN_ERR "module %s: REL relocs in section %u unsupported\n", mod->name, relsec);	return -ENOEXEC;}/* * Modules contain a single unwind table which covers both the core and the init text * sections but since the two are not contiguous, we need to split this table up such that * we can register (and unregister) each "segment" seperately.  Fortunately, this sounds * more complicated than it really is. */static voidregister_unwind_table (struct module *mod){	struct unw_table_entry *start = (void *) mod->arch.unwind->sh_addr;	struct unw_table_entry *end = start + mod->arch.unwind->sh_size / sizeof (*start);	struct unw_table_entry tmp, *e1, *e2, *core, *init;	unsigned long num_init = 0, num_core = 0;	/* First, count how many init and core unwind-table entries there are.  */	for (e1 = start; e1 < end; ++e1)		if (in_init(mod, e1->start_offset))			++num_init;		else			++num_core;	/*	 * Second, sort the table such that all unwind-table entries for the init and core	 * text sections are nicely separated.  We do this with a stupid bubble sort	 * (unwind tables don't get ridiculously huge).	 */	for (e1 = start; e1 < end; ++e1) {		for (e2 = e1 + 1; e2 < end; ++e2) {			if (e2->start_offset < e1->start_offset) {				tmp = *e1;				*e1 = *e2;				*e2 = tmp;			}		}	}	/*	 * Third, locate the init and core segments in the unwind table:	 */	if (in_init(mod, start->start_offset)) {		init = start;		core = start + num_init;	} else {		core = start;		init = start + num_core;	}	DEBUGP("%s: name=%s, gp=%lx, num_init=%lu, num_core=%lu\n", __FUNCTION__,	       mod->name, mod->arch.gp, num_init, num_core);	/*	 * Fourth, register both tables (if not empty).	 */	if (num_core > 0) {		mod->arch.core_unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,								core, core + num_core);		DEBUGP("%s:  core: handle=%p [%p-%p)\n", __FUNCTION__,		       mod->arch.core_unw_table, core, core + num_core);	}	if (num_init > 0) {		mod->arch.init_unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,								init, init + num_init);		DEBUGP("%s:  init: handle=%p [%p-%p)\n", __FUNCTION__,		       mod->arch.init_unw_table, init, init + num_init);	}}intmodule_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod){	DEBUGP("%s: init: entry=%p\n", __FUNCTION__, mod->init);	if (mod->arch.unwind)		register_unwind_table(mod);	return 0;}voidmodule_arch_cleanup (struct module *mod){	if (mod->arch.init_unw_table)		unw_remove_unwind_table(mod->arch.init_unw_table);	if (mod->arch.core_unw_table)		unw_remove_unwind_table(mod->arch.core_unw_table);}#ifdef CONFIG_SMPvoidpercpu_modcopy (void *pcpudst, const void *src, unsigned long size){	unsigned int i;	for_each_cpu(i) {		memcpy(pcpudst + __per_cpu_offset[i], src, size);	}}#endif /* CONFIG_SMP */

⌨️ 快捷键说明

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