Logiciel de Base : examen de première session



Documents pareils
Logiciel de base. Première année ENSIMAG

Architecture des ordinateurs

Structure d un programme

Programmation assembleur : aperçu

Architecture des ordinateurs : Programmation des processeurs avec l'environnement «y86» (INF155)

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Machines virtuelles. Brique ASC. Samuel Tardieu Samuel Tardieu (ENST) Machines virtuelles 1 / 40

Initiation à la sécurité

Cours de Programmation Impérative: Zones de mémoires et pointeurs

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

Cours d initiation à la programmation en C++ Johann Cuenin

4. Initiation à l'assembleur

Rappels d architecture


EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Cours d introduction à l informatique. Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions

Les techniques de protection du logiciel

SSTIC Désobfuscation automatique de binaires. Alexandre Gazet. Yoann Guillot. Et autres idyles bucoliques...

UE Programmation Impérative Licence 2ème Année

Java Licence Professionnelle CISII,

Argument-fetching dataflow machine de G.R. Gao et J.B. Dennis (McGill, 1988) = machine dataflow sans flux de données

Résumé Génération de code Le code intermédiaire

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Compilation (INF 564)

MICROINFORMATIQUE NOTE D APPLICATION 1 (REV. 2011) ARITHMETIQUE EN ASSEMBLEUR ET EN C

Les vulnérabilités du noyau. LECORNET Olivier LEGROS Bruno VIGIER Nicolas Promo 2005

Conception de circuits numériques et architecture des ordinateurs

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Introduction au langage C

Représentation d un entier en base b

ARDUINO DOSSIER RESSOURCE POUR LA CLASSE

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Informatique Générale

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

Analyse de sécurité de logiciels système par typage statique

Traduction des Langages : Le Compilateur Micro Java

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

Le Projet BINSEC. Automatiser l analyse de sécurité au niveau binaire. Airbus group, CEA, IRISA, LORIA, Uni. Joseph Fourier. p.

UE C avancé cours 1: introduction et révisions

Licence Sciences et Technologies Examen janvier 2010

Conventions d écriture et outils de mise au point

GlobalScape Secure FTP Server Buffer Overflow

Assembleur. Faculté I&C, André Maurer, Claude Petitpierre

Prentice Hall, 2011 (ISBN )

Introduction à l algorithmique et à la programmation M1102 CM n 3

Département informatique de l université d Angers

Bases de programmation. Cours 5. Structurer les données

Architecture des ordinateurs. Loïc Cuvillon. 20 novembre 2013

Architecture des ordinateurs

Logiciel Libre Cours 2 Fondements: Programmation

Programmer en JAVA. par Tama

Réalisation d un OS 32 bits pour PC(x86)

Recherche dans un tableau

TD3: tableaux avancées, première classe et chaînes

STS SE. FreeRTOS. Programmation réseau WIFI. Programmation réseau. Socket Tcp. FlyPort smart Wi-Fi module

Chap III : Les tableaux

Cours 1 : Introduction Ordinateurs - Langages de haut niveau - Application

Cours d Algorithmique et de Langage C v 3.0

4. Utilisation d un SGBD : le langage SQL. 5. Normalisation

Plan du cours. Historique du langage Nouveautés de Java 7

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

Gestion de la mémoire

La mémoire. Un ordinateur. L'octet. Le bit

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Assembleur i8086. Philippe Preux IUT Informatique du Littoral. Année universitaire 95 96

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

Désobfuscation automatique de binaire - The Barbarian Sublimation

Programmation C. Apprendre à développer des programmes simples dans le langage C

Algorithmique et Programmation, IMA

INF111. Initiation à la programmation impérative en C amini/cours/l1/inf111/ Massih-Reza Amini

Corrigé des exercices sur les références

Corrigé des TD 1 à 5

Algorithmique I. Algorithmique I p.1/??

Programmation en Java IUT GEII (MC-II1) 1

Algorithmique, Structures de données et langage C

Traduction binaire dynamique de l extension SIMD Néon de l ARMv7 dans Qemu

Contraintes, particularités. 1. Généralités Gestion de la mémoire a. Type des variables et constantes... 2

Architecture de l ordinateur

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Les structures. Chapitre 3

V- Manipulations de nombres en binaire

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

SUPPORT DE COURS. Langage C

UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux.

Brefs rappels sur la pile et le tas (Stack. / Heap) et les pointeurs

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Programmation en langage C

