Разное

Вывод строки ассемблер: Статья 7. Вывод на экран символьной информации

Статья 7. Вывод на экран символьной информации

Статья 7. Вывод на экран символьной информации
< Назад  Далее >

Представим себе, что мы создаем обучающую программу и нам понадобилось вывести на экран несколько строк из введения к этой книге. Соответствующая программа приведена в примере 7.1.

Пример 7.1. Вывод на экран информационного сообщения



text     segment 'code'       ; Начало сегмента команд
         assume CS:text, DS:data
begin:   mov    AX,data       ; Инициализация сегментного
         mov    DS,AX         ; регистра DS
         mov    AH,9          ; Функция DOS вывода на экран
         mov    DX,offset message ; Адрес выводимого сообщения
         int    21h           ; Вызов DOS
         mov    AX,4C00h      ; Завершение программы
         int    21h
text     ends                 ; Конец сегмента команд
data     segment              ; Начало сегмента данных
message  db 'Другую группу составляют различные аспекты реализации '
         db 'в программах на языке ассемблера аппаратных и '
         db 'системных возможностей персонального компьютера:'
         db '- программирование ввода-вывода;'
         db '- использование прерываний BIOS и функций DOS;'
         db '- программирование арифметического сопроцессора;'
         db '- работа в защищенном режиме;'
         db '- управление обычной и расширенной памятью.
$' data ends ; Конец сегмента данных stk segment stack ; Начало сегмента стека dw 128 dup (0) ; Стек stk ends ; Конец сегмента стека end begin ; Конец текста программы

Заметим, что эта программа написана стандартным образом: в ней имеются сегменты команд, данных и стека. Так же будут составляться и программы последующих примеров этой книги.

Текст, предназначенный для вывода на экран, включен в программу в помощью директивы db (определить байт). Поскольку длина текста превышает ширину экрана, он разбит на участки, каждый из которых формально составляет отдельное предложение языка ассемблера. Заканчивается текст знаком $, характеризующим конец строки для функции DOS 09h.

Подготовив и выполнив эту программу, мы увидим, что весь текст вывелся на экран сплошной последовательностью символов без разбивки на строки и абзацы. Неприятно также и то, что наш текст вывелся на «грязный» экран с остатками предыдущих выводов. Для получения более удобочитаемого вывода в символьную строку следует включить коды управления курсором:

  • 09 — табуляция;
  • 10 — перевод строки;
  • 13 — «возврат каретки», т.е. возврат курсора в начало строки экрана.

С очисткой экрана дело обстоит сложнее. Единственное, что пока можно сделать — это вывести на экран столько строк пробелов, чтобы, перемещаясь по мере вывода вверх по экрану, они очистили всю его верхнюю часть.

В примере 7.2 представлено описание модифицированной строки message (все остальные предложения программы не изменяются).

Пример 7.2. Вывод на экран форматированного текста



message  db 80 * 18 dup (' ')
         db 9, 'Другую группу составляют различные аспекты реализации в'
         db ' программах на', 10, 13, 'языке ассемблера аппаратных и'
         db ' системных возможностей персонального компьютера:', 10, 13
         db 9, '- программирование ввода-вывода;', 10, 13
         db 9, '- использование прерываний BIOS и функций DOS;', 10, 13
         db 9, '- программирование арифметического сопроцессора;', 10, 13
         db 9, '- работа в защищенном режиме;', 10, 13
         db 9, '- управление обычной и расширенной памятью.
$'

Пробелы (18 строк по 80 пробелов в строке) описаны с помощью оператора dup (duplicate, дублировать). Перед словом dup указывается коэффициент повторения (в котором можно использовать арифметические выражения), а после оператора dup в скобках — повторяемая строка (состоящая не обязательно из одного символа). Коды табуляции создадут отступы красных строк. Чтобы текст выглядел на экране аккуратно, мы в середину первого абзаца включили коды 10 и 13 для перехода на следующую строку.

Кроме обычных алфавитно-цифровых символов и других знаков, имеющихся на клавиатуре компьютера (например, знаков < > [ ] { } | и др.) на экран можно выводить символы псевдографики. Таких символов всего 48; им соответствуют коды от 176 до 223. Так, например, для формирования на экране двойной рамки используются следующие коды:

Наконец, если в строку, выводимую на экран, включить код 7, прозвучит короткий звуковой сигнал.

В примере 7.3 приведена символьная строка, вывод которой с помощью функции 09h DOS приведет к выводу длительного звукового сигнала и изображению приблизительно в центре чистого экрана слова «Внимание!» в рамке.

Пример 7.3. Вывод на экран информационного кадра



