2013-07-25 55 views
3

我正在尝试获取内核函数的边界(例如系统调用)。现在,如果我理解正确,我可以通过阅读/proc/kallsymsSystem.map得到感兴趣的函数的起始地址,但我不知道如何获得此函数的结束地址。在运行时获取Linux内核函数的结束地址

正如您所知,/proc/kallsyms允许我们查看Linux内核的符号表,因此我们可以看到所有导出符号的起始地址。我们可以使用下一个函数的起始地址来计算前一个函数的结束地址吗?如果我们不能这样做,你能否以另一种方式给我建议?

+0

为什么你需要知道函数的“结束地址”? –

+1

我需要知道它,因为我想在运行时执行“函数内联”。之后,我可以构建控制流图,其中包含感兴趣的功能的基本块及其所有被调用者。 – user2571676

回答

1

通常,可执行文件仅存储函数的起始地址,因为它只是调用该函数所需的全部内容。你将不得不推断最终地址,而不是简单地查看它。

您可以尝试查找后续函数的起始地址,但这并不总是有效。想象一下以下内容:

void func_a() { 
    // do something 
} 

static void helper_function() { 
    // do something else 
} 

void func_b() { 
    // ... 
    helper_function(); 
    // ... 
} 

你可以得到的func_afunc_b,但helper_function地址不会出现,因为没有什么需要链接到它。如果您试图使用func_b作为func_a的末尾(假设编译代码中的顺序等价于源代码中的顺序,但不能保证),那么最终会意外地包含您不需要的代码包括 - 并且在将其他函数内联到func_b时可能找不到需要查找的代码。

那么,我们如何找到这些信息呢?那么,如果你仔细想想 - 确实存在的信息 - func_a中的所有路径最终都会终止(在循环中,返回语句,尾部调用等),可能在helper_function开始之前。

您需要解析出func_a的代码并构建其中所有可能代码路径的映射。当然,无论如何你都需要这样做,以将其他功能嵌入其中 - 所以不应该太难以简单地不关心该函数的结束地址。

最后一个注意事项:在这个例子中,如果找到helper_function以便知道将它内联,将会遇到问题,因为符号不会显示在kallsyms中。这里的解决方案是,您可以跟踪单个函数中的call指令,以确定您不知道的其他隐藏函数。

TL; DR:您只能通过解析编译后的代码来找到结束地址。无论如何你必须解析这个,所以只需要做一次。

相关问题