🚀 1. Быстрое Решение за 3 Шага
Минимальная конфигурация для немедленного начала работы (10-15 минут).
Шаг 1: Выбор платформы
Используется:
WSL (Windows Subsystem for Linux) — полноценное Linux-окружение внутри Windows.
Требования:
- Windows 10 версии 2004+ (сборка 19041+) или Windows 11
- Включенная виртуализация в BIOS
Установка WSL:
- Откройте PowerShell от имени администратора
- Выполните команды:
wsl --install wsl --set-default-version 2 - Перезагрузите компьютер
- После перезагрузки Ubuntu запустится автоматически
- Создайте пользователя и пароль
ℹ️ После настройки WSL все дальнейшие команды выполняются в Ubuntu.
Если у вас уже установлен Linux, пропустите установку WSL.
Дистрибутивы в руководстве:
- Ubuntu/Debian
- Fedora
- Arch Linux
ℹ️ Команды приведены для этих дистрибутивов. Для других используйте соответствующий пакетный менеджер — инструменты те же.
Проверка версии Windows и включение виртуализации
Проверка версии Windows:
- Нажмите
Win + R - Введите
winverи нажмите Enter - Убедитесь: версия 2004+ (сборка 19041+) или Windows 11
Включение виртуализации:
- Откройте Диспетчер задач (
Ctrl + Shift + Esc) - Вкладка Производительность → ЦП
- Проверьте параметр Виртуализация
- Если Выключено:
- Перезагрузите компьютер
- Войдите в BIOS (
F2,Del,F10илиF12) - Найдите Intel VT-x / AMD-V / SVM
- Включите и сохраните настройки
Шаг 2: Установка инструментов
Выполните команды в зависимости от вашего дистрибутива:
Ubuntu/Debian (включая WSL):
sudo apt update && sudo apt upgrade -y
sudo apt install build-essential gdb nasm -y
Fedora:
sudo dnf update -y
sudo dnf groupinstall "Development Tools" -y
sudo dnf install nasm gdb -y
Arch Linux:
sudo pacman -Syu
sudo pacman -S base-devel nasm gdb
Что устанавливается:
| Пакет | Назначение |
|---|---|
| build-essential / Development Tools / base-devel | GCC, G++, Make и библиотеки для компиляции |
| nasm | Ассемблер для преобразования .asm файлов в объектные файлы (.o) |
| gdb | Отладчик GNU для пошаговой отладки |
Шаг 3: Быстрая проверка
Создайте тестовый проект:
# Создайте проект
mkdir ~/hello_asm && cd ~/hello_asm
mkdir src
# Создайте hello.asm
cat > src/hello.asm << 'EOF'
section .data
msg db "Hello, World!", 10
len equ $ - msg
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, len
syscall
mov rax, 60
xor rdi, rdi
syscall
EOF
# Соберите и запустите
nasm -f elf64 -g -F dwarf src/hello.asm -o hello.o
ld hello.o -o hello
./hello
Ожидаемый результат:
Hello, World!Если всё работает — окружение готово!
🐛 Не работает или падает ошибка?
Если программа не собирается или выдаёт
Segmentation fault, изучите руководство «Отладка ASM в VS Code: Настройка GDB» и список «Топ ошибок в NASM: Segfault и неверные расчёты».
🤔 2. Зачем это было нужно?
Проблема: Почему нельзя просто установить NASM?
NASM — это только ассемблер. Он превращает .asm файлы в объектные файлы .o, но не может создать исполняемый файл самостоятельно.
Что происходит при сборке:
hello.asm → [NASM] → hello.o → [LD] → hello (исполняемый)Полный набор инструментов:
| Инструмент | Роль | Зачем нужен |
|---|---|---|
| NASM | Ассемблер | Преобразует .asm в машинный код (.o) |
| LD | Компоновщик | Создаёт исполняемый файл из .o |
| GCC | Компилятор C | Нужен для проектов C + Assembly |
| GDB | Отладчик | Пошаговое выполнение, просмотр регистров |
| VS Code | Редактор | Удобство редактирования и сборки |
Почему WSL для Windows?
Системные вызовы (syscalls) отличаются:
; Вывод текста в Linux
mov rax, 1 ; syscall write
mov rdi, 1 ; stdout
mov rsi, msg
mov rdx, len
syscall; Вывод текста в Windows
mov rcx, STD_OUTPUT_HANDLE
call GetStdHandle
mov rcx, rax
mov rdx, msg
; ... (WinAPI, не syscalls)Преимущества WSL:
- Работает из коробки — не нужно настраивать MinGW, Cygwin или бороться с путями Windows
- Полная совместимость с Linux-инструментами без костылей
- Избавляет от проблем компиляции C/Assembly кода в Windows
- Один и тот же код работает в WSL и чистом Linux без изменений
- Не требует перезагрузки или виртуальной машины
Почему два типа проектов?
C + Assembly:
- Баланс между производительностью и удобством
- Доступна стандартная библиотека C (
printf,malloc) - Графическая отладка в VS Code
- Типичное применение: оптимизация критичных участков
Assembly-only:
- Полный контроль над каждой инструкцией
- Минимальный размер исполняемого файла
- Прямая работа с системными вызовами
- Типичное применение: изучение архитектуры, системное программирование
🔀 3. Какой тип проекта выбрать?
Таблица Сравнения
| Аспект | C + Assembly | Assembly-only |
|---|---|---|
| Когда использовать | Оптимизация узких мест в C-программах | Изучение архитектуры x86-64 |
| Стандартная библиотека | ✅ Доступна (printf, malloc, etc.) |
❌ Нет (только syscalls) |
| Отладка VS Code | ✅ Графический интерфейс (F5, breakpoints) | ❌ Только GDB в терминале |
| Точка входа | main |
_start |
| Линковка | Через gcc |
Через ld |
| Сложность | Средняя | Высокая |
| Размер исполняемого файла | Больше (включает libc) | Минимальный |
Рекомендации по выбору
Вы хотите:
- Оптимизировать критичные участки C-кода
- Использовать SIMD-инструкции (SSE, AVX)
- Иметь привычную отладку с breakpoints
- Работать с библиотеками C
Примеры задач:
- Математические вычисления с SIMD
- Криптографические функции
- Обработка изображений/видео
- Портирование legacy ассемблерного кода
Вы хотите:
- Глубоко понять работу процессора
- Научиться работать с syscalls напрямую
- Написать минимальный исполняемый файл
- Изучить calling conventions
Примеры задач:
- Обучающие проекты по архитектуре
- Системное программирование
- Embedded-разработка
- Написание загрузчиков
Совет для начинающих: Начните с C + Assembly. Это даст вам:
- Привычные инструменты отладки
- Возможность комбинировать высокоуровневый и низкоуровневый код
- Плавный переход к чистому ассемблеру
🛠️ 4. Настройка окружения: Пошаговая реализация
Опциональная настройка консоли
Для удобной работы в терминале можно установить Oh My Zsh с плагинами.
Что такое Oh My Zsh и зачем он нужен?
Oh My Zsh — фреймворк для управления конфигурацией Zsh:
- Сотни готовых плагинов и тем
- Автодополнение команд
- Подсветка синтаксиса
- Интеграция с Git
- Удобные алиасы
Основные возможности:
- Плагины — расширения функциональности
- Темы — изменение внешнего вида prompt
- Алиасы — короткие команды (
gstвместоgit status) - Автообновление — фреймворк обновляется автоматически
1. Установка дополнительных пакетов
sudo apt install vim-gtk3 zsh -y # Ubuntu/Debian
sudo dnf install vim-enhanced zsh -y # Fedora
sudo pacman -S gvim zsh # Arch Linux
| Пакет | Описание |
|---|---|
| vim-gtk3 / vim-enhanced / gvim | Vim с поддержкой буфера обмена |
| zsh | Альтернативная оболочка с расширенными возможностями |
2. Установка Oh My Zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
После установки Zsh станет оболочкой по умолчанию, и появится конфигурационный файл ~/.zshrc.
3. Установка плагинов
# zsh-syntax-highlighting: подсветка корректных/некорректных команд
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
# zsh-autosuggestions: автоподсказки из истории команд
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
4. Установка темы Powerlevel10k
Что даёт Powerlevel10k?
Powerlevel10k — современная и быстрая тема для Zsh:
- Показывает текущую директорию, ветку Git, статус команд
- Настраиваемый внешний вид
- Отображает статус виртуальных окружений, время выполнения
- Значительно быстрее стандартных тем
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k"
5. Настройка конфигурации
Откройте файл конфигурации:
nano ~/.zshrc
Найдите строку с ZSH_THEME и измените:
ZSH_THEME="powerlevel10k/powerlevel10k"
Найдите строку с plugins и замените:
plugins=(
git
zsh-autosuggestions
zsh-syntax-highlighting
history
)
Сохраните: Ctrl + O, Enter, затем выйдите: Ctrl + X.
6. Применение изменений
source ~/.zshrc
Запустится мастер настройки Powerlevel10k. Следуйте инструкциям на экране.
Для повторной настройки темы:
p10k configure
7. Практические примеры использования плагинов
zsh-autosuggestions:
- Подсказки появляются из истории ваших команд
- Если ранее вводили
cd ~/asm_project, то при вводеcd ~/asm_prпоявится серая подсказка - Нажмите
→(стрелка вправо) для принятия всей подсказки - Или
Ctrl+→для принятия одного слова - Продолжайте печатать для уточнения
zsh-syntax-highlighting:
- Зелёный цвет:
ls -la(команда существует и корректна) - Красный цвет:
lss -la(опечатка, команда не найдена) - Желтый цвет: строки в кавычках и пути к файлам
- Синий цвет: параметры и флаги
history plugin:
Ctrl+R: интерактивный поиск в истории команд!!: повторить последнюю команду!make: выполнить последнюю команду, начинающуюся сmake!$: последний аргумент предыдущей команды
git plugin (встроенный):
gstвместоgit statusga .вместоgit add .gc -m "message"вместоgit commit -m "message"gpвместоgit pushglвместоgit pull
Настройка Git
Настройте Git для создания коммитов с вашим именем и email.
Применяются ко всем репозиториям на компьютере
git config --global user.name "Ваше Имя"
git config --global user.email "youremail@example.com"
git config --global core.editor "nano"
Параметры:
user.name— имя в коммитахuser.email— email в коммитахcore.editor— редактор по умолчанию
Где хранятся: ~/.gitconfig
Проверить:
git config --list
Переопределяют глобальные для конкретного проекта
Полезно для разделения рабочих и личных проектов.
# Перейдите в директорию проекта
cd ~/asm_project
# Установите локальные настройки
git config user.name "Другое Имя"
git config user.email "work@example.com"
Где хранятся: .git/config в директории проекта
Проверить:
git config --local --list # Только локальные
git config user.name # С учётом приоритета
Приоритет настроек:
- Локальные (
.git/config) — наивысший - Глобальные (
~/.gitconfig) - Системные (
/etc/gitconfig) — наименьший
Настройка VS Code
Установка
Скачайте VS Code с официального сайта: code.visualstudio.com
Подключение к WSL (только для Windows)
После установки VS Code подключитесь к WSL:
-
Запустите VS Code на Windows
-
Нажмите зелёную кнопку “Open a Remote Window” (иконка
><) в левом нижнем углу
- Выберите “Connect to WSL”
- Дождитесь установки серверных компонентов (происходит автоматически при первом подключении)
- После подключения в левом нижнем углу появится индикатор “WSL: Ubuntu”
Установка расширений
⚠️ Для WSL: Устанавливайте расширения в WSL-режиме (кнопка “Install in WSL: Ubuntu”)
| Расширение | Описание |
|---|---|
| C/C++ Extension Pack (Microsoft) | Поддержка отладки C/C++ и ассемблера, IntelliSense |
| Makefile Tools (Microsoft) | Подсветка синтаксиса Makefile, интеграция со сборкой |
| x86 and x86_64 Assembly (13xforever) | Подсветка синтаксиса .asm файлов |
Как установить:
- Откройте Extensions (
Ctrl + Shift + X) - Найдите расширение
- Нажмите Install
- Для WSL: убедитесь в кнопке “Install in WSL: Ubuntu”
Проверка
Что должно быть:
- ✅ VS Code установлен
- ✅ Для Windows: индикатор “WSL: Ubuntu” виден
- ✅ Все три расширения установлены
- ✅ Встроенный терминал открывается корректно
Проекты C + Assembly
Концепция проектов C + Assembly
Этот подход используется, когда нужно:
- Оптимизация критичных участков — переписать узкие места на ассемблере
- Использование специфичных инструкций — SIMD, атомарные операции
- Обучение — понимание взаимодействия высокоуровневого и низкоуровневого кода
- Портирование legacy-кода — интеграция старых ассемблерных модулей
Типичные примеры:
- Математические библиотеки с SIMD-оптимизациями
- Криптографические функции
- Обработка изображений и видео
- Низкоуровневые системные утилиты
Особенности:
- ✅ Доступна стандартная библиотека C
- ✅ Простое управление памятью через malloc/free
- ✅ Графическая отладка в VS Code
- ✅ Точка входа — функция
main
Структура проекта
c_asm_project/
├── src/
│ ├── main_8bit.c
│ ├── calc_8bit.asm
│ ├── main_16bit.c
│ └── calc_16bit.asm
├── build/ # Создаётся автоматически
├── bin/ # Создаётся автоматически
├── .vscode/
│ ├── launch.json
│ └── tasks.json
└── MakefileСоздание структуры:
mkdir ~/c_asm_project && cd ~/c_asm_project
mkdir src .vscode
touch Makefile .vscode/launch.json .vscode/tasks.json
Концептуальный пример
Полный рабочий проект: Калькулятор с 8-битными и 16-битными операциями
src/main_8bit.c:
#include <stdio.h>
#include <stdint.h>
// Объявляем функции из ассемблера
extern uint8_t add_8bit(uint8_t a, uint8_t b);
extern uint8_t sub_8bit(uint8_t a, uint8_t b);
extern uint16_t mul_8bit(uint8_t a, uint8_t b);
int main(void) {
uint8_t a = 25;
uint8_t b = 17;
printf("8-bit Calculator\n");
printf("================\n");
printf("%u + %u = %u\n", a, b, add_8bit(a, b));
printf("%u - %u = %u\n", a, b, sub_8bit(a, b));
printf("%u * %u = %u\n", a, b, mul_8bit(a, b));
return 0;
}
src/calc_8bit.asm:
section .text
global add_8bit
global sub_8bit
global mul_8bit
; uint8_t add_8bit(uint8_t a, uint8_t b)
; Параметры: a в dil, b в sil
; Возврат: результат в al
add_8bit:
mov al, dil ; al = a
add al, sil ; al = a + b
ret
; uint8_t sub_8bit(uint8_t a, uint8_t b)
sub_8bit:
mov al, dil ; al = a
sub al, sil ; al = a - b
ret
; uint16_t mul_8bit(uint8_t a, uint8_t b)
; Параметры: a в dil, b в sil
; Возврат: результат в ax (полный 16-битный результат)
mul_8bit:
mov al, dil ; al = a
mul sil ; ax = al * sil
; Результат в ax (все 16 бит, без потерь)
ret
src/main_16bit.c:
#include <stdio.h>
#include <stdint.h>
// Объявляем функции из ассемблера
extern uint16_t add_16bit(uint16_t a, uint16_t b);
extern uint16_t sub_16bit(uint16_t a, uint16_t b);
extern uint32_t mul_16bit(uint16_t a, uint16_t b);
int main(void) {
uint16_t a = 1000;
uint16_t b = 250;
printf("16-bit Calculator\n");
printf("=================\n");
printf("%u + %u = %u\n", a, b, add_16bit(a, b));
printf("%u - %u = %u\n", a, b, sub_16bit(a, b));
printf("%u * %u = %u\n", a, b, mul_16bit(a, b));
return 0;
}
src/calc_16bit.asm:
section .text
global add_16bit
global sub_16bit
global mul_16bit
; uint16_t add_16bit(uint16_t a, uint16_t b)
; Параметры: a в di, b в si
; Возврат: результат в ax
add_16bit:
mov ax, di ; ax = a
add ax, si ; ax = a + b
ret
; uint16_t sub_16bit(uint16_t a, uint16_t b)
sub_16bit:
mov ax, di ; ax = a
sub ax, si ; ax = a - b
ret
; uint32_t mul_16bit(uint16_t a, uint16_t b)
; Параметры: a в di, b в si
; Возврат: результат в eax (полный 32-битный результат)
mul_16bit:
mov ax, di ; ax = a
mul si ; dx:ax = ax * si
; Объединяем dx:ax в eax для возврата полного результата
shl edx, 16 ; Сдвигаем dx в старшие 16 бит
movzx eax, ax ; Обнуляем старшую часть eax, копируем ax
or eax, edx ; eax = (dx << 16) | ax (все 32 бита)
ret
Makefile
Создайте Makefile:
.PHONY: all build_8bit build_16bit prepare_dirs clean
all: build_8bit build_16bit
prepare_dirs:
@mkdir -p build bin
build_8bit: prepare_dirs
gcc -c -g -ggdb -o build/main_8bit.o src/main_8bit.c
nasm -f elf64 -g -F dwarf src/calc_8bit.asm -o build/calc_8bit.o
gcc -o bin/8_bit build/main_8bit.o build/calc_8bit.o -m64 -no-pie -z noexecstack
build_16bit: prepare_dirs
gcc -c -g -ggdb -o build/main_16bit.o src/main_16bit.c
nasm -f elf64 -g -F dwarf src/calc_16bit.asm -o build/calc_16bit.o
gcc -o bin/16_bit build/main_16bit.o build/calc_16bit.o -m64 -no-pie -z noexecstack
clean:
@echo "Cleaning project..."
rm -f build/*.o
rm -f bin/8_bit bin/16_bit
@echo "Done."
Использование:
make # Собрать всё
make build_8bit # Только 8-битную версию
make clean # Очистить
Пояснение флагов компиляции
gcc -c -g -ggdb -o build/main.o src/main.c
Флаги:
-c— только компиляция, без линковки-g— отладочная информация-ggdb— расширенная информация для GDB-o file— имя выходного файла
nasm -f elf64 -g -F dwarf src/calc.asm -o build/calc.o
Флаги:
-f elf64— формат ELF 64-bit для Linux-g— отладочная информация-F dwarf— формат DWARF для GDB-o file— имя выходного файла
Линковка:
gcc -o bin/program build/main.o build/calc.o -m64 -no-pie -z noexecstack
| Флаг | Описание |
|---|---|
-o file |
Имя исполняемого файла |
-m64 |
Генерировать 64-битный код |
-no-pie |
Отключить PIE (упрощает отладку) |
-z noexecstack |
Неисполняемый стек (безопасность) |
🛡️ Почему важен флаг -z noexecstack?
Этот флаг критически важен для безопасности современных программ.
Суть проблемы: По умолчанию в старых системах стек считался «исполняемым». Это означало, что злоумышленник мог записать вредоносный код (шелл-код) в переменную на стеке (через переполнение буфера), а затем заставить процессор выполнить его.
Что делает флаг: Передает компоновщику (линкеру) указание пометить секцию стека специальным битом NX (No-Execute).
- Результат: Процессор физически запрещает исполнение инструкций, находящихся в области стека.
- Если забыть: При попытке запуска программы на современных ядрах Linux вы можете получить предупреждение от линкера
warning: execstack, а сама программа станет уязвимой для атак.
tasks.json
Создайте .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Make 8-bit",
"type": "shell",
"command": "make build_8bit",
"group": "build",
"problemMatcher": ["$gcc"]
},
{
"label": "Make 16-bit",
"type": "shell",
"command": "make build_16bit",
"group": "build",
"problemMatcher": ["$gcc"]
},
{
"label": "Make clean",
"type": "shell",
"command": "make clean"
}
]
}
Использование: Ctrl+Shift+B → выбрать задачу
launch.json
Создайте .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug 8-bit",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/8_bit",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"preLaunchTask": "Make 8-bit",
"setupCommands": [
{
"description": "Включить pretty-printing для gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Установить архитектуру",
"text": "set architecture i386:x86-64",
"ignoreFailures": true
}
]
},
{
"name": "Run 8-bit",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/8_bit",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"preLaunchTask": "Make 8-bit"
}
]
}
Ключевые параметры:
| Параметр | Описание |
|---|---|
program |
Путь к исполняемому файлу |
stopAtEntry |
true — остановка на main(), false — запуск без остановки |
preLaunchTask |
Задача сборки перед запуском |
MIMode |
Режим Machine Interface: gdb |
Отладка в VS Code
Управление отладкой:
| Клавиша | Действие |
|---|---|
F5 |
Продолжить |
F10 |
Шаг с обходом |
F11 |
Шаг с заходом |
Shift+F11 |
Выход из функции |
Shift+F5 |
Остановить |
Ctrl+Shift+F5 |
Перезапустить |
Возможности:
- Графический интерфейс
- Точки останова мышью
- Просмотр переменных и регистров
- Пошаговое выполнение
- Стек вызовов
Проекты Assembly-only
Концепция проектов Assembly-only
Этот подход используется, когда нужно:
- Полный контроль над кодом — каждая инструкция написана вручную
- Минимальный размер исполняемого файла — нет зависимостей от библиотек
- Изучение работы процессора на самом низком уровне
- Написание загрузчиков, драйверов или embedded-кода
Особенности:
- Нет стандартной библиотеки (malloc, printf, etc.)
- Все взаимодействие с ОС через syscalls
- Максимальная производительность и полное понимание работы программы
Структура проекта
asm_project/
├── src/
│ └── hello.asm
├── build/ # Создаётся автоматически
├── bin/ # Создаётся автоматически
├── .vscode/
│ └── tasks.json # ТОЛЬКО tasks.json
└── MakefileСоздание структуры:
mkdir ~/asm_project && cd ~/asm_project
mkdir src .vscode
touch Makefile .vscode/tasks.json
Концептуальный пример
Полный рабочий проект: Hello World с обработкой ввода
src/hello.asm:
section .data
prompt db "Введите ваше имя: ", 0
prompt_len equ $ - prompt
greeting db "Привет, ", 0
greeting_len equ $ - greeting
newline db 10
section .bss
name resb 64 ; Буфер для имени (64 байта)
name_len resq 1 ; Длина введённого имени
section .text
global _start
_start:
; Вывод приглашения
mov rax, 1 ; syscall: write
mov rdi, 1 ; fd: stdout
mov rsi, prompt ; buf: prompt
mov rdx, prompt_len ; count: prompt_len
syscall
; Чтение имени
mov rax, 0 ; syscall: read
mov rdi, 0 ; fd: stdin
mov rsi, name ; buf: name
mov rdx, 64 ; count: 64
syscall
; Сохранить длину (минус newline)
dec rax ; Убираем символ новой строки
mov [name_len], rax
; Вывод приветствия
mov rax, 1 ; syscall: write
mov rdi, 1 ; fd: stdout
mov rsi, greeting ; buf: greeting
mov rdx, greeting_len ; count: greeting_len
syscall
; Вывод имени
mov rax, 1 ; syscall: write
mov rdi, 1 ; fd: stdout
mov rsi, name ; buf: name
mov rdx, [name_len] ; count: name_len
syscall
; Вывод newline
mov rax, 1 ; syscall: write
mov rdi, 1 ; fd: stdout
mov rsi, newline ; buf: newline
mov rdx, 1 ; count: 1
syscall
; Выход
mov rax, 60 ; syscall: exit
xor rdi, rdi ; status: 0
syscall
Пример работы:
$ ./bin/hello
Введите ваше имя: Алексей
Привет, Алексей
Makefile
Создайте Makefile:
.PHONY: all build prepare_dirs clean
all: build
prepare_dirs:
@mkdir -p build bin
build: prepare_dirs
nasm -f elf64 -g -F dwarf src/hello.asm -o build/hello.o
ld build/hello.o -o bin/hello
clean:
@echo "Cleaning project..."
rm -f build/*.o
rm -f bin/hello
@echo "Done."
Использование:
make # Собрать
make clean # Очистить
./bin/hello # Запустить
tasks.json
Создайте .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Make build",
"type": "shell",
"command": "make build",
"group": "build",
"problemMatcher": []
},
{
"label": "Make clean",
"type": "shell",
"command": "make clean"
}
]
}
Использование: Ctrl+Shift+B
Ключевое отличие от C+Assembly
Линковка через GCC:
gcc -o bin/program main.o calc.o
- Точка входа:
main - Подключается libc
Линковка через LD:
ld hello.o -o bin/hello
- Точка входа:
_start - “Голый” исполняемый файл
Важно: В Assembly-only проектах точка входа всегда называется
_start, а неmain. Линковщикldпо умолчанию ищет именно этот символ.
Отладка Assembly-only проектов
Доступные варианты
Для отладки чистого ассемблера существует два подхода:
- Графическая отладка в VS Code (рекомендуется) — требует минимальной C-обёртки, подробно описана в отдельной статье
- Консольный GDB (описан ниже) — не требует изменений в коде, но менее удобен
Почему графическая отладка VS Code не работает напрямую
VS Code использует Debug Adapter Protocol (DAP). Расширение C/C++ предоставляет адаптер для GDB, но оно рассчитано на программы с точкой входа main и стандартной библиотекой C. Для чистого ассемблера с _start требуется адаптация через временную C-обёртку.
Для большинства задач удобнее использовать графическую отладку. Способ её настройки описан в статье «Отладка ASM в VS Code: Настройка GDB и визуальный интерфейс».
Когда использовать консольный GDB
Консольный GDB полезен в следующих случаях:
- Финальная отладка перед сдачей проекта без временных обёрток
- Работа на сервере без графического интерфейса
- Необходимость специфических команд GDB, недоступных через VS Code
- Изучение низкоуровневой отладки как самостоятельного навыка
Работа с GDB
Справочная таблица команд
| Задача | Команда | Сокращение | Пример |
|---|---|---|---|
| Запуск | gdb ./bin/prog |
— | — |
| Точка останова | break |
b |
b _start |
| Старт | run |
r |
r arg1 arg2 |
| Шаг в инструкцию | step |
s |
— |
| Шаг через call | next |
n |
— |
| Регистры | info registers |
i r |
i r rax rdi |
| Память | examine |
x/FMT addr |
x/10xb $rsi |
| Значение | print |
p/FMT |
p/x $rax |
| Продолжить | continue |
c |
— |
| Выход | quit |
q |
— |
Форматы: x (hex), d (decimal), t (binary), s (string), i (instruction)
Основные команды
Запуск и управление выполнением:
gdb ./bin/hello # Запуск с TUI-интерфейсом
break _start # Точка останова на _start
run # Старт программы
continue # Продолжить после останова
quit # Выход из GDBПошаговое выполнение:
s # Одна инструкция (заходит внутрь call)
n # Шаг с обходом call (выполняет функцию целиком)
finish # Выполнить до конца текущей функцииПросмотр данных:
# Проверка всех регистров
info registers
# Значение конкретного регистра
print/x $rax # В hex
print/d $rdi # В decimal
# Следующие инструкции
x/10i $rip
# Строка по адресу (когда в регистре адрес строки)
x/s $rsi
# Содержимое массива
x/10xb &numbers # 10 байт в hex
x/3gx &numbers # 3 qword в hexИнтерфейс:
layout asm # Показать ассемблерный код
layout regs # Показать регистры
layout split # Код + регистры
refresh # Перерисовать экранФорматы вывода памяти
| Формат | Описание | Пример | Результат |
|---|---|---|---|
/x |
Hexadecimal | p/x $rax |
0x2a |
/d |
Decimal | p/d $rax |
42 |
/t |
Binary | p/t $rax |
101010 |
/s |
String | x/s $rsi |
"Hello" |
/i |
Instruction | x/5i $rip |
Дизассемблированный код |
/xb |
Hex bytes | x/10xb $rsi |
48 65 6c 6c 6f... |
/xg |
Hex qwords | x/3xg &array |
0x0000000000000001... |
Пример сессии отладки
$ gdb ./bin/hello
(gdb) layout regs
(gdb) break _start
Breakpoint 1 at 0x401000: file src/hello.asm, line 17.
(gdb) run
Breakpoint 1, _start() at src/hello.asm:17
(gdb) info registers
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x0 0
rsp 0x7fffffffd920 0x7fffffffd920
rip 0x401000 0x401000 <_start>
eflags 0x202 [ IF ]
(gdb) step
(gdb) print/x $rax
$1 = 0x1
(gdb) i address prompt
Symbol "prompt" is at 0x402000 in a file compiled without debugging.
(gdb) x/s 0x402000
0x402000: "Введите ваше имя: "
(gdb) continue
Continuing.
Введите ваше имя: Алексей
Привет, Алексей
[Inferior 1 (process 43112) exited normally]Улучшение опыта работы
Создайте ~/.gdbinit для автоматической настройки:
# Контекст при каждой остановке
set disassemble-next-line on
# История команд
set history save on
set history size 10000
set history filename ~/.gdb_history
# Красивый вывод структур
set print pretty on
# Intel-синтаксис
set disassembly-flavor intel
# Без подтверждения при выходе
set confirm off
Опционально: GDB Dashboard
Что такое GDB Dashboard:
GDB Dashboard — это конфигурация для GDB с визуальным интерфейсом, которая одновременно показывает код, регистры, стек и другие данные.
Сравнение со стандартным GDB:
| Функция | Стандартный GDB | С Dashboard |
|---|---|---|
| Код | layout asm → одна панель |
Несколько панелей одновременно |
| Регистры | info registers вручную |
Постоянно видны |
| Стек | backtrace вручную |
Автоматическое обновление |
| Подсветка | Нет | Цветной код |
Возможности:
- Автоматические панели для кода, регистров, стека
- Подсветка синтаксиса
- Контекст выполнения без дополнительных команд
- Настраиваемые модули
Установка:
# Резервная копия существующего .gdbinit
[ -f ~/.gdbinit ] && cp ~/.gdbinit ~/.gdbinit.backup
# Скачивание конфигурации
wget -P ~ https://github.com/cyrus-and/gdb-dashboard/raw/master/.gdbinit
Внимание: Команда перезапишет существующий
~/.gdbinit.
Базовые команды:
Важно: GDB Dashboard несовместим с флагом
-tui. Dashboard сам управляет интерфейсом через свои панели. Запускайте простоgdb ./bin/progбез-tui.
dashboard # Показать/скрыть
dashboard -layout assembly registers stack # Выбрать панели
dashboard assembly -style height 15 # Настроить высотуВосстановление:
cp ~/.gdbinit.backup ~/.gdbinit
Практический пример: Отладка ошибки сегментации
Процесс отладки программы с выходом за границы массива
Проблемный код (src/buggy.asm):
section .data
numbers dq 10, 20, 30
array_size equ 3
section .text
global _start
_start:
; BUG: Попытка записи в read-only секцию .text
; Это гарантированно вызовет segmentation fault
mov qword [_start], 0x90909090
mov rax, 60
xor rdi, rdi
syscall
Процесс отладки:
# 1. Запуск программы
$ ./bin/buggy
[1] 7460 segmentation fault (core dumped) ./bin/buggy
# 2. Запуск GDB
$ gdb ./bin/buggy
(gdb) run
Starting program: /home/basted/test_asm/bin/buggy
Program received signal SIGSEGV, Segmentation fault.
_start () at src/buggy.asm:11
11 mov qword [_start], 0x90909090
# 3. Анализ состояния регистров
(gdb) info registers
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x0 0
rbp 0x0 0x0
rsp 0x7fffffffd8a0 0x7fffffffd8a0
rip 0x401000 0x401000 <_start>
eflags 0x10202 [ IF RF ]
# 4. Дизассемблирование
(gdb) disassemble _start
Dump of assembler code for function _start:
=> 0x0000000000401000 <+0>: movq $0xffffffff90909090,0x401000
0x000000000040100c <+12>: mov $0x3c,%eax
0x0000000000401011 <+17>: xor %rdi,%rdi
0x0000000000401014 <+20>: syscall
End of assembler dump.
# 5. Проверка карты памяти и прав доступа
(gdb) info proc mappings
Start Addr End Addr Size Offset Perms File
0x0000000000400000 0x0000000000401000 0x1000 0x0 r--p buggy
0x0000000000401000 0x0000000000402000 0x1000 0x1000 r-xp buggy
0x0000000000402000 0x0000000000403000 0x1000 0x2000 rw-p buggy
# Секция .text (0x401000) имеет права r-xp (read-execute), НЕТ записи!
# 6. Пошаговое выполнение
(gdb) break _start
Breakpoint 1 at 0x401000: file src/buggy.asm, line 11.
(gdb) run
Breakpoint 1, _start () at src/buggy.asm:11
11 mov qword [_start], 0x90909090
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
_start () at src/buggy.asm:11
11 mov qword [_start], 0x90909090Исправленный код:
section .data
numbers dq 10, 20, 30
array_size equ 3
result dq 0 ; Добавили переменную для записи
section .text
global _start
_start:
; Правильно: доступ к последнему элементу массива
mov rcx, 2 ; Индекс: 0, 1, 2
mov rax, [numbers + rcx*8] ; numbers[2] = 30
; Правильно: запись в секцию .data (разрешена запись)
mov [result], rax
mov rax, 60
xor rdi, rdi
syscall
Вывод: Для массива из 3 элементов по 8 байт валидные offset: 0, 8, 16. Попытка записи в секцию .text (адрес 0x401000 с правами r-xp) всегда вызывает segmentation fault, так как эта секция защищена от записи операционной системой.
💡 Подробный разбор частых ошибок, которые можно найти с помощью GDB, читайте в статье «Топ ошибок в NASM: Почему падает Segfault и неверные расчёты».
📋 5. Типичные ошибки и решения
Проблемы с компиляцией и линковкой
"NASM: fatal error - unable to open input file"
Причина: Неверный путь к файлу в Makefile или команде
Решение:
# Проверьте текущую директорию
pwd
# Проверьте наличие файла
ls -la src/hello.asm
# Убедитесь, что пути в Makefile относительные:
nasm -f elf64 src/hello.asm # Правильно
nasm -f elf64 /src/hello.asm # Неправильно (абсолютный путь от корня)"ld: warning: cannot find entry symbol _start"
Причина: Неправильное имя метки или отсутствие global _start
Решение:
; Убедитесь, что есть обе строки:
section .text
global _start ; Экспортируем метку
_start: ; Определяем метку
; ваш код"undefined reference to `main`"
Причина: Используется gcc для линковки Assembly-only проекта
Решение:
# Неправильно для Assembly-only:
gcc -o bin/hello hello.o
# Правильно:
ld hello.o -o bin/hello
# Или измените точку входа на main и добавьте exit:section .text
global main
extern exit
main:
; ваш код
; Вызов exit(0)
xor rdi, rdi
call exit"Segmentation fault" сразу при запуске
Возможные причины и решения:
1. Неправильное выравнивание стека:
; Неправильно (стек не выровнен по 16 байт перед call):
_start:
call some_function
; Правильно:
_start:
sub rsp, 8 ; Выравнивание стека
call some_function
add rsp, 82. Забыт ret в функции:
; Неправильно:
my_function:
mov rax, 42
; ret забыт! Выполнение продолжится дальше
; Правильно:
my_function:
mov rax, 42
ret3. Испорчен базовый указатель:
; Неправильно:
my_function:
push rbp
mov rbp, rsp
; ... код ...
pop rbp
mov rax, 123 ; Перезатерли rax после восстановления rbp!
ret
; Правильно:
my_function:
push rbp
mov rbp, rsp
; ... код ...
mov rax, 123 ; Сначала возвращаемое значение
pop rbp ; Потом восстанавливаем rbp
retПроблемы с VS Code
Расширения не работают в WSL
Причина: Расширения установлены на Windows, но не работают в WSL
Решение:
- Подключитесь к WSL (зелёная кнопка
><→ “Connect to WSL”) - Откройте Extensions (
Ctrl+Shift+X) - Найдите расширение
- Нажмите “Install in WSL: Ubuntu” (НЕ просто “Install”)
Breakpoints не работают в C+Assembly
Причина: Отсутствует отладочная информация или используется PIE
Решение:
-
Убедитесь в флагах компиляции:
gcc -c -g -ggdb src/main.c # Для C nasm -f elf64 -g -F dwarf src/calc.asm # Для ASM -
Отключите PIE при линковке:
gcc -o bin/prog main.o calc.o -no-pie -
Пересоберите проект:
make clean && make
Проблемы с GDB
"No symbol table is loaded"
Причина: Программа скомпилирована без отладочной информации
Решение:
# Пересоберите с флагами отладки:
nasm -f elf64 -g -F dwarf src/hello.asm -o hello.o
ld hello.o -o bin/hello
# Проверьте наличие отладочной информации:
file bin/hello
# Должно быть: "not stripped""Cannot access memory at address"
Причина: Попытка доступа к невыделенной или защищенной памяти
Решение:
# Проверьте, что адрес валиден:
(gdb) info proc mappings # Показать карту памяти
# Проверьте границы вашего массива:
section .data
array db 1, 2, 3
array_size equ $ - array # Размер в байтах
# Используйте только валидные смещения:
mov al, [array + 0] # OK
mov al, [array + 2] # OK (последний элемент)
mov al, [array + 3] # ОШИБКА (выход за границы)Проблемы с Makefile
"Makefile:X: *** missing separator"
Причина: Использование пробелов вместо табуляции
Решение:
# НЕПРАВИЛЬНО (пробелы):
hello:
nasm -f elf64 src/hello.asm
# ПРАВИЛЬНО (табуляция):
hello:
nasm -f elf64 src/hello.asm
В VS Code настройте автозамену для Makefile:
// settings.json
{
"[makefile]": {
"editor.insertSpaces": false,
"editor.detectIndentation": false
}
}
🏁 6. Итоговая проверка
Проверка окружения
Убедитесь, что все инструменты установлены:
nasm -v # NASM version 2.16.xx+
gcc --version # gcc 11.x+
ld -v # GNU ld version 2.xx
gdb -v # GNU gdb version 12.x+
Ожидаемый вывод:
NASM version 2.16.01
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
GNU ld (GNU Binutils for Ubuntu) 2.38
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1Проверка Git:
git config user.name
git config user.email
Должны вывестись ваши имя и email.
Проверка C + Assembly проекта
Структура:
- ✅ Директории
src/,.vscode/,build/,bin/ - ✅ Файлы
Makefile,tasks.json,launch.json - ✅ C-файлы и .asm файлы в
src/
Работоспособность:
cd ~/c_asm_project
make # Без ошибок
ls bin/ # Файлы появились
./bin/8_bit # Программа запускается
make clean # Очистка успешна
ls build/ bin/ # Директории пусты
Отладка в VS Code:
- Откройте проект в VS Code:
code . - Установите breakpoint в
main.c - Нажмите
F5→ выберите “Debug 8-bit” - Программа должна остановиться на
main() F10для пошагового выполнения- Проверьте панель Variables
Чек-лист:
- ✅
F5запускает отладку - ✅ Остановка на
main() - ✅
F10переходит к следующей строке - ✅ Видны значения переменных
- ✅ Можно просмотреть регистры в Debug Console:
-exec info registers
Проверка Assembly-only проекта
Структура:
- ✅ Директории
src/,.vscode/,build/,bin/ - ✅ Файлы
Makefile,tasks.json(БЕЗlaunch.json) - ✅ .asm файл имеет точку входа
_start
Работоспособность:
cd ~/asm_project
make # Без ошибок
ls bin/ # Файл появился
./bin/hello # Программа запускается и выводит текст
echo $? # Проверить код возврата (должно быть 0)
make clean # Очистка успешна
Отладка через GDB:
gdb ./bin/hello
(gdb) layout asm
(gdb) layout regs
(gdb) break _start
Breakpoint 1 at 0x401000
(gdb) run
(gdb) info registers
(gdb) stepi
(gdb) continueЧек-лист:
- ✅ GDB запускается без ошибок
- ✅ TUI-режим работает (
layout asm,layout regs) - ✅ Breakpoint устанавливается на
_start - ✅
stepiиnextiработают - ✅
info registersпоказывает значения - ✅
x/s адресчитает строки - ❌ VS Code отладка не работает (это нормально)
Финальная проверка VS Code
Для C + Assembly проектов:
cd ~/c_asm_project
code .
Ctrl+Shift+B→ выберите “Make 8-bit”- Проверьте вывод в Terminal
F5→ “Debug 8-bit”- Убедитесь, что отладка запускается
Для Assembly-only проектов:
cd ~/asm_project
code .
Ctrl+Shift+B→ “Make build”Ctrl+`→ открыть терминалgdb ./bin/hello→ отладка в терминале
📚 7. Быстрая справка
Горячие клавиши VS Code
| Действие | Клавиша |
|---|---|
| Открыть терминал | Ctrl+` |
| Быстрая сборка | Ctrl+Shift+B |
| Запустить отладку | F5 |
| Запустить без отладки | Ctrl+F5 |
| Breakpoint | F9 |
| Шаг с обходом | F10 |
| Шаг с заходом | F11 |
| Выход из функции | Shift+F11 |
| Продолжить | F5 |
| Остановить | Shift+F5 |
| Перезапустить | Ctrl+Shift+F5 |
| Extensions | Ctrl+Shift+X |
| Debug панель | Ctrl+Shift+D |
| Командная палитра | Ctrl+Shift+P |
| Открыть файл | Ctrl+O |
| Поиск в файлах | Ctrl+Shift+F |
Команды терминала
# Сборка
make # Собрать всё
make <target> # Конкретную цель
make clean # Очистить
# Запуск
./bin/<program> # Запустить программу
./bin/<program> arg1 # С аргументами
# Проверка инструментов
nasm -v # Версия NASM
gcc --version # Версия GCC
ld -v # Версия линкера
gdb -v # Версия GDB
which nasm # Путь к исполняемому файлу
# Git
git config --list # Все настройки
git config --global user.name "Имя"
git config --global user.email "email"
git config --local user.name "Другое имя" # Для текущего репо
# WSL (PowerShell на Windows)
wsl --list # Список дистрибутивов
wsl --list --verbose # Подробная информация
wsl --shutdown # Остановить все WSL
wsl --update # Обновить WSL
wsl --set-default-version 2
wsl -d Ubuntu # Запустить конкретный дистрибутив
# Навигация
cd ~/project # Перейти в директорию
pwd # Текущая директория
ls -la # Список файлов (подробно)
mkdir -p dir/subdir # Создать директории
rm -rf directory # Удалить директорию
cp file1 file2 # Копировать файл
mv file1 file2 # Переместить/переименовать
Команды GDB
# Запуск
gdb ./bin/hello # Стандартный режим
gdb -tui ./bin/hello # TUI-режим
gdb --args ./bin/prog arg1 arg2 # С аргументами
# Основные команды
break _start # Breakpoint на функции
break *0x401000 # Breakpoint на адресе
break hello.asm:10 # Breakpoint на строке
info breakpoints # Список breakpoints
delete 1 # Удалить breakpoint #1
disable 1 # Отключить breakpoint #1
enable 1 # Включить breakpoint #1
# Выполнение
run # Запустить программу
run arg1 arg2 # С аргументами
continue # Продолжить выполнение
stepi # Одна инструкция
nexti # Шаг с обходом call
finish # До конца функции
until # До следующей строки
kill # Остановить программу
# Информация
info registers # Все регистры
info registers rax rbx # Конкретные регистры
print $rax # Значение регистра
print/x $rax # В hex
print/d $rax # В decimal
print/t $rax # В binary
print/c $rax # Как символ
# Память
x/10i $rip # 10 инструкций от rip
x/s $rsi # Строка по адресу
x/16xb 0x404000 # 16 байт в hex
x/4xg 0x404000 # 4 qword в hex
disassemble # Дизассемблировать текущую функцию
disassemble _start # Конкретную функцию
disassemble 0x401000 # По адресу
# Интерфейсы
layout asm # Показать ассемблерный код
layout regs # Показать регистры
layout split # Код + регистры
layout src # Исходный код (для C)
tui disable # Отключить TUI
tui enable # Включить TUI
Ctrl+L # Обновить экран
Ctrl+X затем A # Переключить TUI
# Другое
set disassembly-flavor intel # Intel синтаксис
set disassembly-flavor att # AT&T синтаксис
backtrace # Стек вызовов
frame 0 # Перейти к кадру стека
info stack # Информация о стеке
quit # Выйти из GDB
Форматы данных в GDB
| Формат | Команда | Описание | Пример вывода |
|---|---|---|---|
/x |
x/x или p/x |
Hexadecimal | 0x2a |
/d |
x/d или p/d |
Decimal | 42 |
/u |
x/u или p/u |
Unsigned decimal | 42 |
/o |
x/o или p/o |
Octal | 052 |
/t |
x/t или p/t |
Binary | 101010 |
/c |
x/c или p/c |
Character | '*' |
/s |
x/s |
String | "Hello" |
/i |
x/i |
Instruction | mov rax, 1 |
Размеры:
b= byte (1 байт)h= halfword (2 байта)w= word (4 байта)g= giant word (8 байт)
Примеры:
x/4xb 0x404000 # 4 байта в hex
x/2xw 0x404000 # 2 слова (4 байта каждое) в hex
x/8xg 0x404000 # 8 qword (8 байт каждый) в hex✅ Заключение
Теперь у вас есть полноценное окружение для разработки на ассемблере с:
✅ Автоматической сборкой через Makefile
✅ Интеграцией с VS Code (редактирование и сборка)
✅ Графической отладкой (только C + Assembly)
✅ Консольной отладкой через GDB (Assembly-only)
✅ Поддержкой смешанных и чистых проектов
✅ Знанием типичных ошибок и их решений
✅ Полным справочником команд и инструментов
Ключевые моменты:
- C + Assembly: VS Code для редактирования, сборки и отладки
- Assembly-only: VS Code для редактирования и сборки, GDB для отладки
- Все конфигурации универсальны для Linux и WSL
- Всегда используйте флаги отладки (
-g,-ggdb,-F dwarf) - Помните о различиях в точках входа:
mainvs_start