Skip to content

Latest commit

 

History

History
216 lines (142 loc) · 25.8 KB

lab01_helloworld.textile

File metadata and controls

216 lines (142 loc) · 25.8 KB

Лабораторная работа №1. Первая программа на языке ассемблера

Краткие теоретические сведения

Структура ассемблерной программы

Каждый язык программирования имеет свои особенности и часто - отличия, характерные для конкретной программно-аппаратной платформы. В языке ассемблера, благодаря его низкоуровневости, особенности и специфика платформы ощущаются очень сильно. Рассмотрим пример простой программы на этом языке для 32-битной архитектуры x86 и ОС Linux. Традиционно первая программа выводит приветственное сообщение на экран.

SECTION .data
    hello:     DB 'Hello world!',10 ; 'Hello world!' плюс символ
                                    ; возврата каретки
    helloLen:  EQU $-hello          ; Длина строки 'Hello world!'

SECTION .text           ; Начало секции кода
    GLOBAL _start       ; Метка _start должна быть глобальной, 
                        ; чтобы линкер смог её найти и сделать 
                        ; точкой входа в программу.
_start:
    mov eax,4           ; Системный вызов для записи (sys_write)
    mov ebx,1           ; Описатель файла $1$ - стандартный вывод
    mov ecx,hello       ; Адрес строки hello в ecx
    mov edx,helloLen    ; helloLen - константа, а не переменная, 
                        ; потому нет необходимости использовать 
                        ; mov edx,[helloLen] для получения 
                        ; действительного значения

    int 80h             ; Вызов ядра

    mov eax,1           ; Системный вызов для выхода (sys_exit)
    mov ebx,0           ; Выход с кодом возврата $0$ (без ошибок)
    int 80h             ; Вызов ядра

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

Синтаксис ассемблера NASM, которым мы будем пользоваться далее, является регистрочувствительным. Т.е. есть разница между большими и малыми буквами.

Команда может быть директивой — указанием транслятору, которое выполняется в процессе превращения программы в машинный код. Многие директивы начинаются с точки. Для удобства чтения программы они обычно пишутся БОЛЬШИМИ БУКВАМИ. Кроме директив еще бывают инструкции — команды процессору. Именно они и будут составлять машинный код программы.

Нужно отметить, что понятие «машинного кода» очень условно. Часто оно обозначает просто содержимое выполняемого файла, хранящего кроме собственно машинных команд еще и данные (в нашем случае — текст выводимого сообщения «Hello world»).

Особенности создания ассемблерной программы

На платформе Linux язык ассемблера является самым низкоуровневым языком программирования. Т.е. он больше любых других приближен к архитектуре ЭВМ и ее аппаратным возможностям, позволяет получить к ним более полный доступ, нежели в языках выского уровня, наподобие C/C++, Perl, Python и пр. Заметим, что получить полный доступ к ресурсам компьютера в современных архитектурах нельзя, самым низким уровнем работы прикладной программы является обращение напрямую к ядру ОС. Именно на этом уровне и работают программы, написанные на ассемблере в Linux. Но, в отличие от языков высокого уровня (ЯВУ), ассемблерная программа содержит только тот код, который ввел программист, и конечно же вся ответственность за логичность кода полностью лежит на плечах программиста.

Простой пример. Обычно подпрограммы заканчиваются командой возврата. Если в ЯВУ ее не задать явно, транслятор все равно добавит ее в конец подпрограммы. Ассемблерная подпрограмма без команды возврата не вернется в точку вызова, а будет выполнять код, следующий за подпрограммой, как будто он является ее продолжением.

Еще пример. Можно попробовать «выполнить» данные вместо кода. Часто это лишено смысла. Но если программист это сделает, транслятор не выдаст никаких сообщений об ошибке. Язык ассемблера позволяет делать все! Вопрос состоит лишь в том, какие усилия придется приложить, чтобы реализовать идею на этом языке. Тут меньше ограничений, чем в ЯВУ, но, в то же время, и удобства и простоты создания программ тоже меньше.

Эти особенности приводят к тому, что ассемблерные программы часто «подвешивают» компьютер, особенно у начинающих программистов. Выделим разновидности «зависания» по способу борьбы с ним.

  • Простое — для выхода из него достаточно нажать Ctrl+C (сначала нажимается клавиша Ctrl, и дальше нужно, не отпуская ее, нажать вторую клавишу — C; затем клавиши отпускаются в любом порядке). Программа при этом аварийно завершается выходом в ОС.
  • Мягкое — кажется, что машина никак не реагирует на клавиатуру и безнадежно зависла. В любом случае, ядро системы при этом продолжает работать и позволяет использовать базовые функции для сохранения целостности данных. Этими функциями можно управлять при помощи т. н. Magic Keys (см. описание SysRq Keys).
  • Жесткое — если зависло ядро ОС. Это может случиться в случае использования тестового ядра, находящегося в разработке, или при неправильной ручной сборке ядра, или при попытке использовать недокументированные особенности аппаратного обеспечения. В этом случае поможет аппаратный сброс при помощи кнопки «Reset», расположенной на передней панели системного блока.

