Статья 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
, а не выходного аргумента.)
В стек больше ничего класть не нужно. Ядро не ищет там аргументы, все в регистрах. Это отличие от обычного соглашения о вызове функции.