9
votes

Lecture d'un fichier en montage

J'essaie d'apprendre l'assemblage - X86 dans un environnement Linux. Le tutoriel le plus utile que je puisse trouver est écrire un programme utile avec NASM . La tâche que je me cadre est simple: lisez un fichier et écrivez-le à stdout.

C'est ce que j'ai: xxx

un problème crucial ici est que le Le tutoriel ne mentionne jamais comment créer un tampon, le bufsize variable ou en effet des variables du tout.

Comment puis-je faire cela?

(A de côté: Après au moins une heure de recherche, je suis vaguement consterné à la mauvaise qualité des ressources pour l'assemblage d'apprentissage. Comment sur Terre utilise-t-il un ordinateur lorsque la seule documentation est le dossier négocié sur le 'net?)


5 commentaires

J'ai lu pour résoudre ce problème en recherchant l'équivalent en C, mais tout le tout utilise le package stdio.h au lieu de simplement Ouvrir , lisez et écrire . J'ai même regardé stdio.h , mais les organes de fonction ne sont définis nulle part.


Ouvrir, lire et écrire des appels système. Les corps sont dans le noyau Linux.


Je voulais dire que je cherchais que je cherchais les corps de fopen , fread et fwrite , pour voir comment Ouvrir , lire et écriture sont utilisés.


Les corps des fonctions Wrapper sont à la source de GLIBC.


RE: Ressources d'apprentissage: Stackoverflow.com/tags/x86/info a un tas de liens. Les tutoriels de bonne qualité sont rares, mais réelle la documentation est généralement très bonne, notamment les manuels d'Intel et d'AMD, ainsi que la documentation NASM ( nasm.us ). Pour les interfaces OS / Conventions d'appel des appels, Linux dispose d'une page syscall (2) Man, et voir le système X86-64 System V ABI Doc en PDF.


3 Réponses :


12
votes

Ohh, ça va être amusant.

Le langage de montage n'a pas de variables. Ce sont une construction de langues de niveau supérieur. En langage de montage, si vous voulez des variables, vous les faites vous-même. Montée. Dans les deux sens. Dans la neige.

Si vous voulez un tampon, vous devez utiliser une région de votre pile comme tampon (après avoir appelé les instructions de configuration de la pile appropriées) ou utilisez une région sur le tas. Si votre tas est trop petit, vous devrez faire une instruction SYSCALL (un autre INT 80H) pour prier le système d'exploitation pour plus (via SBRK).

Une autre alternative consiste à en apprendre davantage sur le format ELF et à créer une variable globale dans la section appropriée (je pense que c'est .Data).

Le résultat final de l'une de ces méthodes est un emplacement de mémoire que vous pouvez utiliser. Mais vos seules «variables» telles que vous êtes habituée à partir du monde désigné-merveilleux de C sont vos registres. Et il n'y en a pas beaucoup d'entre eux.

L'assembleur pourrait vous aider avec des macros utiles. Lire la documentation de l'assembleur; Je ne me souviens pas d'eux en haut de ma tête.

La vie est difficile là-bas au niveau de l'ASM.


5 commentaires

Je comprends que buf est juste un pointeur à la mémoire que j'ai besoin de créer et que je dois demander bufsize de la mémoire du système d'exploitation. Cependant, je ne fais pas comment faire de ces choses et je ne peux pas savoir.


EEGG: MALLOC n'est pas réellement un appel système. Vous devez mettre en place un tas. Ceci est fait, comme je l'ai mentionné, avec le BRK et sbrk appels système. Voir Man 2 BRK . Vous devez rechercher le numéro d'appel système correspondant à BRK (voir /usr/include/sys/syscall.h ), puis faire un MOV EAX, # et int 80h pour l'appeler selon votre modèle SYSCall ci-dessus. Une fois que vous avez fait cela, vous avez un tas à l'adresse que vous spécifiez! Neato!


Ok, apparemment brk est un appel système, mais sbrk n'est pas. sbrk semble décidément plus utile. Utiliser Just BRK serait possible, si je savais où se trouve dans la mémoire la pause actuelle du programme. Malgré la recherche, je ne sais pas comment le trouver. À la recherche de la source de SBRK (qui enveloppe vraisemblablement brk ), je ne peux trouver que Ce , que je ne peux faire ni tête ni queue de.


@eegg Que sbrk est l'appel brk (0) et enregistre sa valeur de retour (qui est la pause actuelle du programme). Est ce que ça aide?


Pourquoi gâcher avec brk lorsque vous pouvez simplement MMAP (map_anonymous) pour obtenir de nombreuses pages que vous voulez? Ou honnêtement pour un programme de jouet ayant besoin d'un grand tampon, un tampon statique dans le BSS est certainement le choix le plus facile. Section .BSS / MYBUF: RESB 1024 * 1024 * 1024 Réserves 1GIB. (Et non, vous ne le voulez pas dans .data , qui mettrait des zéros dans le fichier exécutable.) J'adorerais +1 cette réponse pour la bonne partie expliquant les étiquettes vs. Variables de langage de niveau, cependant. Mais les variables statiques font une sorte de carte pour étiqueter + stockage; C'est un stockage automatique qui mesure à REG.



5
votes

Vous devez déclarer votre tampon dans la section BSS et le bufsize dans les données

section .data
   bufsize dw      1024

section .bss
   buf     resb    1024


2 commentaires

Et si vous ne connaissez pas la taille du fichier, comment faites-vous cela?


La taille est une constante de temps d'assemblage, vous n'avez pas besoin de le stocker en mémoire. (Et dans un mot a peu de sens en code 32 bits). Utilisez buf: resb 1024 / bufsize EQA € -BUF Pour que l'assembleur calculera une taille pour vous que vous pouvez utiliser comme immédiat au lieu de devoir charger de la mémoire.



2
votes

Après l'ouverture de l'appel, la poignée du fichier est dans EAX. Vous déplacez légitimement EAX à EBX, où l'appel à lire le cherchera. Malheureusement, à ce stade, vous avez déjà écrasé avec 3, le syscall pour la lecture.


0 commentaires