/libasm

Assembly language project

Primary LanguageC

libasm

Проект выполнялся на Mac OS X 10.14.6
Узнать вашу версию можно командой

$ sw_vers

Или нажмите на яблоко в верхнем левом углу экрана и выберете About This Mac.

Установка NASM

Для компиляции я использовал NASM. Установка:

brew install nasm

Если нет brew, выполните:

curl -fsSL https://rawgit.com/kube/42homebrew/master/install.sh | zsh

Еще необходим gcc, подразумевается, что он есть. Чтобы проверить, что у вас все работает, склонируйте репозиторий, перейдите в него и выполните:

./check.sh

Если вы увидели поздравление, значит всё работает.

Hello world

Разберем код поздравления.

1   global  _main                   ; точка входа в программу, будет вызвана процедура _main
2 
3   section .text                   ; в секции text пишется код программы
4   _main:                          ; объявляем процедуру _main
5       mov     rax, 0x02000004     ; помещаем в регистр rax номер системного вызова - write
6       mov     rdi, 1              ; помещаем в регистр rdi файловый дескриптор - stdout
7       lea     rsi, message        ; помещаем в регистр rsi сообщение для вывода
8       mov     rdx, len            ; помещаем в регистр rdx длину сообщения
9       syscall                     ; просим ОС выполнить то, что мы закодировали выше
10      call    _exit               ; вызываем процедуру _exit
11
12  _exit:                          ; объявляем процедуру _exit
13      mov       rax, 0x02000001   ; помещаем в регистр  rax номер системного вызова - exit
14      xor       rdi, rdi          ; помещаем в регистр rdi код ошибки - 0
15      syscall                     ; просим ОС выполнить то, что мы закодировали выше
16
17  section   .data                 ; в секции data объявляются "переменные"
18  message default rel             ; объявляем message и помещаем туда сообщение
19          db      "Congrats! Everything is working OK!", 10, 0
20  len     equ     $-message       ; объявляем len и помещаем туда длину сообщения 

Заметки

Для работы нашей программы ОС выделяет память, которая будет поделена на:

  1. Код программы (section .text) - фиксированный размер
  2. Данные программы
    • section .data - здесь содержатся данные программы, которые не могут быть изменены. Фиксированный размер
    • .bss - буфер для данных, которые будут изменены или объявлены позже в программе, фиксированый размер. Буфер изначально заполнен нулями
  3. Стэк - область памяти для передачи данных процедурам в программе

Иногда вместо section можно увидеть segment, это синонимы, можно использовать любое слово. Код будет работать, если не указывать их вообще, но они упрощают чтение кода.


Коды системных вызовов можно найти в файле syscall.h. Воспользуйтесь поиском, чтобы посмотреть его.


При передаче аргументов в функции, они помещаются в rdi, rsi, rdx, rcx, r8, r9 соответственно rax - регистр "обмена", через него осуществляется передача значений между функциями.


xor rdi, rdi равносильно mov rdi, 0, но эффективней по памяти и скорости.


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

  • размер 16 байт
  • смещение 8 байт
typedef struct     s_list
{
	void           *content;
	struct s_list  *next;
}                  t_list;

size of t_list - 16 bytes
offset - 8 bytes

0                       8                       16
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|        content        |          next         |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

поэтому, если адрес t_list в rdi, то:

  • для доступа в content используем [rdi]
  • доступ в next - [rdi + 8]

Полезные ссылки