2010-09-30 39 views
3

Je crée un exécutable ELF i386 qui doit importer une fonction de libc6. (C'est printf, en passant.)Comment importer une fonction de libc6 dans un exécutable ELF?

J'ai créé un très petit exécutable ELF qui affiche "Hello, world!" à la console en utilisant l'interruption du noyau Linux 0x80. Ce n'est pas optimal et j'aimerais que l'application utilise plutôt libc.

Voici ce que j'ai jusqu'à présent: (. Crédit this page pour la plupart du code d'alignement de la structure)

BITS 32 

      org  0x08048000 

ehdr:             ; Elf32_Ehdr 
      db  0x7F, "ELF", 1, 1, 1, 0   ; e_ident 
    times 8 db  0 
      dw  2        ; e_type 
      dw  3        ; e_machine 
      dd  1        ; e_version 
      dd  _start       ; e_entry 
      dd  52 
      dd  0        ; e_shoff 
      dd  0        ; e_flags 
      dw  52 
      dw  32 
      dw  1        ; e_phnum 
      dw  0        ; e_shentsize 
      dw  0        ; e_shnum 
      dw  0        ; e_shstrndx 

; this is the header for the code section 

      dd  1        ; p_type 
      dd  0        ; p_offset 
      dd  $$        ; p_vaddr 
      dd  $$        ; p_paddr 
      dd  filesize      ; p_filesz 
      dd  filesize      ; p_memsz 
      dd  5        ; p_flags 
      dd  0x1000       ; p_align 

_start: 

      ; We want to print the string 

    mov eax,4   ; 'write' system call 
    mov ebx,1   ; file descriptor 1 = screen 
    mov ecx,teststr  ; string to write 
    mov edx,14   ; length of string to write 
    int 80h    ; call the kernel 

    ; Terminate program 
    mov eax,1   ; 'exit' system call 
    mov ebx,0   ; exit with error code 0 
    int 80h    ; call the kernel 

_stringtable: 

      teststr db "Hello, world!",10,0 

filesize  equ  $ - $$ 

Je pense que je dois ajouter un autre en-tête du programme pour les importations, mais je vraiment Je ne sais pas - je ne connais pas non plus le format du contenu de cette section.

+0

Pourquoi l'utilisation de l'appel système write n'est-elle pas optimale? Puisque vous imprimez simplement une chaîne statique, cela semble être le meilleur moyen. Y compris printf statiquement créerait probablement un exécutable beaucoup plus grand, vu que printf a tendance à être assez grand. –

+0

@Michael: Cela fait partie d'un projet plus vaste qui nécessite libc6 pour un certain nombre d'autres fonctions. –

Répondre

2

Si vous êtes prêt à laisser l'éditeur de liens faire son travail, cela suffit (syntaxe GAZ, compilation avec gcc hello.s):

 .text 
     .globl main 
     .type main, @function 
main: 
     leal .LC0, %eax 
     pushl %eax 
     call puts 
     xorl %eax, %eax 
     ret 
     .size main, .-main 
.LC0: 
     .asciz "Hello, world!" 

(Techniquement .LC0 devrait être mis en .rodata mais je ne me souviens pas exactement comment vous faites cela et je ne suis pas sur ma machine Linux en ce moment.En outre, cela ne maintient aucun alignement de pointeur de pile, ce qui ne devrait pas être un problème pour un programme de jouet comme celui-ci, mais je ne fais aucune promesse

Si vous voulez vraiment construire l'ensemble exécutable à la main, lisez d'abord ce livre: http://www.iecc.com/linker/ Ensuite, vous aurez besoin de lire la spécification ELF, l'ABI générique System V, et le supplément x86-32 psABI; ceux-ci peuvent tous être trouvés ici: http://refspecs.freestandards.org/. Ensuite, utilisez readelf, objdump et/ou hexdump pour démonter l'image exécutable que vous obtenez de la compilation de ce qui précède et déterminer comment il est construit.