如何以字节为单位获取函数的长度?

Tho*_*son 18 c

我想在运行时知道C函数的长度(由我编写).任何获得它的方法?似乎sizeof在这里不起作用.

Clo*_*cks 19

有一种方法可以确定函数的大小.命令是:

 nm -S <object_file_name>
Run Code Online (Sandbox Code Playgroud)

这将返回目标文件中每个函数的大小.使用'man nm'查阅GNU中的手册页以收集更多相关信息.

  • `nm -S --size-sort -td &lt;objfile&gt; | grep &lt;pattern&gt;` 显示名称中包含 `pattern` 的符号的大小,以 10 为基数(`-td` 代表*十进制*),按大小排序。很酷。 (2认同)

Jam*_*lis 14

标准C中无法获得函数占用的内存量.


Faz*_*ton 14

如果使用自定义链接描述文件,则可以从链接器获取此信息.仅为给定函数添加链接器部分,并在任一侧添加链接器符号:

mysec_start = .;
*(.mysection)
mysec_end = .;
Run Code Online (Sandbox Code Playgroud)

然后,您可以专门将该功能分配给该部分.符号之间的差异是函数的长度:

#include <stdio.h>

int i;

 __attribute__((noinline, section(".mysection"))) void test_func (void)
{
    i++;
}

int main (void)
{
    extern unsigned char mysec_start[];
    extern unsigned char mysec_end[];

    printf ("Func len: %lu\n", mysec_end - mysec_start);
    test_func ();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此示例适用于GCC,但任何C工具链都应该有一种方法来指定要为其分配函数的部分.我会根据汇编列表检查结果,以验证它是否按照您希望的方式工作.

  • 您可以在没有自定义链接器脚本的情况下通过使用有效的 C 标识符名称调用该部分来完成此操作,例如用“mysection”代替“.mysection”,并使用“__start_mysection”和“__stop_mysection”代替“mysec_start”和“mysec_end” . 链接器会自动为遇到的每个部分定义这些符号。 (3认同)

Vov*_*ium 5

可执行文件(至少是那些去除了调试信息的)不以任何方式存储函数长度。所以不可能在运行时自己解析这些信息。如果您必须使用函数进行操作,您应该在链接阶段对您的对象做一些事情,或者通过从您的可执行文件中访问它们作为文件。例如,您可以告诉链接器将符号表作为普通数据段链接到可执行文件中,为其分配一些名称,并在程序运行时进行解析。但请记住,这将特定于您的链接器和对象格式。

另请注意,该功能布局也是特定于平台的,并且有些事情使术语“功能长度”不清楚:

  1. 函数可能在函数代码之后直接将使用过的常量存储在代码段中,并使用 PC 相对寻址来访问它们(ARM 编译器会这样做)。
  2. 函数可能有“prologs”和“epilogs”,它们可能是几个函数共有的,因此位于主体之外。
  3. 功能码可以内联其他功能码

它们都可以计算或不计算函数长度。

函数也可能被编译器完全内联,所以它失去了它的主体。


小智 5

函数的开头是函数指针,你已经知道了。

问题是要找到终点,但这可以通过以下方式完成:

#include <time.h>

int foo(void)
{
   int i = 0;
   ++i + time(0); // time(0) is to prevent optimizer from just doing: return 1;
   return i;
}

int main(int argc, char *argv[])
{
   return (int)((long)main - (long)foo);
}
Run Code Online (Sandbox Code Playgroud)

它在这里工作是因为程序只有两个函数,所以如果代码被重新排序(主要在 foo 之前实现)那么你将得到一个不相关的(负)计算,让你知道它不能以这种方式工作,但它会工作如果您将 foo() 代码移动到 main() 中 - 只需减去初始否定回复得到的 main() 大小。

如果结果是肯定的,那么它就是正确的——如果没有进行填充(是的,一些编译器很乐意膨胀代码,无论是为了对齐还是其他不太明显的原因)。

结尾的 (int)(long) 类型转换是为了 32 位和 64 位代码之间的可移植性(函数指针在 64 位平台上会更长)。

这是可移植性失败的,应该可以很好地工作。


小智 5

我刚刚为完全相同的问题想出了一个解决方案,但我编写的代码取决于平台。

背后的想法是,将已知的操作码放在函数的末尾并从头开始搜索它们,同时计算我们跳过的字节数。这是我用一些代码解释的中等链接 https://medium.com/@gurhanpolat/calculate-c-function-size-x64-x86-c1f49921aa1a


aca*_*ola 5

一个完全解决的解决方案,没有链接器或肮脏的平台相关技巧:

#include <stdio.h>

int i;

 __attribute__((noinline, section("mysec"))) void test_func (void)
{
    i++;
}

int main (void)
{
    extern char __start_mysec[];
    extern char __stop_mysec[];

    printf ("Func len: %lu\n", __stop_mysec - __start_mysec);
    test_func ();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这就是当您阅读FazJaxton 的答案jakobbotsch 的评论时得到的结果