2010-11-11 2 views
12

Я хочу знать длину функции C (написанную мной) во время выполнения. Любой способ получить его? Кажется, sizeof здесь не работает.Как получить длину функции в байтах?

+2

Уточнитните «длина функции C» ** точно ** – pmg

+0

Я имею в виду память, занимаемую кодом этой функции. – Thomson

+1

Если вы спрашиваете об этом по той же причине, о которой я много лет назад задавался вопросом, позвольте мне указать на [Написание нового джита] (http://stackoverflow.com/questions/4097301/writing-a-new-jit) –

ответ

13

В стандартном C нет способа получить объем памяти, занимаемый функцией.

0

Нет стандартного способа сделать это либо на C, либо на C++. Естественно, существуют варианты реализации/платформы для doiung it, но я не знаю ни одного

3

В частности. Codewarrior, вы можете помещать метки вокруг функции, например.

label1: 
void someFunc() 
{ 
    /* code goes here. */ 
} 
label2: 

, а затем рассчитать размер как (int)(label2-label1), но это, очевидно, очень компилятор зависит. В зависимости от вашей системы и компилятора вам, возможно, придется взломать сценарии компоновщика и т. Д.

+0

Не знал этого. Веселая. Вроде. – haylem

+2

Существует аналогичное [расширение GCC] (http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Labels-as-Values.html#Labels-as-Values), используя его, вы бы умеет вычислять размер как '&& label2 - && label1' – Hasturkun

+0

Я надеюсь, что это сработает, но похоже, что он не может работать на Visual C++ (язык C). – Thomson

4

Исполняемые файлы (по крайней мере, те, которые содержат информацию об отладке) не сохраняют функциональные длины каким-либо образом. Таким образом, нет возможности анализировать эту информацию во время выполнения самостоятельно. Если вам нужно манипулировать функциями, вы должны что-то сделать с вашими объектами в фазе ссылок или путем доступа к ним в виде файлов из вашего исполняемого файла. Например, вы можете сообщить компоновщику, чтобы связать таблицы символов как раздел обычных данных с исполняемым файлом, назначить им какое-то имя и проанализировать, когда программа запускается. Но помните, что это было бы специфично для вашего компоновщика и формата объекта.

Также обратите внимание, что расположение функции также от платформы, и есть некоторые вещи, которые делают термин «длину функции» неясную:

  1. Функции может иметь хранилище используется константы в секциях коды непосредственно после кода функции и доступа они используют PC-относительную адресацию (это делают компиляторы ARM).
  2. Функции могут иметь «прологи» и «эпилоги», которые могут быть общими для нескольких функций и, таким образом, лежат вне основного тела.
  3. Код функции может встраивать другой функции кода

Все они могут рассчитывать или не рассчитывать длину функции.

Также функция может быть полностью встроена компилятором, поэтому она освобождает свое тело.

+0

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

1

В языке C не существует объекта, который бы определял длину функции; существует слишком много переменных (компилятор, целевой набор команд, файл объекта/исполняемый формат файла, параметры оптимизации, настройки отладки и т. д.). Тот же исходный код может привести к функциям разного размера для разных систем.

C просто не предоставляет каких-либо возможностей отражения для поддержки такого рода информации (хотя отдельные компиляторы могут предоставлять расширения, такие как пример Codewarrior, цитируемый sskuce). Если вам нужно знать, сколько байтов занимает ваша память в памяти, вам нужно будет напрямую изучить сгенерированный объект или исполняемый файл.

sizeof func не будет работать, потому что выражение func рассматривается как указатель на функцию, поэтому вы получаете размер значения указателя, а не самой функции.

+0

В соответствующем компиляторе 'sizeof func' не работает, потому что указатель функции не является допустимым операндом оператора' sizeof'. – caf

+0

@caf: * facepalm * Да, вы правы. Я знал это. В самом деле. –

+0

@JohnBode, пока вы правы, что эта информация не переносима; компилятор по-прежнему хорошо осведомлен обо всех этих факторах во время компиляции, и результат имеет смысл для этой конкретной платформы. Знание размера функции имеет смысл на этой платформе, потому что она позволяет вам memcpy shell-код функций «только для чтения», который имеет очень интересные и последовательные последствия, которые мы не можем изучать, не имея такой возможности. – Dmitry

3

Начало функции - указатель функции, вы уже знаете это.

Проблема заключается в том, чтобы найти конец, но это может быть сделано таким образом:

#include <time.h> 

int foo(void) 
{ 
    int i = 0; 
    ++i + time(0); // time(0) is to prevent optimizer from just doing: return 1; 
    return i; 
} 

int main(int argc, char *argv[]) 
{ 
    return (int)((long)main - (long)foo); 
} 

Он работает здесь, потому что программа имеет только две функции, так что если код повторно упорядоченная (главный реализован до обува), то вы получите нерелевантный (отрицательный) расчет, сообщив, что он не работает таким образом, но что это будет работать, если вы переместите код foo() в main() - просто вычтите основной() размер, который вы получили начальный отрицательный ответ.

Если результат положительный, то он будет правильным - если никакие дополнения не выполняются (да, некоторые компиляторы с радостью раздувают код, либо для выравнивания, либо для других, менее очевидных причин).

Окончание (int) (long) cast предназначено для переносимости между 32-битным и 64-битным кодом (указатели функций будут длиннее на 64-битной платформе).

Это неудобно переносное устройство и должно работать достаточно хорошо.

12

Существует способ определения размера функции. Команда:

nm -S <object_file_name> 

Это вернет размеры каждой функции внутри объектного файла. Обратитесь к страницам руководства в GNU с помощью man man, чтобы собрать дополнительную информацию об этом.

+0

или objdump, FWIW. – sehe

+0

'nm -S --size-sort -t d | grep 'отображает размер в базе 10 (' -t d' для * decimal *) символов, содержащих 'pattern' в их имени, отсортированные по размеру. Довольно круто. – hdl

12

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

mysec_start = .; 
*(.mysection) 
mysec_end = .; 

Затем вы можете конкретно назначить функцию этого раздела. Разница между символами длина функции:

#include <stdio.h> 

int i; 

__attribute__((noinline, section(".mysection"))) void test_func (void) 
{ 
    i++; 
} 

int main (void) 
{ 
    extern unsigned char mysec_start[]; 
    extern unsigned char mysec_end[]; 

    printf ("Func len: %lu\n", mysec_end - mysec_start); 
    test_func(); 

    return 0; 
} 

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

+0

Вы можете сделать это без специального скрипта компоновщика, вызвав раздел с помощью допустимого имени идентификатора C, например 'mysection' вместо' .mysection', и используя '__start_mysection' и' __stop_mysection' вместо 'mysec_start' и' mysec_end '. Компилятор автоматически определяет эти символы для каждого обнаруженного раздела. – Janiels

-3

Вы можете найти длину вашей функции C, вычитая адреса функций. Позволь мне привести вам пример

int function1() 
    { 
    } 

int function2() 
{ 
    int a,b; //just defining some variable for increasing the memory size 
    printf("This function would take more memory than earlier function i.e function01 "); 
} 

int main() 
{ 
    printf("Printing the address of function01 %p\n",function01); 
    printf("Printing the address of function02 %p\n",function02); 
    printf("Printing the address of main %p\n",main); 
    return 0; 
} 

Надеется, что вы получите ответ на свой вопрос после компиляции. После компиляции вы сможете увидеть разницу в размере функции01 и функции2.

Примечание: Обычно между одной функцией и другой функцией существует 16 бит.

+0

ваш пример ничего не доказывает :) вы просто печатаете адреса функций! –

1

Просто вычтите адрес своей функции с адреса следующей функции. Но обратите внимание, что не может работать в вашей системе, так что используйте его только если вы 100% уверены:

#include <stdint.h> 

int function() { 
    return 0; 
} 

int function_end() { 
    return 0; 
} 

int main(void) { 
    intptr_t size = (intptr_t) function_end - (intptr_t) function; 
} 
Смежные вопросы