行业知识
Linux 内核获取函数size
2026-11-04 21:44:09
来源:互联网转载
方式一:通过objdump -t直接从目标文件中获取函数size
#objdump -t file_unread.o | grep hook0000000000000030 l F .text 000000000000012f hook_vfs_read
0000000000000030 l F .text 000000000000012f hook_vfs_read各个字段说明
()- 0000000000000030:符号的地址或值,这里是一个相对地址,表示该符号在.text节中的偏移量。
- l:符号的绑定属性,这里是小写字母l,表示该符号是一个局部符号,只在当前目标文件中可见。
- F:符号所在的节(section)的类型,这里是大写字母F,表示该符号所在的节是一个函数节(function section)。
- .text:符号所在的节的名称,这里是.text,表示该符号所在的节是代码节。
- 000000000000012f:符号的大小,以字节为单位,这里是0x12f,表示该函数的大小为303字节。
- hook_vfs_read:符号的名称,这里是hook_vfs_read,表示该符号是一个名为hook_vfs_read的函数。
vfs_read+0xe6/0x2c0 表示什么意思呢?
其中vfs_read 是函数名,+0xe6/0x2c0 是函数在代码中的偏移量。具体来说,+0xe6 表示函数内部代码的偏移量,/ 后面的 0x2c0 表示函数的总大小(以字节为单位)。
()hook_vfs_read+0xe4/0x130 [fi_file]为动态打印进程调用栈信息。
方式二:通过objdump -D反汇编后计算函数size
用objdump对目标文件进行反汇编,从汇编代码中计算hook_vfs_read的函数size
0000000000000030 : 30: e8 00 00 00 00 callq 35 35: 41 57 push %r15 37: 41 56 push %r14 39: 31 c0 xor %eax,%eax ...... 14f: eb c3 jmp 114 151: 48 c7 c7 00 00 00 00 mov
-t, --syms Display the contents of the symbol table(s)-D, --disassemble-all Display assembler contents of all sections
x0,%rdi 158: e8 00 00 00 00 callq 15d 15d: eb a3 jmp 102 15f: 90 nophook_vfs_read_size = 0x15f - 0x30 = 0x12f + 1,从计算的结果来看,加上偏移与调用栈打印的函数size是一致的。
方式三:通过内核函数动态获取函数size
/** * sprint_symbol - Look up a kernel symbol and return it in a text buffer * @buffer: buffer to be stored * @address: address to lookup * * This function looks up a kernel symbol with @address and stores its name, * offset, size and module name to @buffer if possible. If no symbol was found, * just saves its @address as is. * * This function returns the number of bytes stored in @buffer. */int sprint_symbol(char *buffer, unsigned long address){ return __sprint_symbol(buffer, address, 0, 1);}EXPORT_SYMBOL_GPL(sprint_symbol);#include static int __init my_init(void){ const char *str = "hook_vfs_read+0x0/0x130 [fi_file]"; const char *prefix = "/0x"; const char *suffix = " ["; char *start, *end; unsigned long value; // 查找前缀字符串 start = strstr(str, prefix); if (!start) { printk(KERN_ERR "Failed to find prefix string\n"); return -EINVAL; } start += strlen(prefix); // 查找后缀字符串 end = strstr(start, suffix); if (!end) { printk(KERN_ERR "Failed to find suffix string\n"); return -EINVAL; } // 截取字符串 *end = '/* * Lookup an address * - modname is set to NULL if it's in the kernel. * - We guarantee that the returned name is valid until we reschedule even if. * It resides in a module. * - We also guarantee that modname will be valid until rescheduled. */const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, unsigned long *offset, char **modname, char *namebuf){const char *ret;namebuf[KSYM_NAME_LEN - 1] = 0;namebuf[0] = 0;if (is_ksym_addr(addr)) {unsigned long pos;pos = get_symbol_pos(addr, symbolsize, offset);/* Grab name */kallsyms_expand_symbol(get_symbol_offset(pos), namebuf, KSYM_NAME_LEN);if (modname)*modname = NULL;return namebuf;}/* See if it's in a module or a BPF JITed image. */ret = module_address_lookup(addr, symbolsize, offset, modname, namebuf);if (!ret)ret = bpf_address_lookup(addr, symbolsize, offset, modname, namebuf);if (!ret)ret = ftrace_mod_address_lookup(addr, symbolsize,offset, modname, namebuf);return ret;}'; value = simple_strtoul(start, NULL, 16); printk(KERN_INFO "Value: 0x%lx\n", value); return 0;}路径1:
获取到的字符串信息示例为hook_vfs_read+0x0/0x130 [fi_file],这种方式需要从数组str中解析出函数大小0x130
解析字符串中的函数size,还是要骚操作获取,在内核中没有看到直接获取函数size的函数。
路径二:
内核代码v4.18.20中sprint_symbol最终调用kallsyms_lookup获取函数size,因此也可以直接调用该函数获取函数size,免去上述复杂的字符串解析过程。