lundi 20 janvier 2020

Chapitre 79 : Assembleur Arm 64 : lecture d’une page d’un site Web.


Au chapitre 56, nous avons vu l’utilisation des sockets en 32 bits pour accéder à une page sur Internet. A l’aide des tests des fonctions système du chapitre précédent, nous allons voir la même utilisation en 64 bits.
Dans le programme rechMeteo64.s, nous lançons un thread pour exécuter la commande Linux ping pour récupérer l’adresse IP du site de méteoFrance. En effet, dans le container 64 bits de la version Buster que j’utilise, la commande Linux host n’existe pas, j’ai donc du utiliser la commande ping pour récupérer l’adresse.
Comme nous l’avons vu au chapitre précedent l’execution de la commande au travers de execve, ne retourne pas dans le programme appelant. Il nous faut donc dupliquer la sortie Sysout vers un fichier tampon à l’aide des appels system pipe (code 59) et dup3(code 24). Ce qui nous permet de récuperer l’adresse IP dans un buffer et de la convertir pour créer la socket.
Comme en 32 bits, dans la routine envoiRequeteP80 nous ouvrons la socket (code 198) créons la connexion avec le site (code 203) envoyons la requête de lecture (code 206) après avoir calculé sa longueur puis lu la réponse avec le code 207. La lecture s’effectue dans une boucle pour récuperer tout le contenu de la page.

Vous remarquerez que l'utilisation des instructions cinc et csel permettent de résoudre le remplacement des instructions conditionnelles du type incne ou moveq.
 
Le reste du programme concerne l’analyse et l’extraction des données qui nous intéressent.
Attention, ce programme ne concerne que les pages des sites accessibles en http. Pour les sites accessibles en https, il faudra utiliser la librairie openSSL comme je l’avais fait en 32 bits.

dimanche 19 janvier 2020

Chapitre 78 : assembleur ARM 64 bits : lancement d'un thread. Exécution d'une commande Unix


Je repars du programme assembleur 32 bits vu au chapitre 20 pour l’adapter à l’assembleur 64 bits. (source du programme).
Après les modifications des registres, des accès à la pile il ne reste plus qu’à trouver les codes des appels système en en 64 bits. Hélas l’appel fork ne semble pas exister en 64 bits et donc je modifie le programme pour utiliser l’appel clone.
Ces modifications refusant de fonctionner, j’effectue des recherches sur internet pour trouver la source de mon erreur. En fait, les paramètres de la fonction clone sont identiques à la fonction fork du 32 bits et donc ne correspondent pas à la première description que j’avais trouvée. En effet la documentation des appels système en 64 bits n’est pas très disponible.

J’adapte aussi les appels système pour les fonctions sleep et wait4 sans problème. Par contre je ne trouve pas de fonction pause en 64 bits.
Après recherche sur internet je trouve une solution en utilisant les appels système rt_sigprocmask et rt_sigsuspend.

Tout fonctionne parfaitement après quelques tests !!


Puis, j’ai réécrit un programme pour tester l’exécution d’une commande Linux en utilisant l’appel system execve. Pour cela je me suis contenté de lancer la commande ls –l mais vous trouverez en commentaire la chaine de caractères pour lancer une commande ping.
Ici la seule difficulté est de passer correctement les paramètres à l’appel systeme qui est un peu différent de l’appel 32 bits.
 Comme en 32 bits, vous remarquerez que l’exécution correcte de la commande interrompt le programme appelant.

mercredi 8 janvier 2020

Chapitre 77 : Assembleur ARM 64 bits : calculs en virgule flottante (instructions Float)


Je commence l’année par découvrir les instructions de calcul en virgule flottante. En 64 bits, ces instructions sont très différentes de l’assembleur 32 bits et à première vue sont plus simples d’utilisation. Pour effectuer des calculs en double précision, nous disposons de 32 registres de 64 bits dont le nom commence par d.

