TP 2 : La constitution d'un programme en assembleur



L'objectif

Dans le TP précèdent, nous avons vu que les deux programmes hello1 et hello2 faisaient la même chose et pourtant avaient des tailles bien différentes. Dans ce TP nous allons voir pourquoi. Attention, il est nécessaire d'utiliser la version initiale de ces deux programmes, et non la version modifiée de fin de TP...

Le temps imparti

1h30

Le sujet

Dans ce TP nous allons voir pourquoi deux programmes faisant la même chose ont des tailles bien différentes. Nous allons voir en quoi consiste une compilation dynamique et une compilation statique.

Remarque : Il est possible que les messages d'erreur ne soient pas exactement les mêmes. En effet ce TP a été monté il y a quelques années et les bibliothèques des programmes écrits en langage C ont évolué. Alors soyez réactifs...

A faire

Lancer la commande :

file hello1

Vous devez obtenir le message suivant : (ou presque...)
  hello1: ELF 32-bit LSB exécutable, Intel 80386, version 1, dynamically linked, not stripped

Lancer la commande :

$file hello2

Vous devez obtenir le message suivant : (ou presque...)
  hello2: ELF 32-bit LSB exécutable, Intel 80386, version 1, statically linked, not stripped

Explications :

Pour le fichier hello1, lors de la compilation, un petit fragment de code qui permet l’exécution de ld.so (éditeur de liens dynamiques, d'où le terme dynamically linked) y est ajouté.
Pour le fichier hello2, il n'y a pas ce code. On fait référence directement à une interruption logicielle (du noyau) d'ou le terme statically linked.

En effet le code de puts pour hello1 est nécessaire à l’exécution de hello1, alors que pour hello2, on fait référence à l’appel système n°4 (eax=4) qui correspond à sys_write (voir la liste des appels systèmes.).

Pour s'en rendre compte, il suffit de lancer les commandes suivantes :

$ldd hello1
$ldd hello2

Pour hello1 vous devez obtenir la liste des bibliothèques partagées utilisées et pour hello2 le message suivant : (ou presque...)
  not a dynamic exécutable

Afin d'obtenir la table des symboles des deux programmes, lancer les commandes suivantes :

$nm hello1
$nm hello2


Désassembler les deux fichiers binaires en lançant les deux commandes suivantes :

$objdump -d hello1.o > hello1_obj.dis
$objdump -d hello2 o > hello2_obj.dis

Puis étudiez les deux fichiers hello1.dis et hello2.dis
Pour le programme hello2.o vous devez obtenir quelque chose comme :

hello2_obj.dis
    hello2:file format elf32-i386
    Disassembly of section .text:
    00000000 <message>:
    0: 68 65 6c 6c 6fpushl$0x6f6c6c65
    5: 20 77 6fandb%dh,0x6f(%edi)
    8: 72 6cjb<_pointdentree+0x66>
    A: 64 21 20andl%esp,%fs:(%eax)
    D: 0a 00orb(%eax),%al
    F: 90nop
    00000010 <_pointdentree>:
    10: b8 04 00 00 00movl$0x4,%eax
    15: bb 01 00 00 00movl$0x1,%ebx
    1A: b9 00 00 00 00movl$0x0,%ecx
    1F: ba 0f 00 00 00movl$0xf,%edx
    24: cd 80 int$0x80
    26: b8 01 00 00 00movl$0x1,%eax
    2b: bb 00 00 00 00movl$0x0,%ebx
    30: cd 80int$0x80

Désassembler les deux fichiers exécutables en lançant les deux commandes suivantes :

$objdump -d hello1 > hello1_exe.dis
$objdump -d hello2 > hello2_exe.dis

Pour le programme hello2 vous devez obtenir quelque chose comme :

hello2_exe.dis
    hello2:file format elf32-i386
    Disassembly of section .text:
    08048074 <message>:
    8048074: 68 65 6c 6c 6fpushl$0x6f6c6c65
    8048079: 20 77 6fandb%dh,0x6f(%edi)
    804807c: 72 6cjb<_pointdentree+0x66>
    804807e: 64 21 20andl%esp,%fs:(%eax)
    8048081: 0a 00orb(%eax),%al
    8048083: 90nop
    08048084 <_pointdentree>:
    8048084: b8 04 00 00 00movl$0x4,%eax
    8048089: bb 01 00 00 00movl$0x1,%ebx
    804808e: b9 74 80 04 08movl$0x8048074,%ecx
    8048093: ba 0f 00 00 00movl$0xf,%edx
    8048098: cd 80int$0x80
    804809a: b8 01 00 00 00movl$0x1,%eax
    804809f: bb 00 00 00 00movl$0x0,%ebx
    80480a4: cd 80int$0x80

Après l’édition des liens, il y a eu modification des adresses. Par exemple l'adresse relative 10 à été remplacée par l’adresse absolue 8048084.

Ouvrez les fichiers hello1_exe.dis et hello1_obj.dis. Constatez qu'il contient le code du fichier hello2_exe.dis, plus de nombreuses lignes de codes qui ne seront pas expliquées dans ce tp.

Explications :

Sur le listing ci-dessus on peut constater la présence de 4 colonnes.

  1. Les adresses relatives ou absolues selon que l’on ait desassemblé le fichier objet ou le fichier exécutable.
  2. Les codes opératoires (binaires) des instructions et les valeurs des opérandes
  3. Les mnémoniques des instructions
  4. Les opérandes.

Traduction de b8 04 00 00 00 movl $0x4,%eax

Nous verrons dans un tp ultérieur les différents modes d'adressage.
Par exemple, le code opératoire de movl $4,%eax est diffèrent de celui de movl (message),%eax.
Vous pouvez essayer en ajoutant la ligne movl (message),%ax juste avant la ligne movl $0x4,%eax (cela ne va pas modifier l’exécution du programme).
Ensuite, réalisez le fichier objet et désassemblez-le. Notez les deux codes opératoires correspondants.

La partie <message> du listing ci-dessus correspond à la partie données du programme, mais le désassembleur, ne pouvait pas le savoir. Il l'a donc traduite en code source (qui fait tout et rien !).
On peut remarquer la valeur des codes ascii des différentes lettres utilisées pour afficher hello world! et le code 00 final pour le caractère NULL (marqueur de fin de chaîne).


Questions :


Retour à la liste des TP