Введение в программирование на языке ассемблера GAS в операционной системе Linux
Покупка
Новинка
Тематика:
Программирование и алгоритмизация
Издательство:
ФЛИНТА
Автор:
Пирогов Владислав Юрьевич
Год издания: 2024
Кол-во страниц: 292
Дополнительно
Вид издания:
Учебное пособие
Уровень образования:
ВО - Бакалавриат
ISBN: 978-5-9765-5585-3
Артикул: 846531.01.99
Учебное пособие посвящено основам программирования на языке ассемблера GAS (GNU assembler) в операционных системах Linux. В нем рассматривается система команд для платформы x86-64, типовые структуры программ. Значительная часть пособия посвящена элементам системного программирования в Linux на ассемблере: управления файловой системой, динамическая память, интегрирование с языками высокого уровня, многозадачное программирование. Для студентов высших учебных заведений, обучающихся по инженерным специальностям, связанным с разработкой программного обеспечения.
Тематика:
ББК:
УДК:
ОКСО:
- ВО - Бакалавриат
- 09.03.01: Информатика и вычислительная техника
- 09.03.02: Информационные системы и технологии
- 09.03.03: Прикладная информатика
ГРНТИ:
Скопировать запись
Фрагмент текстового слоя документа размещен для индексирующих роботов
В.Ю. Пирогов ВВЕДЕНИЕ В ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ АССЕМБЛЕРА GAS В ОПЕРАЦИОННОЙ СИСТЕМЕ LINUX Учебное пособие 2-е издание, стереотипное Шадринск ШГПУ 2024 Москва Издательство «ФЛИНТА» 2024
УДК 004.42(075.8) ББК 32.933я73 П33 Рецензенты: В.К. Волк - канд. техн. наук, доцент ФГБОУ ВО «Курганский государственный университет»; Д.А. Слинкин - канд. пед. наук, доцент, начальник учебновычислительного центра ФГБОУ ВО «Шадринский государственный педагогический университет» П33 Пирогов В. Ю. Введение в программирование на языке ассемблера GAS в операционной системе Linux : учеб. пособие / В.Ю. Пирогов. — 2-е изд., стер. — Москва : ФЛИНТА, 2024. — 292 с. — ISBN 978-5-9765-5585-3 (ФЛИНТА) ; ISBN 978-5-87818-642-1 (ШГПУ). — Текст : электронный. Учебное пособие посвящено основам программирования на языке ассемблера GAS (GNU assembler) в операционных системах Linux. В нем рассматривается система команд для платформы x86-64, типовые структуры программ. Значительная часть пособия посвящена элементам системного программирования в Linux на ассемблере: управления файловой системой, динамическая память, интегрирование с языками высокого уровня, многозадачное программирование. Для студентов высших учебных заведений, обучающихся по инженерным специальностям, связанным с разработкой программного обеспечения. УДК 004.42(075.8) ББК 32.933я73 © Пирогов В.Ю., 2024 © ШГПУ , 2024 ISBN 978-5-9765-5585-3 (ФЛИНТА) ISBN 978-5-87818-642-1 (ШГПУ) 2
ОГЛАВЛЕНИЕ ВВЕДЕНИЕ ........................................................................................................................ 5 ГЛАВА 1. АССЕМБЛЕР. НАЧАЛО .................................................................................. 8 1.1. Как работает компьютер ........................................................................................ 8 1.2. Машинный язык ................................................................................................... 11 1.3. Ассемблеры ........................................................................................................... 14 1.3.1. Ассемблер TASM ........................................................................................... 14 1.3.2. Ассемблер MASM ......................................................................................... 15 1.3.3. Ассемблер FASM ........................................................................................... 15 1.3.4. Ассемблер NASM .......................................................................................... 16 1.3.5. Ассемблер YASM .......................................................................................... 16 1.3.6. Ассемблер RosAsm ........................................................................................ 17 1.3.7. Ассемблер GAS ............................................................................................. 17 1.4. Первые программы для Linux на GNU Assembler ............................................. 18 1.5. Пишем первую программу Hello, world! ............................................................ 22 1.6. Системы счисления .............................................................................................. 24 1.6.1. Десятичная система счисления .................................................................... 24 1.6.2. Двоичная система счисления ....................................................................... 25 1.6.3. Шестнадцатеричная система счисления ..................................................... 28 1.7. Представление чисел в компьютере ................................................................... 30 1.7.1. Беззнаковые целые числа в компьютере ..................................................... 30 1.7.2. Числа со знаком в компьютере ..................................................................... 33 1.7.3. Вещественные числа ..................................................................................... 35 1.8. Послание старых мастеров .................................................................................. 38 ГЛАВА 2. ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ АССЕМБЛЕРА ........... 40 2.1. Архитектура x86-64 для прикладного программиста ....................................... 40 2.2. Операции с ячейками памяти .............................................................................. 43 2.3. Системные вызовы ............................................................................................... 46 2.4. Стандартный ввод-вывод ..................................................................................... 49 2.5. Строки и числа ...................................................................................................... 53 2.6. Стек ........................................................................................................................ 59 2.7. Функции в ассемблере ......................................................................................... 63 2.8. Функции в ассемблере. Передача параметров через стек ................................ 66 2.9. Функции в ассемблере. Передача параметров в системах архитектуры x86-64 ... 73 2.10. Функции в ассемблере. Локальные переменные ............................................. 77 2.11. Пример программы с использованием функций ............................................. 80 2.12. Пример рекурсивной функции на ассемблере с использованием локальной переменной ................................................................................................................... 86 ГЛАВА 3. КОМАНДЫ ПРОЦЕССОРА АРХИТЕКТУРЫ X86-64 .............................. 89 3.1. Адресация памяти ................................................................................................ 89 3.2. Строковые операции процессора x86-64 ............................................................ 94 3.3. Команды условных и безусловных переходов ................................................... 98 3.4. Условные конструкции на языке ассемблера ................................................... 103 3.5. Базовые арифметические операции .................................................................. 109 3.6. Битовые и логические операции ....................................................................... 113 3.7. Команды для работы с числами с плавающей точкой .................................... 119 3.8. Действия с числами с плавающей точкой ........................................................ 130 3
3.9. Расширения процессоров x86-64 ...................................................................... 133 ГЛАВА 4. УПРАВЛЕНИЕ ФАЙЛАМИ ........................................................................ 136 4.1. Открытие файла, чтение из файла .................................................................... 136 4.2. Запись в файл. Пример копирования ................................................................ 140 4.3. Пример работы с текстовым файлом ................................................................ 144 4.4. Перемещение внутри файла .............................................................................. 148 4.5. Программное изменение режимов доступа к файлам и папкам .................... 151 4.6. Удаление и переименование файлов ................................................................. 156 4.7. Создание и удаление каталогов ......................................................................... 161 4.8. Параметры командной строки ........................................................................... 165 4.9. Пример использования параметров командной строки в простой утилите . 168 4.10. Программа чтения содержимого каталога ..................................................... 172 ГЛАВА 5. ВЗАИМОДЕЙСТВИЕ С ОПЕРАЦИОННОЙ СИСТЕМОЙ. УПРАВЛЕНИЕ ПАМЯТЬЮ ......................................................................................... 186 5.1. Глобальная статическая память......................................................................... 186 5.2. Стековая память .................................................................................................. 190 5.3. Динамическая память ......................................................................................... 197 5.4. Файлы, отображаемые в память, функция mmap ............................................ 200 5.5. Использование системной функции mmap для получения динамической памяти ......................................................................................................................... 204 ГЛАВА 6. БИБЛИОТЕКИ И ЯЗЫКИ ВЫСОКОГО УРОВНЯ .................................. 209 6.1. Объектные модули и их объединение ............................................................... 209 6.2. Компилирование с помощью программы gcc .................................................. 215 6.3. Использование стандартных библиотечных функций C и доступ к параметрам командной строки ................................................................................. 219 6.4. Создание статических библиотек...................................................................... 221 6.5. Использование ассемблерного кода в языках высокого уровня .................... 226 6.6. Динамические библиотеки на языке ассемблера ............................................ 228 6.7. Использование кода на языке высокого уровня в программе на языке ассемблера .................................................................................................................. 230 ГЛАВА 7. МНОГОЗАДАЧНОСТЬ ............................................................................... 233 7.1. Запуск процессов. Системная функция execve ................................................ 233 7.2. Создание процесса .............................................................................................. 240 7.3. Ожидание конца работы дочернего процессах ................................................ 246 7.4. Получение строк окружения ............................................................................. 251 7.5. Взаимодействие процессов. Разделяемая память ............................................ 256 7.6. Взаимодействие процессов. Канал pipe ........................................................... 261 7.7. Использование семафоров для синхронизации процессов ............................ 269 ПРИЛОЖЕНИЯ .............................................................................................................. 280 Приложение 1. Примеры для математического сопроцессора .............................. 280 Приложение 2. Примеры управления файлами ...................................................... 285 Приложение 3. Изменение прав доступа ................................................................. 289 СПИСОК РЕКОМЕНДУЕМОЙ И ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ .............. 291 4
ВВЕДЕНИЕ Когда говорят об ассемблере (или языке ассемблера), то часто несколько преувеличивают или преуменьшают те или иные особенности этого языка программирования. В действительности, поскольку ассемблер основывается на командах процессора, то следовало бы говорить о разных языках ассемблера. Добавив сюда еще и разных производителей трансляторов, а также особенности реализации в разных операционных системах, мы получим множество ассемблеров. В нашей книге мы ограничиваем себя вполне конкретным процессором архитектуры x86-64 и вполне конкретным транслятором GAS (GNU Assembler) со своим специфическим синтаксисом. Кроме того, мы рассматриваем программирование на ассемблере для семейства операционных систем Linux. Т.о. когда мы в дальнейшем будем говорить о языке ассемблера, то будем иметь в виду вполне конкретный язык, со своим набором средств программирования, со своим вполне определенным синтаксисом и со своим набором процессорных команд. И так, какие же крайности можно увидеть в отношении языка ассемблера. 1. Язык ассемблера очень сложен для усвоения. 2. Язык ассемблера сейчас нигде не используется. Конечно, во введении не стоит углубляться в детали программирования, для этого есть целая книга, поэтому отвечу очень кратко. Любой язык программирования сложен для усвоения, если собираешься достигнуть на нем достаточно высокого уровня мастерства. Язык ассемблера не сложен, он детален. И если освоить эти детали, то программировать на нем гораздо проще, чем, например, на действительно сложном языке C++. Программирование на языке ассемблера как на 5
любом языке требует умения структурировать программу. Если научиться этому, то писать на нем не составит никакого труда. Теперь о том, что язык ассемблера нигде не используется. В действительности все не так. Да, область применения ассемблера со времен 80-х годов прошлого века сузилась, сжалась как шагреневая кожа. Но свою нишу ассемблер занимает твердо. Это и разработка драйверов и операционных систем. Это программирование микроконтроллеров. Да, мне возразят, что все-таки здесь превалирует C. Но все-таки отдельные вставки на ассемблере в ядре операционных систем и в программах для микроконтроллеров неизбежны. Но есть еще один важный аспект программирования на языке ассемблера. Эта практика дает будущему программисту глубину понимания того, как работает компьютер и операционная система. И вот это последнее может быть самая главная причина того, почему каждый профессиональный программист должен изучать основы ассемблера. Несколько слов о выборе ассемблера, который сделал автор. Выбор происходил, в действительности в два этапа. В начале был сделан выбор операционной системы, точнее семейство операционных систем Linux. И выбор был сделан по двум причинам: 1. Расширение области использования операционной системы Linux в первую очередь в нашей стране. 2. О программировании на языке ассемблера в Linux всегда писали мало и хотелось восполнить этот недостаток. Теперь о выборе ассемблера GAS. И здесь выбор обусловлен двумя причинами. 1. GAS является родным ассемблером для семейства операционных систем Linux. 2. Именно этот ассемблер менее всего освещался в литературе по программированию. О чем данная книга В книгах принято объяснять для чего и для кого они предназначена, а также почему в качестве темы взята именно эта. 6
1. Почему я занимаюсь ассемблером? Язык ассемблера, программирование на языках низкого уровня всегда меня интересовал. Я написал несколько книг по программированию на языке ассемблера в операционной системе Windows. Мне показалось интересным написать о программировании на ассемблере в операционной системе Linux. Тем более эта операционная система становится все более популярной в нашей стране. 2. Почему в качестве ассемблера взят именно ассемблер GAS или GNU Assembler? На это есть важная причина причины: GAS является родным для всех Unix-подобных операционных систем, т.е. поддерживается в качестве одной из основных утилит, и используется для компилирования и самой операционной системы и при компиляции с использованием gcc (GNU Compiler Collection). 3. Почему в качестве главного процессора в книге рассматриваются процессоры x86-64? В первую очередь потому, что они являются основными для настольных компьютеров, используемых для профессиональной деятельности, в том числе и программистов. 4. Для кого данная книга? Я бы разделил возможных читателей данной книги на четыре категории: а. Будущие программисты на языке ассемблера. б. Будущие программисты. Любого программиста обогащают знания в области низкоуровневого программирования. в. Все те, кому интересно как происходит выполнение программ на низком уровне и как связана архитектура компьютера с его программным управлением. г. Те, кто интересуется программированием в среде Linux, системным программированием в этой операционной системе. И так, когда я кратко объяснил свои побудительные мотивы и кратко объяснил содержимое книги, приступим к самому главному, т.е. к языку ассемблера GAS и программированию на нем. 7
ГЛАВА 1. АССЕМБЛЕР. НА ЧАЛО 1.1. Как работает компьютер Для того, чтобы с пониманием начать программировать на языке ассемблера, стоит вспомнить в общих чертах то, как функционирует компьютер. Центральную роль в функционировании компьютера играет процессор. Его также называют центральным процессором, так как в системе есть и другие процессоры, управляющие периферийными устройствами. Процессор предназначен для выполнения известного набора команд, с помощью которых можно выполнять разного рода операции: всевозможные действия над числовыми операндами, пересылку данных между памятью и процессором, изменение порядка выполнения команд, всевозможные команды влияющие на особенности выполнения других команд, а также особенность функционирования самого процессора. В нормальном рабочем состоянии процессор непрерывно выполняет команды, которые расположены в памяти компьютера. Таким образом, для нормального функционирования компьютера требуется минимальная связка процессор – память. Тут стоит также отметить, что большинство современных компьютеров работают по принципу: память одна и для программы, и для данных (архитектура Джона фон Неймана). Другими словами, записанные в память команды процессора можно трактовать и как обычные данные, т.е. динамически изменять их. Т.е. программа на машинном языке может создавать и модифицировать самую себя (ну или другую программу). Не правда ли, для языков высокого уровня, это возможность не обычна, хотя заниматься самомодификацией и здесь вполне возможно. В действительности в компьютере есть и другие устройства, о которых следует сказать, чтобы картина была полной. Очень важно 8
понимать принцип взаимодействия процессора, памяти и других устройств. Основным подходом в современных компьютерных архитектурах является принцип общей шины. Если рассматривать упрощенную модель, то шина (или системная шина) это проводник, к которому могут быть подключено несколько устройств. Устройства взаимодействуют друг с другом через эту общую шину1. При этом каждому устройству присваивается свой адрес, по которому к нему и происходит обращение. У процессора есть специальный набор команд, с помощью которых можно обращаться к внешним устройствам по их адресам. Эти адреса также называются номерами портов. В отличие от других устройств доступ процессора к памяти осуществляется по адресу ячейки памяти, с помощью набора команд процессора, описание которых будет ниже. Конечно, в связи с тем, что устройства бывают разные и по скорости выполнения действий, и по принципам управления, взаимодействие процессора с ними осуществляется через посредников, называемых контроллерами. Несколько слов следует сказать и о памяти. Та память, о которой мы говорили до сих пор, обычно называется оперативной. Объем ее должен быть достаточно велик для хранения резидентной части операционной системы и запускаемых программ. Но ее особенность заключается в том, что она стирается при выключении питания. Именно с ней взаимодействует процессор при взаимодействии процессора с ячейками памяти. В действительности, однако, между оперативной памятью и процессором (регистрами процессора) существует, так называемая кэшпамять. Объем ее меньше чем у оперативной памяти, но скорость доступа выше. В ней динамически сохраняются данные при их передаче от процессора к оперативной памяти и обратно. Команды процессора аппаратно выполняются так, что при возможности обращаются вместо 1 Точнее было бы сказать, что именно процессор взаимодействует с памятью и другими устройствами, а также память взаимодействует с другими устройствами. 9
оперативной памяти к кеш-памяти (и при чтении, и при записи), что приводит к ускорению выполнения программы. Также существует еще один тип памяти – внешняя память. Сейчас к ней относят обычно жесткие диски. Основная роль жестких дисков – это хранение файловой системы. Это важная часть любой операционной системы. Объем жесткого диска может быть огромен, а главное его достоинство – данные на нем сохраняются и после выключения питания. Любой современный компьютер работает под управлением операционной системы (ОС). ОС представляет собой набор программ, которые обычно загружаются автоматически при запуске компьютера. Суть любой операционной системы заключается в предоставлении унифицированного доступа к ресурсам компьютера: памяти, жесткому диску, процессорному времени, а также другим внешним устройствам. Две главные функции любой операционной системы: 1. Автоматизация запуска программ специального формата (поддерживаемого данной ОС) и предоставление им доступа к ресурсам компьютера. Прямой доступ к ресурсам в современных операционных системах, как правило, закрыт. Важной особенностью современных операционных систем, является их многозадачность, позволяющая выполнять несколько программ одновременно. Одновременность выполнения может быть настоящей, когда разные программы выполняются разными ядрами процессора и мнимой, при которой происходит передача управления то одной программе то другой согласно некоторого алгоритма. 2. Предоставление интерфейса пользователю для выполнения основных команд по управлению компьютером. Unix-совместимые ОС предоставляют пользователю богатый интерфейс командной строки, позволяющий управлять всеми ресурсами компьютера. Но, как правило, вместе с операционной системой загружается еще и графическая 10