Comme nous n’avons pas de routines assembleur pour afficher des nombres en virgule flottante, il nous faut utiliser l’instruction printf du C en utilisant le formatage « %+09.25f\n ». Comme il y a peu d’exemple sur internet de programmation 64 bits arm en float, il nous faut découvrir comment passer les arguments à la fonction.
Après quelques essais, je trouve que la chaine de formatage doit être passée dans le registre x0 et les valeurs à afficher dans les registres d0 d1 etc. En effet en virgule flottante les registres à utiliser en double précisions sont des registres 64 bits qui commencent par d et nous pouvons utiliser xx registres. Attention : l’appel de la fonction printf détruit le contenu des registres d0 d1 et peut être d’autres (à vérifier). L’utilisation des instructions du langage C necessite aussi l’utilisation de gcc pour effectuer le link. 
Source du programme calculFloat1.s
Donc je commence à alimenter le registre d0 avec une valeur immédiate avec l’instruction fmov d0,2 et tout se passe bien avec plusieurs valeurs lorsqu’une erreur de compilation arrive pour la valeur 50 !!
La recherche dans les 5000 pages de la documentation ARM montre que les valeurs immediates possibles doivent pouvoir être codées sur 8 bits dont un exposant de 3 bits et une mantisse de 4 bits. La figure C2-2 de la page C2-136 donne les valeurs possibles : par exemple 1 2 4 8 16 mais aussi 0,25 ou 0,1796875 mais pas 50.
Bien ! maintenant passons une valeur dans le registre x0 puis dans le registre d0 et comme en 32 bit, il faut effectuer une opération de conversion en float avec l’instruction scvtf d0,d0.
Et enfin nous chargeons une valeur double stockée en mémoire par la simple instruction ldr.
Après affichage, nous la rechargeons dans le registre d0 puis la convertissons en entier non signé avec l’instruction fcvtzu et la transferrons dans le registre x0 en passant par le registre d1 pour varier un peu. L’affichage du registre x0 montre bien la valeur 3. Pour les valeurs signées il faut utiliser fcvtzs.
Nous effectuons quelques opérations de calcul, addition, multiplication, division, minimum, racine carrée et quelques comparaisons qui sont plus simples qu’en 32 bits.
Enfin nous vérifions le stockage d’une valeur en mémoire. Il existe encore plein d’instructions pour manipuler ces nombres (et pour des conversions en simple précision).
J’effectue aussi quelques tests pour voir les conversions 32 bits 64 bits.
Comme exemple je vais reprendre le programme écrit en 32 bits pour analyser la génération de nombres aléatoires. Voir le programme verifAlea.s. Celui çi ne pose pas de problème particulier sauf que la valeur immédiate zéro ne peut pas être mis dans un registre dn avec l’instruction fmov. Mais en utilisant le registre particulier xzr, cela fonctionne.
Vous remarquerez que j’utilise le registre d8 pour les calculs pour éviter la modification d’un registre comme d4 par le premier appel de printf.

Ensuite le programme saisieFloat1.s donne une routine de conversion d’une chaine de caractères (abc,def ou abc.def) en nombre float. La chaine est passés d’abord dans la ligne de commande puis est ensuite saisie en utilisant l’appel système read.
Je voulais utiliser l’instruction de conversion     scvtf d0,x0, n bits   mais le position de la virgule par n bits ne peut pas être la valeur d’un registre. Donc j’ai utilisé une autre technique, je recopie la chaine de caractère en supprimant la virgule ou le point et en conservant leur position. Ensuite je convertit en décimal la chaine résultante et convertit en float le résultat.
Avec la position de la virgule, je calcule la puissance de 10 necessaire pour effectuer la division en float pour trouver le résultat correct. Exemple :
Soit la saisie de 12345,67 qui donne la chaine 1234567 convertit en float pour donner le dividende.
La virgule est en position 5 à partir de la gauche et 2 à partir de la droite . Il faut calculer la puissance 2 de 10 soit 100 qui convertit en float donnera le diviseur.
Il ne reste plus qu’à effectuer la division en float de 1234567 par 100 pour avoir un nombre float résultant correct dans le registre d0.