Я публикую это, чтобы сказать две вещи:
1) Большинство ответов, приведенных здесь, действительно плохи и легко сломаются .Если вы используете указатель на функцию C (используя имя функции), в debug
сборке вашего исполняемого файла и, возможно, в других обстоятельствах, он может указывать на JMP
shim , который не будет иметьфункционировать само тело.Вот пример.Если я сделаю следующее для функции, которую я определил ниже:
FARPROC pfn = (FARPROC)some_function_with_possibility_to_get_its_size_at_runtime;
pfn
, которое я получу (например: 0x7FF724241893
), укажет на это, что является просто JMP
инструкцией:
Кроме того, компилятор может вкладывать несколько таких оболочек или ветвить код вашей функции, чтобы иметь несколько эпилогов ,или ret
инструкции.Черт возьми, он может даже не использовать ret
инструкцию.Тогда нет никакой гарантии, что сами функции будут скомпилированы и скомпонованы в том порядке, в котором вы определяете их в исходном коде.
Все это можно делать на языке Assembly , но не на языке Cили C ++.
2) Так что выше были плохие новости.Хорошей новостью является то, что ответ на первоначальный вопрос: да, есть способ (или хак ), чтобы получить точный размер функции, но он имеет следующие ограничения:
Работает в 64-битных исполняемых файлах только в Windows.
Это, очевидно, специфично для Microsoft и не переносимо.
Вы должны сделать это во время выполнения.
Концепция проста - использовать способ SEH в x64 Windowsдвоичные файлы.Компилятор добавляет сведения о каждой функции в заголовок PE32 + (в каталог IMAGE_DIRECTORY_ENTRY_EXCEPTION
необязательного заголовка), который можно использовать для получения точного размера функции.(Если вам интересно, эта информация используется для перехвата, обработки и раскручивания исключений в блоках __try/__except/__finally
.)
Вот краткий пример:
//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;
}
}