Getting The Size of a C++ Function

后端 未结 16 2139
醉酒成梦
醉酒成梦 2020-12-06 09:37

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 target

16条回答
  •  伪装坚强ぢ
    2020-12-06 10:03

    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:

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

提交回复
热议问题