Важно помнить, что в 90% случаев зависание является простым. Чаще всего не хватает аппаратных возможностей компьютера для быстрой обработки данных и необходимо просто подождать или нажать Ctrl+C.

Процесс обработки программы на языке ассемблера

Из-за специфики программирования, а также по традиции, для создания программ на языке ассемблера обычно пользуются утилитами командной строки (хотя поддержка ассемблера и есть в некоторых универсальных интегрированных средах). Весь процесс технического создания ассемблерной программы можно разбить на 4 шага (исключены этапы создания алгоритма, выбора структур данных и т.д.).

  1. Набор программы в текстовом редакторе и сохранение ее в отдельном файле. Каждый файл имеет имя и тип, называемый иногда расширением. Тип в основном используется для определения назначения файла. Например, программа на C имеет тип c, на Pascal — pas, на языке ассемблера — asm.
  2. Обработка текста программы транслятором. На этом этапе текст превращается в машинный код, называемый объектным. Кроме того есть возможность получить листинг программы, содержащий кроме текста программы различную дополнительную информацию и таблицы, созданные транслятором. Тип объектного файла — o, файла листинга — lst. Этот этап называется трансляцией.
  3. Обработка полученного объектного кода компоновщиком. Тут программа «привязывается» к конкретным условиям выполнения на ЭВМ. Полученный машинный код называется выполняемым. Кроме того, обычно получается карта загрузки программы в ОЗУ. Выполняемый файл обычно не имеет расширения в отличие от программ ОС семейства DOS и Windows, карта загрузки — map. Этот этап называется компоновкой или линковкой.
  4. Запуск программы. Если программа работает не совсем корректно, перед этим может присутствовать этап отладки программы при помощи специальной программы — отладчика. При нахождении ошибки приходится проводить коррекцию программы, возвращаясь к шагу 1.

Таким образом, процесс создания ассемблерной программы можно изобразить в виде следующей схемы. Конечной целью, напомним, является работоспособный выполняемый файл hello (см. рис. [pic:l1]).

[ht] [pic:l1]

Основные возможности текстового редактора mcedit

mcedit — это текстовый редактор, встроенный в двухпанельный файловый менеджер Midnight Commander. Сама по себе среда Midnight Commander (или просто mc) очень схожа с другими «командерами». Например, чтобы создать в текущем каталоге файл lab1.asm и начать его редактирование, можно набрать:

mcedit ./lab1.asm

Общий вид командной строки для запуска:

mcedit [-bcCdfhstVx?] [+число] file

Некоторые параметры:

+число переход к указанной числом строке (не ставьте пробел между знаком + и числом)
-b черно-белая цветовая гамма
-c цветовой режим ANSI для терминалов без поддержки цвета
-d отключить поддержку мыши
-V вывести версию программы

mcedit — это полноценный полноэкранный редактор, позволяющий редактировать файлы размером до 64 Мб, с возможностью редактирования бинарных файлов. Основными возможностями являются: копирование блока, перемещение, удаление, вырезка, вставка; отмена; выпадающие меню; вставка файлов; макро-команды; поиск регулярных выражений и их замена; подсветка синтаксиса; перенос по словам; изменяемая длина табуляции; использование перенаправления потоков для применения, например, проверки орфографии при помощи ispell.

Редактор крайне прост в использовании и может быть использован без предварительного изучения. Выпадающее меню вызывается клавишей F9. Список наиболее часто используемых горячих клавиш приведен ниже (Ctrl и Shift обозначают соответствующие клавиши клавиатуры, Meta — условное обозначение для набора мета-клавиш, на современном компьютере это обычно Alt или Esc):

F3 Начать выделение текста. Повторное нажатие F3 закончит выделение
Shift+F3 Начать выделение блока текста. Повторное нажатие F3 закончит выделение
F5 Скопировать выделенный текст
F6 Переместить выделенный текст
F8 Удалить выделенный текст
Meta+l Переход к строке по её номеру
Meta+q Вставка литерала (непечатного символа). См. ниже
Meta+t Сортировка строк выделенного текста
Meta+u Выполнить внешнюю команду и вставить в позицию под курсором её вывод
Ctrl+f Занести выделенный фрагмент во внутренний буфер обмена mc (записать во внешний файл)
Ctrl+k Удалить часть строки до конца строки
Ctrl+n Создать новый файл
Ctrl+s Включить или выключить подсветку синтаксиса
Ctrl+t Выбрать кодировку текста
Ctrl+u Отменить действия
Ctrl+x Перейти в конец следующего слова
Ctrl+y Удалить строку
Ctrl+z Перейти на начало предыдущего слова
Shift+F5 Вставка текста из внутреннего буфера обмена mc (прочитать внешний файл)
Meta+Enter Диалог перехода к определению функции
Meta+- Возврат после перехода к определению функции
Meta++ Переход вперед к определению функции
Meta+n Включение/отключение отображения номеров строк
tab Отодвигает вправо выделенный текст, если выключена опция «Постоянные блоки»
Meta-tab Отодвигает влево выделенный текст, если выключена опция «Постоянные блоки»
Shift+Стрелки Выделение текста
Meta+Стрелки Выделение вертикального блока
Meta+Shift+- Переключение режима отображения табуляций и пробелов
Meta+Shift++ Переключение режима «Автовыравнивание возвратом каретки»

