Compare commits

...

15 Commits

Author SHA1 Message Date
Пытков Роман
2332be6293 Простое окно 2025-09-25 23:50:14 +03:00
Пытков Роман
1698b43da6 Начало проекта wayland 2025-09-24 02:05:38 +03:00
Пытков Роман
17096efe0f Сумма цифр 2025-09-23 21:16:00 +03:00
Пытков Роман
0716753b1f Подсчёт слов 2025-09-23 21:12:41 +03:00
Пытков Роман
4e111c6148 Перевод в бинарь 2025-09-23 20:28:48 +03:00
Пытков Роман
885f62867e более менее 10 2025-09-23 18:33:50 +03:00
Пытков Роман
1f40ef4467 Больше или меньше 10 2025-09-23 18:00:44 +03:00
Пытков Роман
184eeb8525 Перенос stepik в подпапку 2025-09-23 17:48:53 +03:00
Пытков Роман
6a90ff02c8 id_digit и min 2025-09-23 17:16:48 +03:00
Пытков Роман
00273bf803 repeat_str 2025-09-23 14:26:36 +03:00
Пытков Роман
01c7a248ad even_odd 2025-09-23 01:24:01 +03:00
Пытков Роман
8d019a59d7 minimal -> sum 2025-09-22 00:58:48 +03:00
Пытков Роман
444a2da5a8 Сложение двух чисел 2025-09-22 00:53:15 +03:00
Пытков Роман
6ef051900a всякое 2025-09-21 19:25:45 +03:00
Пытков Роман
62bcc7f9cd Обновлён git ignore 2025-09-21 12:05:40 +03:00
53 changed files with 3096 additions and 89 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
**/build/
**/build/
**/out/

View File

@@ -11,6 +11,27 @@
"env": {
"PATH": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
}
},
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
},
],
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
]
}
]
}

View File

@@ -7,4 +7,4 @@ enable_language(ASM_NASM)
set(CMAKE_ASM_NASM_FLAGS "-f elf64")
set(CMAKE_ASM_NASM_FLAGS_DEBUG "-gdwarf")
add_executable(casm asm.asm c.c cpp.cpp)
add_executable(casm asm.asm c.c)

View File

@@ -1,9 +1,10 @@
global main
extern sum, print, scan, test_vector, a
extern sum, print, scan
extern a
section .text
main:
push rbx ; сохранить rbx
push rbx
call scan ; прочитать первое число
mov rbx, rax ; сохранить первое число
call scan ; прочитать второе число
@@ -11,12 +12,12 @@ main:
mov rsi, rax ; b
call sum ; сумма
mov rdi, rax ; результат
push rax
call print ; напечатать
call test_vector
pop rbx ; восстановить rbx
pop rax
pop rbx
mov dword [rel a], 42 ; записать значение 42 в переменную a
mov dword [rel a], eax ; записать значение 42 в переменную a
mov rdi, 0
mov rax, 60
syscall
mov rax, 0
ret

View File

@@ -1,11 +0,0 @@
#include <vector>
#include <iostream>
extern "C" void test_vector() {
std::vector<int> vec = std::vector<int>();
for(auto i = 0; i < 10; i++)
vec.push_back(i);
for(auto num : vec)
std::cout << num << ", ";
std::cout << std::endl;
}

2
casm/input.txt Normal file
View File

@@ -0,0 +1,2 @@
10
20

BIN
docs/Intel manual.pdf Normal file

Binary file not shown.

36
docs/cdecl.md Normal file
View File

@@ -0,0 +1,36 @@
## System V AMD64 ABI (cdecl): шпаргалка
Кратко о соглашении вызова для x86-64 в Unix-подобных ОС (Linux, macOS, BSD) по ABI System V.
### Быстрые правила
- Аргументы (целые/указатели): RDI, RSI, RDX, RCX, R8, R9; остальные — на стек (справа налево).
- Аргументы с плавающей точкой/векторы: XMM0XMM7; остальные — на стек.
- Возврат значения: целые/указатели — RAX (до 128 бит: RAX/RDX); float/double — XMM0 (до двух — XMM0/XMM1).
- Перед call: RSP должен быть выровнен по 16 байт. Внутри функции на входе RSP % 16 == 8 (из-за return address).
- Red zone: 128 байт под RSP доступны leaf-функциям; не трогается ОС и обработчиками сигналов.
- Нет «shadow space» (он есть только в Windows x64 ABI).
### Сохранность регистров
- Caller-saved (clobbered): RAX, RCX, RDX, RSI, RDI, R8R11, XMM0XMM15, флаги RFLAGS.
- Callee-saved (надо сохранять и восстанавливать в функции): RBX, RSP, RBP, R12R15.
### Порядок передачи аргументов
#### Для call
- 16-й целочисленные/указательные: RDI, RSI, RDX, RCX, R8, R9.
- Вещественные/векторные: XMM0XMM7 (независимо от целочисленных).
- 7-й и далее, а также переполнение по типам — через стек. Компиляторы обычно размещают их с выравниванием по 8/16.
### Вариативные функции (printf и т.п.)
- Перед вызовом variadic-функции младший байт RAX (AL) содержит число использованных XMM-регистров для передачи аргументов с плавающей точкой (0, если их нет).
### Структуры и большие значения
- Небольшие структуры (до 16 байт) могут возвращаться через регистры (классы INTEGER/SSE распределяются по RAX/RDX или XMM0/XMM1).
- Большие структуры возвращаются через скрытый указатель: вызывающий передаёт адрес буфера (sret), а функция заполняет его.
### Памятка при написании кода
- До call: выровняй стек (RSP%16==0), подготовь регистры аргументов, AL для varargs.
- После call: результат смотри в RAX/XMM0; считай, что caller-saved испорчены — сохрани важное заранее.
- В своей функции сохраняй/восстанавливай RBX, RSP, RBP, R12R15.

BIN
docs/nasmdoc.pdf Normal file

Binary file not shown.

142
docs/syscall.md Normal file
View File

@@ -0,0 +1,142 @@
## Linux x86-64 syscall: шпаргалка
Кратко о низкоуровневых системных вызовах в Linux на x86-64 через инструкцию `syscall` (без libc/glibc-обёрток).
### Быстрые правила
- Номер системного вызова: в RAX.
- Аргументы (целые/указатели): RDI, RSI, RDX, R10, R8, R9
- Возврат: RAX (неотрицательно при успехе; при ошибке — отрицательное значение `-errno` в диапазоне [-4095..-1]).
- Порченные регистры инструкцией `syscall`: RCX, R11 (всегда). RAX меняется на код возврата.
- Остальные GPR обычно возвращаются неизменёнными ядром, но в пользовательском коде всё равно соблюдай ABI: после syscalls/функций не полагайся на caller-saved (RAX, RCX, RDX, RSI, RDI, R8R11).
- Выравнивание стека: сама инструкция `syscall` не требует 16-байтового выравнивания RSP, но если ты в функции, которая также вызывает обычные функции по ABI System V, держи RSP кратным 16 перед `call`.
- Red zone (128 байт под RSP) по ABI доступна и не трогается ядром/обработчиками сигналов — её можно использовать в leaf-коде. Если есть сомнения/нестандартное окружение — не полагайся на неё.
### Возврат и обработка ошибок
- При успехе RAX содержит неотрицательный результат (часто количество байт, файловый дескриптор и т.п.).
- При ошибке RAX содержит отрицательное число `-errno` (в диапазоне [-4095..-1]). Никаких флагов (CF/ZF) для ошибки не используется — проверяй знак RAX.
- Обёртки libc (например, `write(2)`) конвертируют `-errno` в `-1` и устанавливают `errno`. В чистом `syscall` этого нет — обрабатывай сам.
### Где взять номера системных вызовов
- Заголовки ядра: `/usr/include/x86_64-linux-gnu/asm/unistd_64.h` (или `/usr/include/asm/unistd_64.h` в зависимости от дистрибутива).
- `man 2 syscall`, `man 2 <имя>` (например, `man 2 write`). Часто используется `openat` вместо устаревающего `open`.
### Примеры (NASM)
#### write(1, msg, len)
```nasm
; ssize_t write(int fd, const void *buf, size_t count)
; x86-64: rax=1 (SYS_write), rdi=fd, rsi=buf, rdx=count
mov rax, 1 ; SYS_write
mov rdi, 1 ; fd = stdout
lea rsi, [rel msg] ; buf
mov rdx, msg_end - msg ; count
syscall
; при успехе: rax = число записанных байт (>=0)
; при ошибке: rax < 0 ( = -errno )
msg: db "Hello, syscall!\n", 0x0A
msg_end:
```
#### exit(status)
```nasm
; void _exit(int status) — завершает текущий поток/процесс (exit_group завершит все потоки процесса)
mov rax, 60 ; SYS_exit
xor rdi, rdi ; status = 0
syscall ; не возвращается
```
#### openat(AT_FDCWD, path, flags, mode)
```nasm
; long openat(int dirfd, const char *pathname, int flags, mode_t mode)
; x86-64: rax=257 (SYS_openat), rdi=dirfd, rsi=pathname, rdx=flags, r10=mode
mov rax, 257 ; SYS_openat
mov rdi, -100 ; AT_FDCWD
lea rsi, [rel path]
mov rdx, 0x0002 ; O_RDWR (пример)
mov r10, 0o644 ; mode
syscall
; rax >= 0 => fd, rax < 0 => -errno
path: db "./file.txt", 0
```
#### mmap(addr, length, prot, flags, fd, offset) — пример с 6 аргументами
```nasm
; void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
; x86-64: rax=9, rdi=addr, rsi=length, rdx=prot, r10=flags, r8=fd, r9=offset
mov rax, 9 ; SYS_mmap
xor rdi, rdi ; addr = NULL (hint)
mov rsi, 4096 ; length
mov rdx, 3 ; PROT_READ|PROT_WRITE
mov r10, 0x22 ; MAP_PRIVATE|MAP_ANONYMOUS (пример)
mov r8, -1 ; fd = -1 (анонимно)
xor r9, r9 ; offset = 0
syscall
; при успехе: rax = адрес (неотрицательный с точки зрения знака)
; при ошибке: rax < 0 => -errno
```
### Часто используемые номера (x86-64)
- 0 — read
- 1 — write
- 2 — open (лучше использовать 257 — openat)
- 3 — close
- 9 — mmap
- 11 — munmap
- 12 — brk
- 60 — exit
- 61 — wait4
- 62 — kill
- 63 — uname
- 78 — gettimeofday (устар.; лучше clock_gettime: 228)
- 202 — futex
- 231 — exit_group (завершает все потоки процесса)
- 257 — openat
Подробный список — в заголовках ядра и `man 2`.
### Замечания и подводные камни
- Не путай ABI функций и ABI `syscall`. У `syscall` 4-й аргумент — R10 (не RCX), и `syscall` портит RCX/R11.
- Не используй `int 0x80` на x86-64: это 32-битный интерфейс, он не совместим и может вести к неверной работе.
- Проверка ошибок только по знаку RAX, флаги процессора неинформативны.
- Если смешиваешь `syscall` и обычные вызовы функций, следи за выравниванием стека (RSP%16==0 перед `call`).
- В многопоточных программах предпочитай `exit_group(231)` для завершения целого процесса; `exit(60)` завершает только текущий поток.
### Мини-макрос для NASM (опционально)
```nasm
; Использование: SYS SYS_write, fd, buf, len
%define SYS_read 0
%define SYS_write 1
%define SYS_openat 257
%define SYS_exit 60
%macro SYS 1-7
mov rax, %1
%if %0 > 1
mov rdi, %2
%endif
%if %0 > 2
mov rsi, %3
%endif
%if %0 > 3
mov rdx, %4
%endif
%if %0 > 4
mov r10, %5
%endif
%if %0 > 5
mov r8, %6
%endif
%if %0 > 6
mov r9, %7
%endif
syscall
%endmacro
```
### Памятка при написании кода
- Положи номер вызова в RAX, аргументы — в RDI, RSI, RDX, R10, R8, R9.
- Вызови `syscall`; помни, что RCX и R11 будут испорчены.
- Проверяй RAX: `rax < 0` — ошибка (`-errno`), `rax >= 0` — успех.
- Соблюдай сохранность регистров по ABI System V для своего кода (RBX/RBP/R12R15 — сохраняй, если меняешь).