message  db 25 dup (7)
         db 80 * 12 dup (' ')
         db 35 dup (' '), 201, 9 dup (205), 187, 10, 13
         db 35 dup (' '), 186, 'Внимание!', 186, 10, 13
         db 35 dup (' '), 200, 9 dup (205), 188, 10, 13
         db 10 * 80 dup (' '), '$'

В приведенных выше примерах некоторые символы вводились в программу в виде их изображений (букв), а другие — с помощью их кодов. В действительности все символы, отображаемые на экране терминала или выводимые на печать, имеют закрепленные за ними коды, которые называются кодами ASCII. Каждый код ASCII занимает один байт и может принимать значение от 0 до 255. Совокупность всех 255 кодов вместе с изображениями символов составляют кодовою таблицу ASCII (рис. 7.1).

Рис. 7.1. Кодовая таблица для нашей страны в десятичном представлении

Очевидно, что описывать в программе текстовые строки с помощью кодов ASCII по меньшей мере неудобно. В то же время для вывода на экран псевдографических изображений или других пиктограмм, для которых нет соответствующих клавиш, приходится пользоваться кодами ASCII. Однако иметь в виду соответствие символов и кодов ASCII приходится довольно часто. Например, упорядочивание символов или символьных строк по алфавиту фактически выполняется по кодам ASCII.


Сайт управляется системой uCoz

ассемблер — Ввод и вывод строк TASM/Assembler

Вопрос задан

Изменён 6 дней назад

Просмотрен 3k раза

Ввожу строку, нажимаю Enter, но при выводе строки (после прерывания) выводится мусор.

STACKSG SEGMENT PARA STACK
    DW 128 DUP(?)
STACKSG ENDS
;---------------------
DATASG SEGMENT PARA
    BUFF LABEL BYTE
    MAX_LEN = 128
    MaxSymb DB MAX_LEN
    LEN DB ?
    STRING DB MAX_LEN DUP(?)
DATASG ENDS
;---------------------
CODESG SEGMENT PARA
    ASSUME DS:DATASG, CS:CODESG, ES:CODESG, SS:STACKSG
START:
    .386
    PUSH DS
    MOV AX, DATASG
    MOV DS, AX
    MOV ES, AX
    XOR AX, AX
    ;--------------------
    LEA DX, BUFF
    MOV AH, 10
    INT 21H
    MOV AH, 9
    INT 21H
    ;завершение программы
    MOV AX, 4C00h
    INT 21h
CODESG ENDS
END START
  • ассемблер
  • dos
  • tasm

4

STACKSG SEGMENT PARA STACK
    DW 128 DUP(?)
STACKSG ENDS
;---------------------
DATASG SEGMENT PARA
    MAX_LEN = 128
    STRING DB MAX_LEN, MAX_LEN DUP('$')
DATASG ENDS
;---------------------
CODESG SEGMENT PARA
    ASSUME DS:DATASG, CS:CODESG, ES:CODESG, SS:STACKSG
START:
    .
386 PUSH DS MOV AX, DATASG MOV DS, AX MOV ES, AX XOR AX, AX ;-------------------- LEA DX, STRING MOV AH, 10 INT 21H ;вывод на экран MOV STRING+1, 0AH LEA DX, STRING+1 MOV AH, 9 INT 21H ;завершение программы MOV AX, 4C00h INT 21h CODESG ENDS END START

0

Вариант кода на диалекте fasm (основное отличие от диалекта tasm в данном случае — для tasm смещения нужно указывать с ключевым словом offset: mov dx, offset buff и mov dx, offset string), компилируется в com:

org 100h
; Считываем строку
mov dx, buff
mov ah, 0Ah
int 21h
; Выводим перенос строки
mov dl, 0Ah
mov ah, 2
int 21h
; Выводим строку
mov dx, string
mov ah, 9
int 21h
mov ax, 4C00h
int 21h
buff:
    max_len = 128
    MaxSymb db max_len
    len db ?
    string db max_len+1 dup ('$')

Зарегистрируйтесь или войдите

Регистрация через Google

Регистрация через Facebook

Регистрация через почту

Отправить без регистрации

Почта

Необходима, но никому не показывается

Отправить без регистрации

Почта

Необходима, но никому не показывается

Нажимая на кнопку «Отправить ответ», вы соглашаетесь с нашими пользовательским соглашением, политикой конфиденциальности и политикой о куки

nasm — Как печатать строки на ассемблере

спросил

Изменено 11 месяцев назад

Просмотрено 26 тысяч раз

Я пытаюсь напечатать строку в эмуляторе Q, используя NASM. Мой код выглядит следующим образом:

 mov bx,HELLO
