获取C++函数的大小

Ada*_*dam 22 c++ windows code-size

我正在阅读这个问题,因为我试图在C++程序中找到一个函数的大小,暗示可能有一种特定于平台的方法.我的目标平台是windows

我目前掌握的方法如下:
1.获取指向函数
的指针2.递增指针(和计数器),直到达到3的机器代码值ret
.计数器将是函数的大小?

编辑1:澄清我的意思'大小'我的意思是组成函数的字节数(机器代码).
编辑2:有一些评论询问为什么或我打算用这个做什么.诚实的答案是我没有意图,我无法真正看到了解函数长度预编译时间的好处.(虽然我确定有一些)

这对我来说似乎是一种有效的方法,这会有用吗?

Rem*_*anu 13

可以获得函数的所有块,但是询问函数的"大小"是一个不自然的问题.优化的代码将按执行顺序重新排列代码块,并将很少使用的块(异常路径)移动到模块的外部部分.有关更多详细信息,请参阅配置文件引导优化,例如Visual C++如何在链接时代码生成中实现此目的.因此,一个函数可以从地址0x00001000开始,在0x00001100处跳转到0x20001000的跳转和一个ret,并且有一些异常处理代码0x20001000.在0x00001110,另一个函数启动.你的功能的"大小"是多少?它确实从0x00001000到+ 0x20001000,但它'拥有'在该范围内只有几个块.所以你的问题应该是没有问题的.

在此上下文中还有其他有效的问题,例如函数的指令总数(可以从程序符号数据库和图像中确定),更重要的是,内部频繁执行的代码路径中的指令数是多少功能.所有这些都是通常在绩效衡量的背景下提出的问题,并且有工具可以检测代码并提供非常详细的答案.

在内存中追逐指针并搜索ret将让你无处可去.现代代码比这更复杂.


Mic*_*sen 12

不,这不起作用:

  1. 无法保证您的函数只包含一条ret指令.
  2. 即使它只包含ret单个字节,您也不能只查看单个字节 - 因为相应的值可能只是一个值,而不是一条指令.

如果你将编码风格限制在你的函数中只有一个单一的返回点,那么第一个问题可能会解决,但另一个基本上需要一个反汇编程序,这样你就可以区分各个指令.

  • 即使您修改C/C++编码样式以使每个函数只有一个返回,也不能保证编译器/优化器发出的代码执行相同的汇编代码! (4认同)
  • 此外,没有任何内容表明函数的编译输出需要是连续的.特别是在优化时,编译器(和链接器)将遍布整个地方(在函数之前,可能在另一个函数的中间)放置代码块,以试图避免它认为是"热"路径的代码中的分支,将跳转目标放置在特定的对齐位置,或者合并相同的指令序列(或其他).关键在于还有一件事让这件事变得愚蠢. (3认同)
  • 根据迈克尔的意见,它根本不需要包含"ret"线.GCC有时会进行优化,它只是跳转到另一个包含`ret`的函数/块.我想如果只有异常退出它也可能没有返回. (3认同)
  • 如果程序中的其他地方,函数永远不会被内联,他会请求一个函数指针.虽然同意"这通常不可能/困难"的概念. (2认同)
  • 除了已经提出的所有重要论据之外,没有人提到过,在可变宽度指令集*(如x86)*中,如果不运行它,它甚至不可能可靠地反汇编代码**.例如,考虑组件`jmp Cont; db 01; Cont:...`也就是说,在`jmp`语句和下一个语句之间插入字节`0x01`.当您单步执行时,您无法知道`0x01`*不是*下一条指令的开始,因此在该点之后反汇编的所有内容都将是垃圾.这就是为x86编写反汇编程序如此困难的原因. (2认同)

小智 10

哇,我一直使用函数大小计数,它有很多很多用途.它可靠吗?没门.它是标准的c ++吗?没门.但这就是为什么每次发布新版本时都需要在反汇编程序中检查它以确保它有效.编译器标志可能会破坏排序.

static void funcIwantToCount()
{
   // do stuff
}
static void funcToDelimitMyOtherFunc()
{
   __asm _emit 0xCC
   __asm _emit 0xCC
   __asm _emit 0xCC
   __asm _emit 0xCC
}

int getlength( void *funcaddress )
{
   int length = 0;
   for(length = 0; *((UINT32 *)(&((unsigned char *)funcaddress)[length])) != 0xCCCCCCCC; ++length);
   return length;
}
Run Code Online (Sandbox Code Playgroud)

它似乎与静态函数更好地工作.全局优化可以杀死它.

PS我讨厌别人,问你为什么要这样做,这是不可能的等等.请不要再问这些问题了.让你听起来很愚蠢.程序员经常被要求做非标准的事情,因为新产品几乎总是突破了可用的极限.如果他们不这样做,那么您的产品可能是对已经完成的工作的重复.无聊!


Meh*_*dad 7

这不会起作用......如果有跳跃,假人ret,然后是跳跃的目标呢?你的代码会被愚弄.

通常,不可能以100%的准确率执行此操作,因为您必须预测所有代码路径,这就像解决暂停问题一样.如果你实现自己的反汇编程序,你可以获得"非常好"的准确性,但没有任何解决方案几乎像你想象的那样容易.

一个"技巧"是找出你正在寻找的函数之后的哪个函数的代码,假设某些(危险的)假设,这将给出相当好的结果.但是你必须知道在你的函数之后出现了什么函数,在优化之后很难弄清楚.


编辑1:

如果函数甚至不带到底是什么ret指令在所有?它很可能只是jmp回到它的调用者(尽管不太可能).


编辑2:

不要忘记x86至少有可变长度指令......


更新:

对于那些说流量分析与解决暂停问题不同的人:

考虑当您拥有以下代码时会发生什么:

foo:
    ....
    jmp foo
Run Code Online (Sandbox Code Playgroud)

每次都找出函数结束时跟着跳,你不能忽视它过去的第一时间,因为你不知道你是否正在处理自修改代码.(例如,您可以在C++代码中使用内联汇编来修改自身.)它可以很好地扩展到其他内存位置,因此您的分析器将(或应该)以无限循环结束,除非您容忍漏报.

这不是停滞问题吗?