mercredi 20 février 2019

Chapitre 55 : Accès à une base de donnée mariadb (ou mysql) en assembleur.


Pour cela, il faut d’abord avoir mis en place une base de données de ce type sur le Raspberry. Pour cela je vous renvoie à la nombreuse documentation disponible sur internet. Sur mon système, j’ai mis en place la base de donnée mariaDb à l’aide du package mariadb-server. Ensuite j’ai crée une base testvinc et une table département avec 2 champs, le N° du département et le nom du département. Pour ces premiers tests, je n’ai crée que 2 enregistrements dans la table. J’ai crée aussi un nouvel utilisateur pgmasm avec des droits réduits sur l’accès à la base testvinc. Pour être sûr que tout est ok, il faut mieux déjà vérifier par la commande mysql, que ce nouvel utilisateur peut bien afficher le contenu de la table (et éventuellement la modifier). Cela peut vous éviter des recherches inutiles lors de l’exécution du programme assembleur. Par exemple dans mon cas, le programme n’affichait pas la table et je n’avais pas fait cette vérification. Ce n’est qu’après en vérifiant par mysql, que j’avais créé la table dans la base mysql et pas dans ma base testvinc (Voui, il faut penser à changer de base par use testvinc avant de créer une table !!!).

Pour créer l’exécutable et faire fonctionner ce programme, il faut faire appel à des librairies de mariadb que l’on obtient en installant les packages supplémentaires :  libmariadbd-dev et libmariadbclient-dev. Pour vérifier et connaitre les options à ajouter au linker il suffit de taper la commande mysql_config --cflags –libs .
Sur mon système, celle-ci a retourné les 2 lignes :
-I/usr/include/mysql
-L/usr/lib/arm-linux-gnueabihf  -lmariadbclient -lpthread -lz -lm –ldl
La directive include ne nous concerne pas (concerne le C) et nous ajoutons les autres directives à gcc qui ici nous sert de linker après la compilation du programme assembleur.
La documentation des fonctions mysql peut être trouvée ici (mais en anglais) :
https://dev.mysql.com/doc/refman/8.0/en/c-api.html

Dans le programme assembleur (voir le source ici) nous commençons à initialiser les structures de mariadb par l’appel de la fonction mysql_init et nous testons le code retour.
Puis nous établissons une connexion à la base crée précédemment avec l’identifiant utilisateur crée et son mot de passe par l’appel de la fonction bl mysql_real_connect. Vous remarquerez que cette fonction a besoin de 8 paramètres dont les 4 premiers sont passés par les registres r0 à r3 et les autres par la pile dans l’ordre inverse de celui attendu par la procédure. Rappelez vous pour cela les premiers chapitres de ce blog ou les appels des fonctions X11 !! Et au retour de la procédure il faut penser à réaligner la pile avec l’instruction add sp,#16  (4 paramètres de 4 octets chacun !!). Puis il faut tester le code retour pour vérifier la bonne connexion. En cas d’erreur il faut revérifier votre saisie du nom de la base, du nom utilisateur et du mot de passe et l’ordre des paramètres.

Puis nous lançons une requête qui est contenue en totalité dans une chaîne de caractères et dont nous passons l’adresse à la fonction mysql_query par le registre r1. Le registre r0 contient le pointeur vers les structures mariadb. Comme ce pointeur va être très utilisé nous le conservons dans le registre r10. Remarque : la requête ne doit se terminer par le point virgule comme dans les commandes directes sous Mysql.
Nous récupérons le set des résultats par l’appel de la fonction mysql_store_result mais nous pouvons aussi utiliser mysql_use_result mais qui offre moins de possibilité. Après le test du code retour, nous conversons le pointeur du set de résultat dans r9, et nous utilisons la fonction mysql_fetch_field qui va nous donner l’adresse des données du premier champ. Nous affichons les noms des premières données à savoir le nom du champ (ou son alias) le nom du champ d’origine, le nom de la table (ou son alias) le nom de la table d’origine et le nom de la base utilisée. Nous refaisons un nouvel appel à cette fonction pour avoir les données du 2 ième champ.

Maintenant, nous allons afficher tous les champs de toutes les rangées de la base. D’abord nous récupérons le nombre de champ de chaque rangée par la fonction mysql_num_fields. Puis nous balayons chaque rangée par appel successif de la fonction mysql_fetch_row qui retourne l’adresse de chaque rangée ou zéro quand il n’y a plus de rangée. Avec l’adresse de chaque rangée, nous balayons les pointeurs de chaque champ pour afficher leurs valeurs.
Rien de bien compliqué !! En fin nous libérons les ressources du résultat et nous fermons la base de données utilisée.

