```asm movb // копировать 1 байт movw // копировать 2 байтa movl // копировать 4 байта movq // копировать 8 байт leaq data, %rbx // загрузить адрес переменной data в регистр rbx ``` ~={yellow}Способы адресации=~ ```asm // Способ 1: прямая адресация movw 0x402008, %ax // скопировать 2 байта (адрес 0x402008) в регистр ax // или по метке movw M, %ax // Способ 2: косвенная адресация // Предварительно загружаем адрес в регистр (3 способа) movq $0x402008, %rbx movq $M, %rbx leaq M, %rbx // Скопировать в регистр %ax значение из памяти по тому адресу // который содержиться в регистре %rbx movw (%rbx), %ax // Можно указать базовое смещение адреса (положительное - вправо, отрицательное - влево) movw 8(%rbx), %ax // Можно указать текущее смещение предварительно загрузив его в регистр leaq data, %rbx movq $8, %rcx movw 0(%rbx, %rcx), %ax // Можно указать базовое и текущее смещение одновременно movw 0(%rbx, %rcx), %ax // Можно указать размер позиции смещения. // Вот здесь он равен 2-ум байтам movw 4(%rbx, %rcx, 2), %ax ``` ~={yellow}Адресация относительно регистра rip=~ %rip - Re-Extended Instruction Pointer - указатель команд. Хранит адрес очередной команды, которая будет выполнена. Если в качестве базового смещения относительно регистра %rip указана метка, то на место этой метки будет поставлено расстояние в байтах от значения %rip до того адреса, который обозначен данной меткой ```bash movb data(%rip), %al ``` Поместить значение регистра rip в другой регистр ```asm leaq (%rip) %rax ``` **PIC (PIE) - Position Independent Code** Это код, который не зависит от абсолютных адресов. Все ссылки на ячейки памяти относительные (например относительно счетчика команд). Этот код может быть размещен в любой области памяти. Может использоваться при создании динамических библиотек. ~={yellow}Регистр указателя стека=~ %rsp - Re-extended Stack Pointer - Указатель стека В начале выполнения программы содержит адрес, слева от которого можно хранить данные. Для работы со стеком используются два регистра: %rsp и %rdp %rsp - адрес левой границы стека %rdp - адрес правой границы стека Перед использованием стека нужно скопировать содержимое регистра %rsp в %rbp. Для того, чтобы выделить на стеке память под N байтов нужно вычесть число N из регистра %rsp, тем самым "сместить" %rsp влево на N байтов. ```asm // Можно загрузить двухбайтовое значение в стек movw $0xabcd, 0(%rsp) // Или 4-ех байтовое movl 0x12345678, 2(%rsp) // Но 8-и байтовое загрузить напрямую нельзя subq %8, %rsp; // выделить 8 байт movq $0x0123456789abxdef, %rax // запись в регистр movq %rax, 0(%rsp) // перемещение в стек // Загрузка данных в стек частями subq %1, %rsp; // выделить 1 байт в стеке movb $0x12, 0(%rsp); // поместить 1 байт в стек // Далее помещаем два байта в стек subq %2, %rsp; // выделить 1 байт в стеке movb $0x1234, 0(%rsp); // поместить 1 байт в стек // Moжно загрузить в стек 2 (8) байта одной командой pushw %0x1234 movq $0x0123456789abxdef, %rax // запись в регистр pushq %rax; // Очисить стек movq %rbp, %rsp ``` Если в программе применяются функции, использующие стандартизованные соглашения о вызовах функций (например функции стандартной библиотеки языка Си), то стек должен быть выровнен по 16-байтовой границе, т.е. адреса правой и левой границ стека должны быть кратны 16 (Шестнадцатеричное представление должно оканчиваться на 0). В начале программы адрес правой границы стека изначально кратен 16. Далее, память на стеке нужно выделять порциями, объем которых кратен 16. ~={yellow}Вывод строки на экран=~ Для вывода строки на экран можно воспользоваться системной функцией sys_write. Для этого номер этой функции нужно загрузить в регистр %rax. У функции sys_write три параметра: fd - file descriptor, загружается в регистр %rdi = целое положительное число, которое определяет, куда будет производиться вывод. Для вывода на экран нужно строку отправить в выходной поток. Дескриптор выходного потока равен 1. 2-ой параметр buf - buffer - загружается в регистр %rsi - адрес первого байта выводимых данных (адрес начала строки, которую нужно вывести). 3-ий параметр count - загружается в регистр %rdx - количество выводимых байтов (символов) ```asm // Директивы .string и .asciz добавляют в конце строки нулевой байт. ``` Можно вставлять символы по кодам ```asm .ascii "test\12"; // это код символа в восьмеричной системе .ascii "test\x0a"; // это в шестнадцатиричной ``` Так же работает обычное экранирование символов ~={yellow} Бинарные и текстовые файлы=~ *Текстовый файл* - файл в котором каждый байт соответствует коду печатного символа (а так же управляющие элементы: перенос строки, табуляция и т.д.). ~={yellow}Сегменты программы=~ *Сегмент кода* является главным в программе, именно он определяет последовательность действий, которые выполняет программа. Сегмент кода является обязательным, в то время как других сегментов может не быть, так как сами данные без кода - это уже не программа. Объявляется директивой .text. *Сегмент данных* начинается с директивы .data. ~={yellow}JMP - команда безусловного перехода=~ ```asm // Переход по на метку jmp M // или addr: .quad 0x401023 _start: jmp *addr // или загрузить адрес метки в регистр _start movq $M, %rax jmp *%rax // или поместить нужный адрес в сегмент стека _start: movq %rsp, %rdp movq $M, -8(%rdp) jmpq *-8(%rdp); // jmpq - если адрес перехода где-то хранится ``` ~={yellow}Команды call и ret (продвинутый jmp)=~ Команда ~={magenta}call=~ осуществляет переход по указанному адресу, предварительно помещая в стек адрес команды, которая идет после команды call. Команда ~={magenta}ret=~ извлекает 8-байтовый адрес из стека (при этом освобождая 8 байт на стеке) и осуществляет переход по этому адресу. Команды ~={magenta}call и ret=~ используются для реализации механизма подпрограмм и функций. Команда call (вызвать) используется для для перехода из основной программы в подпрограмму, при этом сохраняя на стеке так называемый адрес возврата. Команда ret (вернуться) помещается в конец подпрограммы и осуществляет возврат в основную программу по этому адресу, который был ранее занесен в стек командой call. ~={green}остановился на начале 17=~