Ассемблер

Как работать на ассемблере

Работать на ассемблере значит писать .asm-файлы, собирать их подходящим assembler, связывать через linker, запускать программу и проверять результат в отладчике. В отличие от языков высокого уровня, здесь нужно внимательно следить за регистрами, памятью, флагами, стеком и платформой

Рабочий процесс

Практический цикл такой:

  1. написать небольшой фрагмент кода;
  2. собрать .asm в .o или .obj;
  3. связать программу;
  4. запустить;
  5. проверить вывод или состояние регистров;
  6. исправить ошибку;
  7. повторить.

Для Linux x64:

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

Для Visual Studio и MASM работа чаще идет внутри C++ проекта. Для TASM нужен DOSBox и команды tasm, tlink

Как организовать файлы

Держите проект просто:

project/
  app.asm
  notes.md
  build.sh

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

Как проверять код

Ассемблерный код проверяют не только выводом на экран. Часто нужно смотреть регистры и память

В GDB:

info registers
stepi
x/16xb $rsp

info registers показывает регистры. stepi выполняет одну инструкцию. x/16xb $rsp показывает байты около стека

Как работать с ошибками

Ошибки обычно относятся к одному из уровней:

  • assembler не понял синтаксис;
  • linker не нашел символ;
  • программа запускается, но логика неверная;
  • пример написан под другую платформу.

Если ошибка на этапе сборки, смотрите строку и синтаксис. Если ошибка на этапе linking, смотрите имена функций, global, extern и объектные файлы. Если программа запускается, но результат неверный, смотрите регистры и флаги

Как работать с C

На практике ассемблер часто используют не как отдельную большую программу, а как маленькую функцию рядом с C или C++

Пример идеи:

global add_two

add_two:
    mov rax, rdi
    add rax, rsi
    ret

Здесь важно знать соглашение вызова: в Linux x86-64 первые аргументы идут через rdi, rsi, rdx, rcx, r8, r9. В Windows x64 порядок другой: rcx, rdx, r8, r9

Как не ломать программу

Следите за регистрами, которые обязаны сохраняться по соглашению вызова. Если функция меняет callee-saved регистр и не восстанавливает его, ошибка может проявиться далеко не сразу

Также следите за стеком. Если вы сделали push, должен быть соответствующий pop или корректное восстановление rsp. Неправильный стек может сломать ret

Где ассемблер полезен

Ассемблер используют для:

  • чтения дизассемблированного кода;
  • отладки низкоуровневых ошибок;
  • понимания компилятора;
  • микроконтроллеров;
  • загрузчиков;
  • отдельных критичных фрагментов;
  • обучения архитектуре процессора.

Писать большую программу целиком на ассемблере сегодня нужно редко. Но понимать его полезно даже разработчику на C, C++, Rust или Go

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

Работать без отладчика

Без регистров и памяти вы не видите, что происходит

Не различать синтаксисы

NASM, MASM, GAS и TASM пишутся по-разному

Переносить код между Linux и Windows без правок

Системные вызовы и соглашения вызова отличаются

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

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

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

Настройки cookie

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