- •Системное программное обеспечение
- •Isbn 978-5-8149-2441-4
- •Введение
- •1. Основы программирования на ассемблере
- •1.1. Принципы построения ассемблерных программ
- •1.2. Понятие архитектуры компьютера
- •1.3. Регистры программиста в ia32
- •1.4. Описание сегментной структуры программы
- •2. Простейшие средства ассемблера
- •2.1. Средства описания данных
- •2.2. Обращения к функциям операционной системы посредством прерываний
- •2.3. Средства преобразования в исполняемый файл
- •2.4. Управление строками при выводе и вводе данных
- •2.5. Простейшие способы адресации
- •3. Архитектурные элементы для построения программ
- •3.1. Организация условных переходов
- •Команды условных переходов
- •3.2. Средства организации циклов
- •3.3. Особенности команд умножения и деления
- •3.4. Организация процедур
- •3.5. Неарифметические операции над кодами
- •3.6. Архитектура amd64 процессоров в ассемблерных Linux программах
- •4. Использование неэлементарных способов адресации
- •4.1. Косвенно-регистровая адресация и ее использование
- •4.2. Использование индексной адресации данных
- •4.3. Базовая и индексно-базовая адресации
- •5. Взаимодействие программных компонентов
- •5.1. Многомодульная разработка программ
- •5.2. Организация стекового кадра подпрограммы
- •5.3. Программный доступ к системным функциям Win32
- •5.4. Использование свободно распространяемых утилит для Win32
- •5.5. Вызов функций из стандартных библиотек Linux
- •6. Библиотеки объектных модулей
- •6.1. Использование библиотек объектных модулей в Linux
- •6.2. Использование библиотек объектных модулей в Win32
- •7. Разделяемые библиотеки выполняемых программ
- •7.1. Понятие о статической и динамической компоновке
- •7.2. Конструкция библиотеки динамической компоновки
- •7.3. Компоновка времени загрузки с использованием GoLink
- •Контрольные вопросы
- •Заключение
- •Библиографический список
2.4. Управление строками при выводе и вводе данных
При выполнении программы, приведенной исходным текстом в листинге 2.2.1, текст из внутренней области txt и далее выводимый символ из внутренней области symbl сливаются в общий текст. Более того, в Linux последующий ввод приглашения для дальнейшей работы также сливается с введенным текстом без перехода на новую строку. Даже в таких простейших примерах происходящее не очень удобно. Поэтому в любой из операционных систем, ориентированных на диалоговое взаимодействие с пользователем, присутствуют простые средства управления выводом на экран. Этими средствами являются управляющие символы, которые на языке Си изображаются внутри текста специальными символьными комбинациями '\n'и '\r'. В рассматриваемых ассемблерах такие символьные комбинации не используются (но используются в специализированном ассемблере AT&T, вызываемом командой as ОС Unix). Вместо управляющих символьных комбинаций следует использовать числовые значения управляющих символов. Ими являются соответственно числа 10 и 13. Причем для перевода на новую строку с автоматическим переходом в ее начало для Unix достаточно использовать единственный управляющий символ со значением 10, а в MS-DOS указанные управляющие символы действовали независимо друг от друга.
Для ввода данных из файлов, согласно стандарту POSIX на операционные системы, предназначена системная функция, задаваемая следующим прототипом на языке Си:
unsigned int read(int handle, char *buffer, unsigned int size).
Число действительно введенных байтов эта функция возвращает в качестве собственного значения. Это число включает не только явно видимые символы, но и завершающий символ перевода строки '\n', образуемый при вводе с клавиатуры нажатием клавиши Enter. Например, число, возвращаемое функцией read после ввода с клавиатуры текста Privet, будет равно 7 (а вовсе не шести, как можно было бы подумать).
При реализации функций, возвращающих значения, на системном уровне принято, что такие значения по возможности возвращаются в регистре eax или, если используемая ОС 16-битная, то в регистре ax. Естественно, что это соглашение используется и для собственно системных функций.
Последняя информация дает нам возможность составить программу, которая использует ввод данных с клавиатуры. Для этого достаточно использовать хэндл стандартного ввода, имеющий в Unix и MS-DOS константное значение, равное нулю. В листинге 2.4.1 приведена программа для Linux, которая после запуска ожидает ввода текста (не более чем двадцати символов) и после этого отображает введенный текст с предшествующим ему текстовым примечанием, взятым из области данных с именем txt. Полученное в регистре eax число введенных символов складывается с известным числом символов в области txt, а результат переносится в регистр edx, который в ближайшем обращении к функции вывода должен содержать число выводимых символов. Заметим, что в число символов, выводимых программой, входит и управляющий символ перевода строки, помещенный в буфер buf системной функцией read и учитываемый возвращаемым значением в регистре eax.
GLOBAL _start
SEGMENT .text
_start:
;--- read(0, buf, 20) == <3>(ebx, ecx, edx)
mov eax,3 ; N function=write
mov ebx,0 ; N handle=1 (stdout)
mov ecx, buf ; address of txt
mov edx,20 ; number of byte
int 80h
add eax, 9 ; ; sum length of txt + actual read
mov edx, eax
;--- write(1, txt, len) == <4>(ebx, ecx, edx)
mov eax,4 ; N function=write
mov ebx,1 ; N handle=1 (stdout)
mov ecx, txt ; address of txt
int 80h
mov eax,1 ; N function=exit
int 80h
SEGMENT .data
txt db 'Vvedeno: '
buf times 20 db 0
Листинг 2.4.1. Использование элементарных ввода и вывода в Linux
Само сложение выполняется с помощью команды ADD, которая по своему назначению складывает число, заданное вторым операндом, со значением, заданным в первом операнде. Практически действие этой команды аналогично действиям оператора += из языка Си, и результат сложения размещается в месте, указанном первым операндом.
Заметим, что в качестве второго операнда этой команды можно использовать как регистр или имя места в области данных, так и числовое значение, но первый операнд может быть задан либо регистром, либо обозначением места в памяти (а числовую константу на этом месте записать нельзя).
