Getting The Size of a C++ Function

2019-01-15 12:32发布

I was reading this question because I'm trying to find the size of a function in a C++ program, It is hinted at that there may be a way that is platform specific. My targeted platform is windows

The method I currently have in my head is the following:
1. Obtain a pointer to the function
2. Increment the Pointer (& counter) until I reach the machine code value for ret
3. The counter will be the size of the function?

Edit1: To clarify what I mean by 'size' I mean the number of bytes (machine code) that make up the function.
Edit2: There have been a few comments asking why or what do I plan to do with this. The honest answer is I have no intention, and I can't really see the benefits of knowing a functions length pre-compile time. (although I'm sure there are some)

This seems like a valid method to me, will this work?

15条回答
该账号已被封号
2楼-- · 2019-01-15 12:56

In C++, the there is no notion of function size. In addition to everything else mentioned, preprocessor macros also make for an indeterminate size. If you want to count number of instruction words, you can't do that in C++, because it doesn't exist until it's been compiled.

查看更多
The star\"
3楼-- · 2019-01-15 12:58

There is no facilities in Standard C++ to obtain the size or length of a function.
See my answer here: Is it possible to load a function into some allocated memory and run it from there?

In general, knowing the size of a function is used in embedded systems when copying executable code from a read-only source (or a slow memory device, such as a serial Flash) into RAM. Desktop and other operating systems load functions into memory using other techniques, such as dynamic or shared libraries.

查看更多
何必那么认真
4楼-- · 2019-01-15 12:58

I'm posting this to say two things:

1) Most of the answers given here are really bad and will break easily. If you use the C function pointer (using the function name), in a debug build of your executable, and possibly in other circumstances, it may point to a JMP shim that will not have the function body itself. Here's an example. If I do the following for the function I defined below:

FARPROC pfn = (FARPROC)some_function_with_possibility_to_get_its_size_at_runtime;

the pfn I get (for example: 0x7FF724241893) will point to this, which is just a JMP instruction:

enter image description here

Additionally, a compiler can nest several of those shims, or branch your function code so that it will have multiple epilogs, or ret instructions. Heck, it may not even use a ret instruction. Then, there's no guarantee that functions themselves will be compiled and linked in the order you define them in the source code.

You can do all that stuff in assembly language, but not in C or C++.

2) So that above was the bad news. The good news is that the answer to the original question is, yes, there's a way (or a hack) to get the exact function size, but it comes with the following limitations:

  • It works in 64-bit executables on Windows only.

  • It is obviously Microsoft specific and is not portable.

  • You have to do this at run-time.

The concept is simple -- utilize the way SEH is implemented in x64 Windows binaries. Compiler adds details of each function into the PE32+ header (into the IMAGE_DIRECTORY_ENTRY_EXCEPTION directory of the optional header) that you can use to obtain the exact function size. (In case you're wondering, this information is used for catching, handling and unwinding of exceptions in the __try/__except/__finally blocks.)

Here's a quick example:

//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);

and then:

#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;
    }
}
查看更多
登录 后发表回答