Comment obtenir la taille d’une fonction C depuis un programme C ou avec un assemblage en ligne?

Supposons que j’ai une fonction comme ci-dessous:

# cat 003.c int foo(int a, int b) { return a+b; } 

Et comstackz-le comme ceci:

 gcc -S 003.c 

Obtient le résultat d’assemblage suivant:

  .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 dernière ligne ci-dessus donne la taille de la fonction. Où le compilateur stocke-t-il la taille? Puis-je obtenir la taille de la fonction d’une manière ou d’une autre dans mon programme d’origine C en utilisant C ou inline asm ?

Les informations sur la taille d’une fonction sont stockées dans les atsortingbuts ELF pour le symbole (nom) correspondant. C exemple de code comment parsingr cela par programme se trouve au bas de la page de gelf_getsym(3ELF) Solaris pour gelf_getsym(3ELF) (libelf existe également sous Linux, * BSD et MacOS, vous devez également rechercher le champ st_size de la structure GElf_Sym ), mais vous pouvez également utiliser objdump / elfdump (Solaris) / readelf (Linux) pour la tâche suivante:

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

 foo3.o: format de fichier elf64-x86-64

 Sections:
 Nom Idx Taille VMA LMA Fichier sur Algn
   0 .text 00000012 0000000000000000 0000000000000000 00000040 2 ** 2
                   CONTENU, ALLOC, LOAD, READONLY, CODE
 [...]
 Déassembly de la section .text:

 0000000000000000 :
    0: 55 push% rbp
    1: 48 89 e5 mov% rsp,% rbp
    4: 89 7j fc mov% edi, 0xfffffffffffffffc (% rbp)
    7: 89 75 f8 mov% esi, 0xfffffffffffffff8 (% rbp)
    a: 8b 45 f8 mov 0xfffffffffffffff8 (% rbp),% eax
    d: 03 45 ajouts 0xfffffffffffffffc (% rbp),% eax
   10: c9 quitte
   11: c3 retq 

Ceci est pour une compilation non optimisée de votre code, tandis que la version optimisée est:

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

 foo3.o: format de fichier elf64-x86-64

 Sections:
 Nom Idx Taille VMA LMA Fichier sur Algn
   0 .text 00000004 0000000000000000 0000000000000000 00000040 2 ** 4
                   CONTENU, ALLOC, LOAD, READONLY, CODE
 [...]
 Déassembly de la section .text:

 0000000000000000 :
    0: 8j 04 37 lea (% rdi,% rsi, 1),% eax
    3: c3 retq 

Notez le changement de “taille” de 0x12 à 4 ? C’est ce qui vient de la directive .size assembler.

L’astuce consistant à essayer d’utiliser un assemblage en ligne pour vous donner des tailles de fonction / des emplacements de code ne tient pas compte du code collé généré par le compilateur (prologs d’entrée de fonction / épilogues de sortie, génération de code en ligne, …), ni pour le compilateur. -orderering inline assembly (gcc est notoire pour le faire), donc ce n’est généralement pas une bonne idée de faire confiance à cela. En fin de compte, cela dépend de ce que vous essayez exactement de faire …

Edit: Quelques références supplémentaires, externes ainsi que sur stackoverflow:

  1. Dans la liste de diffusion gcc, filez sur sizeof(function)
  2. que retourne sizeof (nom de la fonction)?
  3. Trouver la taille d’une fonction en C
  4. LibELF par exemple avec le projet sourceforge (il s’agit de documentation / d’un tutoriel)

Pourquoi ne pas prendre la différence du pointeur de la fonction et l’adresse actuelle à la fin de la fonction? Jetez un coup d’œil à cette question pour récupérer l’adresse IP actuelle: Obtenir l’adresse de l’instruction actuelle pour x86 , peut-être que ce code, volé dans la réponse :

 unsigned long get_PC() { unsigned long current_instruction; __asm__ __volatile__ ( "movq 8(%rbp), %rax\n\t" : "=a" (current_instruction) ); return current_instruction; } 

ferait l’affaire,