Сложение двух чисел

This commit is contained in:
Пытков Роман
2025-09-22 00:53:15 +03:00
parent 6ef051900a
commit 444a2da5a8
7 changed files with 230 additions and 39 deletions

55
docs/cdecl.md Normal file
View File

@@ -0,0 +1,55 @@
## 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.
### Порядок передачи аргументов
- 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), а функция заполняет его.
### Типичный каркас функции на NASM (Linux)
; extern printf
; global main
; section .data
; msg db "x=%d", 10, 0
; section .text
; main:
; push rbp
; mov rbp, rsp
; ; на входе rsp%16==8 → для вызова нужно выровнять до 16
; sub rsp, 8 ; выравнивание стека перед call
; lea rdi, [rel msg] ; 1-й аргумент (fmt) → RDI
; mov esi, 42 ; 2-й аргумент (int) → ESI
; xor eax, eax ; AL=0: нет XMM-аргументов (variadic правило)
; call printf
; add rsp, 8 ; вернуть выравнивание
; xor eax, eax ; return 0
; pop rbp
; ret
### Памятка при написании кода
- До call: выровняй стек (RSP%16==0), подготовь регистры аргументов, AL для varargs.
- После call: результат смотри в RAX/XMM0; считай, что caller-saved испорчены — сохрани важное заранее.
- В своей функции сохраняй/восстанавливай RBX, RSP, RBP, R12R15.