Pour commencer, il faut créer un fichier source du langage d’assemblage
avec un éditeur de texte soit directement sur le raspberry avec l’éditeur nano
(ou un autre éditeur plus perfectionné) soit sur un autre ordinateur (par
exemple avec notepad++ sur un PC) puis le transférer sur le raspberry.
Si vous utilisez notepad++ il faudra ajouter la coloration syntaxique
pour l’assembleur ARM qui n’est pas disponible par défaut. Mais l’avantage de
notepad++ est de pouvoir transférer directement le source sur le raspberry avec
le menu NppFtp.
Le source crée est à sauvegarder avec l’extension de nom .s
Pour la compilation sur le raspberry, il faut utiliser le compilateur as
en tapant la commande :
as –o nomduprogramme.o nomduprogramme.s
Pour l’édition de lien, il faut utiliser ld avec la commande :
ld –o nomduprogramme nomduprogramme.o
Les 2 outils as et ld sont disponibles en standard dans la version
raspbian du raspberry.
Il est préférable d’écrire un script qui effectue les 2 opérations à
partir du seul nom de programme par
exemple :
#compilation assembleur
#echo $0,$1
echo "Compilation de "$1".s"
as -o $1".o" $1".s" -a >$1".txt"
ld -o $1 $1".o" -e main
ls -l $1*
echo "Fin de compilation."
Si ce script s’appelle compilasm, il suffira de le lancer par :
compilasm nomduprogramme
pour effectuer la compilation et l’édition de liens.
Et pour l’exécution
(si aucune erreur n’a été détectée) il suffit de taper nomduprogramme.
Pour tester ces outils et scripts, il vous faudra saisir (ou copier-coller) le petit
programme suivant qui affiche le « Bonjour le monde » classique. Évidement si vous êtes débutant, ce code vous paraitra obscur mais cela est le paradoxe de l'assembleur, car pour afficher un simple message, il est nécessaire d'avoir des connaissances qui ne seront acquises que petit à petit.
/* ARM assembleur Raspberry PI 32 bits */
/* program pgm1.s */
/* Données initialisées */
.data
szMessage: .asciz "Pgm1 : Bonjour le monde. \n" @ message
/* Code du programme */
.text
.global main
main:
ldr r0,iAdrszMessage @ adresse du message
bl affichageMess @ appel fonction d'affichage
/* fin du programme */
mov r0, #0 @ code retour OK
mov r7, #1 @ code fin LINUX
svc 0 @ appel système LINUX
iAdrszMessage: .int szMessage
/******************************************************************/
/* affichage des messages avec calcul longueur */
/******************************************************************/
/* r0 contient l adresse du message */
affichageMess:
push {r0,r1,r2,r7,lr} @ save des registres
mov r2,#0 @ compteur longueur
1: @ calcul de la longueur
ldrb r1,[r0,r2] @ recup octet position debut + indice
cmp r1,#0 @ si 0 c est fini
beq 2f
add r2,r2,#1 @ @ sinon on ajoute 1
b 1b
2: @ donc ici r2 contient la longueur du message
mov r1,r0 @ adresse du message en r1
mov r0,#1 @ code pour écrire sur la sortie standard Linux */
mov r7,#4 @ code de l appel systeme 'write'
svc #0 @ appel systeme Linux
pop {r0,r1,r2,r7,lr} @ restaur des registres
bx lr @ retour procedure
Il faut sauvegarder ce programme sous le nom pgm1.s puis le compiler et linker avec les commandes ou le script précédents.
Après correction des erreurs de frappe éventuelles, l’exécution s'effectuera en tapant simplement pgm1
Tant que vous n'avez pas obtenu un résultat, il faut vérifier et corriger chacune des étapes. Si tout est OK, je vous demande saisir (ou de copier coller) ce deuxième programme (pgm2.s) qui nous permettra d'afficher le contenu d'un registre et qui va nous servir dans la suite de ce cours :
Par la suite, il vous suffira de modifier et/ou d'ajouter des instructions comprises entre
les lignes :
Tant que vous n'avez pas obtenu un résultat, il faut vérifier et corriger chacune des étapes. Si tout est OK, je vous demande saisir (ou de copier coller) ce deuxième programme (pgm2.s) qui nous permettra d'afficher le contenu d'un registre et qui va nous servir dans la suite de ce cours :
/* ARM assembleur Raspberry PI 32 bits */
/* program pgm1.s */
/* Données initialisées */
.data
szMessDebut: .asciz "Début programme. \n" @ message debut
szMessFin : .asciz "Fin programme OK. \n" @ message fin
sMessAffBin: .ascii "Valeur du registre : "
sZonemess: .space 36,' '
.asciz "\n"
/* Code du programme */
.text
.global main
main:
ldr r0,iAdrszMessDebut @ adresse du message
bl affichageMess @ appel fonction d'affichage
/***********DEBUT*********/
mov r0,#1
bl affichageReg2
/***********FIN************/
/* fin du programme */
ldr r0,iAdrszMessFin @ adresse du message
bl affichageMess @ appel fonction d'affichage
mov r0, #0 @ code retour OK
mov r7, #1 @ code fin LINUX
svc 0 @ appel système LINUX
iAdrszMessDebut: .int szMessDebut
iAdrszMessFin: .int szMessFin
/******************************************************************/
/* affichage des messages avec calcul longueur */
/******************************************************************/
/* r0 contient l adresse du message */
affichageMess:
push {r0,r1,r2,r7,lr} @ save des registres
mov r2,#0 @ compteur longueur
1: @ calcul de la longueur
ldrb r1,[r0,r2] @ recup octet position debut + indice
cmp r1,#0 @ si 0 c est fini
beq 2f
add r2,r2,#1 @ sinon on ajoute 1
b 1b
2: @ donc ici r2 contient la longueur du message
mov r1,r0 @ adresse du message en r1
mov r0,#1 @ code pour écrire sur la sortie standard Linux
mov r7,#4 @ code de l appel systeme 'write'
swi #0 @ appel systeme
pop {r0,r1,r2,r7,lr} @ restaur des registres
bx lr @ retour procedure
/******************************************************************/
/* affichage registre en binaire */
/******************************************************************/
/* r0 contient le registre */
affichageReg2:
push {r0-r5,lr} @ sauvegarde des registres
mrs r5,cpsr @ save du registre d'état dans r5
ldr r1,iAdrsZonemess @ chargement adresse zone reception message
mov r2,#0 @ compteur du nombre de bits traités
mov r3,#0 @ compteur de position des caractères à afficher
1:
lsls r0,#1 @ décalage à gauche des bits avec positionnement des flags
movcc r4,#48 @ si le bit le plus à gauche (et passé dans le carry) = 0
movcs r4,#49 @ s'il est egal à 1
strb r4,[r1,r3] @ on stocke le caractère code 48 (0) ou 49 (1) dans le message
add r2,r2,#1 @ passage au bit suivant
add r3,r3,#1 @ position du caractère suivante
cmp r2,#8 @ si 8 bits traités, on laisse un blanc
addeq r3,r3,#1
cmp r2,#16 @ si 16 bits traités, on laisse un blanc
addeq r3,r3,#1
cmp r2,#24 @ si 24 bits traités, on laisse un blanc
addeq r3,r3,#1
cmp r2,#31 @ restent des bits ?
ble 1b @ oui on boucle
ldr r0,iAdrsZonemessbin @ et affichage du message
bl affichageMess
100:
msr cpsr,r5 @ restaur registre d'état
pop {r0-r5,lr} @ restaur des registres
bx lr
iAdrsZonemess: .int sZonemess
iAdrsZonemessbin: .int sMessAffBin
Par la suite, il vous suffira de modifier et/ou d'ajouter des instructions comprises entre
les lignes :
/***********DEBUT*********/
/***********FIN************/
Documentation sur as :
https://web.eecs.umich.edu/~prabal/teaching/resources/eecs373/Assembler.pdf
et sur ld :
http://man7.org/linux/man-pages/man1/ld.1.html
Documentation sur as :
https://web.eecs.umich.edu/~prabal/teaching/resources/eecs373/Assembler.pdf
et sur ld :
http://man7.org/linux/man-pages/man1/ld.1.html
Aucun commentaire:
Enregistrer un commentaire