Опубликован: 19.01.2025 | Доступ: свободный | Студентов: 0 / 0 | Длительность: 05:57:00
Тема: Программирование
Лекция 8:
Лабораторная работа №7. Вызов подпрограммы, работа со стеком
7.2.4 Стек
Для динамического хранения локальных переменных и адресов возврата нужен стек. Стек регулируется соответствующим соглашением ABI:
- выделенный регистр sp (x2)
- определено дно стека и его начальное значение
- начальное значение отделено от дна буфером
- стек растёт вниз по одному слову (4 байта)
- операции добавления и снятия:
- при добавлении сначала уменьшается указатель, затем записывается значение
- при снятии сначала считывается значение, затем увеличивается указатель
- при такой организации не используется исходная ячейка стека (начальное значение)
Пример
li t1 123 # какое-то значение addi sp sp -4 # положить на стек - 1 sw t1 (sp) # положить на стек - 2 addi t2 t1 100 # какое-то ещё значение addi sp sp -4 # положить на стек - 1 sw t2 (sp) # положить на стек - 2 lw t3 (sp) # доступ к вершине стека lw t4 4(sp) # доступ ко 2-му элементу стека lw t0 (sp) # снятие со стека - 1 addi sp sp 4 # снятие со стека - 2 addi sp sp -4 # положить на стек - 1 sw zero (sp) # положить на стек - 2
Особенности хранения данных в стеке
- Несколько более эффективно, чем в произвольном месте памяти (lw/sw не превращаются в псевдоинструкции).
- Использует адресацию относительно постоянно меняющегося sp. Как следствие, требует аккуратного подсчёта текущей глубины стека.
- Не требует явного указания адреса и заведения метки в программе на языке ассемблера.
- Может привести к сбоям в работе при переполнении/исчерпании/неаккуратном использовании стека.
7.3 Задание к лабораторной работе
- Создать программу согласно варианту, которая
- выполняет заданные действия,
- выводит на экран сообщения о результатах/ошибках.
- Откомпилировать программу и запустить на исполнение.
- Отладить программу, проследить изменения в регистрах и ОП.
7.3.1 Описание последовательности выполнения работы
Скомпилируйте исходную программу и убедитесь в ее работоспособности в RISC-V ОС, либо через qemu-riscv64.
7.3.2 Пример выполнения задания на защиту
Напишите программу, которая вычисляет наибольший общий делитель двух значений с помощью алгоритма Евклида:
function gcd(a, b) while a ? b if a > b a := a ? b else b := b ? a return a
Фрагмент решения:
main: # read_int (t0) # read_int (t1) mv a0, t0 mv a1, t1 jal euclid li a7, 1 ecall li a7, 10 ecall euclid: beq a0, a1, finish blt a0, a1, if_less sub a0, a0, a1 j euclid if_less: sub a1, a1, a0 j euclid finish: jr ra
ВАРИАНТЫ ЗАДАНИЙ
- Напишите программу, которая вводит целые числа M и N и выводит сетку M x N, составленную с помощью + и -. Вы должны написать подпрограмму, который принимает два параметра: M и N, и выводит строку, подобную этой: +-+-+-+-+
Input: 3 4 Output: +-+-+-+ | | | | +-+-+-+ | | | | +-+-+-+ | | | | +-+-+-+ | | | | +-+-+-+
- Написать функцию, которая меняет местами два значения, переданные в стек.
- Написать функцию, которая находит минимальное и максимальное значение в заданном массиве целых чисел.
7.4 Вопросы для контроля
- В чем состоит основная идея использования подпрограмм?
- Какими командами можно реализовать вызов подпрограммы в RISC-V?
- Для чего используется стек?