Получение размера функции C ++ - PullRequest
22 голосов
/ 14 апреля 2011

Я читал этот вопрос, потому что я пытаюсь найти размер функции в программе на C ++. Намекнули, что может быть способ, который зависит от платформы. Моя целевая платформа - Windows

Метод, который у меня сейчас в голове, следующий:
1. Получить указатель на функцию
2. Увеличивайте указатель (и счетчик), пока я не достигну значения машинного кода для ret
3. Счетчик будет размером функции?

Edit1: Чтобы пояснить, что я имею в виду под «размером», я имею в виду количество байтов (машинный код), составляющих функцию.
Edit2: Было несколько комментариев, спрашивающих, почему или что я планирую делать с этим. Честный ответ: у меня нет намерений, и я не могу увидеть преимущества знания времени до компиляции длины функции. (хотя я уверен, что они есть)

Мне кажется, это правильный метод, сработает ли это?

Ответы [ 15 ]

1 голос
/ 14 апреля 2011

Что вы подразумеваете под "размером функции"?

Если вы имеете в виду указатель на функцию, то для 32-битных систем это всегда всего 4 байта.

Если вы имеете в виду размер кода, то вам просто нужно разобрать сгенерированный код и найти точку входа и ближайший вызов ret.Один из способов сделать это - прочитать регистр указателя инструкций в начале и в конце вашей функции.

Если вы хотите выяснить количество инструкций, вызываемых в среднем случае для вашей функции, вы можете использоватьпрофилировщики и делят количество выбывших инструкций на количество звонков.

0 голосов
/ 01 ноября 2018

Непереносимый, но основанный на API и правильно работающий подход заключается в использовании программ чтения программных баз данных - таких как dbghelp.dll в Windows или readelf в Linux. Их использование возможно только в том случае, если отладочная информация включена / присутствует вместе с программой. Вот пример того, как это работает в Windows:

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

Вы получите размер функции в символе. Размер , но вам также может понадобиться дополнительная логика, определяющая, является ли данный адрес на самом деле функцией, прокладкой, размещенной там инкрементным компоновщиком или DLL вызов thunk (тоже самое).

Я полагаю, что нечто подобное можно сделать с помощью readelf в Linux, но, возможно, вам придется создать библиотеку поверх ее исходного кода ...

Вы должны иметь в виду, что, хотя подход, основанный на дизассемблировании, возможен, вам, в основном, придется анализировать ориентированный граф с конечными точками в ret, halt, jmp (ДОКАЗАНО, что включено инкрементное связывание и вы можете читать jmp -table для определения того, является ли jmp, с которым вы сталкиваетесь в функции, внутренним по отношению к этой функции (отсутствует в jmp-таблице изображения) или внешним (присутствует в этой таблице; такие jmp часто встречаются как часть оптимизации хвостового вызова на x64, так как я знать)) любые вызовы, которые должны быть нерегламентированными (например, помощник, генерирующий исключение) и т. д.

0 голосов
/ 10 января 2018

ниже кода, чтобы получить точный размер функционального блока, он отлично работает с моим тестом runtime_checks отключает _RTC_CheckEsp в режиме отладки

    #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;
};
0 голосов
/ 08 января 2012

Использование GCC, совсем не сложно.

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));
0 голосов
/ 27 июля 2011

Просто установите PAGE_EXECUTE_READWRITE по адресу, по которому вы получили свою функцию. Затем прочитайте каждый байт. Когда вы получили байт "0xCC", это означает, что конец функции - фактический_адрес_адрес - 1.

...