Skip to main content

Стек

LIFO. Управляется через регистр RSP. Когда программа начинает выполняться, ОС инициализирует регистр RSP адресом последней ячейки памяти в сегменте стека. Размер стека зависит от системы. На Linux х86-64 стек ограничен 2 мегабайтами.

Стек растет от больших адресов к меньшим. При начале стек выровнен по 16-байтовой границе.

Использование стека

push добавляет данные в стек. Возможно добавить 16- и 64-разрядный регистр, адрес в памяти 16- и 64-разрядного числа или значение 16- и 32-разрядной константы (32-битная констранта расширяется до 64 бит). 

При выполнении инструкции push от значения регистра RSP вычитается размер операнда. А по адресу, который хранится в стеке, помещается значение операнда.

pop получает из стека значение, адрес которого в регистре RSP. Можно сохранить в 16- и 64-разрядный регистр или адрес в памяти 16- и 64-разрядного числа. 

global _start
 
section .text
_start:
    mov rdx, 15
    push rdx            ; в стек помещаем содержимое регистра RDX
    pop rdi             ; значение из вершины стека помещаем в регистр RDI
    mov rax, 60
    syscall

Сохранение регистров в стек 

global _start
 
section .text
_start:
... 
    push rdi
    push rdx
...
    pop rdx
    pop rdi

Сохранение флагов состояния

pushfq и popfq (без аргументов) сохраняет/восстанавливает регистр RFLAGS

Восстановление стека без извлечения данных

При завершении программы нужно восстановить адрес в RSP. Можно через pop. Можно прибавть нужное значение к RSP 

global _start
 
section .text
_start:
    mov rdi, 11
    mov rdx, 33
 
    push rdi
    push rdx
 
    add rsp, 16     ; прибавляем к адресу в RSP 16 байт 
 
    mov rax, 60
    syscall

Резервирование пространства в стеке: 

global _start
 
section .text
_start:
    sub rsp, 16  ; резервируем в стеке 16 байт
     
    ; некоторая работа со стеком
 
    add rsp, 16     ; восстанавливаем значение стека
    mov rax, 60
    syscall

Косвенная адресация в стеке

Как и в случае с любым другим регистром, в отношении регистра стека RSP можно использовать косвенную адресацию и обращаться к данным в стеке без смещения указателя RSP.  

global _start
 
section .text
_start:
    push 12
    push 13
    push 14
    push 15
 
    mov rdi, [rsp+16]      ; [rsp+16] - адрес значения 13
 
    add rsp, 32     ; восстанавливаем значение стека
 
    mov rax, 60
    syscall