Программы на языке ассемблере могут быть разделены на три секции: data, bss, text.
Секция data используется для объявления инициализированных данных или констант. Данные в этой секции НЕ могут быть изменены во время выполнения программы. Вы можете хранить константные значения и названия файлов в этой секции. Синтаксис объявления:
1 |
section.data |
Секция bss используется для объявления переменных. Синтаксис объявления:
1 |
section.bss |
Секция text используется для хранения кода программы. Данная секция должна начинаться с объявления global_start
, которое сообщает ядру, откуда нужно начинать выполнение программы. Синтаксис объявления:
1 2 3 |
section.text global _start _start: |
Комментарии
Комментарии в ассемблере должны начинаться с точки с запятой (;
). Они могут содержать любой печатный символ, включая пробел. Комментарий может находиться как на отдельной строке:
1 |
; эта программа выводит сообщение на экран |
Так и на строке со стейтментом:
1 |
add eax, ebx ; добавляет ebx к eax |
Стейтменты
В ассемблере есть три вида стейтментов:
Выполняемые инструкции (или просто «инструкции») — сообщают процессору, что нужно делать. Каждая инструкция хранит в себе код операции (или «опкод») и генерирует одну инструкцию на машинном языке.
Директивы ассемблера — сообщают программе об аспектах компиляции. Они не генерируют инструкции на машинном языке.
Макросы — являются простым механизмом вставки кода.
В ассемблере на одну строку приходится один стейтмент, который должен соответствовать следующему формату:
1 |
[метка] mnemonic [операнды] [; комментарий] |
Базовая инструкция состоит из названия инструкции (mnemonic
) и операндов (они же «параметры»). Вот примеры типичных стейтментов ассемблера:
1 2 3 4 5 6 7 8 9 10 |
INC COUNT ; выполняем инкремент переменной памяти COUNT MOV TOTAL, 48 ; перемещаем значение 48 в переменную памяти TOTAL ADD AH, BH ; добавляем содержимое регистра BH к регистру AH AND MASK1, 128 ; выполняем операцию AND с переменной MASK1 и 128 ADD MARKS, 10 ; добавляем 10 к переменной MARKS MOV AL, 10 ; перемещаем значение 10 в регистр AL |
Первая программа
Следующая программа на языке ассемблера выведет строку Hello, world!
на экран:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
section .text global _start ; необходимо для линкера (ld) _start: ; сообщает линкеру стартовую точку mov edx,len ; длина строки mov ecx,msg ; строка mov ebx,1 ; дескриптор файла (stdout) mov eax,4 ; номер системного вызова (sys_write) int 0x80 ; вызов ядра mov eax,1 ; номер системного вызова (sys_exit) int 0x80 ; вызов ядра section .data msg db 'Hello, world!', 0xa ; содержимое строки для вывода len equ $ - msg ; длина строки |
Результат выполнения программы:
Hello, world!
Сборка программ
Убедитесь, что у вас установлен NASM. Запишите вашу программу в текстовом редакторе и сохраните её как hello.asm. Затем:
откройте терминал;
убедитесь, что вы находитесь в той же директории, в которой вы сохранили hello.asm;
чтобы собрать программу, введите команду nasm -f elf hello.asm
;
если не было ошибок, то создастся объектный файл вашей программы под названием hello.o;
чтобы ваш объектный файл прошел линкинг и создался исполняемый файл под названием hello, введите команду ld -m elf_i386 -s -o hello hello.o
;
запустите программу командой ./hello
.
Если всё прошло успешно, то вам выведется Hello, world!
.
Если у вас нет возможности скомпилировать программу, например, у вас нет Linux и вы пока не хотите на него переходить, то можете использовать одну из следующих онлайн-IDE:
Примечание: Запоминать две вышеприведенные команды для сборки программы на ассемблере для некоторых может быть несколько затруднительно, поэтому вы можете написать скрипт для сборки программ на ассемблере. Для этого создайте файл под названием Makefile со следующим содержимым:
1 2 3 4 |
all: nasm –f elf $(source) ld –m elf_i386 –s –o $(source) $(source).o rm $(source).o |
Для сборки hello.asm выполните следующие действия:
откройте терминал;
убедитесь, что вы находитесь в той же директории, в которой вы сохранили hello.asm и Makefile;
введите команду make source=hello
.
Код для автоматизации процесса сборки через CMake
Эм полчаса дебажил, оказывается вместо спейсов нужен таб на строчках и символ — в исходнике отличается от консольного, вот рабочий вариант
all:
Хех, спасибо! Да, символы дефиса в примере не валидный для консоли, просто скопипастить в Makefile не получится. Тоже не сразу сообразил.
Я использую вот такой скрипт:
https://gist.github.com/MinerChAI/62c60442d4bb904bb87e0ca5fa1b9473
Его удобнее использовать, т.к. не надо указывать source и как аргумент он получает полное имя файла, таким образом можно компилить файлы с другими расширениями (можно даже просто точку в конце имени файла написать) + работает автодополнение
Для тех, кому нужно автоматизировать процесс сборки и запуска с помощью bash-скрипта:
создайте скрипт > touch Makefile
отредактируйте его с помощью vim > vim Makefile
впишите туда это:
#!/bin/bash
fileasm=$(ls *.asm)
nasm -f elf $fileasm
file=${fileasm//.asm/}
fileo=$(ls *.o)
ld -m elf_i386 -s -o $file $fileo
rm $fileo
./$file
ой, а как отсюда выйти? ХДХДХД
сохраните и выйдите нажав esc и введя :wq
выдайте права на исполнение > sudo chmod +x Makefile
А теперь просто запустите его > ./Makefile
Он создаст исполняемый файл и запустит его, а ненужный файл object удалит. При обновлении самого кода на асме, скрипт перезапишет и запустит новую версию, без косяков и лишних файлов. ТОЛЬКО работает он, если в текущей директории нет других файлов с расширением .asm
А почему Makefile? Тут же не make используется
"чтобы ваш объектный файл прошёл линкинг и создался исполняемый файл под названием hello, введите команду ld -m elf_i386 -s -o hello hello.o;"
"username@PC:~/Документи/1$ ld -m elf_i386 -s -o hello.s hello.o
bash: ld: команду не обнаружено"
стопорнулся на даном моменте.
что может быть не так.
(работаю с debian)
Вам нужно установить пакет lld:
P.S. Я понимаю, что комментарий оставлен слишком поздно, но может быть ещё кто-нибудь столкнётся с этой проблемой
После команды:
Возникает ошибка:
ld: warning: cannot find entry symbol _start; not setting start address
Исполняемый файл создается, но не запускается
У меня тоже самое было, я поставил пробел в строке
global_start таким образом: global _start и заработало т. к. оказалось, что это не одна команда, а определение _start как глобальной…(переменной?)
Мне в Makefile нужно было заменить nasm –f elf $(source) на nasm –f elf $(source).asm чтобы make заработал, возможно стоит исправить
Под macOS эту программу еще нужно постараться собрать.
Спасибо за ваши уроки)) Вы — супер, не скажете пожалуйста интервал выхода уроков по ассемблеру?
Пожалуйста) Как получится, ничего гарантировать не могу)
В самом начале Вы написали, что данные в секции data не могут быть изменены. Это неверно. В качестве проверки в исходнике hello.asm после 4-й и до 9-й строки можно написать:
И тогда вместо Hello, World! программа выведет Aello, World!
Я бы еще на вашем месте уточнил бы что за команды используются и что они делают, потому что например новичок, к примеру, может int начать ассоциировать с типом данных integer, а не с прерыванием interrupt. И тоже самое с регистрами и что это вообще такое, потому что почему именно тот или иной регистр используем не понятно.
Всё постепенно, а не сразу. Будем объяснять в следующих уроках)
Отлично написано, продолжайте в том же духе, новичкам будет проще разобраться, нежели если начнут читать того же Зубкова.
Будем продолжать 🙂