мов ах, 0x0e
интервал 0x10
ПРИВЕТ:
  дб 'Привет', 0
jmp $
раз 510-($-$$) дб 0
дв 0xaa55
 

Однако, когда я компилирую этот код, я получаю вывод:

 UU
 

Может ли кто-нибудь сказать мне, почему это так? И как получить нужную строку на выходе?

Заранее спасибо.

  • в сборе
  • nasm
  • qemu

6

ХОРОШО ИТАК, здесь есть вещь на ваш вопрос

Чтобы загрузить строку, вы должны переместить ее в si (на самом деле не хотите углубляться, просто сделайте это). Далее для загрузки символа в регистр AL используйте лодсб . Затем мы должны напечатать его, поэтому используйте int 10h mov ah, 0Eh . Int 10h обрабатывает видео, а ah сообщает BIOS, чтобы он печатал все, что у нас есть в al (aka lodsb). Затем у нас должен быть конечный загрузочный символ, чтобы мы просто не зацикливались вечно. Лично я использую 0x00 , однако вы используете 0. 0x00 намного лучше в моем случае, потому что вы не только можете использовать 0, 0x00 ничего не печатает, так зачем вам это нужно?

ХОРОШО, так что мы все сделали, и вот код:

    mov si, message ;Расположение сообщения *вы можете изменить это*
    call print ;CALL сообщает преклиру вернуться сюда, когда закончите
    Распечатать:
      mov ah, 0Eh ;Установить функцию
    .бежать:
      lodsb ;Получить символ
    ; cmp al, 0x00 ;Я бы использовал это, но вы не должны так использовать:
      cmp al, 0 ;0 имеет шестнадцатеричный код 0x48, поэтому это не 0x00
      je .done ;Перейти к выполнению, если найден конечный код
      int 10h ;иначе напечатать
      jmp .run ; и вернуться к .run
    .Выполнено:
      возврат ;Возврат
    message db 'Hello, world', 0; ЕСЛИ вы используете 0x00
    ;сообщение БД 'Привет, мир', 0x00
 

3

Зарегистрируйтесь или войдите в систему

Зарегистрируйтесь с помощью Google

Зарегистрироваться через Facebook

Зарегистрируйтесь, используя электронную почту и пароль

Опубликовать как гость

Электронная почта

Требуется, но никогда не отображается

Опубликовать как гость

Электронная почта

Требуется, но не отображается

Сборка

— использование write() для вывода строки в стек

В Ubuntu 20 в сборке x86 я пытаюсь вывести строку push в стек с помощью системного вызова write . Шестнадцатеричные байты с прямым порядком байтов , помещающие ed в стек, представляют собой «hello world» в ASCII. Моя цель — вывести строку исключительно из стека. Почему? Чтобы лучше понять стек и то, как аргументы передаются системным вызовам/функциям через регистры.

Из моего базового понимания я должен поместить аргументы в стек и mov регистр esp (указывающий на вершину стека) в регистры в порядке напишите необходимые аргументы .

Вот моя попытка (ничего не выводит):

 ; скомпилировать: nasm -f elf32 -g test.asm && ld -melf_i386 test.o -o test
раздел .текст
глобальный _start
_Начало:
    xor eax, eax
    нажать 0xc
    мов ebx, esp
    нажать eax
    нажать 0x00646c72
    нажать 0x6f77206f
    нажать 0x6c6c6568
    mov ecx, esp
    мов эдкс, 1
    мов акс, 4
    интервал 0x80
    мов акс, 1
    интервал 0x80
 

Ожидаемый результат:

 привет мир
 

Как исправить код, чтобы он отображал ожидаемый результат? И что я делаю неправильно?

  • строка
  • сборка
  • x86
  • системные вызовы

7

Я предлагаю прочитать Каковы соглашения о вызовах для системных вызовов UNIX и Linux (и функций пользовательского пространства) на i386 и x86-64. Вам нужен номер системного вызова в eax и аргументы в ebx , ecx , edx , esi , edi , ebp в указанном порядке. запись принимает три аргумента, поэтому вам нужно:

  • номер системного вызова (4) в eax

  • дескриптор файла (1 для стандартного вывода) в ebx

  • указатель на буфер ( esp ) в ecx , это у вас есть право

  • количество записываемых байтов (11, так как нет причин записывать нулевой байт) в эдкс . (По значению, а не по указателю на длину: write позволяет узнать, сколько байтов было фактически записано с помощью возвращаемого значения в eax , а не выходного аргумента.)

В стек больше ничего класть не нужно. Ядро не ищет там аргументы, все в регистрах. Это отличие от обычного соглашения о вызове функции.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *