LdB Seance 7

De Ensiwiki.

Aller à : Navigation, rechercher
Spécifique EnsimagCette page est maintenue par les enseignants et utilisée par les élèves de la matière concernée. Vos contributions sont les bienvenues, mais merci d'en discuter avant de faire des modifications non-triviales de la page, pour être sûr de ne pas perturber le déroulement du cours.

  Première Année    Informatique 

Sommaire

  • 1 Introduction
  • 2 Manipulation de chaînes de caractères
    • 2.1 Calcul de la longueur de la chaine
    • 2.2 Inversion de chaine
  • 3 Manipulation de tableaux d'entiers
    • 3.1 Recherche du maximum
    • 3.2 Découpage du tableau

Introduction

Le but de cette séance est de travailler sur différents modes d'adressage du Pentium. On n'utilisera pas ici tous les modes fournis par le processeur, mais la plupart peuvent facilement être dérivés les uns des autres.

On rappelle que pour ceux qui utiliseraient MacOS, les programmes assembleur fournis peuvent être facilement adaptés :

  • en ajoutant l'option -gstabs à gcc lors de la compilation ;
  • en utilisant la directive .globl à la place de la directive .global ;
  • en préfixant tous les noms de fonctions exportées par un _ , par exemple ici _main au lieu de main. Cela vaut aussi pour les fonctions utilisées : ici notamment _puts.

Si vous souhaitez utiliser des commentaires du type //, vous devez terminer vos fichiers assembleur par un .S (majuscule, pas minuscule).

Attention : dans tout l'exercice, vous n'avez le droit d'utiliser que les registres %eax, %ecx et %edx. On comprendra pourquoi lors de la prochaine séance de TD.

Manipulation de chaînes de caractères

Dans ce premier exercice, on va écrire des petits programmes de manipulation de chaînes de caractères.

Recopier le squelette de code ci-dessous dans un fichier chaines.S :

    .globl main
    .text
main:
    // debut de la fonction
    enter $0, $0

    // on stocke l'adresse de la chaine dans %edx
    movl $chaine, %edx

// completer ici avec le calcul de la longueur de la chaine

// completer ici avec l'inversion de la chaine

    // return 0;
    xorl %eax, %eax
    leave
    ret

    .data
// la chaine : changer sa valeur pour vos tests
chaine:    .asciz "azerty" // on peut utiliser aussi .string sous Linux (pas sous MacOS)

senti:     .asciz "zzzzzz" // cette zone memoire NE DOIT PAS etre accedee

Dans ce squelette, on commence par stocker l’adresse de la chaine dans le registre %edx. : dans tout l’exercice, on se servira toujours de ce registre comme adresse de base.

Calcul de la longueur de la chaine

Dans cette question, on utilisera un deuxième registre (par exemple %ecx) pour calculer le déplacement par rapport à la base (dans %edx). Le mode d’adressage utilisé sera donc le mode indirect avec index : par exemple, movl %eax, (%edx, %ecx).

Compléter le code ci-dessus pour calculer dans un registre la taille de la chaine. On rappelle qu’une chaine de caractères est terminée par le caractère ’\0’ (c’est à dire l’octet zéro) et qu’on ne compte pas ce caractère de fin dans la taille de la chaine. Attention, les caractères sont codés sur 8 bits : on ne manipule pas ici des entiers.

En C, le code demandé s’écrirait par exemple :

unsigned taille;
for (taille = 0; chaine[taille] != 0; taille++);

Tester ce programme avec gdb sur les chaines "azerty", "aze", "a" et "". On rappelle qu'on peut facilement suivre la valeur d'un registre sous gdb avec la commande display $ecx (pour voir %ecx par exemple).

Inversion de chaine

Dans cette question, en plus d'utiliser un registre d'index, on pourra modifier la base dans %edx. Le mode d’adressage utilisé sera donc le mode indirect avec ou sans index : par exemple, movl %eax, (%edx, %ecx) ou movb (%edx), %al.

Ajouter au squelette fourni le code permettant d’inverser la chaine de caractère (e.g. "azerty" donne "ytreza"). On utilisera la taille de la chaine calculée précédemment pour écrire ce code. Le code C correspondant pourrait être par exemple :

int dep = taille - 1;
char *ptr = chaine;
while (dep > 0) {
    char tmp = *ptr;
    *ptr = ptr[dep];
    ptr[dep] = tmp;
    dep = dep - 2;
    ptr++;
}

On pourra se servir de l’instruction xchg src, dst qui échange les valeurs de src et dst : attention, src et dst ne peuvent pas être tous les deux des valeurs en mémoire. On peut aussi faire l’échange seulement en utilisant plusieurs fois l’instruction mov.