Также работают и привычные по Norton и Volkov Commander’ам клавиши:

Ctrl-Ins копировать
Shift-Ins вставить
Shift-Del вырезать
Ctrl-Del удалить выделенный текст

Выделение мышью также работает на некоторых терминалах.

Клавиши автозавершения (обычно Alt-Tab или Escape Tab) завершают слово, на котором находится курсор, используя ранее применявшиеся в файле слова.

Для задания макроса нажмите Ctrl-R и нажимайте клавиши, которые нужны для воспроизведения в будущем. Повторное нажатие Ctrl-R завершит запись макроса. Затем нажмите на клавишу, на которую хотите повесить этот макрос. Макрос сохранится, когда нажмете Ctrl-A и затем назначенную макросу клавишу. Макрос выполнится по нажатию Meta, Ctrl, или Esc назначенной клавиши, если клавиша не используется другими функциями.

Дополнительную информацию, как обычно в Linux, можно получить при помощи команды man mc.

Правила оформления ассемблерных программ

При наборе программ на языке ассемблера придерживайтесь следующих правил:

  • директивы набирайте большими буквами, инструкции – малыми;
  • пишите текст широко;
  • не выходите за край экрана – его неудобно будет редактировать и печатать;
  • для отступов пользуйтесь табуляцией (клавиша TAB);
  • блоки комментариев задавайте с одинаковым отступом.

Оптимальной считается такая строка:

<TAB><TAB>mov<TAB>eax,<пробел>ebx<(1-3)TAB>;<пробел>текст комментария

Количество табуляций перед комментарием определяется длиной аргументов команды и может быть от 1 до 3.

По мере знакомства с синтаксисом языка будут приводиться дополнительные правила.

Транслятор NASM

NASM превращает текст программы в объектный код. Имя программы задается в командной строке. В простейшем случае это выглядит так: nasm hello.asm (расширение указывать обязательно). Текст программы из файла hello.asm преобразуется в объектный код, который запишется в файл hello.o. Т. о. имена всех файлов получаются из имени входного файла и расширения по умолчанию.

NASM всегда создает выходные файлы в текущем каталоге.

NASM не запускают без параметров, т. к. он — всего лишь транслятор, а не интегрированная среда разработки.

Рекомендуется в рабочем каталоге все файлы хранить в определенной иерархии. Например, для первой работы создайте каталог ~/labs/asm/01.

Для запуска транслятора достаточно набрать nasm hello.asm. При этом вы не увидите никаких сообщений — они появляются только в случае ошибок или предупреждений. При наличии ошибок объектный файл не создается.

Например, для компиляции приведенного выше текста программы «Hello World» необходимо писать:

nasm -f elf hello.asm

Ключ -f указывает транслятору создавать бинарные файлы в формате ELF (если используется 64-битная версия Linux, следует вместо elf указывать elf64 для генерации 64-битного кода).

Более подробно синтаксис командной строки рассмотрен в следующих работах.

Компоновщик LD

Как видно из схемы на рис. [pic:l1], чтобы получить исполняемую программу, объектный файл необходимо передать на обработку компоновщику (или, как его еще называют, линковщику):

ld -o hello hello.o

Ключ -o с последующим значением задает в данном случае имя создаваемого исполняемого файла.

Формат командной строки LD подробно рассмотрен в следующих работах, также его можно увидеть, набрав ld --help. Для получения более подробной информации см. man ld. Запустить на выполнение созданный исполняемый файл можно, набрав в командной строке:

./hello

Примечание: в данном случае исполняемый файл hello выполняется из текущего каталога (что обеспечивают символы «./» перед его именем).

Порядок выполнения работы

  1. Создайте в своем домашнем каталоге новый подкаталог с именем asm_01. Создайте в нем с помощью редактора mcedit текстовый файл lab1.asm, и введите в него текст программы из п. [sec:11], пользуясь правилами оформления ассемблерных программ.
  2. Оттранслируйте полученный текст программы в объектный файл.
  3. Выполните линковку объектного файла и запустите получившийся исполняемый файл.
  4. Измените в тексте программы выводимую на экран строку с Hello world! на свою фамилию. Повторите пункты 2 и 3.

Контрольные вопросы

  1. Как обрабатываются блоки текста в редакторе mcedit?
  2. Как восстановить в mcedit удаленные строки?
  3. Какие основные отличия ассемблерных программ от ЯВУ?
  4. В чем отличие инструкции от директивы?
  5. Каковы правила оформления программ на языке ассемблера?
  6. Каковы этапы получения выполняемого файла?
  7. Каково назначение этапа трансляции?
  8. Каково назначение этапа компоновки?
  9. Какие файлы могут создаваться при трансляции программы, какие из них создаются по-умолчанию?
  10. Каковы форматы файлов для nasm и ld?