Ce premier programme nous permet de voir l’utilisation de ces fonctions de base. Dans le deuxième programme, nous allons effectuer des mises à jour de notre base. Mais tout d’abord, j’ai récupéré la description de la structure des données des champs et je l’ai adapté au langage assembleur. Nous voyons que en plus des noms, nous pouvons récupérer le type de chaque champ et sa longueur. Cela permet d’envisager de nombreuses possibilité d’utilisation.
Ce deuxième programme contient une boucle de saisie du code département, du nom et de leur insertion dans la base. Après la saisie du code, nous vérifions que celui-ci n’est pas déjà connu dans la base. Remarque : comme nous l’avons déjà vu, l’appel au call system de lecture de Linux retourne une chaine de caractère avec un 0x0A final qu’il nous faut transformer en 0X00 final.

Nous concaténons le code saisi au début de la requête sous forme de chaine de caractère. Si le code est Ok, nous demandons la saisie du nom puis nous créons la requête de mise à jour, en concaténant tous les éléments. Nous vérifions la bonne exécution de la mise à jour puis nous bouclons sur une autre saisie jusqu’à la saisie du code 999 qui terminera la saisie.
Nous terminons par l’affichage complet de la base comme vu dans le programme précédant.

Il ne reste plus qu’à regarder toutes les autres fonctions et à les expérimenter !!

lundi 4 février 2019

Chapitre 54 : Calcul sur des nombres entiers doubles


Après tous ces chapitres sur le développement en assembleur sans OS, nous revenons à des exemples de programmes avec Linux. Dans ce chapitre nous allons voir des routines de calcul sur des nombres entiers doubles qui sont codés sur 64 bits soit 8 octets ce qui permet de traiter des entiers jusqu’à 2<<63 – 1 soit : 9223372036854775807 en non signé et +4611686018427387903 en signé.
Pour cela nous commençons par déclarer plusieurs nombres positifs et négatifs avec la pseudo instruction .quad. et nous réservons dans la .bbs des zones de 8 octets pour stocker des résultats intermédiaires.
Source du programme ici .
Dans le code, nous commençons par afficher par la macro habituelle les zones mémoires pour voir le stockage des doubles : La partie basse est dans les 4 premiers octets, la partie haute dans les 4 suivants.
Pour vérifier les calculs suivants, il nous faut commencer par afficher correctement un double et première difficulté il nous faut écrire une routine qui divise un double contenu dans 2 registres par 10. C’est le rôle des routines conversionDoubleU et divisionReg64U. Puis il nous faut aussi écrire les routines pour afficher des doubles signés : conversionDoubleS et divisionReg64S. Les divisions utilisent un algorithme classique de division binaire et ne divisent un double que par une valeur contenue dans un seul registre.
Pour lire un double ou stocker un double en mémoire, nous disposons de l’instruction ldrd r0,r1,[r2] et de l’instruction strd r0,r1,[r2] avec bien sûr r2 contenant l’adresse mémoire du double, r0 la partie basse et r1 la partie haute. Nous pouvons utiliser d’autres registres en condition que le premier soit pair et que le second soit le suivant (il y a une erreur de compilation pour r5,r8,[r2] par exemple !!).
Ensuite nous écrivons une routine de saisie d’un double à partir de la lecture d’une chaine de caractère à l’aide du système call READ. La conversion de la chaine stocke le double dans une zone en mémoire après avoir vérifié le dépassement de capacité éventuel.
Les autres routines correspondent à la division, addition soustraction multiplication signés et non signés de 2 nombres de 64 bits. Certaines routines utilisent les doubles stockés en mémoire et d’autres dans les registres. La difficulté est de penser à traiter les 2 registres qui contiennent le double et à bien reporter les retenues éventuelles. Il faut aussi veiller à bien utiliser les codes des comparaisons suivant que les nombres traités sont signées ou non. Par exemple pour la partie basse, il faut utiliser les codes hi (> non signé) lo (< non signé) et pour les parties hautes gt ou lt.
Enfin le programme se termine par une extraction de racine carrée entière par la méthode de héron et par des routines de comparaisons.
Il ne vous reste plus qu’à écrire les routines manquantes et d’optimiser celles qui sont dans ce programme !!
Ah j’oubliais, dans le fichier des macros, j’ai ajouté une macro qui affiche un simple libellé dans la console. Cela permet un petit gain de temps pour incluse un libellé entre les différents tests des routines.