获取C+的大小+;作用 我正在阅读问题,因为我试图在C++程序中找到一个函数的大小,它暗示了可能有一种特定于平台的方法。我的目标平台是windows
目前我脑海中的方法如下:获取C+的大小+;作用 我正在阅读问题,因为我试图在C++程序中找到一个函数的大小,它暗示了可能有一种特定于平台的方法。我的目标平台是windows,c++,windows,code-size,C++,Windows,Code Size,目前我脑海中的方法如下: 1.获取指向函数的指针 2.递增指针(&计数器),直到达到ret 3.计数器将是函数的大小 Edit1:为了澄清我所说的“大小”是指组成函数的字节数(机器代码)。 Edit2:有一些评论问我为什么要这样做,或者我打算怎么做。诚实的回答是我没有任何意图,我也看不到知道函数长度预编译时间的好处。(虽然我肯定有一些) 对我来说,这似乎是一种有效的方法,这种方法行得通吗?这种方法行不通。。。如果有一个跳转,一个虚拟的ret,然后是跳转的目标呢?你的代码将被愚弄 一般来说,不可能
1.获取指向函数的指针
2.递增指针(&计数器),直到达到
ret
3.计数器将是函数的大小 Edit1:为了澄清我所说的“大小”是指组成函数的字节数(机器代码)。
Edit2:有一些评论问我为什么要这样做,或者我打算怎么做。诚实的回答是我没有任何意图,我也看不到知道函数长度预编译时间的好处。(虽然我肯定有一些)
对我来说,这似乎是一种有效的方法,这种方法行得通吗?这种方法行不通。。。如果有一个跳转,一个虚拟的
ret
,然后是跳转的目标呢?你的代码将被愚弄
一般来说,不可能以100%的准确率做到这一点,因为您必须预测所有代码路径,这就像解决问题一样。如果您实现自己的反汇编程序,您可以获得“相当好”的精度,但没有任何解决方案会像您想象的那么简单
一个“诀窍”是找出哪个函数的代码在您正在寻找的函数之后,这将在假设某些(危险的)假设的情况下给出相当好的结果。但是你必须知道在你的函数之后是什么函数,在优化之后,这是很难弄清楚的
编辑1: 如果函数根本没有以
ret
指令结束,该怎么办?它完全可以jmp
返回给它的调用者(尽管这不太可能)
编辑2: 别忘了x86至少有可变长度的指令
更新: 对于那些认为流量分析与解决停车问题不同的人: 考虑一下当您有如下代码时会发生什么:
foo:
....
jmp foo
您必须每次都跟随跳转来计算函数的结尾,并且您不能在第一次跳转后忽略它,因为您不知道是否正在处理自修改代码。(例如,您可以在C++代码中使用内联程序集来修改自身)。它可以很好地扩展到其他内存的地方,因此,除非您容忍错误的否定,否则分析器将(或应该)以无限循环结束。
这不是像停顿问题吗?你说的“函数的大小”是什么意思
如果您指的是函数指针,那么对于32位系统,它总是只有4个字节
如果您指的是代码的大小,那么您应该反汇编生成的代码并找到入口点和最近的ret
调用。一种方法是在函数开始和结束时读取指令指针寄存器
如果你想找出函数的平均情况下调用的指令数,可以使用分析器,并将调用的指令数除以调用数。
C++中,没有函数大小的概念。除了上面提到的所有内容之外,预处理器宏也会产生不确定的大小。如果你想计算指令字的数目,你不能在C++中这样做,因为它在编译之前就不存在了。< /P> < P>不,这将不起作用:
ret
指令ret
,也不能只查看单个字节,因为相应的值可能只是一个值,而不是一条指令第一个问题可以解决,如果你限制你的编码风格,比如说,在你的函数中只有一个单一的返回点,但是另一个基本上需要一个反汇编程序,这样你就可以区分各个指令。解决这个问题的真正办法是深入研究编译器的文档。我们使用的ARM编译器可以生成一个程序集转储(code.dis),从中减去给定的函数标签和下一个函数标签之间的偏移量是非常简单的 但是,我不确定在windows目标中需要哪些工具。看起来答案中列出的工具可能就是您正在寻找的工具 还请注意,我(在嵌入式空间中工作)假设您正在谈论编译后分析。作为构建的一部分,仍然可以以编程方式检查这些中间文件,前提是:
- 目标函数位于不同的对象中
- 构建系统已经学习了依赖关系
- 您肯定知道编译器将构建这些对象文件
请注意,我不完全确定您为什么想知道这些信息。在过去,我需要它来确保我可以将特定的代码块放在内存中非常特定的位置。我不得不承认,我很好奇这对更通用的桌面操作系统目标有什么作用。我认为它可以在用msvc创建的windows程序上运行,至于分支,“ret”似乎总是在最后出现(即使有分支返回得早,它也会在最后出现)。 但是,您需要某种反汇编程序库来计算当前的操作码长度,因为它们对于x86来说是可变长度的。如果你不这样做,你会遇到误报
如果有这样的情况,我不会感到惊讶。可以获得函数的所有块,但是问函数的“大小”是一个不自然的问题。优化的代码将按照执行顺序重新排列代码块,并将很少使用的块(异常路径)移动到模块的外部部分。更多
#pragma runtime_checks("", off)
static DWORD WINAPI InjectionProc(LPVOID lpvParameter)
{
// do something
return 0;
}
static DWORD WINAPI InjectionProcEnd()
{
return 0;
}
#pragma runtime_checks("", on)
size_t cbInjectionProc = (size_t)InjectionProcEnd - (size_t)InjectionProc;
void do_something(void) {
printf("%s!", "Hello your name is Cemetech");
do_something_END:
}
...
printf("size of function do_something: %i", (int)(&&do_something_END - (int)do_something));
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;
}
#pragma runtime_checks("", off)
DWORD __stdcall loadDll(char* pDllFullPath)
{
OutputDebugStringA(pDllFullPath);
//OutputDebugStringA("loadDll...................\r\n");
return 0;
//return test(pDllFullPath);
}
#pragma runtime_checks("", restore)
DWORD __stdcall getFuncSize_loadDll()
{
DWORD maxSize=(PBYTE)getFuncSize_loadDll-(PBYTE)loadDll;
PBYTE pTail=(PBYTE)getFuncSize_loadDll-1;
while(*pTail != 0xC2 && *pTail != 0xC3) --pTail;
if (*pTail==0xC2)
{ //0xC3 : ret
//0xC2 04 00 : ret 4
pTail +=3;
}
return pTail-(PBYTE)loadDll;
};
FARPROC pfn = (FARPROC)some_function_with_possibility_to_get_its_size_at_runtime;
//You will have to call this when your app initializes and then
//cache the size somewhere in the global variable because it will not
//change after the executable image is built.
size_t fn_size; //Will receive function size in bytes, or 0 if error
some_function_with_possibility_to_get_its_size_at_runtime(&fn_size);
#include <Windows.h>
//The function itself has to be defined for two types of a call:
// 1) when you call it just to get its size, and
// 2) for its normal operation
bool some_function_with_possibility_to_get_its_size_at_runtime(size_t* p_getSizeOnly = NULL)
{
//This input parameter will define what we want to do:
if(!p_getSizeOnly)
{
//Do this function's normal work
//...
return true;
}
else
{
//Get this function size
//INFO: Works only in 64-bit builds on Windows!
size_t nFnSz = 0;
//One of the reasons why we have to do this at run-time is
//so that we can get the address of a byte inside
//the function body... we'll get it as this thread context:
CONTEXT context = {0};
RtlCaptureContext(&context);
DWORD64 ImgBase = 0;
RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(context.Rip, &ImgBase, NULL);
if(pRTFn)
{
nFnSz = pRTFn->EndAddress - pRTFn->BeginAddress;
}
*p_getSizeOnly = nFnSz;
return false;
}
}
SYMBOL_INFO symbol = { };
symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
// Implies, that the module is loaded into _dbg_session_handle, see ::SymInitialize & ::SymLoadModule64
::SymFromAddr(_dbg_session_handle, address, 0, &symbol);