Ассемблер

Как писать на ассемблере на Linux

Писать на ассемблере на Linux лучше начинать с понятной связки: архитектура x86-64, NASM-синтаксис, объектный формат elf64, сборка через nasm, linking через ld или gcc, запуск из терминала. Linux хорошо подходит для изучения ассемблера, потому что инструменты сборки доступны из командной строки, а системные вызовы можно увидеть прямо в коде

Выберите синтаксис и инструмент

На Linux чаще встречаются два подхода:

  • NASM — Intel-подобный синтаксис, удобен для учебных примеров;
  • GAS — assembler из GNU binutils, часто используется вместе с GCC.

Новичку проще начать с NASM. В нем код читается ближе к тому, что обычно показывают в учебниках по x86-64: mov rax, 1, mov rdi, 1, syscall. GAS тоже полезен, но у него другой стиль записи, особенно если используется AT&T-синтаксис

Установите инструменты

Для Debian или Ubuntu:

sudo apt install nasm binutils gcc gdb

Проверьте:

nasm -v
ld -v
gcc --version
gdb --version

nasm нужен для сборки .asm, ld — для linking, gcc удобно использовать, когда ассемблерная функция вызывается из C, gdb нужен для отладки

Первый пример без C-библиотеки

Создайте hello.asm:

section .data
    msg db "Linux asm", 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

Сборка:

nasm -f elf64 hello.asm -o hello.o
ld hello.o -o hello
./hello

Вывод:

Linux asm

В этом варианте программа общается с ядром напрямую. rax хранит номер системного вызова, rdi, rsi, rdx хранят аргументы. Для write номер 1, для exit номер 60

Второй путь: ассемблерная функция из C

Если вам удобнее видеть привычный main, можно написать функцию на ассемблере и вызвать ее из C

add.asm:

section .text
    global add_two

add_two:
    mov rax, rdi
    add rax, rsi
    ret

main.c:

#include <stdio.h>

long add_two(long a, long b);

int main(void) {
    printf("%ld\n", add_two(2, 5));
    return 0;
}

Сборка:

nasm -f elf64 add.asm -o add.o
gcc main.c add.o -o app
./app

Результат:

7

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

Как отлаживать

Запустите:

gdb ./hello

Полезные команды:

break _start
run
info registers
x/16xb &msg
stepi

Команда info registers показывает значения регистров. stepi выполняет одну машинную инструкцию. Это главный плюс ассемблера: можно увидеть, как меняется процессорное состояние после каждой команды

Что не путать

Linux-ассемблер не равен DOSBox/TASM. Если код содержит .model small, int 21h, ah = 09h, это DOS-пример. В Linux x64 вам нужны ELF-файлы, регистры rax, rdi, rsi, rdx и команда syscall

Также не путайте assembler и архитектуру. NASM может собирать код под разные форматы, но пример все равно должен соответствовать платформе. Команда nasm -f elf64 говорит о формате выходного объектного файла, а не исправляет код, написанный под другую операционную систему

Частые ошибки

Запускают .o вместо программы

file.o — объектный файл. Его нужно связать:

ld file.o -o app

Не понимают, где main

Если вы используете _start, C-библиотека не подключается. Если хотите main, собирайте вместе с C через gcc

Берут пример под Windows

Windows x64 использует другое соглашение и другие системные вызовы. Для Linux берите Linux-примеры

Не передают длину строки

Системный вызов write получает адрес и длину. Он не ищет нулевой байт или $

Что почитать дальше по ассемблеру

Если нужен общий маршрут по теме, откройте рубрику ассемблеру. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x