C++ COURS N 2 : CLASSES, DONNÉES ET FONCTIONS MEMBRES Classes et objets en C++ Membres d'une classe Spécification d'une classe Codage du comportement

Algorithme. Table des matières

Programmation C++ (débutant)/instructions for, while et do...while

Déroulement. Evaluation. Préambule. Définition. Définition. Algorithmes et structures de données 28/09/2009

Génération de code binaire pour application multimedia : une approche au vol

Initiation. àl algorithmique et à la programmation. en C

PROJET ALGORITHMIQUE ET PROGRAMMATION II

Support de Cours de Langage C. Christian Bac

Travaux Dirigés n 1 : chaînes de caractères

Transcription:

Logiciel de Base : examen de première session ENSIMAG 1A Année scolaire 2008 2009 Consignes générales : Durée : 2h. Tous documents et calculatrices autorisés. Le barème est donné à titre indicatif. Les exercices sont indépendants et peuvent être traités dans le désordre. Merci d indiquer votre numéro de groupe de TD et de rendre votre copie dans le tas correspondant à votre groupe. Consignes relatives à l écriture de code C et assembleur Pentium : Pour chaque question, une partie des points sera affectée à la clarté du code et au respect des consignes ci-dessous. Pour les questions portant sur la traduction d une fonction C en assembleur, on demande d indiquer en commentaire chaque ligne du programme C original avant d écrire les instructions assembleur correspondantes. Pour améliorer la lisibilité du code assembleur, on utilisera systématiquement des constantes (directive.equ) pour les déplacements relatifs à %ebp (i.e. paramètres des fonctions et variables locales). Par exemple, si une variable locale s appelle var en langage C, on y fera référence avec var(%ebp). Sauf indication contraire dans l énoncé, on demande de traduire le code C en assembleur de façon systématique, sans chercher à faire la moindre optimisation : en particulier, on stockera les variables locales dans la pile (pas dans des registres), comme le fait le compilateur C par défaut. On respectera les conventions de gestions des registres Intel vues en cours, c est à dire : %eax, %ecx et %edx sont des registres scratch ; %ebx, %esi et %edi ne sont pas des registres scratch. Ex. 1 : Parcours de tableaux (12 pts) Le Crible d Ératosthène 1 est un algorithme itératif permettant de générer les nombres premiers inférieurs ou égaux à un entier N donné. On travaille ici sur une version de cet algorithme utilisant des tableaux. Plus précisément, l algorithme consiste à : J.-C. 1 Ératosthène était un astronome, géographe, philosophe et mathématicien grec du III e siècle avant 1

initialiser un tableau de booléens allant de 0 à N (inclus) avec la valeur Faux pour les cases 0 et 1 (qui ne sont pas des nombres premiers) et Vrai pour les autres ; parcourir ce tableau pour marquer avec la valeur Faux toutes les cases dont l indice est un multiple d un entier inférieur : on démontre qu on peut arrêter le parcours dès qu on a supprimé tous les multiples des entiers inférieurs ou égaux à N ; afficher les indices des cases contenant la valeur Vrai, car les indices en question sont tous des nombres premiers. Le programme principal de cet algorithme s écrit donc en C (où N est un naturel supérieur ou égal à 2) : int main() unsigned int tab[n + 1]; /* unsigned int est equivalent a unsigned */ remplir(tab, N); supprimer_multiples(tab, N); afficher(tab, N); urn 0; } Question 1 Ecrire en C la fonction void remplir(unsigned int tab[], unsigned int sup) qui initialise le tableau tab comme expliqué plus haut (on rappelle qu en C il n existe pas de type booléen : on utilisera donc 0 pour la valeur Faux et 1 pour la valeur Vrai). void remplir(unsigned int tab[], unsigned int sup) unsigned int i; tab[0] = tab[1] = 0; for (i = 2; i <= sup; i ++) tab[i] = 1; } Question 2 Traduire cette fonction remplir en assembleur. On rappelle qu il est demandé de précéder chaque séquence d instructions assembleur par la ligne de C correspondante, et d utiliser des constantes pour les déplacements relatifs à %ebp. /* void remplir(unsigned int tab[], unsigned int sup) */.equ tab, 8.equ sup, 12 remplir: /* unsigned int i; */.equ i, -4 enter $4, $0 2