568
docs/x86-64_asm_sheet.ru.md Normal file
View File

@@ -0,0 +1,568 @@
# Шпаргалка по x8664 ASM
## Адресация
* Без сегментации (кроме `fs` и `gs` для специальных целей, например, потоков)
* Относительно базового регистра
* используется для **данных в стеке**, **массивов**, **структур** и **членов классов**
* [`base` + `index` * `scale` + `immediate_offset`]
* `base` обязателен, может быть любым 64битным регистром
* `index` может быть любым 64битным регистром, кроме `rsp`
* `scale` может быть 1, 2, 4 или 8
* `immediate_offset` (в GAS называется displacement) — смещение относительно базового регистра
* Синтаксис GAS: `immediate_offset(base, index, scale)`
* Относительно RIP (также PCrelative)
* используется для **статических данных**
* содержит 32битное знаково расширяемое смещение относительно указателя команд
* явно задаётся в NASM через `mov eax [rel label]` или директивы `default rel` / `default abs` (в противном случае используется 32битная абсолютная адресация)
* явно задаётся в GAS через `mov eax label(%rip)`
* 32битная абсолютная адресация
* 32битный константный адрес, знаково расширяемый до 64 бит
* работает для адресов ниже 2^31
* не используйте для простых операндов памяти: RIPrelative короче, быстрее (не нужны релокации) и работает везде
* используется для доступа к **статическим массивам с индексным регистром**, например `mov ebx, [intarray + rsi*4]`, однако это не работает для DLL в Windows и Linux, а также для исполняемых файлов и DLL в macOS, потому что адреса выше 2^32 (gcc и clang используют это для Linuxисполняемых файлов; для Windowsисполняемых MASM использует адресацию относительно базы образа)
* альтернативный, работающий везде вариант: сначала загрузить адрес статического массива в `rbx` через `lea` с RIPrelative адресом, а затем адресовать относительно этого базового регистра (`lea rbx, [array]`, затем `mov eax, [rbx + rcx*4]`); другие статические массивы затем можно адресовать относительно (`mov [(array2-array1) + rbx + rcx*4], eax`)
* 64битная абсолютная адресация
* `mov eax, dword [qword a]`
* применима только с `mov` и регистрами `al`, `ax`, `eax` или `rax` (источник или приёмник)
* не может содержать сегмент, базовый или индексный регистр
## Позиционно‑независимый код (PIC)
* Проще и быстрее, чем 32битная техника GOT (Global Offset Table), поскольку RIPrelative уже позиционно‑независим (заметьте, что описанная выше техника доступа к статическим массивам с индексным регистром также позиционно‑независима)
## Регистры общего назначения
bit 0 - 63 | bit 0 - 31 | bit 0 - 15 | bit 8 - 15 | bit 0 - 7
:----------:|:----------:|:----------:|:----------:|:---------:
`rax` | `eax` | `ax` | `ah` | `al`
`rbx` | `ebx` | `bx` | `bh` | `bl`
`rcx` | `ecx` | `cx` | `ch` | `cl`
`rdx` | `edx` | `dx` | `dh` | `dl`
`rsi` | `esi` | `si` | | `sil`
`rdi` | `edi` | `di` | | `dil`
`rbp` | `ebp` | `bp` | | `bpl`
`rsp` | `esp` | `sp` | | `spl`
`r8` | `r8d` | `r8w` | | `r8b`
`r9` | `r9d` | `r9w` | | `r9b`
`r10` | `r10d` | `r10w` | | `r10b`
`r11` | `r11d` | `r11w` | | `r11b`
`r12` | `r12d` | `r12w` | | `r12b`
`r13` | `r13d` | `r13w` | | `r13b`
`r14` | `r14d` | `r14w` | | `r14b`
`r15` | `r15d` | `r15w` | | `r15b`
`rflags` | | `flags` | |
`rip` | | | |
## Регистр `rflags`
* CF (Carry Flag, бит 0) — устанавливается, если арифметическая операция генерирует перенос или заём из старшего бита результата; очищается иначе. Флаг показывает переполнение для беззнаковой арифметики. Также применяется в многоточечной (многословной) арифметике.
* PF (Parity Flag, бит 2) — устанавливается, если младший байт результата содержит чётное число единиц; очищается иначе.
* AF (Auxiliary carry Flag, бит 4) — устанавливается, если операция вызывает перенос или заём из бита 3 результата; очищается иначе. Используется в двоично‑десятичной (BCD) арифметике.
* ZF (Zero Flag, бит 6) — устанавливается, если результат равен нулю; очищается иначе.
* SF (Sign Flag, бит 7) — устанавливается равным старшему биту результата, то есть знаковому биту знакового целого (0 — положительное, 1 — отрицательное).
* OF (Overflow Flag, бит 11) — устанавливается, если целочисленный результат слишком велик (без учёта знакового бита), чтобы поместиться в операнд назначения: слишком большой положительный или слишком маленький отрицательный; очищается иначе. Показывает переполнение для знаковой (дополнительный код) арифметики.
## Режимы насыщения и циклического переполнения (набора инструкций)
* Циклическая арифметика (wraparound) — истинный выход за диапазон усечётся (перенос/переполнение игнорируется, возвращаются только младшие биты результата). Подходит, когда диапазон операндов контролируется. Иначе возможны большие ошибки. Пример: сложение двух больших знаковых чисел может вызвать положительное переполнение и дать отрицательный результат.
* Арифметика со знаковым насыщением — выход за диапазон ограничивается представимым диапазоном знаковых целых для данного размера. Например, при положительном переполнении для знаковых слов результат насыщается до 7FFFH (наибольшее положительное 16битное); при отрицательном — до 8000H.
* Арифметика с беззнаковым насыщением — выход за диапазон ограничивается представимым диапазоном беззнаковых целых данного размера. Положительное переполнение для беззнаковых байтов даёт FFH, отрицательное — 00H.
## Стековые кадры
## Инструкции передачи данных
* [**MOV**](http://www.felixcloutier.com/x86/MOV.html) — Перемещение данных между регистрами общего назначения; между памятью и регистрами общего назначения или сегментными; загрузка непосредственных значений в регистры общего назначения.
* [**CMOVcc**](http://www.felixcloutier.com/x86/CMOVcc.html) — Условное перемещение.
* [**XCHG**](http://www.felixcloutier.com/x86/XCHG.html) — Обмен значениями.
* [**BSWAP**](http://www.felixcloutier.com/x86/BSWAP.html) — Перестановка байтов.
* [**XADD**](http://www.felixcloutier.com/x86/XADD.html) — Обмен с добавлением.
* [**CMPXCHG**](http://www.felixcloutier.com/x86/CMPXCHG.html) — Сравнить и обменять.
* [**CMPXCHG8B / CMPXCHG16B**](http://www.felixcloutier.com/x86/CMPXCHG8B:CMPXCHG16B.html) — Сравнить и обменять 8/16 байт.
* [**PUSH**](http://www.felixcloutier.com/x86/PUSH.html) — Поместить на стек.
* [**POP**](http://www.felixcloutier.com/x86/POP.html) — Снять со стека.
* [**PUSHA / PUSHAD**](http://www.felixcloutier.com/x86/PUSHA:PUSHAD.html) — Поместить все регистры общего назначения на стек.
* [**POPA / POPAD**](http://www.felixcloutier.com/x86/POPA:POPAD.html) — Снять все регистры общего назначения со стека.
* [**CWD / CDQ / CQO**](http://www.felixcloutier.com/x86/CWD:CDQ:CQO.html) — Расширить слово до двойного слова / двойное слово до квадрослова.
* [**CBW / CWDE / CDQE**](http://www.felixcloutier.com/x86/CBW:CWDE:CDQE.html) — Расширить байт до слова / слово до двойного слова в регистре `rax`.
* [**MOVSX / MOVSXD**](http://www.felixcloutier.com/x86/MOVSX:MOVSXD.html) — Перемещение с знаковым расширением.
* [**MOVZX**](http://www.felixcloutier.com/x86/MOVZX.html) — Перемещение с нулевым расширением.
## Инструкции целочисленной арифметики
* [**ADCX**](http://www.felixcloutier.com/x86/ADCX.html) — Беззнаковое сложение с переносом.
* [**ADOX**](http://www.felixcloutier.com/x86/ADOX.html) — Беззнаковое сложение с переполнением.
* [**ADD**](http://www.felixcloutier.com/x86/ADD.html) — Сложение целых.
* [**ADC**](http://www.felixcloutier.com/x86/ADC.html) — Сложение с переносом.
* [**SUB**](http://www.felixcloutier.com/x86/SUB.html) — Вычитание.
* [**SBB**](http://www.felixcloutier.com/x86/SBB.html) — Вычитание с заёмом.
* [**IMUL**](http://www.felixcloutier.com/x86/IMUL.html) — Умножение со знаком.
* [**MUL**](http://www.felixcloutier.com/x86/MUL.html) — Умножение без знака.
* [**IDIV**](http://www.felixcloutier.com/x86/IDIV.html) — Деление со знаком.
* [**DIV**](http://www.felixcloutier.com/x86/DIV.html) — Деление без знака.
* [**INC**](http://www.felixcloutier.com/x86/INC.html) — Инкремент.
* [**DEC**](http://www.felixcloutier.com/x86/DEC.html) — Декремент.
* [**NEG**](http://www.felixcloutier.com/x86/NEG.html) — Изменить знак (двойка‑дополнение).
* [**CMP**](http://www.felixcloutier.com/x86/CMP.html) — Сравнение.
## Логические инструкции
* [**AND**](http://www.felixcloutier.com/x86/AND.html) — Побитовое И.
* [**OR**](http://www.felixcloutier.com/x86/OR.html) — Побитовое ИЛИ.
* [**XOR**](http://www.felixcloutier.com/x86/XOR.html) — Побитовое исключающее ИЛИ.
* [**NOT**](http://www.felixcloutier.com/x86/NOT.html) — Побитовое НЕ.
## Сдвиги и ротации
* [**SAL / SAR / SHL / SHR**](http://www.felixcloutier.com/x86/SAL:SAR:SHL:SHR.html) — Арифметический/логический сдвиг влево/вправо.
* [**SHLD**](http://www.felixcloutier.com/x86/SHLD.html) — Двойной сдвиг влево.
* [**SHRD**](http://www.felixcloutier.com/x86/SHRD.html) — Двойной сдвиг вправо.
* [**RCL / RCR / ROL / ROR**](http://www.felixcloutier.com/x86/RCL:RCR:ROL:ROR.html) — Ротация влево/вправо и через перенос.
## Битовые и байтовые инструкции
* [**BT**](http://www.felixcloutier.com/x86/BT.html) — Тест бита.
* [**BTS**](http://www.felixcloutier.com/x86/BTS.html) — Тест и установка бита.
* [**BTR**](http://www.felixcloutier.com/x86/BTR.html) — Тест и сброс бита.
* [**BTC**](http://www.felixcloutier.com/x86/BTC.html) — Тест и инверсия бита.
* [**BSF**](http://www.felixcloutier.com/x86/BSF.html) — Поиск первого (младшего) установленного бита.
* [**BSR**](http://www.felixcloutier.com/x86/BSR.html) — Поиск последнего (старшего) установленного бита.
* [**SETcc**](http://www.felixcloutier.com/x86/SETcc.html) — Установить байт по условию.
* [**TEST**](http://www.felixcloutier.com/x86/TEST.html) — Логическое сравнение (AND, флаги).
* [**CRC32**](http://www.felixcloutier.com/x86/CRC32.html) — Аппаратное ускорение вычисления CRC для быстрого контроля целостности данных.
* [**POPCNT**](http://www.felixcloutier.com/x86/POPCNT.html) — Подсчёт количества единичных битов во втором операнде с возвратом счётчика в первый (регистр назначения).
## Инструкции передачи управления
* [**JMP**](http://www.felixcloutier.com/x86/JMP.html) — Безусловный переход.
* [**Jcc**](http://www.felixcloutier.com/x86/Jcc.html) — Переход при выполнении условия (операнд RIPrelative).
* [**LOOP / LOOPcc**](http://www.felixcloutier.com/x86/LOOP:LOOPcc.html) — Цикл с счётчиком в `rcx`.
* [**CALL**](http://www.felixcloutier.com/x86/CALL.html) — Вызов процедуры.
* [**RET**](http://www.felixcloutier.com/x86/RET.html) — Возврат из процедуры.
* [**IRET / IRETD / IRETQ**](http://www.felixcloutier.com/x86/IRET:IRETD.html) — Возврат из прерывания.
* [**INT n / INTO / INT 3**](http://www.felixcloutier.com/x86/INTn:INTO:INT3.html) — Вызов обработчика прерывания.
* [**ENTER**](http://www.felixcloutier.com/x86/ENTER.html) — Высокоуровневый вход в процедуру.
* [**LEAVE**](http://www.felixcloutier.com/x86/LEAVE.html) — Высокоуровневый выход из процедуры.
## Строковые инструкции
* [**MOVS / MOVSB / MOVSW / MOVSD / MOVSQ**](http://www.felixcloutier.com/x86/MOVS:MOVSB:MOVSW:MOVSD:MOVSQ.html) — Копирование данных из строки в строку.
* [**CMPS / CMPSB / CMPSW / CMPSD / CMPSQ**](http://www.felixcloutier.com/x86/CMPS:CMPSB:CMPSW:CMPSD:CMPSQ.html) — Сравнение строковых операндов.
* [**SCAS / SCASB / SCASW / SCASD**](http://www.felixcloutier.com/x86/SCAS:SCASB:SCASW:SCASD.html) — Сканирование строки.
* [**LODS / LODSB / LODSW / LODSD / LODSQ**](http://www.felixcloutier.com/x86/LODS:LODSB:LODSW:LODSD:LODSQ.html) — Загрузка из строки.
* [**STOS / STOSB / STOSW / STOSD / STOSQ**](http://www.felixcloutier.com/x86/STOS:STOSB:STOSW:STOSD:STOSQ.html) — Запись в строку.
* [**REP / REPE / REPZ / REPNE / REPNZ**](http://www.felixcloutier.com/x86/REP:REPE:REPZ:REPNE:REPNZ.html) — Префиксы повторения строковых операций.
## Инструкции управления `rflags`
* [**STC**](http://www.felixcloutier.com/x86/STC.html) — Установить флаг переноса.
* [**CLC**](http://www.felixcloutier.com/x86/CLC.html) — Очистить флаг переноса.
* [**CMC**](http://www.felixcloutier.com/x86/CMC.html) — Инвертировать флаг переноса.
* [**CLD**](http://www.felixcloutier.com/x86/CLD.html) — Очистить флаг направления.
* [**STD**](http://www.felixcloutier.com/x86/STD.html) — Установить флаг направления.
* [**LAHF**](http://www.felixcloutier.com/x86/LAHF.html) — Загрузить флаги в регистр `ah`.
* [**SAHF**](http://www.felixcloutier.com/x86/SAHF.html) — Сохранить регистр `ah` в флаги.
* [**PUSHF / PUSHFQ**](http://www.felixcloutier.com/x86/PUSHF:PUSHFD:PUSHFQ.html) — Поместить `rflags` на стек.
* [**POPF / POPFQ**](http://www.felixcloutier.com/x86/POPF:POPFD:POPFQ.html) — Снять `rflags` со стека.
* [**STI**](http://www.felixcloutier.com/x86/STI.html) — Установить флаг прерываний.
* [**CLI**](http://www.felixcloutier.com/x86/CLI.html) — Очистить флаг прерываний.
## Прочие инструкции
* [**LEA**](http://www.felixcloutier.com/x86/LEA.html) — Загрузка эффективного адреса.
* [**NOP**](http://www.felixcloutier.com/x86/NOP.html) — Пустая операция.
* [**UD**](http://www.felixcloutier.com/x86/UD.html) — Неопределённая инструкция.
* [**XLAT / XLATB**](http://www.felixcloutier.com/x86/XLAT:XLATB.html) — Табличное преобразование байта.
* [**CPUID**](http://www.felixcloutier.com/x86/CPUID.html) — Идентификация процессора.
* [**MOVBE**](http://www.felixcloutier.com/x86/MOVBE.html) — Перемещение данных с перестановкой байтов.
* [**PREFETCHW**](http://www.felixcloutier.com/x86/PREFETCHW.html) — Предвыборка данных в кэш с ожиданием записи.
* [**CLFLUSH**](http://www.felixcloutier.com/x86/CLFLUSH.html) — Сброс и инвалидация операнда памяти и связанной линии кэша на всех уровнях иерархии кэшей процессора.
* [**CLFLUSHOPT**](http://www.felixcloutier.com/x86/CLFLUSHOPT.html) — То же, с оптимизацией пропускной способности памяти.
* [**RDRAND**](http://www.felixcloutier.com/x86/RDRAND.html) — Получение случайного числа, сгенерированного аппаратно.
* [**RDSEED**](http://www.felixcloutier.com/x86/RDSEED.html) — Получение зерна (seed) для ГСЧ из аппаратного источника.
## Сохранение/восстановление расширенных состояний в пользовательском режиме
* [**XSAVE**](http://www.felixcloutier.com/x86/XSAVE.html) — Сохранить расширенные состояния процессора в память.
* [**XSAVEC**](http://www.felixcloutier.com/x86/XSAVEC.html) — Сохранить расширенные состояния с уплотнением.
* [**XSAVEOPT**](http://www.felixcloutier.com/x86/XSAVEOPT.html) — Оптимизированное сохранение расширенных состояний.
* [**XRSTOR**](http://www.felixcloutier.com/x86/XRSTOR.html) — Восстановить расширенные состояния из памяти.
* [**XGETBV**](http://www.felixcloutier.com/x86/XGETBV.html) — Прочитать состояние расширенного управляющего регистра.
## Манипуляции битами (BMI1, BMI2)
* [**ANDN**](http://www.felixcloutier.com/x86/ANDN.html) — Побитовое AND первого операнда с инвертированным вторым.
* [**BEXTR**](http://www.felixcloutier.com/x86/BEXTR.html) — Извлечение непрерывного диапазона битов.
* [**BLSI**](http://www.felixcloutier.com/x86/BLSI.html) — Извлечь младший установленный бит.
* [**BLSMSK**](http://www.felixcloutier.com/x86/BLSMSK.html) — Установить в 1 все младшие биты ниже первого установленного.
* [**BLSR**](http://www.felixcloutier.com/x86/BLSR.html) — Сбросить младший установленный бит.
* [**BZHI**](http://www.felixcloutier.com/x86/BZHI.html) — Обнулить старшие биты, начиная с указанной позиции.
* [**LZCNT**](http://www.felixcloutier.com/x86/LZCNT.html) — Подсчёт ведущих нулей.
* [**MULX**](http://www.felixcloutier.com/x86/MULX.html) — Беззнаковое умножение без изменения флагов.
* [**PDEP**](http://www.felixcloutier.com/x86/PDEP.html) — Параллельная «загрузка» битов по маске.
* [**PEXT**](http://www.felixcloutier.com/x86/PEXT.html) — Параллельное «извлечение» битов по маске.
* [**RORX**](http://www.felixcloutier.com/x86/RORX.html) — Ротация вправо без изменения флагов.
* [**SARX / SHLX / SHRX**](http://www.felixcloutier.com/x86/SARX:SHLX:SHRX.html) — Арифметический/логический сдвиг без изменения флагов.
* [**TZCNT**](http://www.felixcloutier.com/x86/TZCNT.html) — Подсчёт замыкающих нулей (с конца).
## Обзор x87 FPU
* Состояние x87 FPU отображается на состояние MMX; при переходах к MMXинструкциям нужно соблюдать осторожность, чтобы избежать неконсистентности результатов.
## Инструкции передачи данных x87 FPU
* [**FLD**](http://www.felixcloutier.com/x86/FLD.html) — Загрузка числа с плавающей точкой.
* [**FST / FSTP**](http://www.felixcloutier.com/x86/FST:FSTP.html) — Сохранить число с/без извлечения из стека FPU.
* [**FILD**](http://www.felixcloutier.com/x86/FILD.html) — Загрузка целого.
* [**FIST / FISTP**](http://www.felixcloutier.com/x86/FIST:FISTP.html) — Сохранить целое с/без извлечения.
* [**FBLD**](http://www.felixcloutier.com/x86/FBLD.html) — Загрузка BCD.
* [**FBSTP**](http://www.felixcloutier.com/x86/FBSTP.html) — Сохранение BCD и извлечение.
* [**FXCH**](http://www.felixcloutier.com/x86/FXCH.html) — Обмен регистров.
* [**FCMOVcc**](http://www.felixcloutier.com/x86/FCMOVcc.html) — Условное перемещение (FPU).
## Базовая арифметика x87 FPU
* [**FADD / FADDP / FIADD**](http://www.felixcloutier.com/x86/FADD:FADDP:FIADD.html) — Сложение с плавающей точкой.
* [**FSUB / FSUBP / FISUB**](http://www.felixcloutier.com/x86/FSUB:FSUBP:FISUB.html) — Вычитание с плавающей точкой.
* [**FSUBR / FSUBRP / FISUBR**](http://www.felixcloutier.com/x86/FSUBR:FSUBRP:FISUBR.html) — Вычитание в обратном порядке.
* [**FMUL / FMULP / FIMUL**](http://www.felixcloutier.com/x86/FMUL:FMULP:FIMUL.html) — Умножение с плавающей точкой.
* [**FDIV / FDIVP / FIDIV**](http://www.felixcloutier.com/x86/FDIV:FDIVP:FIDIV.html) — Деление с плавающей точкой.
* [**FDIVR / FDIVRP / FIDIVR**](http://www.felixcloutier.com/x86/FDIVR:FDIVRP:FIDIVR.html) — Деление в обратном порядке.
* [**FPREM**](http://www.felixcloutier.com/x86/FPREM.html) — Частный остаток.
* [**FPREM1**](http://www.felixcloutier.com/x86/FPREM1.html) — Частный остаток (IEEE).
* [**FABS**](http://www.felixcloutier.com/x86/FABS.html) — Модуль.
* [**FCHS**](http://www.felixcloutier.com/x86/FCHS.html) — Смена знака.
* [**FRNDINT**](http://www.felixcloutier.com/x86/FRNDINT.html) — Округление до целого.
* [**FSCALE**](http://www.felixcloutier.com/x86/FSCALE.html) — Масштабирование по степени двойки.
* [**FSQRT**](http://www.felixcloutier.com/x86/FSQRT.html) — Квадратный корень.
* [**FXTRACT**](http://www.felixcloutier.com/x86/FXTRACT.html) — Извлечение показателя и мантиссы.
## Сравнения x87 FPU
* [**FCOM / FCOMP / FCOMPP**](http://www.felixcloutier.com/x86/FCOM:FCOMP:FCOMPP.html) — Сравнение чисел с плавающей точкой.
* [**FUCOM / FUCOMP / FUCOMPP**](http://www.felixcloutier.com/x86/FUCOM:FUCOMP:FUCOMPP.html) — Неупорядоченное сравнение чисел с плавающей точкой.
* [**FICOM / FICOMP**](http://www.felixcloutier.com/x86/FICOM:FICOMP.html) — Сравнение целых.
* [**FCOMI / FCOMIP / FUCOMI / FUCOMIP**](http://www.felixcloutier.com/x86/FCOMI:FCOMIP:FUCOMI:FUCOMIP.html) — Сравнение чисел с плавающей точкой с установкой флагов `rflags`.
* [**FTST**](http://www.felixcloutier.com/x86/FTST.html) — Тест (сравнение с 0.0).
* [**FXAM**](http://www.felixcloutier.com/x86/FXAM.html) — Анализ (exam) числа с плавающей точкой.
## Трансцендентные функции x87 FPU
* [**FSIN**](http://www.felixcloutier.com/x86/FSIN.html) — Синус.
* [**FCOS**](http://www.felixcloutier.com/x86/FCOS.html) — Косинус.
* [**FSINCOS**](http://www.felixcloutier.com/x86/FSINCOS.html) — Синус и косинус.
* [**FPTAN**](http://www.felixcloutier.com/x86/FPTAN.html) — Частичная тангенс‑функция.
* [**FPATAN**](http://www.felixcloutier.com/x86/FPATAN.html) — Частичная арктангенс‑функция.
* [**F2XM1**](http://www.felixcloutier.com/x86/F2XM1.html) — 2^x 1.
* [**FYL2X**](http://www.felixcloutier.com/x86/FYL2X.html) — y log2(x).
* [**FYL2XP1**](http://www.felixcloutier.com/x86/FYL2XP1.html) — y log2(x + 1).
## Загрузка констант x87 FPU
* [**FLD1 / FLDL2T / FLDL2E / FLDPI / FLDLG2 / FLDLN2 / FLDZ**](http://www.felixcloutier.com/x86/FLD1:FLDL2T:FLDL2E:FLDPI:FLDLG2:FLDLN2:FLDZ.html) — Загрузка констант.
## Управление x87 FPU
* [**FINCSTP**](http://www.felixcloutier.com/x86/FINCSTP.html) — Инкремент указателя стека FPU.
* [**FDECSTP**](http://www.felixcloutier.com/x86/FDECSTP.html) — Декремент указателя стека FPU.
* [**FFREE**](http://www.felixcloutier.com/x86/FFREE.html) — Освободить регистр FPU.
* [**FINIT / FNINIT**](http://www.felixcloutier.com/x86/FINIT:FNINIT.html) — Инициализация FPU.
* [**FCLEX / FNCLEX**](http://www.felixcloutier.com/x86/FCLEX:FNCLEX.html) — Очистка флагов исключений FPU.
* [**FSTCW / FNSTCW**](http://www.felixcloutier.com/x86/FSTCW:FNSTCW.html) — Сохранить управляющее слово FPU.
* [**FLDCW**](http://www.felixcloutier.com/x86/FLDCW.html) — Загрузить управляющее слово FPU.
* [**FSTENV / FNSTENV**](http://www.felixcloutier.com/x86/FSTENV:FNSTENV.html) — Сохранить окружение FPU.
* [**FLDENV**](http://www.felixcloutier.com/x86/FLDENV.html) — Загрузить окружение FPU.
* [**FSAVE / FNSAVE**](http://www.felixcloutier.com/x86/FSAVE:FNSAVE.html) — Сохранить состояние FPU.
* [**FRSTOR**](http://www.felixcloutier.com/x86/FRSTOR.html) — Восстановить состояние FPU.
* [**FSTSW / FNSTSW**](http://www.felixcloutier.com/x86/FSTSW:FNSTSW.html) — Сохранить статусное слово FPU.
* [**WAIT / FWAIT**](http://www.felixcloutier.com/x86/WAIT:FWAIT.html) — Ожидание готовности FPU.
* [**FNOP**](http://www.felixcloutier.com/x86/FNOP.html) — Пустая операция FPU.
## Управление состоянием x87 FPU и SIMD
* [**FXSAVE**](http://www.felixcloutier.com/x86/FXSAVE.html) — Сохранить состояние x87 FPU и SIMD.
* [**FXRSTOR**](http://www.felixcloutier.com/x86/FXRSTOR.html) — Восстановить состояние x87 FPU и SIMD.
## Обзор MMX
* SIMDмодель вычислений для 64битных упакованных целых.
* Восемь 64битных регистров данных MMX.
* Три новых типа упакованных данных:
* 64битные упакованные байтовые целые (со знаком и без)
* 64битные упакованные словные целые (со знаком и без)
* 64битные упакованные двойные слова (со знаком и без)
* Состояние MMX отображается на состояние x87 FPU; при переходах к инструкциям x87 FPU требуется осторожность во избежание неконсистентности результатов.
## Передача данных MMX
* [**MOVD / MOVQ**](http://www.felixcloutier.com/x86/MOVD:MOVQ.html) — Перемещение двойного/квадрослова между MMX и памятью/регистрами.
## Преобразования MMX
* [**PACKSSWB / PACKSSDW**](http://www.felixcloutier.com/x86/PACKSSWB:PACKSSDW.html) — Упаковка слов/двойных слов в байты со знаковым насыщением.
* [**PACKUSWB**](http://www.felixcloutier.com/x86/PACKUSWB.html) — Упаковка слов в байты с беззнаковым насыщением.
* [**PUNPCKHBW / PUNPCKHWD / PUNPCKHDQ**](http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html) — Распаковка старших байтов/слов/двойных слов.
* [**PUNPCKLBW / PUNPCKLWD / PUNPCKLDQ**](http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html) — Распаковка младших байтов/слов/двойных слов.
## Упакованная арифметика MMX
* [**PADDB / PADDW / PADDD**](http://www.felixcloutier.com/x86/PADDB:PADDW:PADDD:PADDQ.html) — Сложение упакованных байтов/слов/двойных слов.
* [**PADDSB / PADDSW**](http://www.felixcloutier.com/x86/PADDSB:PADDSW.html) — Сложение упакованных знаковых байтов/слов со знаковым насыщением.
* [**PADDUSB / PADDUSW**](http://www.felixcloutier.com/x86/PADDUSB:PADDUSW.html) — Сложение упакованных беззнаковых байтов/слов с беззнаковым насыщением.
* [**PSUBB / PSUBW / PSUBD**](http://www.felixcloutier.com/x86/PSUBB:PSUBW:PSUBD.html) — Вычитание упакованных байтов/слов/двойных слов.
* [**PSUBSB / PSUBSW**](http://www.felixcloutier.com/x86/PSUBSB:PSUBSW.html) — Вычитание упакованных знаковых байтов/слов со знаковым насыщением.
* [**PSUBUSB / PSUBUSW**](http://www.felixcloutier.com/x86/PSUBUSB:PSUBUSW.html) — Вычитание упакованных беззнаковых байтов/слов с беззнаковым насыщением.
* [**PMULHW**](http://www.felixcloutier.com/x86/PMULHW.html) — Умножение упакованных знаковых слов с сохранением старшей части результата.
* [**PMULLW**](http://www.felixcloutier.com/x86/PMULLW.html) — Умножение упакованных знаковых слов с сохранением младшей части.
* [**PMADDWD**](http://www.felixcloutier.com/x86/PMADDWD.html) — Умножение и сложение упакованных слов.
## Сравнения MMX
* [**PCMPEQB / PCMPEQW / PCMPEQD**](http://www.felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html) — Сравнение упакованных байтов/слов/двойных слов на равенство.
* [**PCMPGTB / PCMPGTW / PCMPGTD**](http://www.felixcloutier.com/x86/PCMPGTB:PCMPGTW:PCMPGTD.html) — Сравнение упакованных знаковых байтов/слов/двойных слов «больше чем».
## Логика MMX
* [**PAND**](http://www.felixcloutier.com/x86/PAND.html) — Побитовое И.
* [**PANDN**](http://www.felixcloutier.com/x86/PANDN.html) — Побитовое И‑НЕ.
* [**POR**](http://www.felixcloutier.com/x86/POR.html) — Побитовое ИЛИ.
* [**PXOR**](http://www.felixcloutier.com/x86/PXOR.html) — Побитовое исключающее ИЛИ.
## Сдвиги и ротации MMX
* [**PSLLW / PSLLD / PSLLQ**](http://www.felixcloutier.com/x86/PSLLW:PSLLD:PSLLQ.html) — Логический сдвиг упакованных слов/двойных слов/квадрослов влево.
* [**PSRLW / PSRLD / PSRLQ**](http://www.felixcloutier.com/x86/PSRLW:PSRLD:PSRLQ.html) — Логический сдвиг упакованных слов/двойных слов/квадрослов вправо.
* [**PSRAW / PSRAD**](http://www.felixcloutier.com/x86/PSRAW:PSRAD:PSRAQ.html) — Арифметический сдвиг упакованных слов/двойных слов вправо.
## Управление состоянием MMX
* [**EMMS**](http://www.felixcloutier.com/x86/EMMS.html) — Очистить состояние MMX.
## Обзор SSE
* Расширяет SIMDмодель, добавляя операции над упакованными и скалярными числами одиночной точности в 128битных регистрах.
* Шестнадцать (в 32битном режиме — восемь) 128битных регистров XMM.
* 128битные инструкции для упакованных и скалярных чисел одиночной точности.
* Расширения MMXинструкций новыми операциями над упакованными целыми в регистрах MMX.
* Явная предвыборка данных, управление кэшируемостью данных и упорядочиванием операций записи.
## Передача данных SSE
* [**MOVAPS**](http://www.felixcloutier.com/x86/MOVAPS.html) — Перемещение четырёх выровненных упакованных чисел одиночной точности между XMM и памятью.
* [**MOVUPS**](http://www.felixcloutier.com/x86/MOVUPS.html) — Перемещение четырёх невыровненных упакованных чисел одиночной точности между XMM и памятью.
* [**MOVHPS**](http://www.felixcloutier.com/x86/MOVHPS.html) — Перемещение двух чисел одиночной точности из/в старшую квадрословную часть XMM и память.
* [**MOVHLPS**](http://www.felixcloutier.com/x86/MOVHLPS.html) — Перемещение двух чисел из старшей части одного XMM в младшую часть другого XMM.
* [**MOVLPS**](http://www.felixcloutier.com/x86/MOVLPS.html) — Перемещение двух чисел одиночной точности из/в младшую квадрословную часть XMM и память.
* [**MOVLHPS**](http://www.felixcloutier.com/x86/MOVLHPS.html) — Перемещение двух чисел из младшей части одного XMM в старшую часть другого XMM.
* [**MOVMSKPS**](http://www.felixcloutier.com/x86/MOVMSKPS.html) — Извлечь маску знаков из четырёх упакованных чисел одиночной точности.
* [**MOVSS**](http://www.felixcloutier.com/x86/MOVSS.html) — Перемещение скалярного числа одиночной точности между XMM и памятью.
## Арифметика SSE (FP32)
* [**ADDPS**](http://www.felixcloutier.com/x86/ADDPS.html) — Сложение упакованных чисел одиночной точности.
* [**ADDSS**](http://www.felixcloutier.com/x86/ADDSS.html) — Сложение скалярных чисел одиночной точности.
* [**SUBPS**](http://www.felixcloutier.com/x86/SUBPS.html) — Вычитание упакованных чисел одиночной точности.
* [**SUBSS**](http://www.felixcloutier.com/x86/SUBSS.html) — Вычитание скалярных чисел одиночной точности.
* [**MULPS**](http://www.felixcloutier.com/x86/MULPS.html) — Умножение упакованных чисел одиночной точности.
* [**MULSS**](http://www.felixcloutier.com/x86/MULSS.html) — Умножение скалярных чисел одиночной точности.
* [**DIVPS**](http://www.felixcloutier.com/x86/DIVPS.html) — Деление упакованных чисел одиночной точности.
* [**DIVSS**](http://www.felixcloutier.com/x86/DIVSS.html) — Деление скалярных чисел одиночной точности.
* [**RCPPS**](http://www.felixcloutier.com/x86/RCPPS.html) — Обратные значения (1/x) для упакованных чисел.
* [**RCPSS**](http://www.felixcloutier.com/x86/RCPSS.html) — Обратное значение для скаляра.
* [**SQRTPS**](http://www.felixcloutier.com/x86/SQRTPS.html) — Квадратные корни упакованных чисел.
* [**SQRTSS**](http://www.felixcloutier.com/x86/SQRTSS.html) — Квадратный корень скалярного числа.
* [**RSQRTPS**](http://www.felixcloutier.com/x86/RSQRTPS.html) — Обратные квадратные корни упакованных чисел.
* [**RSQRTSS**](http://www.felixcloutier.com/x86/RSQRTSS.html) — Обратный квадратный корень скаляра.
* [**MAXPS**](http://www.felixcloutier.com/x86/MAXPS.html) — Максимумы упакованных чисел одиночной точности.
* [**MAXSS**](http://www.felixcloutier.com/x86/MAXSS.html) — Максимум скаляра одиночной точности.
* [**MINPS**](http://www.felixcloutier.com/x86/MINPS.html) — Минимумы упакованных чисел одиночной точности.
* [**MINSS**](http://www.felixcloutier.com/x86/MINSS.html) — Минимум скаляра одиночной точности.
## Сравнения SSE
* [**CMPPS**](http://www.felixcloutier.com/x86/CMPPS.html) — Сравнение упакованных чисел одиночной точности.
* [**CMPSS**](http://www.felixcloutier.com/x86/CMPSS.html) — Сравнение скалярных чисел одиночной точности.
* [**COMISS**](http://www.felixcloutier.com/x86/COMISS.html) — Упорядоченное сравнение скаляров и установка флагов `rflags`.
* [**UCOMISS**](http://www.felixcloutier.com/x86/UCOMISS.html) — Неупорядоченное сравнение скаляров и установка флагов `rflags`.
## Логика SSE
* [**ANDPS**](http://www.felixcloutier.com/x86/ANDPS.html) — Побитовое И упакованных чисел одиночной точности.
* [**ANDNPS**](http://www.felixcloutier.com/x86/ANDNPS.html) — Побитовое И‑НЕ упакованных чисел.
* [**ORPS**](http://www.felixcloutier.com/x86/ORPS.html) — Побитовое ИЛИ упакованных чисел.
* [**XORPS**](http://www.felixcloutier.com/x86/XORPS.html) — Побитовое XOR упакованных чисел.
## Перестановки и распаковка SSE
* [**SHUFPS**](http://www.felixcloutier.com/x86/SHUFPS.html) — Перестановка значений в упакованных операндах.
* [**UNPCKHPS**](http://www.felixcloutier.com/x86/UNPCKHPS.html) — Распаковка и чередование двух старших значений из двух операндов.
* [**UNPCKLPS**](http://www.felixcloutier.com/x86/UNPCKLPS.html) — Распаковка и чередование двух младших значений из двух операндов.
## Преобразования SSE
* [**CVTPI2PS**](http://www.felixcloutier.com/x86/CVTPI2PS.html) — Преобразование упакованных двойных слов в упакованные числа одиночной точности.
* [**CVTSI2SS**](http://www.felixcloutier.com/x86/CVTSI2SS.html) — Преобразование двойного слова в скаляр одиночной точности.
* [**CVTPS2PI**](http://www.felixcloutier.com/x86/CVTPS2PI.html) — Преобразование упакованных чисел одиночной точности в упакованные двойные слова.
* [**CVTTPS2PI**](http://www.felixcloutier.com/x86/CVTTPS2PI.html) — То же с усечением.
* [**CVTSS2SI**](http://www.felixcloutier.com/x86/CVTSS2SI.html) — Преобразование скаляра одиночной точности в двойное слово.
* [**CVTTSS2SI**](http://www.felixcloutier.com/x86/CVTTSS2SI.html) — То же с усечением.
## Управление MXCSR (SSE)
* [**LDMXCSR**](http://www.felixcloutier.com/x86/LDMXCSR.html) — Загрузка регистра MXCSR.
* [**STMXCSR**](http://www.felixcloutier.com/x86/STMXCSR.html) — Сохранение состояния MXCSR.
## SSE: 64битные целые (расширения MMX)
* [**PAVGB / PAVGW**](http://www.felixcloutier.com/x86/PAVGB:PAVGW.html) — Среднее значение упакованных беззнаковых байтов.
* [**PEXTRW**](http://www.felixcloutier.com/x86/PEXTRW.html) — Извлечь слово.
* [**PINSRW**](http://www.felixcloutier.com/x86/PINSRW.html) — Вставить слово.
* [**PMAXUB**](http://www.felixcloutier.com/x86/PMAXUB:PMAXUW.html) — Максимум упакованных беззнаковых байтов.
* [**PMAXSW**](http://www.felixcloutier.com/x86/PMAXSB:PMAXSW:PMAXSD:PMAXSQ.html) — Максимум упакованных знаковых слов.
* [**PMINUB**](http://www.felixcloutier.com/x86/PMINUB:PMINUW.html) — Минимум упакованных беззнаковых байтов.
* [**PMINSW**](http://www.felixcloutier.com/x86/PMINSB:PMINSW.html) — Минимум упакованных знаковых слов.
* [**PMOVMSKB**](http://www.felixcloutier.com/x86/PMOVMSKB.html) — Маска байтов (перенос знаков в маску).
* [**PMULHUW**](http://www.felixcloutier.com/x86/PMULHUW.html) — Умножение упакованных беззнаковых слов, сохранение старшей части.
* [**PSADBW**](http://www.felixcloutier.com/x86/MPSADBW.html) — Сумма абсолютных разностей.
* [**PSHUFW**](http://www.felixcloutier.com/x86/PSHUFW.html) — Перестановка слов в регистре MMX.
## SSE: кэшируемость, предвыборка и упорядочивание
* [**MASKMOVQ**](http://www.felixcloutier.com/x86/MASKMOVQ.html) — Нетемпоральная запись выбранных байтов из MMX в память.
* [**MOVNTQ**](http://www.felixcloutier.com/x86/MOVNTQ.html) — Нетемпоральная запись квадрослова из MMX в память.
* [**MOVNTPS**](http://www.felixcloutier.com/x86/MOVNTPS.html) — Нетемпоральная запись четырёх упакованных чисел одиночной точности из XMM в память.
* [**PREFETCHh**](http://www.felixcloutier.com/x86/PREFETCHh.html) — Загрузка 32 и более байт из памяти в выбранный уровень кэша.
* [**SFENCE**](http://www.felixcloutier.com/x86/SFENCE.html) — Сериализация операций записи.
## Обзор SSE2
* Упакованные и скалярные 128битные числа двойной точности.
* Дополнительные инструкции для 64 и 128битных упакованных байтов/слов/двойных слов/квадрослов.
* 128битные версии целочисленных инструкций из MMX и SSE.
* Дополнительные инструкции управления кэшируемостью и упорядочиванием инструкций.
## SSE2: перемещение данных FP64
* [**MOVAPD**](http://www.felixcloutier.com/x86/MOVAPD.html) — Перемещение двух выровненных упакованных чисел двойной точности между XMM и памятью.
* [**MOVUPD**](http://www.felixcloutier.com/x86/MOVUPD.html) — Перемещение двух невыровненных упакованных чисел двойной точности между XMM и памятью.
* [**MOVHPD**](http://www.felixcloutier.com/x86/MOVHPD.html) — Перемещение старшего элемента двойной точности из/в старшую часть XMM и память.
* [**MOVLPD**](http://www.felixcloutier.com/x86/MOVLPD.html) — Перемещение младшего элемента двойной точности из/в младшую часть XMM и память.
* [**MOVMSKPD**](http://www.felixcloutier.com/x86/MOVMSKPD.html) — Извлечь маску знаков из двух упакованных чисел двойной точности.
* [**MOVSD**](http://www.felixcloutier.com/x86/MOVSD.html) — Перемещение скалярного числа двойной точности между XMM и памятью.
## SSE2: арифметика FP64
* [**ADDPD**](http://www.felixcloutier.com/x86/ADDPD.html) — Сложение упакованных чисел двойной точности.
* [**ADDSD**](http://www.felixcloutier.com/x86/ADDSD.html) — Сложение скалярных чисел двойной точности.
* [**SUBPD**](http://www.felixcloutier.com/x86/SUBPD.html) — Вычитание упакованных чисел двойной точности.
* [**SUBSD**](http://www.felixcloutier.com/x86/SUBSD.html) — Вычитание скалярных чисел двойной точности.
* [**MULPD**](http://www.felixcloutier.com/x86/MULPD.html) — Умножение упакованных чисел двойной точности.
* [**MULSD**](http://www.felixcloutier.com/x86/MULSD.html) — Умножение скалярных чисел двойной точности.
* [**DIVPD**](http://www.felixcloutier.com/x86/DIVPD.html) — Деление упакованных чисел двойной точности.
* [**DIVSD**](http://www.felixcloutier.com/x86/DIVSD.html) — Деление скалярных чисел двойной точности.
* [**SQRTPD**](http://www.felixcloutier.com/x86/SQRTPD.html) — Квадратные корни упакованных чисел двойной точности.
* [**SQRTSD**](http://www.felixcloutier.com/x86/SQRTSD.html) — Квадратный корень скалярного числа двойной точности.
* [**MAXPD**](http://www.felixcloutier.com/x86/MAXPD.html) — Максимумы упакованных чисел двойной точности.
* [**MAXSD**](http://www.felixcloutier.com/x86/MAXSD.html) — Максимум скаляра двойной точности.
* [**MINPD**](http://www.felixcloutier.com/x86/MINPD.html) — Минимумы упакованных чисел двойной точности.
* [**MINSD**](http://www.felixcloutier.com/x86/MINSD.html) — Минимум скаляра двойной точности.
## SSE2: логические операции FP64
* [**ANDPD**](http://www.felixcloutier.com/x86/ANDPD.html) — Побитовое И упакованных чисел двойной точности.
* [**ANDNPD**](http://www.felixcloutier.com/x86/ANDNPD.html) — Побитовое И‑НЕ упакованных чисел двойной точности.
* [**ORPD**](http://www.felixcloutier.com/x86/ORPD.html) — Побитовое ИЛИ упакованных чисел двойной точности.
* [**XORPD**](http://www.felixcloutier.com/x86/XORPD.html) — Побитовое XOR упакованных чисел двойной точности.
## SSE2: сравнения FP64
* [**CMPPD**](http://www.felixcloutier.com/x86/CMPPD.html) — Сравнение упакованных чисел двойной точности.
* [**CMPSD**](http://www.felixcloutier.com/x86/CMPSD.html) — Сравнение скаляров двойной точности.
* [**COMISD**](http://www.felixcloutier.com/x86/COMISD.html) — Упорядоченное сравнение скаляров двойной точности с установкой `rflags`.
* [**UCOMISD**](http://www.felixcloutier.com/x86/UCOMISD.html) — Неупорядоченное сравнение скаляров двойной точности с установкой `rflags`.
## SSE2: перестановки и распаковка FP64
* [**SHUFPD**](http://www.felixcloutier.com/x86/SHUFPD.html) — Перестановка значений в упакованных операндах двойной точности.
* [**UNPCKHPD**](http://www.felixcloutier.com/x86/UNPCKHPD.html) — Распаковка и чередование старших значений из двух операндов.
* [**UNPCKLPD**](http://www.felixcloutier.com/x86/UNPCKLPD.html) — Распаковка и чередование младших значений из двух операндов.
## SSE2: преобразования
* [**CVTPD2PI**](http://www.felixcloutier.com/x86/CVTPD2PI.html) — Преобразование упакованных чисел двойной точности в упакованные двойные слова.
* [**CVTTPD2PI**](http://www.felixcloutier.com/x86/CVTTPD2PI.html) — То же с усечением.
* [**CVTPI2PD**](http://www.felixcloutier.com/x86/CVTPI2PD.html) — Преобразование упакованных двойных слов в упакованные числа двойной точности.
* [**CVTPD2DQ**](http://www.felixcloutier.com/x86/CVTPD2DQ.html) — Преобразование упакованных чисел двойной точности в упакованные двойные слова.
* [**CVTTPD2DQ**](http://www.felixcloutier.com/x86/CVTTPD2DQ.html) — То же с усечением.
* [**CVTDQ2PD**](http://www.felixcloutier.com/x86/CVTDQ2PD.html) — Преобразование упакованных двойных слов в упакованные числа двойной точности.
* [**CVTPS2PD**](http://www.felixcloutier.com/x86/CVTPS2PD.html) — Преобразование упакованных чисел одиночной в двойную точность.
* [**CVTPD2PS**](http://www.felixcloutier.com/x86/CVTPS2PD.html) — Преобразование упакованных чисел двойной в одиночную точность.
* [**CVTSS2SD**](http://www.felixcloutier.com/x86/CVTSS2SD.html) — Преобразование скаляра одиночной в двойную точность.
* [**CVTSD2SS**](http://www.felixcloutier.com/x86/CVTSD2SS.html) — Преобразование скаляра двойной в одиночную точность.
* [**CVTSD2SI**](http://www.felixcloutier.com/x86/CVTSD2SI.html) — Преобразование скаляра двойной точности в двойное слово.
* [**CVTTSD2SI**](http://www.felixcloutier.com/x86/CVTTSD2SI.html) — То же с усечением.
* [**CVTSI2SD**](http://www.felixcloutier.com/x86/CVTSI2SD.html) — Преобразование двойного слова в скаляр двойной точности.
## SSE2: FP32 (расширения SSE)
* [**CVTDQ2PS**](http://www.felixcloutier.com/x86/CVTDQ2PS.html) — Преобразование упакованных двойных слов в упакованные числа одиночной точности.
* [**CVTPS2DQ**](http://www.felixcloutier.com/x86/CVTPS2DQ.html) — Преобразование упакованных чисел одиночной точности в упакованные двойные слова.
* [**CVTTPS2DQ**](http://www.felixcloutier.com/x86/CVTTPS2DQ.html) — То же с усечением.
## SSE2: целочисленные инструкции
* [**MOVDQA**](http://www.felixcloutier.com/x86/MOVDQA:VMOVDQA32:VMOVDQA64.html) — Перемещение выровненного двойного квадрослова.
* [**MOVDQU**](http://www.felixcloutier.com/x86/MOVDQU:VMOVDQU8:VMOVDQU16:VMOVDQU32:VMOVDQU64.html) — Перемещение невыровненного двойного квадрослова.
* [**MOVQ2DQ**](http://www.felixcloutier.com/x86/MOVQ2DQ.html) — Перемещение квадрослова из MMX в XMM.
* [**MOVDQ2Q**](http://www.felixcloutier.com/x86/MOVDQ2Q.html) — Перемещение квадрослова из XMM в MMX.
* [**PMULUDQ**](http://www.felixcloutier.com/x86/PMULUDQ.html) — Умножение упакованных беззнаковых двойных слов.
* [**PADDQ**](http://www.felixcloutier.com/x86/PADDB:PADDW:PADDD:PADDQ.html) — Сложение упакованных квадрослов.
* [**PSUBQ**](http://www.felixcloutier.com/x86/PSUBQ.html) — Вычитание упакованных квадрослов.
* [**PSHUFLW**](http://www.felixcloutier.com/x86/PSHUFLW.html) — Перестановка младших слов.
* [**PSHUFHW**](http://www.felixcloutier.com/x86/PSHUFHW.html) — Перестановка старших слов.
* [**PSHUFD**](http://www.felixcloutier.com/x86/PSHUFD.html) — Перестановка двойных слов.
* [**PSLLDQ**](http://www.felixcloutier.com/x86/PSLLDQ.html) — Логический сдвиг двойного квадрослова влево.
* [**PSRLDQ**](http://www.felixcloutier.com/x86/PSRLDQ.html) — Логический сдвиг двойного квадрослова вправо.
* [**PUNPCKHQDQ**](http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html) — Распаковка старших квадрослов.
* [**PUNPCKLQDQ**](http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html) — Распаковка младших квадрослов.
## SSE2: кэшируемость и упорядочивание
* [**CLFLUSH**](http://www.felixcloutier.com/x86/CLFLUSH.html) — Сброс линии кэша.
* [**LFENCE**](http://www.felixcloutier.com/x86/LFENCE.html) — Сериализация операций чтения.
* [**MFENCE**](http://www.felixcloutier.com/x86/MFENCE.html) — Сериализация операций чтения и записи.
* [**PAUSE**](http://www.felixcloutier.com/x86/PAUSE.html) — Улучшает производительность «циклов активного ожидания» (spinwait).
* [**MASKMOVDQU**](http://www.felixcloutier.com/x86/MASKMOVDQU.html) — Нетемпоральная запись выбранных байтов из XMM в память.
* [**MOVNTPD**](http://www.felixcloutier.com/x86/MOVNTPD.html) — Нетемпоральная запись двух упакованных чисел двойной точности из XMM в память.
* [**MOVNTDQ**](http://www.felixcloutier.com/x86/MOVNTDQ.html) — Нетемпоральная запись двойного квадрослова из XMM в память.
* [**MOVNTI**](http://www.felixcloutier.com/x86/MOVNTI.html) — Нетемпоральная запись двойного слова из регистра общего назначения в память.
## Ссылки
* https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf
* http://www.agner.org/optimize/optimizing_assembly.pdf
* https://www.nasm.us/xdoc/2.13.03/nasmdoc.pdf
* https://godbolt.org/
* https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
* https://0xax.github.io/categories/assembler/
## Таблицы инструкций
* http://www.agner.org/optimize/instruction_tables.pdf
## Примеры
* https://github.com/torvalds/linux/tree/master/arch/x86
* https://gist.github.com/rygorous/bf1659bf6cd1752ed114367d4b87b302
* https://www.csee.umbc.edu/portal/help/nasm/sample_64.shtml
## Утилиты
* https://software.intel.com/sites/landingpage/IntrinsicsGuide/
* https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/libavutil/x86/x86inc.asm
* https://gist.github.com/rygorous/f729919ff64526a46e591d8f8b52058e

View File

@@ -1,49 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "lldb x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/minimal",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "cppdbg x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/minimal",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "by-gdb x64",
"type": "by-gdb",
"request": "launch",
"program": "${workspaceFolder}/build/minimal",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "gdb x64",
"type": "gdb",
"request": "launch",
"program": "${workspaceFolder}/build/minimal",
"preLaunchTask": "asm64",
},
{
"name": "lldb+GCC x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/minimal",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc",
}
]
}

View File

@@ -1,11 +0,0 @@
global _start
section .data
nums dq 112, 113, 114, 115, 116 ; массив чисел типа qword
currentAddr dq $
section .text
_start:
mov rdi, [currentAddr - 8] ; rdi = 116
mov rax, 60
syscall

View File

@@ -4,14 +4,15 @@
"path": "casm"
},
{
"path": "minimal"
"path": "wayland"
},
{
"path": "docs"
}
},
],
"settings": {
"debug.allowBreakpointsEverywhere": true,
"debug.inlineValues": "on",
"editor.codeLens": false,
}
}
}

29
stepik_base/10_to_2/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/10_to_2",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/10_to_2",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/10_to_2",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -7,9 +7,9 @@
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/minimal;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/minimal.asm;",
"ld -g -m elf_x86_64 -o $rawfilename $rawfilename.o;"
"rawfilename=$builddir/10_to_2;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/10_to_2.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
@@ -33,8 +33,8 @@
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/minimal;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/minimal.asm;",
"rawfilename=$builddir/10_to_2;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/10_to_2.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {

View File

@@ -0,0 +1,147 @@
global _start
section .data
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
lea rsi, [rel buff] ; поставить указатель на начало буфера
call read_num
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция складывает два значения
; In: RDI, RSI
; Out: RAX
calculate_sum:
lea rax, [rdi + rsi]
ret
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [rel buff] ; rdi - конец данных
add rdi, [count]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
.while:
xor rdx, rdx
test rax, rax
jz .break
mov dl, al
and dl, 1
or dl, 0x30
mov [rsi], dl
dec rsi
shr rax, 1
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/even_odd",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/even_odd",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/even_odd",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/even_odd/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/even_odd;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/even_odd.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/even_odd;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/even_odd.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,80 @@
global _start
section .data
buff times 32 db 0
count dq 0
even db "Even"
evenCount dq $-even
odd db "Odd"
oddCount dq $-odd
section .text
default rel
_start:
call read_text
lea rsi, [buff]
add rsi, qword [count]
sub rsi, 2
mov rax, [rsi]
test rax, 0x1
jnz .even
.odd:
lea rsi, [even]
mov rdx, [evenCount]
jmp .write
.even:
lea rsi, [odd]
mov rdx, [oddCount]
.write:
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/is_digit",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/is_digit",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/is_digit",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/is_digit/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/is_digit;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/is_digit.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/is_digit;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/is_digit.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,79 @@
global _start
section .data
g_buff times 10 db 0
g_buffLen dq 0
g_digit db "Digit"
g_digitLen dq $-g_digit
g_notDigit db "Not a digit"
g_notDigitLen dq $-g_notDigit
section .text
default rel
_start:
call read_text
movzx rax, byte [g_buff] ; первый символ
cmp rax, '0'
jl .notDigit
cmp rax, '9'
jg .notDigit
.digit:
lea rsi, [g_digit]
mov rdx, [g_digitLen]
jmp .write
.notDigit:
lea rsi, [g_notDigit]
mov rdx, [g_notDigitLen]
.write:
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel g_buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [g_buffLen], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [g_buffLen], rax
pop rdx
pop rsi
pop rdi
pop rax
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,108 @@
; Макрос для вывода сообщения
; In:
; - %1 - указатель на буффер с сообщением
; - %2 - длина сообщения
%macro PRINT_MSG 2
mov rsi, %1
mov rdx, %2
mov rdi, 1 ; stdout
mov rax, 1 ; sys_write
syscall
%endmacro
global _start
section .data
g_buff times 32 db 0
g_buff_end:
g_len dq 0
g_less_or_equal db "Less than or equal to 10"
g_less_or_equal_len dq $-g_less_or_equal
g_greater db "Greater than 10"
g_greater_len dq $-g_greater
section .text
default rel
_start:
call read_text
lea rsi, [rel g_buff] ; поставить указатель на начало буфера
call read_num
cmp rax, 10
jle .le
.g:
lea rdi, [g_greater]
mov rdx, [g_greater_len]
jmp .print
.le:
lea rdi, [g_less_or_equal]
mov rdx, [g_less_or_equal_len]
.print:
PRINT_MSG rdi, rdx
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel g_buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [g_len], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [g_buff] ; rdi - конец данных
add rdi, [g_len]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10_neg",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10_neg",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10_neg",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10_neg;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10_neg.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10_neg;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10_neg.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,119 @@
; Макрос для вывода сообщения
; In:
; - %1 - указатель на буффер с сообщением
; - %2 - длина сообщения
%macro PRINT_MSG 2
mov rsi, %1
mov rdx, %2
mov rdi, 1 ; stdout
mov rax, 1 ; sys_write
syscall
%endmacro
global _start
section .data
g_buff times 32 db 0
g_buff_end:
g_len dq 0
g_less_or_equal db "B"
g_less_or_equal_len dq $-g_less_or_equal
g_greater db "A"
g_greater_len dq $-g_greater
section .text
default rel
_start:
call read_text
lea rsi, [rel g_buff] ; поставить указатель на начало буфера
call read_num
cmp rax, 10
jle .le
.g:
lea rdi, [g_greater]
mov rdx, [g_greater_len]
jmp .print
.le:
lea rdi, [g_less_or_equal]
mov rdx, [g_less_or_equal_len]
.print:
PRINT_MSG rdi, rdx
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel g_buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [g_len], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor r8, 1 ; r8 - флаг знака
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [g_buff] ; rdi - конец данных
add rdi, [g_len]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
cmp bl, '-'
jne .add
.neg:
neg r8
jmp .continue
.add:
mul rcx
and bl, 0x0F
add rax, rbx
.continue:
inc rsi
jmp .while
.return:
mul r8
pop rcx
pop rbx
ret

29
stepik_base/macro/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/macro",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/macro",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/macro",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/macro/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/macro;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/macro.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/macro;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/macro.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,27 @@
; Макрос для вывода сообщения
; In:
; - %1 - указатель на буффер с сообщением
; - %2 - длина сообщения
%macro PRINT_MSG 2
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, %1
mov rdx, %2
syscall
%endmacro
global _start
section .data
g_msg db "Hello, Stepic!"
g_msg_len dq $-g_msg
section .text
default rel
_start:
PRINT_MSG g_msg, [g_msg_len]
mov rax, 60
mov rdi, 0
syscall

29
stepik_base/min/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/min",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/min",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/min",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/min/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/min;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/min.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/min;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/min.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

94
stepik_base/min/min.asm Normal file
View File

@@ -0,0 +1,94 @@
global _start
section .data
arr db 5, 7, 3, 1, 2
arrEnd:
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
mov al, 0xFF
lea rsi, [arr]
lea rdi, [arrEnd]
.while:
movzx rbx, byte [rsi] ; текущее число
cmp rbx, rax
cmovl rax, rbx
inc rsi
cmp rsi, rdi
jne .while
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/repeat_str",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/repeat_str",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/repeat_str",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/repeat_str;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/repeat_str.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/repeat_str;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/repeat_str.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,130 @@
global _start
section .data
buff times 256 db 0
buffSize dq $-buff
count dq 0
section .text
default rel
_start:
lea rsi, [buff]
lea rdi, [count]
mov rdx, [buffSize]
call read_text
mov al, 0xA
lea rdi, [buff]
mov rcx, [count]
repne scasb
; Теперь rdi указывает на символ после \n
; Вычисляем длину строки: rdi - buff
lea rax, [buff]
sub rdi, rax
mov [count], rdi ; Сохраняем длину строки в count
; rsi уже установлен на buff + длина строки, т.е. на числе
mov rsi, rax
add rsi, rdi
mov rdx, 256
call read_num
mov rcx, rax
jrcxz .return
.while:
lea rsi, [buff]
mov rdx, [count]
call write_text
loop .while
.return:
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; In:
; - RSI - указатель на буффер
; - RDI - указатель на адрес для сохранения длины
; - RDX - длина буффера
; Регистры не изменяет
read_text:
push rax
push rdi
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
syscall
pop rdi
mov [rdi], rax
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rcx
push rax
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
pop rdx
pop rsi
pop rax
pop rcx
ret
; Функция читает число из буфера
; In:
; - RSI - указатель на буффер
; - RDX - длина буффера
; Out:
; - RAX - число
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
mov rdi, rsi
add rdi, rdx
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0x0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret

View File

@@ -0,0 +1,45 @@
{
"folders": [
{
"path": "sum"
},
{
"path": "even_odd"
},
{
"path": "repeat_str"
},
{
"path": "min"
},
{
"path": "is_digit"
},
{
"path": "macro"
},
{
"path": "less_greater_10"
},
{
"path": "less_greater_10_neg"
},
{
"path": "10_to_2"
},
{
"path": "word_count"
},
{
"path": "sum_digits"
},
{
"path": "../docs"
},
],
"settings": {
"debug.allowBreakpointsEverywhere": true,
"debug.inlineValues": "on",
"editor.codeLens": false,
}
}

21
stepik_base/sum/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/sum",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/sum",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/sum/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

154
stepik_base/sum/sum.asm Normal file
View File

@@ -0,0 +1,154 @@
global _start
section .data
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
lea rsi, [rel buff] ; поставить указатель на начало буфера
call read_num
mov rbx, rax
inc rsi
call read_num
mov rdi, rax
mov rsi, rbx
call calculate_sum
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция складывает два значения
; In: RDI, RSI
; Out: RAX
calculate_sum:
lea rax, [rdi + rsi]
ret
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [rel buff] ; rdi - конец данных
add rdi, [count]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,21 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/sum_digits",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/sum_digits",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum_digits;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum_digits.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum_digits;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum_digits.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,140 @@
global _start
section .data
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
lea rsi, [rel buff] ; поставить указатель на начало буфера
call read_num
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [rel buff] ; rdi - конец данных
add rdi, [count]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/word_count",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/word_count",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/word_count",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/word_count;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/word_count.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/word_count;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/word_count.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,129 @@
global _start
section .data
buff times 350 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
xor rax, rax
mov rcx, [count]
dec rcx
lea rsi, [buff]
mov r10, 1 ; просто единица
mov r8, 0 ; прошлый символ - не пробел
.loop:
mov dl, [rsi]
cmp dl, ' '
jne .continue ; если сейчас не пробел - выйти
test r8, r8
jz .continue ; если прошлое пробел - выйти
.space_after_word:
inc rax
.continue:
mov r8, 0
cmp dl, ' '
cmovne r8, r10
inc rsi
loop .loop
test r8, r8
jz .print ; если прошлое пробел - выйти
inc rax
.print:
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

37
wayland/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"cwd": "${workspaceFolder}",
"env": {
"PATH": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
}
},
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
},
],
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
]
}
]
}

50
wayland/CMakeLists.txt Normal file
View File

@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.14)
project(wayland)
enable_language(ASM_NASM)
set(CMAKE_ASM_NASM_FLAGS "-f elf64")
set(CMAKE_ASM_NASM_FLAGS_DEBUG "-gdwarf")
find_package(PkgConfig REQUIRED)
# Находим программу wayland-scanner
find_program(WAYLAND_SCANNER wayland-scanner REQUIRED)
# Ищем директорию с протоколами Wayland
find_path(WAYLAND_PROTOCOLS_DIR
NAMES stable/xdg-shell/xdg-shell.xml
PATHS /usr/share/wayland-protocols /usr/local/share/wayland-protocols
REQUIRED
)
# Путь к протоколу xdg-shell
set(PROTOCOL_XML ${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml)
# Генерируем заголовочный файл протокола
add_custom_command(
OUTPUT xdg-shell-client-protocol.h
COMMAND ${WAYLAND_SCANNER} client-header ${PROTOCOL_XML} xdg-shell-client-protocol.h
DEPENDS ${PROTOCOL_XML}
)
# Генерируем исходный файл протокола
add_custom_command(
OUTPUT xdg-shell-client-protocol.c
COMMAND ${WAYLAND_SCANNER} private-code ${PROTOCOL_XML} xdg-shell-client-protocol.c
DEPENDS ${PROTOCOL_XML}
)
# Цель для генерации протокола
add_custom_target(generate-xdg-shell DEPENDS xdg-shell-client-protocol.h xdg-shell-client-protocol.c)
# Создаем исполняемый файл из ассемблерного, C и сгенерированного кода
add_executable(wayland asm.asm c.c xdg-shell-client-protocol.c)
# Зависимость от генерации протокола
add_dependencies(wayland generate-xdg-shell)
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
target_link_libraries(wayland ${WAYLAND_CLIENT_LIBRARIES})
target_include_directories(wayland PRIVATE ${WAYLAND_CLIENT_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})

23
wayland/CMakePresets.json Normal file
View File

@@ -0,0 +1,23 @@
{
"version": 8,
"configurePresets": [
{
"name": "debug-gcc",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "/usr/bin/gcc",
"CMAKE_CXX_COMPILER": "/usr/bin/g++",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release-gcc",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "/usr/bin/gcc",
"CMAKE_CXX_COMPILER": "/usr/bin/g++",
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}

11
wayland/asm.asm Normal file
View File

@@ -0,0 +1,11 @@
global main
extern run_wayland
section .text
main:
enter 0, 0
call run_wayland
leave
mov rax, 0
ret

100
wayland/c.c Normal file
View File

@@ -0,0 +1,100 @@
#include <wayland-client.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include "xdg-shell-client-protocol.h"
static struct wl_display *display;
static struct wl_registry *registry;
static struct wl_compositor *compositor;
static struct wl_shm *shm;
static struct xdg_wm_base *xdg_wm_base;
static struct wl_surface *surface;
static struct xdg_surface *xdg_surface;
static struct xdg_toplevel *xdg_toplevel;
static volatile int running = 1;
static int width = 800, height = 600;
static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) {
if (strcmp(interface, "wl_compositor") == 0) {
compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) {
shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) {
xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
}
}
static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name) {}
static const struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove,
};
static void create_buffer();
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) {
xdg_surface_ack_configure(xdg_surface, serial);
create_buffer();
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_configure,
};
static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h, struct wl_array *states) {
if (w > 0) width = w;
if (h > 0) height = h;
}
static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) {
running = 0;
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_configure,
.close = xdg_toplevel_close,
};
static void create_buffer() {
char name[32];
sprintf(name, "/wayland-shm-%d", getpid());
int stride = width * 4;
int size = stride * height;
int fd = shm_open(name, O_RDWR | O_CREAT, 0600);
if (fd == -1) return;
ftruncate(fd, size);
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
memset(data, 0xFF, size); // white
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0, width, height);
wl_surface_commit(surface);
wl_buffer_destroy(buffer);
wl_shm_pool_destroy(pool);
close(fd);
shm_unlink(name);
munmap(data, size);
}
void run_wayland() {
display = wl_display_connect(NULL);
if (!display) return;
registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (!compositor || !shm || !xdg_wm_base) return;
surface = wl_compositor_create_surface(compositor);
xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, surface);
xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL);
xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL);
wl_surface_commit(surface);
while (running && wl_display_dispatch(display) != -1) {}
wl_display_disconnect(display);
}