Как получить размер функции 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:
- Из списка рассылки gcc нить на
sizeof(function)
- что возвращает sizeof (имя функции)?
- Найти размер функции в C
- 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;
}
сделал бы трюк,