Déboguer le programme en utilisant gdb et en affichant la chaine résultat à la fin, sur les chaines "azerty", "aze", "a" et "". On rappelle que si par exemple %al contient un caractère, on peut facilement afficher son contenu grâce à la commande display /c $eax. Pour afficher la chaine au fur et a mesure de son inversion, le plus simple est de commencer par afficher le contenu de %edx une fois qu'on y a copié l'adresse de la chaine (i r edx qui affiche par exemple 0x1234) puis d'afficher la chaine localisée à cette adresse : display /s 0x1234.

Manipulation de tableaux d'entiers

On va maintenant travailler sur des tableaux d’entiers strictement positifs.

On part du squelette de code ci-dessous, à copier dans un fichier tableaux.S :

    .globl main
    .text
main:
    // debut de la fonction
    enter $0, $0

// completer ici avec le code de recherche du maximum

// completer ici avec le code de decoupage du tableau

    // return 0;
    xorl %eax, %eax
    leave
    ret

    .data
// tableau initial : changer sa valeur pour les tests
tab:    .long 1, 4, 7, 5, 9, 1, 3, 2, 4, 8, 0

// espace memoire pour les tableaux tab1 et tab2
.comm tab1, 11 * 4
.comm tab2, 11 * 4
// une mysterieuse case memoire au nom evocateur
.comm sav, 4

Recherche du maximum

Écrire le code assembleur cherchant dans un registre l’entier maximum du tableau tab. On note que le tableau ne contient que des entiers strictement positifs et qu’il est terminé par l’entier 0.

Le code C correspondant pourrait être :

unsigned max, i;
for (max = i = 0; tab[i] != 0; i++) {
    if (tab[i] > tab[max]) {
        max = i;
    }
}

On n’utilisera dans cette question que l’adressage indirect avec index typé et déplacement : par exemple, movl %eax, tab(, %edx, 4). On demande d’écrire le code de façon naïve, en accédant autant de fois que nécessaire à la case courante du tableau. Tester le code avec gdb, et vérifier aussi qu’il fonctionne avec un tableau vide et un tableau contenant un seul élément.

Découpage du tableau

On va maintenant écrire un code parcourant une seule fois le tableau tab et recopiant dans tab1 (resp. tab2) tous les éléments impaires (resp. pairs) de tab.

En C, cela donnerait par exemple :

unsigned *ptr, *ptr1, *ptr2;
ptr = tab; ptr1 = tab1; ptr2 = tab2;
while (*tab != 0) {
    if (*tab % 2 == 1) {
        *tab1 = *tab;
        tab1++;
    } else {
        *tab2 = *tab;
        tab2++;
    }
    tab++;
}

Vous pouvez utiliser les modes d'adressages qui vous paraissent les plus adaptés à chaque situation dans cette question. Un problème se pose néanmoins immédiatement : si on stocke les adresses de tab, tab1 et tab2 dans par exemple %eax, %ecx et %edx, comment manipuler les valeurs contenues dans le tableau vu qu'il ne nous reste plus de registre disponible ? La solution consiste à passer par la case mémoire sav présente dans le squelette fourni et dont on vous laisse trouver l'utilité.

Tester le programme sur des tableaux de différentes tailles et avec différents contenus. De la même façon que pour les chaines de caractères de l'exercice précédent, on pourra afficher le contenu des tableaux en deux temps : d'abord récupérer l'adresse du tableau voulu en affichant le contenu du registre contenant cette adresse (par exemple i r eax qui afficherait 0x1234 comme adresse de tab), puis en exécutant x /11u 0x1234 pour afficher 11 entiers non-signés (11u) à partir de l'adresse 0x1234. Evidemment, si vous modifiez les valeurs des registres dans la boucle, il faut noter les adresses initiales des tableaux pour afficher leurs contenus !

Récupérée de « http://ensiwiki.ensimag.fr/index.php/LdB_Seance_7 »
Catégories : Assembleur | Première Année | Informatique | Logiciel de Base
Affichages
  • Page
  • Discussion
  • Voir le texte source
  • Historique
Outils personnels
  •  
  • Connexion
Actualité
  • Soutenances de PFE
  • Projet système
  • Projets spécialité
  • Lexique franco-anglais
  • Stage Unix de rentrée
  • Projet C
  • Plannings des stages
Navigation
Logo Ensimag
  • Accueil
  • FAQ
  • Mode d'emploi
  • Droit d'auteur
  • Modifications récentes
  • Page au hasard
Boîte à outils
  • Pages liées
  • Suivi des pages liées
  • Pages spéciales
  • Version imprimable
  • Lien historique
  • Principaux contributeurs
Powered by MediaWiki
Attribution-Share Alike 3.0 Unported
  • Dernière modification de cette page le 29 avril 2010 à 07:31.
  • Cette page a été consultée 915 fois.
  • Contenu disponible sous Attribution-Share Alike 3.0 Unported.
  • Politique de confidentialité
  • À propos de Ensiwiki
  • Avertissements