我正在尝试获取内核函数的边界(例如系统调用)。现在,如果我理解正确,我可以通过阅读/proc/kallsyms
或System.map
来获取感兴趣的函数的起始地址,但我不知道如何获取此函数的结束地址。
如您所知,/proc/kallsyms
允许我们查看Linux内核的符号表,以便我们可以看到所有导出符号的起始地址。我们可以使用下一个函数的起始地址来计算前一个函数的结束地址吗?如果我们不能这样做,你能建议我另外一种方式吗?
答案 0 :(得分:1)
通常,可执行文件仅存储函数的起始地址,因为只需调用该函数即可。您必须推断结束地址,而不是简单地查找它。
您可以尝试查找后续函数的起始地址,但这并不总是有效。想象一下:
void func_a() {
// do something
}
static void helper_function() {
// do something else
}
void func_b() {
// ...
helper_function();
// ...
}
您可以获得func_a
和func_b
的地址,但helper_function
不会显示,因为没有必要链接到它。如果您尝试使用func_b
作为func_a
的结尾(假设编译代码中的顺序等同于源代码中的顺序,这是无法保证的),您最终会意外地包括您不需要包含的代码 - 并且在将其他函数内联到func_b
时可能找不到您需要找到的代码。
那么,我们如何找到这些信息呢?好吧,如果你考虑一下 - 信息确实存在 - func_a
中的所有路径最终将终止(在循环,返回语句,尾调用等),可能在{ {1}}开始。
您需要解析helper_function
的代码并构建其中所有可能代码路径的映射。当然,无论如何你都需要这样做才能将其他函数内联到其中 - 所以简单地不关心函数的结束地址就不会太难了。
最后一点说明:在此示例中,您无法找到func_a
以便知道内联它,因为该符号不会显示在helper_function
中。这里的解决方案是,您可以跟踪各个函数中的kallsyms
指令,以确定存在哪些您不了解的隐藏函数。
TL; DR:您只能通过解析编译的代码来找到结束地址。无论如何你必须解析它,所以只需要做一次。