2012-07-10 17 views
7

Supongamos que tengo una función como la siguiente:¿Cómo obtener el tamaño de una función C desde dentro de un programa C o con un ensamblaje en línea?

# cat 003.c 

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

y compilar esta manera:

gcc -S 003.c 

El obtiene el siguiente resultado montaje:

 .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?*/ 

La última línea a Bove obtiene el tamaño de la función. ¿Dónde almacena el compilador el tamaño? ¿Puedo obtener el tamaño de la función de alguna manera en mi programa C de origen usando C o asm en línea?

+0

Desafortunadamente '__builtin_object_size' no funciona (al menos con gcc 4.7) –

Respuesta

13

La información acerca de un tamaño función se almacena en la ELF Atributos para el símbolo correspondiente (nombre). El código de ejemplo C cómo analizar esto programáticamente se encuentra en la parte inferior de la página de manual de Solaris para gelf_getsym(3ELF) (libelf existe en Linux, * BSD y MacOS también, debe buscar el campo st_size de la estructura GElf_Sym), pero también puede utilizar objdump/elfdump (Solaris)/readelf (Linux) para la tarea:

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

foo3.o:  file format elf64-x86-64 

Sections: 
Idx Name   Size  VMA    LMA    File off Algn 
    0 .text   00000012 0000000000000000 0000000000000000 00000040 2**2 
        CONTENTS, ALLOC, LOAD, READONLY, CODE 
[ ... ] 
Disassembly of section .text: 

0000000000000000 <foo>: 
    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: c9      leaveq 
    11: c3      retq

se trata de una compilación sin optimizar de su código, mientras que la versión optimizada es:

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

foo3.o:  file format elf64-x86-64 

Sections: 
Idx Name   Size  VMA    LMA    File off Algn 
    0 .text   00000004 0000000000000000 0000000000000000 00000040 2**4 
        CONTENTS, ALLOC, LOAD, READONLY, CODE 
[ ... ] 
Disassembly of section .text: 

0000000000000000 <foo>: 
    0: 8d 04 37    lea (%rdi,%rsi,1),%eax 
    3: c3      retq

Nota el "Tamaño "cambio de 0x12 a 4? Eso es lo que proviene de la directiva de ensamblador .size.

El "truco" de tratar de usar el ensamblaje en línea para proporcionar tamaños de función/código no es el código de cola generado por el compilador (entrada de funciones, epílogos, generación de código en línea, ...), ni para el compilador que reordena el montaje en línea (es notorio que gcc lo hace), por lo que generalmente no es una gran idea confiar en esto. Al final, depende de qué es exactamente lo que estamos tratando de hacer ...

Editar: Unas cuantas referencias, externo, así como en StackOverflow:

  1. A partir de la lista de correo de gcc, thread on sizeof(function)
  2. what does sizeof (function name) return?
  3. Find size of a function in C
  4. LibELF by example proyecto en Sourceforge (se trata de la documentación/un tutorial)
+0

No entiendo: el resultado de objdump que cita muestra el tamaño de la sección de texto, no las funciones individuales. 'readelf -s' muestra el atributo' st_size' de los símbolos que mencionas. –

1

¿Por qué no tomar la diferencia del puntero de la función y la dirección actual al final de la función? Echar un vistazo a esta pregunta para recuperar la dirección IP actual: Get address of current instruction for x86, puede ser el código, stolen form one of the reply:

unsigned long get_PC() 
{ 
    unsigned long current_instruction; 

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

    return current_instruction; 
} 

que hacer el truco,

+2

Eso va a ser muy frágil, mucho menos portátil. –

+0

no estoy de acuerdo acerca de lo frágil en el sentido de la idea, tal vez la forma en que utiliza para recuperar la dirección, AFAIK gcc debe tener alguna forma integrada para obtener esto, pero no recuerdo el nombre. –

+0

Si cambia las opciones de optimización o algún código, puede obtener resultados muy diferentes de la realidad. –

Cuestiones relacionadas