/* tab[0] = tab[1] = 0; */ movl tab(%ebp), %eax movl $0, (%eax) movl $0, 4(%eax) /* for (i = 2;... */ movl $2, i(%ebp) remplir_bcl: /*... i <= sup;... */ cmpl sup(%ebp), %eax ja remplir_bcl_fin /* tab[i] = 1; */ movl tab(%ebp), %eax movl i(%ebp), %edx movl $1, (%eax, %edx, 4) /*... i ++) */ incl i(%ebp) jmp remplir_bcl remplir_bcl_fin: Question 3 Traduire en C le code de la fonction supprimer_multiples donnée cidessous en assembleur. On conservera les mêmes noms de paramètres et de variables locales lors de la traduction. On rappelle quelques instructions utiles pour cette question : enter $8, $0 : cette instruction est exactement équivalente à la séquence d instructions : pushl %ebp movl %esp, %ebp subl $8, %esp mull x : multiplie le contenu de la variable 32 bits x par le contenu du registre %eax, et stocke le résultat (sur 64 bits) dans %edx:%eax ; shll %eax : décale le contenu du registre %eax d un bit vers la gauche (ce qui revient en pratique à le multiplier par 2). /* void supprimer_multiples(unsigned int tab[], unsigned int sup) */.equ tab, 8.equ sup, 12 supprimer_multiples: /* unsigned int i, j */.equ i, -4.equ j, -8 enter $8, $0 3

movl $2, i(%ebp) sm_bcl1: mull i(%ebp) cmpl sup(%ebp), %eax ja sm_bcl1_fin shll %eax movl %eax, j(%ebp) sm_bcl2: movl j(%ebp), %eax cmpl sup(%ebp), %eax ja sm_bcl2_fin movl tab(%ebp), %eax movl j(%ebp), %edx movl $0, (%eax, %edx, 4) addl %eax, j(%ebp) jmp sm_bcl2 sm_bcl2_fin: incl i(%ebp) jmp sm_bcl1 sm_bcl1_fin: void supprimer_multiples(unsigned int tab[], unsigned int sup) unsigned int i, j; for (i = 2; i * i <= sup; i ++) for (j = i * 2; j <= sup; j += i) tab[j] = 0; } Question 4 Ecrire en C la fonction void afficher(unsigned int tab[], unsigned int sup) qui affiche à l écran les nombres premiers en fonction du contenu du tableau tab, comme expliqué plus haut. void afficher(unsigned int tab[], unsigned int sup) unsigned int i; for (i = 0; i <= sup; i ++) 4

} if (tab[i] == 1) printf("%u ", i); printf("\n"); Ex. 2 : Optimisation de code (8 pts) On travaille dans cet exercice sur différentes implantations d une fonction permettant de copier le contenu d une zone mémoire dans une autre. Cette fonction existe dans la bibliothèque C standard : /* * Recopie les n premiers octets de la zone memoire pointee par src * dans la zone memoire pointee par dst et renvoie l adresse dst. */ char *memcpy(char *dst, char *src, unsigned int n) Une implantation simpliste de cette fonction en C pourrait être : char *copie_memoire(char *dst, char *src, unsigned int n) unsigned int i; for (i = 0; i < n; i ++) dst[i] = src[i]; urn dst; } Question 1 Traduire cette version simpliste en assembleur. On traduira de façon systématique sans chercher à faire la moindre optimisation. Notamment, les variables locales seront stockées dans la pile et pas dans des registres. /* char *copie_memoire_naif(char *dst, char *src, unsigned int n); */.equ dst, 8.equ src, 12.equ n, 16 copie_memoire_naif: /* unsigned int i; */.equ i, -4 enter $4, $0 /* for (i = 0;... */ movl $0, i(%ebp) cpn_bcl: /*...; i < n;... */ 5

cmpl n(%ebp), %eax jae cpn_bcl_fin /* dst[i] = src[i] */ movl src(%ebp), %ecx movl dst(%ebp), %edx movb (%ecx, %eax), %cl movb %cl, (%edx, %eax) /*... i ++) */ incl i(%ebp) jmp cpn_bcl cpn_bcl_fin: /* urn dst; */ movl dst(%ebp), %eax Question 2 Ecrire une nouvelle version assembleur de cette même fonction, mais en stockant au début du programme les variables locales et les paramètres dans des registres, pour supprimer dans la suite du code autant d accès mémoire que possible. On stockera src dans %esi, dst dans %edi, n dans %edx et i dans %ecx..equ dst, 8.equ src, 12.equ n, 16 copie_memoire_optimisee: enter $0, $0 pushl %esi pushl %edi movl src(%ebp), %esi movl dst(%ebp), %edi movl n(%ebp), %edx xorl %ecx, %ecx cpo1_bcl: cmpl %edx, %ecx jae cpo1_bcl_fin movb (%esi, %ecx), %al movb %al, (%edi, %ecx) incl %ecx jmp cpo1_bcl cpo1_bcl_fin: movl dst(%ebp), %eax 6

