7
votes

Comment lire l'entrée de caractères unique du clavier à l'aide de NasM (Assembly) sous Ubuntu?

J'utilise NASM sous Ubuntu. Au fait, je dois obtenir un seul caractère d'entrée à partir du clavier de l'utilisateur (comme lorsqu'un programme vous demandez-vous pour Y / N?) Donc, en appuyant sur la touche et sans appuyer sur Entrée, j'ai besoin de lire le caractère saisi. Je google beaucoup, mais tout ce que j'ai trouvé était en quelque sorte lié à cette ligne ( int 21h ) qui aboutissent à "défaut de segmentation". Aidez-moi s'il vous plaît à comprendre comment obtenir le caractère unique ou sur la façon de passer à ce défaut de segmentation.


0 commentaires

3 Réponses :


-2
votes

Le moyen facile: pour un programme de mode texte, utilisez libncurses à accéder au clavier; Pour un programme graphique, utilisez GTK + .

La manière difficile: supposer un programme en mode texte, vous devez dire au noyau que vous souhaitez une entrée à caractère unique, puis vous devez faire beaucoup de comptabilité et de décodage. C'est vraiment compliqué. Il n'y a pas d'équivalent du bon vieux DOS getch () routine. Vous pouvez commencer savoir comment faire ici: Terminal I / O . Les programmes graphiques sont encore plus compliqués; L'API de niveau le plus bas pour celui-ci est XLIB .

De toute façon, vous allez devenir fou de coder quoi que ce soit en montage; Utilisez c au lieu.


4 commentaires

Bien que tout ce que vous avez dit est correct pour C, ce n'est pas vraiment une réponse pertinente si l'OP tente d'apprendre l'assemblée.


C'est parce que l'OP ne devrait pas être la programmation dans la langue d'assemblage . La seule bonne raison de faire la main sur le code de la main dans le langage de montage, c'est si c'est un sous-programme informatique critique de la performance, ou l'une des très rares morceaux d'un noyau de système d'exploitation que ne peut pas être codé toute autre manière. L'interaction utilisateur ne se qualifie pas. Ce que l'OP essaye de faire n'est même pas un bon l'exercice d'apprentissage sous Unix.


Cela dit, rien n'empêche l'OP de l'écriture de la langue d'assemblage qui appelle libncurses, bien qu'il semble être une perte de temps profonde et de la santé mentale. Mais cela ne serait pas aussi mauvais que le langage de l'assemblage que le terminal UNIX I / O à la main).


Je n'appellerais pas cela un bon exercice d'apprentissage pour la programmation Unix ou pour l'assemblée, mais c'est certainement un bon exercice d'apprentissage. Bien que l'assemblage n'est pas un choix pratique pour la vaste grande majorité des applications, je ne pense pas qu'apprendre à faire des choses que vous ne feriez pas normalement à l'assemblage est une perte de temps. Cela vous donne une perspective intéressante sur ce qui est possible sur quels niveaux d'abstraction, ainsi que sur la façon dont votre machine et votre système d'exploitation travaillent ensemble.



16
votes

Cela peut être fait de l'assemblage, mais ce n'est pas facile. Vous ne pouvez pas utiliser INT 21H, c'est un appel système DOS et il n'est pas disponible sous Linux.

Pour obtenir des caractères de la borne dans des systèmes d'exploitation de type UNIX (tels que Linux), vous lisez à partir de stdin (numéro de fichier 0). Normalement, l'appel du système de lecture bloquera jusqu'à ce que l'utilisateur appuie sur ENTER. Ceci est appelé mode canonique. Pour lire un seul caractère sans attendre que l'utilisateur appuie sur ENTER, vous devez d'abord désactiver le mode canonique. Bien sûr, vous devrez le réactiver si vous voulez une entrée de ligne plus tard et avant la sortie de votre programme.

Pour désactiver le mode canonique sur Linux, vous envoyez un IOOTL (contrôle IO) à Stdin , en utilisant l'ioctl Syscall. Je suppose que vous savez comment faire des appels système Linux à partir de l'assembleur.

L'IOCETL SysCall a trois paramètres. Le premier est le fichier pour envoyer la commande à (stdin), le second est le numéro IOCTL et le troisième est typiquement un pointeur à une structure de données. IOCTL retourne 0 sur le succès, ou un code d'erreur négatif sur l'échec.

Le premier ioctl dont vous avez besoin est TCgets (numéro 0x5401) qui obtient les paramètres de terminal actuels dans une structure termios. Le troisième paramètre est un pointeur sur une structure terminale. À partir de la source du noyau, la structure termios est définie comme suit: xxx

où TCFLAG_T est de 32 bits de long, CC_T est un octet long et NCCS est actuellement défini comme le 19. Voir la Manuel NASM pour la façon dont vous pouvez définir et réserver de manière commodément une place pour des structures comme celle-ci.

Donc, une fois que vous avez la terminaison actuelle, vous devez effacer le drapeau canonique. Ce drapeau est dans le champ C_LFLAG, avec masque Icanon (0x00000002). Pour le nettoyer, calculez C_LFLAG et (pas iconanon). et stockez le résultat dans le champ C_LFLAG.

Vous devez notifier le noyau de vos modifications à la structure termios. Utilisez les TCsets (Number 0x5402) IOCTL, le troisième paramètre définit l'adresse de votre structure TERMIOS.

Si tout va bien, le terminal est maintenant en mode non canonique. Vous pouvez restaurer le mode canonique en réglant le drapeau canonique (en orateur C_LFLAG avec ICANON) et appelez à nouveau le TCsets IOCTL. restaurer toujours le mode canonique avant de quitter

comme je l'ai dit, ce n'est pas facile.


0 commentaires

7
votes

J'avais besoin de le faire récemment et inspiré par Callum's Excellente réponse , j'ai écrit ce qui suit (nasm pour x86-64): xxx

(Note de l'éditeur: Don ' t Utilisation int 0x80 dans le code 64 bits: Que se passe-t-il si vous utilisez l'ABI de 32 bits Int 0x80 Linux dans 64 -bit code? - il se casserait dans une tarte exécutable (où les adresses statiques ne sont pas dans les basses basses 32), ou avec la mémoire tampon de terminos sur la pile. Il fonctionne réellement dans un exécutable traditionnel non à la tarte , et cette version peut être facilement portée au mode 32 bits.)

Vous pouvez alors faire: xxx

si vous lisez une ligne de ligne de texte, vous voulez probablement aussi faire: xxx

de sorte que chaque caractère ne soit pas écho tel qu'il est dactylographié.

Il peut y avoir de meilleures façons de faire Cela, mais cela fonctionne pour moi sur une installation de Fedora 64 bits.

Plus d'informations peuvent être trouvées dans la page man pour TERMIOS (3) ou dans le Termbits.h Source . < / p>


1 commentaires

Que se passe-t-il si vous utilisez l'ABI de 32 bits Int 0x80 Linux dans le code 64 bits? - Ne le faites pas, ça va casser avec des adresses en dehors du bas 32, par exemple espace de pile. Bien sûr, alors MOV EDX, TERMIOS - qui fonctionne uniquement dans un exécutable non-Pie sur X86-64 Linux, sinon vous voulez Lea RDX, [rel termios] . (Voir Comment charger l'adresse de la fonction ou de l'étiquette dans le registre dans GNU Assembler qui couvre également le nasme)