User Tools

Site Tools


archi:index

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
archi:index [2016/02/13 06:51] – [Les tableaux] orelarchi:index [2019/09/09 19:20] – [Architecture des Ordinateurs] orel
Line 1: Line 1:
 ====== Architecture des Ordinateurs ====== ====== Architecture des Ordinateurs ======
  
 +  * __Supports__ : http://dept-info.labri.fr/ENSEIGNEMENT/archi/
 +  * __UE__ : 4TIN304U (6ECTS)
  
-__Supports__ : http://dept-info.labri.fr/ENSEIGNEMENT/archi/ +====Quelques Notes de TD====
- +
- +
-__ Emploi du Temps__ : [[ http://www.disvu.u-bordeaux1.fr/et/edt_etudiants2/SemCombi/Licence/Semestre2/g109220.html | Groupe A3]] +
- +
-===== Assembleur y86 ===== +
- +
-y86 est un langage assembleur simplifié basé sur l'architecture des processeurs x86 (IA-32). Les mots mémoires sont alignés sur 32 bits et utilise la convention //little endian//.  +
- +
-Le y86 utilise 8 registres généraux de 32 bits, dont certains ont des rôles historiques. +
-  * %eax : le registre d'accummulation  +
-  * %ecx : le registre de compteur utilisé dans les boucles +
-  * %edx : un registre auxiliaire +
-  * %ebx : le registre //base index// utilisé comme pointeur sur la base d'un tableau +
-  * %esp : le registre //stack pointer// qui pointe sur le sommet du cadre d'appel de la fonction courante, c''est-à-dire le sommet de la pile +
-  * %ebp : le registre //frame base pointer// qui pointe la base du cadre d'appel de la fonction courante +
-  * %esi : le registre //source index// utilisé lors des copies de suite d'octets +
-  * %edi : le registre //destination index// utilisé lors des copies de suite d'octets +
- +
-En outre, le registre %eip (//instruction pointer//) pointe sur l'adresse de la prochaîne instruction à exécuter. Ce registre est modifié automatiquement à chaque exécution et peut être manipulé par des instruction du type jmp, call, ret. +
- +
-==== If then ==== +
- +
-Pour effectuer un branchement conditionnel qui dépend d'un test entre deux registres %eax et %ebx, on commence typiquement à comparer ces deux registres par soustraction, ce qui a pour effet de modifier les //codes de condition// (Z pour zéro, O pour overflow et S pour strictement négatif). Il suffit alors d'effectuer le branchement approprié //jle, jl, je, jne, jge, jg// (l = lower, g = greater, e = equal). +
- +
-<code c> +
-long a = 2, b = 3, c; +
-if (a < b) c = 1; +
-</code> +
- +
-<code - ifthen.ys> +
-        .pos 0 +
- mrmovl a,%eax +
- mrmovl b,%ebx +
- subl %ebx,%eax        # on calcule a-b (dans ce sens) +
- jge endif # on teste la condition de sortie : a-b >= 0 ? +
-then: irmovl 1,%ecx +
- rmmovl %ecx,c # c = 1 +
-endif: halt +
- +
-        .pos 0x100 +
-a:      .long 2 +
-b:      .long 3 +
-c:      .long 0   +
-</code> +
- +
-__Astuce__ : L'instruction //subl// modifie la registre cible, ce qui présente un inconvénient. Dans le cas où l'on souhaite tester si un registre %eax est égal à zéro (ou non) avec //je// (ou //jne//), une astuce consiste à effectuer l'opération //andl %eax,%eax// ;-) +
- +
-==== If then Else ==== +
- +
-<code c> +
-long a = 2, b = 3, c; +
-if (b <= a) c = 1; else c = 2; +
-</code> +
- +
-<code - ifthenelse.ys> +
-        .pos 0 +
- mrmovl a,%eax +
- mrmovl b,%ebx +
- subl %eax,%ebx        # on calcule b-a (dans ce sens) +
- jg else         # on teste la condition du else : b-a > 0 ? +
-then: irmovl 1,%ecx +
- rmmovl %ecx,c # c = 1 +
-        jmp endif +
-else:   irmovl 2,%ecx +
-        rmmovl %ecx,c # c = 2 +
-endif: halt +
- +
-        .pos 0x100 +
-a:      .long 2 +
-b:      .long 3 +
-c:      .long 0   +
-</code> +
- +
- +
-==== Boucle For ==== +
- +
-<code c> +
-long sum = 0; +
-for(i = 1 ; i <= 10 ; i++) sum += i; +
-</code> +
- +
-<code - sum.ys> +
- .pos 0 +
- mrmovl sum,%edx # %edx: sum +
- irmovl 1,%eax # %eax: i = 1 +
- +
-loop:   rrmovl %eax,%ebx +
- isubl 10,%ebx # on calcule i-10 +
- jg end                  # condition arrêt si i-10 > 0 +
- addl %eax,%edx # sum += i +
- iaddl 1,%eax # i++ +
- jmp loop  +
-end: rmmovl %edx,sum +
- halt +
- +
- .pos 0x100 +
-sum: .long 0 +
-</code> +
- +
- +
-__Note Bene__ : On peut un peu simplifier ce code en parcourant la boucle à l'envers... la comparaison à zéro est toujours plus facile à écrire ;-) +
- +
-==== Pointeurs ==== +
- +
- +
-<code c> +
-long a = 1, b = 0; +
-long * p = &a; +
-b = *p;              /* b = 1 */ +
-*p = 2;              /* a = 2 */ +
-</code> +
- +
-Dans le code suivant, on utilisera le registre %esi pour désigner le pointeur p. +
- +
-<code> +
-        irmovl a,%esi           # p = &a +
-        mrmovl (%esi),%eax      # b = *p +
-        rmmovl %eax,           +
- irmovl 2,%eax # *p = 2 +
-        rmmovl %eax,(%esi) +
- +
-        .pos 0x100 +
-a:      .long 1  +
-b:      .long 0 +
-</code> +
- +
-==== Les tableaux ==== +
- +
-On rappelle que l'étiquette //t// représente une //adresse immédiate//. La notation //(%ebx)// désigne //l'adresse indirecte// en mémoire pointée par le registre //%ebx//. La notation //4(%ebx)// correspond à l'adresse //(%ebx)+4//. Notons qu'un //long// compte pour 4 octets. +
- +
-<code> +
- irmovl t,%ebx           # l'adresse t est mis dans %ebx, qui joue le rôle de pointeur +
-        mrmovl (%ebx),%eax      # load: %eax = t[0] +
-        ... +
-        rmmovl %ecx,(%ebx)      # t[0] <- %ecx +
-        rmmovl %ecx,4(%ebx)     # t[1] <- %ecx        +
- +
- .pos 0x100 +
-t: .long 1                 # tableau t d'adresse 0x100 et de taille 4 long +
- .long 2 +
- .long 3 +
- .long 4 +
-</code> +
- +
-//expliquer la variante d'adressage indexé : t(%eax)// +
- +
-==== Décalage des valeurs dans un tableau ==== +
- +
-<code c> +
-for(i = 0 ; i < n-1; i++)  +
-  t[i] = t[i+1]; +
-</code> +
- +
-<code - decalage.ys> +
- .pos 0 +
- +
- mrmovl n,%ecx +
- irmovl t,%ebx  +
-  +
-loop: isubl 1,%ecx # n-- +
- je end +
- mrmovl 4(%ebx),%eax # t[0] <- t[1] +
- rmmovl %eax,(%ebx)  +
- iaddl 4,%ebx # t += 4  +
- jmp loop +
- +
-end: halt +
- +
- .pos 0x100 +
-n: .long 5 +
-t: .long 1 +
- .long 2 +
- .long 3 +
- .long 4 +
- .long 5 +
-</code>  +
- +
- +
-==== Appel de fonction et Pile ==== +
- +
-<code c> +
-long f(long i, long j) { return (i+j); } +
-long a = f(1,2); +
-</code> +
- +
- +
-<code - function.ys> +
-        .pos 0 +
- irmovl stack,%esp       # initialisation du pointeur de pile (stack pointer) +
-        jmp main +
- +
-f:      mrmovl 4(%esp),%eax     # on récupère le premier paramètre (a) +
-        mrmovl 8(%esp),%ecx     # on récupère le second paramètre (b) +
-        addl %ecx,%eax          # variable de retour dans %eax +
-        ret +
- +
-main:   mrmovl b,%eax           # on empile les paramètres en sens inverse +
-        pushl %eax +
-        mrmovl a,%eax +
-        pushl %eax +
-        call f                  # appel de la fonction f() +
-aret:   popl %ecx               # on dépile les 2 paramètres avec popl +
-        popl %ecx               # ou iaddl 8,%esp +
-        rmmovl %eax,res   +
-        halt          +
- +
-        .pos 0x100 +
-a:      .long 1 +
-b:      .long 2 +
-res:    .long 0 +
- +
- .pos 0x200              # adresse de base de la pile +
-stack:                          +
- +
-</code> +
- +
- +
-Tout d'abord, il faut noter que la pile stocke les données dans l'ordre décroissant des adresses mémoire, à partir de l'adresse //stack// (0x200) vers la zone des variables (0x100) ! Le registre //%esp// est le pointeur de pile (ou //stack pointer//) qui désigne le sommet de la pile à l'adresse //(%esp)//+
- +
- +
-Avant l'appel de fonction //f()//, on commençe par empiler ces paramètres avec //pushl// dans l'ordre inverse ! Au moment de l'appel de fonction avec l'instruction //call//, l'adresse de retour de la fonction (notée //aret//) est automatiquement empilée et se trouve donc au sommet de la pile. Le retour de fonction avec l'instruction //ret// dépile automatiquement cette adresse et fait sauter le programme sur //aret//. Il faut encore dépiler les paramètres avec //popl// ou en ajoutant explicitement à //%esp// la taille nécessaire (2 long ici, soit 8 octets). +
- +
-Par convention, on place la valeur de retour de la fonction dans le registre //%eax//. +
- +
-__Nota Bene__ : Il ne faut pas oublier d'initialiser la pile au départ du programme ! A la fin du programme, on peut vérifier que %esp est revenu à sa valeur initiale //stack//+
- +
-==== Sauvegarde des registres lors d'un appel de fonction ===== +
- +
-Lors d'un appel de fonction, certains registres utilisés par l'appelant peuvent être modifié par l'appelé ! Il convient donc de les sauvegarder sur la pile. En principe, on distingue deux types de registres : +
-  * les registres //caller-saved// (%eax, %ecx, %edx) qui doivent être sauvegardés par l'appellant si nécessaire ; +
-  * les registres //callee-saved// (%ebx, %esi, %edi, %ebp), qui doivent être sauvegardés par l'appelé. +
- +
-<code - > +
- +
- +
-main:   # sauvegarde des registres caller +
-        pushl %eax               +
-        pushl %ecx               +
-        pushl %edx                       +
-        # empilement des paramètres de f +
-        ... +
-        call f +
-        # dépilement des paramètres de f +
-        ... +
-        # restauration des registres caller +
-        popl %edx                +
-        popl %ecx +
-        popl %eax +
-        halt                 +
- +
-f:      # récupération des paramètres +
-        ... +
-        # sauvegarde des registres callee +
-        pushl %ebp               +
-        pushl %esi +
-        pushl %edi +
-        pushl %ebx +
-        ... +
-        ... +
-        ... +
-        # restauration des registres callee +
-        popl %ebx                +
-        popl %edi +
-        popl %esi         +
-        popl %ebp         +
-        ret +
- +
-</code> +
- +
-__Nota Bene__ : En pratique, on sauvegardera uniquement les registres utiles pour éviter d'allourdir le code. Attention à la modification de %esp ! +
- +
-==== Appel de fonction avec des variables locales ==== +
- +
-Les variables locales sont définies dans la pile après l'adresse de retour. On accède donc aux variables à partir de (%esp), mais du coup les paramètres sont décalés ! Le code de la fonction précédente est modifié pour utiliser une variable locale ! +
- +
- +
-<code - funcloc.ys>  +
-        .pos 0 +
-main: irmovl stack,%esp       # initialisation du pointeur de pile (stack pointer) +
-        mrmovl b,%eax           # on empile le second param b +
-        pushl %eax +
-        mrmovl a,%eax # on empile le premier param a +
-        pushl %eax +
-        call f                  # appel de la fonction f() +
-aret:   popl %ecx               # on depile le premier param +
-        popl %ecx               # on depile le second param +
-        rmmovl %eax,res         # recup resultat +
- halt +
- +
-f:      isubl 4,%esp # alloc variable locale x sur la pile +
- mrmovl 8(%esp),%eax     # recup premier param a +
-        mrmovl 12(%esp),%ebx    # recup second param b +
-        ...                     # compute x +
- mrmovl (%esp),%ecx # load x +
-        pushl %ecx              # save x +
-        ...                     # do something else +
- mrmovl (%esp),%eax      # restore x (variable de retour dans %eax) +
- iaddl 4,%esp # liberation variable locale x +
-        ret +
-  +
-        .pos 0x100 +
-a: .long 1 +
-b: .long 1 +
-res:    .long 0         +
- +
- .pos 0x200 # adresse de base de la pile +
-stack:                          +
-</code> +
- +
-__Nota Bene__ : Dans un soucis de simplification, il est choisi ici (et plus tard) de ne pas utiliser le registre %ebp ! +
- +
- +
-====Passage par référence dans les fonctions ==== +
- +
-Dans les exemples précédent de fonction, nous avons utiliser le //passage de paramètres par valleur//+
-Ici, nous donnons l'exemple d'une fonction //swap(&a,&b)// qui utilise le //passage par référence//. Il s'agit d'échanger les valeurs de deux entiers. +
- +
- +
-<code - swap.ys> +
- .pos 0 +
-main: irmovl stack,%esp # init de la pile  +
- irmovl b,%eax  +
- pushl %eax # empiler &b +
- irmovl a,%eax +
- pushl %eax # empiler &a +
- call swap +
- iaddl 8,%esp # depiler +
- halt +
- +
-swap: mrmovl 4(%esp),%eax # param pa=&a +
- mrmovl 8(%esp),%ebx # param pb=&b +
- mrmovl (%eax),%ecx # valeur a=*pa +
- mrmovl (%ebx),%edx # valeur b=*pb +
- rmmovl %ecx,(%ebx) # swap *pb = a  +
- rmmovl %edx,(%eax) # swap *pa = b  +
- ret +
-  +
- .pos 0x100 +
-a: .long 1 +
-b: .long 2 +
- +
- .pos 0x200 +
-stack:  +
-</code> +
- +
-==== Fonction manipulant un tableau ==== +
- +
-//todo// +
- +
-==== Appel récursif de fonction ==== +
- +
-<code c> +
-f(n) { if(n == 0) return 0 ; else return (f(n-1)+n) ; } +
-main() { res = f(10); } +
-</code> +
- +
-<code - recursif.ys> +
- .pos 0 +
-main: irmovl stack,%esp +
- mrmovl n,%eax +
- pushl %eax # empiler param n +
- call f +
- iaddl 4,%esp # depiler param +
- rmmovl %eax,res # resultat dans %eax +
- halt +
- +
-f: mrmovl 4(%esp),%ecx # param n +
- andl %ecx,%ecx # eval condition code +
- je f0 # si n = 0 ? +
-fn: isubl 1,%ecx # n-1 +
- pushl %ecx # empiler param n-1 +
- call f # retour dans %eax +
- iaddl 4,%esp # depiler param +
- mrmovl 4(%esp),%ecx # restore param n  +
- addl %ecx,%eax # retour dans %eax = n + f(n-1) +
- ret +
-f0: irmovl 0,%eax  +
- ret # valeur de retour dans %eax +
-  +
- +
-end: halt +
- +
- .pos 0x100 +
-n: .long 10 +
-res: .long 0 # res = 55 = 0x37 +
- +
- +
- .pos 0x200 +
-stack:  +
-</code>  +
- +
- +
-==== Structure Liste Chaînée ==== +
- +
-<code c> +
-struct list {  +
-  long x; +
-  struct list * next; +
-}; +
- +
-long length(struct list * l) { +
-  long n = 0; +
-  while(l) { n++; l = l->next; } +
-  return n; +
-+
-</code> +
- +
-<code - linkedlist.ys> +
-main:   .pos 0 +
-        irmovl stack,%esp +
-        irmovl l1,%eax +
-        pushl %eax +
-        call length             # retour dans %eax +
-        iaddl 4,%esp +
-        halt +
- +
-length: mrmovl 4(%esp),%esi     # param l +
-        xorl %eax,%eax          # n = 0 +
-loop:   andl %esi,%esi          # test si l est NULL ? +
-        je end +
-        iaddl 1,%eax            # n++ +
-        mrmovl 4(%esi),%esi     # l l->next +
-        jmp loop +
-end:    ret                     # retour n dans eax         +
- +
-        .pos 0x100              # linked list  +
-l1:     .long 1                  +
-        .long l2                # next l2 +
-l2:     .long 2 +
-        .long l3                # next l1 +
-l3:     .long 3 +
-        .long 0                 # next NULL                 +
-        .pos 0x200 +
-stack: +
-</code>+
  
 +  * [[archi:y86 | Assembleur y86]]
 +  * [[archi:x86 | Un peu de x86]]
 +  * [[archi:circuit | Circuits Combinatoires & Séquentiels]]
 +  * [[archi:proc | Processeur Complet]]
  
archi/index.txt · Last modified: 2024/03/18 15:06 by 127.0.0.1