如何在C程序中找到函数的结束地址?

5

如何找到函数的结束地址?函数的起始地址可以从函数名中获取。

我在面试中被问及:考虑到我编写的函数f()已经跨越了文本部分并开始重写相邻的部分(数据部分)。如何处理这种情况?他还补充说,我应该通过C代码来处理它,而不是查看符号映射文件并获取地址。


没有标准的方法。您可以尝试获取文件中下一个函数的地址,然后进行减法运算 - 但是无法保证它会起作用。例如,链接器可能会将函数按字母顺序排序,因此可能会为其他函数留出空间,或者可能会给出负大小。 - Jerry Coffin
2
你必须指定架构和ABI,否则你将得不到有用的答案。 - Per Johansson
我在面试中被问到了这个问题。我怀疑你误解了问题,他们其实是在问如何判断是否意外执行数据。答案是“数据执行保护”,也称为硬件特性,用于标记内存不可执行。 - Ben
由于代码生成和链接的方式,函数无法“跨越文本段”,函数代码(因此其结束地址)始终位于文本段中。您可以通过遵循错误指针或者编译器出错并生成不正确的汇编代码而跳出文本段,导致无法正确返回或堆栈中返回地址的损坏,但这与函数的结束地址无关。此外,如果编译器决定这样做,函数可以被内联 - 那么结束地址是什么? - Hristo Iliev
4个回答

7

使用GCC编译器,您可以使用&&运算符(是的-不是&)获取标签的地址。
这可以按如下方式使用:

void f(void) {
    printf("Start %p End %p\n", f, &&f_end);
    f_end: return;
}

这样做不能完全得到最终结果,因为标签后面还有某些结尾代码,但我认为这对于面试回答已经足够了。

2

C标准并不保证函数有一个确定的结束地址。

在实践中,函数不一定是一个连续的内存块,可能会重叠或者被代码优化器分散到多个内存块中。

因此,在运行时无法找到函数的结束地址。

此外,无法保证通过GetProcAddress获取的“起始地址”或者通过函数指针获取的地址与代码实际所在的位置有任何关系。

函数指针只保证如果你通过该地址调用函数,函数将被执行。它并不保证代码实际驻留在那里。它可能只是一个thunk的地址,例如。


1

你不能使用语言本身,C语言不为函数暴露“大小”的概念。

你可以尝试检查程序的二进制文件,并解析符号表等内容。


你有什么库可以推荐帮助解析符号表吗?奇怪的是我找不到一个"读取elf库",只找到了一个命令行工具。 - Manuel Selva

0
你的编译器可能可以生成一个汇编清单文件,而链接器可能可以生成一个映射文件。这些文件可以让你手动查看特定函数的长度。不确定是否需要在C程序内部确定大小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接