linux内核符号表

内核镜像的虚拟地址

不管内核被加载到什么物理地址 ,在虚拟地址转物理地址函数里面,都会根据实际的offset来转换

__virt_to_phys

1.通过判断最高有效位如果为1,则表示是(memory)DRAM的地址;直接虚拟地址偏移 + 物理内存起始地址

2.如果为0,则表示是kernel image的地址;直接虚拟地址 - (内核镜像起始虚拟地址 - 内核镜像起始物理地址);也即内核的虚拟地址偏移 + 内核镜像的物理内存起始地址

#define __virt_to_phys(x) ({						\
phys_addr_t __x = (phys_addr_t)(x);				\
__x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET :	\
                (__x - kimage_voffset); })

符号表概念

符号表是记录了Linux内核中的符号列表以及对应符号在内存中的虚拟地址,符号其实就是Linux内核镜像中的变量和函数名称

静态和动态符号表

内核在编译过程中生成的System.map与proc/kallsyms的区别在于System.map是在编译阶段生成的内核符号表,我们可以称为静态Linux内核符号表,而proc/kallsyms方式看到的是在内核启动后生成的动态符号表。

符号表用来做什么

1.自己编写的内核模块中EXPORT_SYMBOL函数,其他的内核模块也可以通过extern声明后,能找到对应函数的地址,并进行调用

2.内核panic时,往往都会打印出调用栈,这个调用栈会打印一系列地址,通过使用符号表,会将这些地址转换为函数名

3.同样dump_stack也是通过符号表的查询,打印的对应函数名。

4.根据名称查到对应地址(内核中相关API),进行hook函数,实现更高级的debug功能,kprobe hook函数时就是利用符号表进行查询的对应地址。

模块的符号地址空间

通过adb shell cat proc/kallsyms > sys.txt导出动态符号表,可以看到编译时产生的静态符号,和加载模块产生的动态符号;

对于ARM构架的设备,模块挂载后,模块中包含的函数和静态变量的虚拟地址不在3G(0xC0000000)以上,而是3G以下一点的位置,可能以0xBF000000开始

......
c063df58 T setup_zone_pageset

c063df78 T init_currently_empty_zone

c063dfcc T init_per_zone_wmark_min

c063e024 T zone_pcp_update

c063e048 T _einittext

bfe63000 t $t	[mfp]

bfe63000 t fastpath_debug_store	[mfp]
......

insmod模块会调用sys_init_module

SYSCALL_DEFINE3(init_module, void __user *, umod,
		unsigned long, len, const char __user *, uargs)
{
	int err;
	struct load_info info = { };

	err = may_init_module();
	if (err)
		return err;

	pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
	       umod, len, uargs);

	err = copy_module_from_user(umod, len, &info);
	if (err)
		return err;

	return load_module(&info, uargs, 0);
}

load_module会调用module_alloc来分配虚拟地址给模块镜像,而且这个虚拟地址的范围就应该在:  MODULES_VADDR----MODULES_END

void *module_alloc(unsigned long size)
{
	gfp_t gfp_mask = GFP_KERNEL;
	void *p;

	/* Silence the initial allocation */
	if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS))
		gfp_mask |= __GFP_NOWARN;

	p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
				gfp_mask, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
				__builtin_return_address(0));
	if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p)
		return p;
	return __vmalloc_node_range(size, 1,  VMALLOC_START, VMALLOC_END,
				GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
				__builtin_return_address(0));
}

在/arch/arm/include/asm/memory.h;所以arm架构,如果是1/3的内核和用户空间的分配的话 ;模块的符号地址空间(MODULES_VADDR,MODULES_END)= (0xBF000000,0xC0000000)

#ifndef CONFIG_THUMB2_KERNEL
#define MODULES_VADDR		(PAGE_OFFSET - SZ_16M)
#else
/* smaller range for Thumb-2 symbols relocation (2^24)*/
#define MODULES_VADDR		(PAGE_OFFSET - SZ_8M)
#endif

#if TASK_SIZE > MODULES_VADDR
#error Top of user space clashes with start of module space
#endif

/*
 * The highmem pkmap virtual space shares the end of the module area.
 */
#ifdef CONFIG_HIGHMEM
#define MODULES_END		(PAGE_OFFSET - PMD_SIZE)
#else
#define MODULES_END		(PAGE_OFFSET)
#endif

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值