Как получить размер функции C изнутри программы на C или встроенной сборки?

Предположим, у меня есть функция, как показано ниже:

# cat 003.c

int foo(int a, int b)
{
    return a+b;
}

И скомпилируйте это так:

gcc -S 003.c

Получает следующий результат сборки:

     .file   "003.c"
     .text
 .globl foo
     .type   foo, @function
 foo:
 .LFB2:
     pushq   %rbp
 .LCFI0:
     movq    %rsp, %rbp
 .LCFI1:
     movl    %edi, -4(%rbp)
     movl    %esi, -8(%rbp)
     movl    -8(%rbp), %edx
     movl    -4(%rbp), %eax
     addl    %edx, %eax
     leave
     ret
 .LFE2:
     .size   foo, .-foo /* size of the function foo, how to get it?*/

Последняя строка выше получит размер функции. Где компилятор хранит размер? Могу ли я получить размер функции каким-либо образом в моей исходной C-программе, используя C или встроенный asm?

2 ответа

Решение

Информация о размере функции хранится в атрибутах ELF для соответствующего символа (имени). Пример кода C, позволяющий проанализировать это программно, находится внизу страницы руководства Solaris для gelf_getsym(3ELF) (libelf также существует в Linux, *BSD и MacOS, вам нужно искать st_size поле GElf_Sym структура), но вы также можете использовать objdump / elfdump (Solaris) / readelf (Linux) для выполнения задачи:

 $ objdump -h -d --section =.text foo3.o

foo3.o: формат файла elf64-x86-64

Разделы:
Idx Имя Размер VMA               LMA Файл выключен Algn
  0 . Текст 00000012  0000000000000000  0000000000000000  00000040  2**2
                  СОДЕРЖАНИЕ, ALLOC, ЗАГРУЗИТЬ, ЧИТАТЬ, КОД
[ ... ]
Разборка раздела.text:

0000000000000000 :
   0: 55 push% rbp
   1: 48 89 e5 mov% rsp,% rbp
   4: 89 7d fc mov% edi, 0xfffffffffffffffc (% rbp)
   7: 89 75 f8 mov% esi, 0xfffffffffffffff8 (% rbp)
   a: 8b 45 f8 mov 0xfffffffffffffff8 (% rbp),% eax
   d: 03 45 fc add 0xfffffffffffffffc (% rbp),% eax
  10: с9 оставь
  11:   c3                      retq 

Это для неоптимизированной компиляции вашего кода, в то время как оптимизированная версия:

 $ objdump -h -d --section =.text foo3.o

foo3.o: формат файла elf64-x86-64

Разделы:
Idx Имя Размер VMA               LMA Файл выключен Algn
  0 . Текст 00000004  0000000000000000  0000000000000000  00000040  2**4
                  СОДЕРЖАНИЕ, ALLOC, ЗАГРУЗИТЬ, ЧИТАТЬ, КОД
[ ... ]
Разборка раздела.text:

0000000000000000 :
   0: 8d 04 37 Леа (% RDI,% RSI,1),% Eax
   3: c3 retq 

Обратите внимание на изменение размера 0x12 в 4? Вот что исходит от .size Директива ассемблера.

"Хитрость" в попытке использовать встроенную сборку, чтобы дать вам размеры функций / места для кода, не учитывает сгенерированный компилятором связующий код (прологи ввода функций / выходные эпилоги, генерация встроенного кода,...), а также повторные компиляторы. -при заказе встроенной сборки (gcc печально известен этим), поэтому доверять этому, как правило, не очень хорошая идея. В конце концов, это зависит от того, что именно вы пытаетесь сделать...

Изменить: еще несколько ссылок, как внешних, так и на stackru:

  1. Из списка рассылки gcc нить на sizeof(function)
  2. что возвращает sizeof (имя функции)?
  3. Найти размер функции в C
  4. LibELF на примере проекта sourceforge (это документация / учебное пособие)

Почему бы не взять разницу указателя функции и текущего адреса в конце функции? Посмотрите на этот вопрос, чтобы восстановить текущий IP-адрес: Получить адрес текущей инструкции для x86, может быть этот код, украденный из одного ответа:

unsigned long get_PC()
{
    unsigned long current_instruction;

    __asm__ __volatile__
    (
        "movq 8(%rbp), %rax\n\t"
        : "=a" (current_instruction)
    );

    return current_instruction;
}

сделал бы трюк,

Другие вопросы по тегам