popl %edi popl %esi En pratique, l implantation de memcpy fournie par la bibliothèque C standard est plus rapide que les deux versions implantées dans les questions précédentes. On peut effectivement optimiser le code en utilisant des instructions dédiées du processeur Pentium : shrl $X, %reg : décale de X bits vers la droite le registre reg ; movsd : recopie le mot de 32 bits pointé par %esi dans la case mémoire pointée par %edi et ajoute ou soustrait 4 à %esi et %edi (le choix entre l addition ou la soustraction se fait en fonction du bit DF du registre %eflags) ; cld : met à zéro le bit DF du registre %eflags, ce qui a pour effet en pratique de sélectionner l addition de 4 à %esi et %edi pour l instruction movsd ; rep : préfixe ajouté avant certaines instructions (e.g. rep movsd) et qui a pour effet de répéter l exécution de l instruction préfixée tant que %ecx est différent de 0, et qui soustrait automatiquement 1 à %ecx après chaque exécution de l instruction. Question 3 En utilisant les instructions présentées ci-dessus, donner une version assembleur optimisée de la fonction de copie mémoire. On supposera pour simplifier que la taille de la zone mémoire à recopier est un multiple de 4. /* Suppose que le nombre d octets a copier est un multiple de 4 */.equ dst, 8.equ src, 12.equ n, 16 copie_memoire_movs: enter $0, $0 pushl %esi pushl %edi movl dst(%ebp), %edi movl src(%ebp), %esi movl n(%ebp), %ecx shrl $2, %ecx cld rep movsd movl dst(%ebp), %eax popl %edi popl %esi 7

Pour les curieux, un test simpliste effectué sur telesun (recopie d une zone mémoire de 1468006400 octets) donne les résultats suivants : version naïve en 5,98 sec., version optimisée en 1,93 sec., version avec les instructions dédiées et memcpy de la bibliothèque C toutes deux en 1,80 sec. En pratique, on copie rarement de très gros blocs de mémoire, mais plus souvent de petits blocs de façon répétitives. L implantation de memcpy de la bibliothèque C est alors très performante grâce à la prise en compte des caractéristiques du pipeline et de la mémoire cache de la machine. Comme suggéré ci-dessus, l implémentation de memcpy dans la libc GNU sur platforme Intel est encore plus optimisée que la version avec les instructions movsd, etc. La version disponible sur telesun dans libc/sysdeps/i386/i586/memcopy.h est principalement constituée de : /* Written like this, the Pentium pipeline can execute the loop at a sustained rate of 2 instructions/clock, or asymptotically 480 Mbytes/second at 60Mhz. */ #undef WORD_COPY_FWD #define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \ do \ \ asm volatile ("subl $32,%2\n" \ "js 2f\n" \ "movl 0(%0),%%edx\n" /* alloc dest line */ \ "1:\n" \ "movl 28(%0),%%eax\n" /* alloc dest line */ \ "subl $32,%2\n" /* decr loop count */ \ "movl 0(%1),%%eax\n" /* U pipe */ \ "movl 4(%1),%%edx\n" /* V pipe */ \ "movl %%eax,0(%0)\n" /* U pipe */ \ "movl %%edx,4(%0)\n" /* V pipe */ \ "movl 8(%1),%%eax\n" \ "movl 12(%1),%%edx\n" \ "movl %%eax,8(%0)\n" \ "movl %%edx,12(%0)\n" \ "movl 16(%1),%%eax\n" \ "movl 20(%1),%%edx\n" \ "movl %%eax,16(%0)\n" \ "movl %%edx,20(%0)\n" \ "movl 24(%1),%%eax\n" \ "movl 28(%1),%%edx\n" \ "movl %%eax,24(%0)\n" \ "movl %%edx,28(%0)\n" \ "leal 32(%1),%1\n" /* update src ptr */ \ "leal 32(%0),%0\n" /* update dst ptr */ \ "jns 1b\n" \ "2: addl $32,%2" : \ 8

"=r" (dst_bp), "=r" (src_bp), "=r" (nbytes_left) : \ "0" (dst_bp), "1" (src_bp), "2" (nbytes) : \ "ax", "dx"); \ } while (0) mais inclue aussi beaucoup d optimisations pour les zones mémoires plus petites (cas particulier pour les cases non-alignées,...). 9