Первая программа: структура файла NASM
Урок разбирает скелет программы на NASM: какие секции бывают и где начинается исполнение.
Секция — именованная область программы: одна для кода, другая для данных. Так линкер знает, что куда положить в памяти.
Минимальная программа целиком
Вот программа, которая просто завершается с кодом возврата 0. Запускать её в браузере нельзя, поэтому код помечен как текст — мы читаем и разбираем его.
section .text ; секция с кодом
global _start ; делаем метку _start видимой для линкера
_start: ; точка входа программы
mov rax, 60 ; номер системного вызова exit
mov rdi, 0 ; код возврата = 0
syscall ; передать управление ядруЧтобы собрать и запустить её под Linux:
nasm -f elf64 prog.asm -o prog.o # ассемблировать в объектный файл
ld prog.o -o prog # слинковать в исполняемый файл
./prog # запустить
echo $? # показать код возврата: 0Три главные секции
Память программы делится на области по назначению:
| Секция | Что хранит |
.text | сам код — машинные команды (только чтение и исполнение) |
.data | заранее заданные данные: строки, числа-константы |
.bss | место под переменные, которые на старте равны нулю |
Пример с данными:
section .data
message db "Hi", 10 ; строка "Hi" и байт 10 (перевод строки)
number dq 42 ; 64-битное число 42
section .bss
buffer resb 64 ; зарезервировать 64 байта под буферЗдесь db — define byte (по байту), dq — define quad (8 байт), resb — reserve bytes. Метка вроде message — это просто адрес начала данных.
Как работает под капотом
Метка _start особенная: именно с её адреса операционная система начинает исполнение, когда вы запускаете программу через ld напрямую. Если же вы линкуете с библиотекой C, точкой входа становится main, а _start прячется внутри стартового кода libc, который потом вызывает ваш main. Линкер собирает секции в единый образ ELF — формат исполняемых файлов в Linux — и записывает в его заголовок адрес точки входа.
Частые ошибки
- Забыть
global _start. Без этого линкер не найдёт точку входа и выдаст ошибку. - Завершать программу через
retв_start. Возвращаться некуда — программу запустило ядро напрямую. Нужен системный вызовexit(rax = 60). - Путать
.dataи.bss. В.dataкладут готовые значения, в.bssтолько резервируют место (оно обнуляется при запуске).
Итог
- Программа делится на секции:
.text(код),.data(данные),.bss(нулевые переменные). - Метка
_start— точка входа; её делают видимой черезglobal _start. - Завершение — через системный вызов exit, а не
ret. - NASM ассемблирует,
ldлинкует в исполняемый файл ELF.