Exercices à rendre :
dupouy@enst.fr Le texte du sujet ( subject ) doit contenir le mot : TPAST pour les AST (INF 201) TP1A pour les éléves de 1ère année
|
L'envoi d'un coup de sabre est simulé par l'émission d'un signal vers l'adversaire. Chacun des combattants se protége en ignorant le signal qui lui est destiné. Des qu'ils attaquent leur adversaire, les protagonistes deviennent sensibles aux signaux, donc peuvent recevoir des coups. Le programme est divise en trois fonctions :
mkdir tp_chprod cd tp_chprod
while (PointsDeVie[Moi] > 0) {
signal (Sabre[Lui], SIG_IGN); /* Commentaire 30 */
sleep (random() % 3);
sleep (TempsDefense[Moi] - 1); /* Commentaire 35 */
signal (Sabre[Lui], Touche); /* Commentaire 40 */
sleep (TempsAttaque[Moi]);
ik = kill (Pids[Lui], Sabre[Moi]);
if (ik < 0) break; /* Commentaire 45 */
}
gcc -static main.o foncs.o -o exo-s gcc main.o foncs.o -o exo
ls -l exo-s ls -l exo
nm (ou /usr/local/bin/nm) exo nm exo-s
libc.so.1 => /usr/lib/libc.so.1 libm.so.2 => /usr/local/lib/libm.so.2
(Pour en savoir plus sur make on consultera le man et/ou la page de Philippe Dax.)
gmake all starwarspour en vérifier le bon fonctionnement.
gmake allModifier le Makefile pour que ce Makefile retrouve les fichiers include sans que vous ayez à modifier le code des fichiers sources.
Faire : gmake starwars
Quelles modifications faut-il faire pour remédier aux erreurs ?
TOUS les warnings doivent disparaitre.
Dans utils.h, changer la ligne:
typedef short POINTS;
en
typedef float POINTS;
Faire à nouveau gmake starwars
Si gmake recompile c'est que vous avez
anticipé la question ! Passez au point suivant.
Sinon, si
il ne se passe rien, c'est que quelque chose manque puisque ce fichier
utils.h concerne foncs.c
et main.c. Pourquoi rien n'a été refait ?
Modifier le fichier Makefile pour résoudre ce problème.
Remarque :
On peut automatiser les inclusions de fichiers de type
.h dans les règles de make en utilisant
makedepend. Nous n'en parlons pas dans cette introduction.
Si on veut utiliser gdb sur le programme starwars, on entre la commande suivante :
gdb starwars
On va maintenant pouvoir exécuter ce programme starwars sous le contrôle de gdb, et on peut essayer les commandes suivantes :
(gdb) break main
Breakpoint 1 at 0x10900: file main.c, line 36.
(gdb) run
Starting program: starwars
Breakpoint 1, main () at main.c:36
36 int TempsDefense[] = {5, 3};
(gdb) step
37 int TempsAttaque[] = {3, 1};
(gdb) step
41 printf ("PointsDeVie : SkyWalker %d DarkVador : %d\n",
(gdb) step
PointsDeVie : SkyWalker 1076101120 DarkVador : 0
44 pid = fork();
(gdb) print PointsDeVie[0]
$1 = 10
(gdb) print PointsDeVie[1]
$2 = 10
(gdb)
adour$ar r libma_bib.a foncs.o ar: creating archive libma_bib.a adour$ ar t libma_bib.a foncs.oOn peut maintenant faire :
adour$rm foncs.o
adour$ranlib libma_bib.a
adour$nm libma_bib.a
libma_bib.a(foncs.o):
U _DegatSabre
00000148 T _Fin
U _Lui
U _Moi
U _Noms
U _PointsDeVie
U _Sabre
00000000 T _Touche
U _exit
U _printf
U _signal
adour$ gcc -Wall -c main.c -I./include adour$ gcc main.o libma_bib.a -o ficDans la première ligne, gcc agit en compilateur, dans la seconde en éditeur de liens.
Si l'éditeur de liens ne trouve pas la bibliothèque, il faut lui indiquer qu'elle
est dans le répertoire courant de la façon suivante :
adour$gcc main.o -L. -lma_bib -o fic
adour$mkdir lib adour$mv libma_bib.a ./lib/libma_bib.a
L'option -Lrep_bib de gcc indique qu'il faut chercher les bibliothèques dans le répertoire rep_bib. La commande à exécuter est alors :
adour$gcc main.o -L./lib -lma_bib -o fic
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000544 00000000 00000000 00000084 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000018 00000000 00000000 000005c8 2**2
CONTENTS, ALLOC, LOAD, RELOC, DATA
2 .rodata 000000b2 00000000 00000000 000005e0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .comment 00000070 00000000 00000000 0000
Commentaires :
00000000 l df *ABS* 00000000 main.c 00000000 l d .data 00000000 00000000 l .text 00000000 gcc2_compiled. 00000000 l d .text 00000000 00000000 l d .rodata 00000000 00000000 *UND* 00000000 Touche 00000000 *UND* 00000000 getpid 00000000 *UND* 00000000 exit 00000008 O *COM* 00000004 Pids 00000004 O *COM* 00000004 Lui 00000004 O *COM* 00000004 Moi 00000000 *UND* 00000000 printf 00000000 *UND* 00000000 kill 00000000 *UND* 00000000 random 00000000 g F .text 00000544 main 00000000 *UND* 00000000 sleep 00000000 *UND* 00000000 fork 00000000 g O .data 00000004 PointsDeVie 00000000 *UND* 00000000 getppid 00000000 *UND* 00000000 .rem 00000004 g O .data 00000004 DegatSabre 00000000 *UND* 00000000 Fin 00000000 *UND* 00000000 signal 00000010 g O .data 00000008 Noms 00000008 g O .data 00000008 SabreCommentaires sur le résultat de cette commande :
00000008 O *COM* 00000004 Pidsveut dire que la variable Pids est implantée sur 4 octets à partir de l'adresse 8 dans la zone COM.
Contents of section .data:
0000 000a000a 00030002 00000010 00000011 ................
0010 00000000 00000000 ........
Contents of section .rodata:
0000 536b7957 616c6b65 72000000 00000000 SkyWalker.......
0010 4461726b 5661646f 72000000 00000000 DarkVador.......
0020 506f696e 74734465 56696520 3a20536b PointsDeVie : Sk
0030 7957616c 6b657220 25642044 61726b56 yWalker %d DarkV
0040 61646f72 203a2025 640a0000 00000000 ador : %d.......
0050 2573202d 3e207069 64202564 2c202573 %s -> pid %d, %s
0060 202d3e20 70696420 25640a00 00000000 -> pid %d......
0070 25732064 6566656e 640a0000 00000000 %s defend.......
0080 25732061 74746171 75652025 730a0000 %s attaque %s...
0090 25732028 70696420 25642920 61207661 %s (pid %d) a va
00a0 696e6375 20257320 28706964 20256429 incu %s (pid %d)
00b0 0a00
Commentaires sur le résultat de cette commande :
0000 000a000a 00030002 00000010 00000011 ................les variables PointsDeVie et DegatSabre qui ont été déclarées ainsi :
typedef short POINTS;
POINTS PointsDeVie[] = {10, 10},
DegatSabre[] = {3, 2};
long Sabre[x] = {SIGUSR1, SIGUSR2}
on constate qu'on a bien deux fois deux octets initialisés à 10 (0a en base 16) , puis DegatSabre sur
deux fois deux octets, puis Sabre sur deux fois quatre octets.
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000017c 00000000 00000000 00000074 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .rodata 00000050 00000000 00000000 000001f0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .comment 00000070 00000000 00000000 000005d4 2**0
CONTENTS, READONLY
Exécuter la commande suivante :
SYMBOL TABLE: 00000000 l df *ABS* 00000000 foncs.c 00000000 l .text 00000000 gcc2_compiled. 00000000 l d .text 00000000 00000000 l d .rodata 00000000 00000000 g F .text 00000110 Touche 00000000 *UND* 00000000 exit 00000000 *UND* 00000000 Lui 00000000 *UND* 00000000 Moi 00000000 *UND* 00000000 printf 00000000 *UND* 00000000 PointsDeVie 00000000 *UND* 00000000 DegatSabre 00000110 g F .text 0000006c Fin 00000000 *UND* 00000000 signal 00000000 *UND* 00000000 Noms 00000000 *UND* 00000000 SabreCommentaires sur le résultat de cette commande :
Contents of section .rodata: 0000 25732074 6f756368 65202573 20285074 %s touche %s (Pt 0010 73205357 203a2025 64290a00 00000000 s SW : %d)...... 0020 25732074 6f756368 65202573 20285074 %s touche %s (Pt 0030 73204456 203a2025 64290a00 00000000 s DV : %d)...... 0040 25732061 20766169 6e637520 25730a00 %s a vaincu %s..Commentaires sur le résultat de cette commande :
gcc main.o foncs.o -o exoExécuter ensuite la commande suivante :
Sections:
11 .rodata 00000110 00010f78 00010f78 00000f78 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .data 00000020 0002123c 0002123c 0000123c 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .bss 0000002c 00021270 00021270 00001270 2**2
ALLOC
Commentaires :
Contents of section .data: 2123c 00021268 00000000 000a000a 00030002 ...h............ 2124c 00000010 00000011 00010f90 00010f80 ................Pour retrouver les variables initialisées (data) et non initialisées (bss), faire :
objdump -t exo | grep .dataExtrait du résultat :
0002123c l d .data 00000000 00021244 l O .data 00000000 force_to_data 00021240 l O .data 00000000 completed.4 0002123c l O .data 00000000 p.3 0002123c l O .data 00000000 force_to_data 00021254 g O .data 00000008 Noms 0002124c g O .data 00000008 Sabre 00021248 g O .data 00000004 DegatSabre 00021244 g O .data 00000004 PointsDeVie
objdump -t exo | grep bssExtrait du résultat :
00021270 l d .bss 00000000 0002129c l O .bss 00000000 _END_ 00021270 l O .bss 00000018 object.11 00021298 g O .bss 00000004 _environ 00021290 g O .bss 00000008 Pids 00021288 g O .bss 00000004 Lui 0002128c g O .bss 00000004 Moi 00021298 w O .bss 00000004 environ 0002129c g O .bss 00000000 _end
pushl %esp sauvegarde de la base de la pile
movl %esp, %ebp deplacement de la base de la pile
subl $16, %esp 16 octets dans la nouvelle pile
movl %ebp,%esp
popl %ebp
4(%ebp) adresse de retour
8(%ebp) argument 1
12(%ebp) argument 2
...
/* * factorielle.c */ #includeLe fichier assembleur (simplifié et commenté) produit par la commande : gcc -Wall -O4 -s factorielle.cint main(void){ int factorielle (int n); static int n, i =4; n = factorielle(i); printf("Factorielle(%d) = %d\n", i, n); return 0; } int factorielle(int n){ int i; if ( (n == 1) || (n == 0) ) i= 1; else i = n * factorielle(n-1); return i; }
//////////////////////////////////////////////////// .comm n.0,4,4 i.1: .long 4 .LC0: .string "Factorielle(%d) = %d\n" .text main: pushl %ebp movl %esp, %ebp pushl %ebx pushl %ebx andl $-16, %esp movl i.1, %ebx mettre i dans ebx subl $16, %esp cmpl $1, %ebx comparer ebx avec 1 movl $1, %eax mettre 1 dans eax (valeur de retour) ja .L11 aller a L11 SEULEMENT SI i > 1 movl %eax, n.0 initialiser n pushl %edx pushl %eax mettre n sur la pile pushl i.1 mettre i sur la pile pushl $.LC0 mettre adresse chaine de carc. sur la pile call printf optimisation : appel direct a printf xorl %eax, %eax movl -4(%ebp), %ebx leave ret .L11: leal -1(%ebx), %eax decrementer ebx et le mettre dans eax (eax est aussi valeur de retour) pushl %eax mettre eax sur la pile comme argument call factorielle imull %ebx, %eax popl %ecx movl %eax, n.0 pushl %edx pushl %eax mettre n sur la pile pushl i.1 mettre i sur la pile pushl $.LC0 mettre adresse chaine de carc. sur la pile call printf xorl %eax, %eax movl -4(%ebp), %ebx leave ret factorielle: pushl %ebp decrementer esp et sauver ebp sur la pile movl %esp, %ebp mettre le esp courant dans ebp (nouvelle fenetre) pushl %ebx decrementer esp et sauver ebx sur la pile movl 8(%ebp), %ebx ebx = valeur du premier argument dans la fenetre precedente cmpl $1, %ebx comparaison avec 1 movl $1, %eax toujours mettre 1 dans eax ja .L6 si argument > 1 : aller a L6 movl -4(%ebp), %ebx (1) restaurer ebx leave restaurer la fenetre de pile précédente (c.a.d movl %ebp,%esp puis popl %ebp) ret depiler le compeur ordinal sauve (c.a.d : popl %eip) .L6: subl $12, %esp decrementer esp de 12 pour preparer une nouvelle fenetre leal -1(%ebx), %eax decrementer ebx et le mettre dans eax (valeur de retour) pushl %eax mettre eax sur la pile comme argument call factorielle appel avec (n-1) en argument imull %ebx, %eax ebx a ici la valeur deposee en (1) addl $16, %esp faire pointer esp sur la fenetre precedente movl -4(%ebp), %ebx restaurer ebx leave restaurer la fenetre de pile précédente ret