Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

1 курс 1 семестр / лекции / Лекция_5_Функции_и_стековая_память_П

.pdf
Скачиваний:
25
Добавлен:
27.12.2022
Размер:
1.02 Mб
Скачать

Лекция 5. Функции и стековая память процессора.

Вопросы:

1.Функции ( процедуры).

2.Стек.

Литература: Цифровая схемотехника и архитектура компьютера, второе издание. Дэвид М. Харрис и Сара Л. Харрис, Издательство Morgan Kaufman © English Edition 2013с.815-838

1.Функции.

Вязыках высокого уровня обычно используют функции или процедуры для повторного использования часто выполняемого операций и для того, чтобы сделать программу модульной и читаемой.

У функций есть входные параметры, называемые аргументами функций, и

выходной результат, называемый возвращаемым значением. Функции должны вычислять возвращаемое значение, не вызывая побочных эффектов при обработке программного кода.

Когда одна функция вызывает другую, вызывающая функция и вызываемая

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

В MIPS, вызывающая функция размещает до четырёх аргументов в регистры $a0–$a3 перед тем, как произвести вызов, а вызываемая функция

помещает возвращаемое значение до двух значений в регистры $v0–$v1

перед тем, как завершить работу.

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

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

Вызывающая функция сохраняет адрес возврата (англ.: return address) в регистре адреса возврата ($ra) в тот момент, когда она передаёт управление вызываемой функции путем выполнения инструкции безусловного перехода с возвратом (jal).

Вызываемая функция не должна изменять архитектурное состояние и содержимое памяти, от которых зависит вызывающая функция.

Вызываемая функция должна оставить неизменным содержимое сохраняемых регистров $s0–$s7, регистра адреса возврата $ra и стека –участка памяти, используемого для хранения временных переменных (прим: если вызываемая функция хочет изменить эти регистры, то она должна сохранить их значения в каком-нибудь другом месте памяти и восстановить эти значения перед выходом из стека).

Вызовы и возвраты из функций.

Архитектура MIPS использует инструкцию безусловного перехода с возвратом (jal) для вызова функции и инструкцию безусловного перехода по регистру (jr) для возврата

из функции.

 

 

Исполнение

Вызывающая функция

 

Инструкции jal

 

 

 

 

 

Сохранение адреса

 

 

 

Вызываемая

возврата

 

 

функция

 

 

 

 

 

 

 

Исполнение

Возврат

 

 

Инструкции jr

 

 

 

 

 

1.1. Вызов и возврат функции simple.

Главная функция main является вызывающей, функция simple - вызываемой. Функция simple не получает входных аргументов и ничего не возвращает, она просто передаёт управление обратно вызывающей функции после исполнения

своего предназначения. Коднаязыкеасс мблера

MIPS

0x00400200

main: jal simple

# call function

0x00400204

 

# return

0x00401020

simple: jr $ra

 

Инструкции безусловного перехода с возвратом (jal) и безусловного перехода по регистру (jr $ra) – две необходимые для вызова и возврата функций инструкции. Инструкция jal

выполняет две операции: сохраняет адрес следующей за ней инструкции в регистре адреса возврата ($ra) и выполняет переход по адресу первой вызываемой функции.

Так, например, инструкция jal выполняет переход на адрес 0x00401020 с меткой simple и сохраняет значение адреса возврата 0x00400204 в регистре $ra.

Функция simple немедленно завершается, выполняя инструкцию jr $ra, то есть осуществляет возврат к инструкции по адресу, находящемуся в регистре возврата $ra(0x00400204). После этого функция main продолжает выполняться с этого адреса.

ВЫВОД. Функция simple бесполезна, потому что она не получает входных значений от вызывающей функции (main) ничего не исполняет и ничего ей не возвращает. Данный пример показывает только взаимодействие инструкций, обеспечивающей вызов и возврат функций.

1.2. Функции с входными аргументами и возвращаемыми значениями.

Код программы в ассемблере:

# $s0 = y- возвеличинращаемая

main:

addi $a0, $0, 2 # argument 0 = 2 addi $a1, $0, 3 # argument 1 = 3 addi $a2, $0, 4 # argument 2 = 4 addi $a3, $0, 5 # argument 3 = 5 jal diffofsums # вызовфункции

add $s0, $v0, $0 # y = возвращаем. велич.

# $s0 = result diffofsums:

add $t0, $a0, $a1 # $t0 = f + g add $t1, $a2, $a3 # $t1 = h + i

sub $s0, $t0, $t1 # result = (f + g) − (h + i) add $v0, $s0, $0 # сохр. возвращ велич. $v0 jr $ra # return to caller

Для входных аргументов по соглашениям, принятым в архитектуре MIPS, функции для аргументов используют регистры $a0–$a3, а для возвращаемого значения - регистры $v0–$v1

Функция diffofsums вызывается с 4 аргументами и возвращает 1 результат. Если функции нужно передать более четырех аргументов, то дополнительные аргументы размещаются в стеке.

Вызывающая функция main помещает аргументы функции в регистры входных значений $a0–$a3.

Вызываемая функция diffofsums размещает возвращаемое значение в регистре возвращаемых значений $v0.

Примечание: Функция, возвращающая 64-битное значение, например, число с плавающей точкой двойной точности, использует оба регистра возвращающих значений $v0 и $v1.

По команде jal diffofsums

вызываетсяфункци

diffofsums,котораявыполняет

 

простейшиеарифмоп: рациитические

 

f + g; h + i иокончательныйрезультатопераци

 

(f + g) − (h + i), который сохраняет в возвращаемом регистре $v0.

$v0

Послепроввсехвычиследенияпокоманийде

 

jr $ra этозначениеврегистре

передаетсяввозвращаемыйадрес,

которыйнаходитсясрзвызываемойзуфункцией

.

2. Cтек.

Стек (англ.: stack) – это участок оперативной памяти для хранения локальных переменных функции. Стек расширяется (увеличивает память), если процессору нужно больше места, и сужается (уменьшает память), если процессору больше не нужны сохранённые там переменные.

Стек расширяется в сторону младших адресов по мере выделения нового места в памяти для программы функции.

Очередь переменных стека работает в режиме «последним пришёл – первым ушёл» (LIFO, от англ. last-in-first-out). Каждая функция может выделить память на стеке для хранения локальных переменных, и она же должна освободить её перед возвратом.

Верхушка стека (англ.: top of the stack) – это регистр памяти, который был выделен первым,

а $sp - это указатель стека ($sp, от англ. stack pointer), в качестве которого используется специальный регистр. Регистр $sp указывает на верхушку стека – наименьший адрес памяти, доступной на стеке. Например, если $sp с адресом 0x7FFFFFFC, тогда стек не может использовать память ниже слова с адресом 0x7FFFFFFC , рис. (a).

На рис. (a) указатель стека $sp содержит адрес 0x7FFFFFFC где записана информация 0x12345678.

Указатель стека ($sp) изначально равен большему адресу памяти стека. Его значение при необходимости уменьшается для увеличения доступного программе места, т.е. памяти стека.

На рис. (b) изображен стек, расширившийся для того, чтобы выделить для хранения временных переменных: двух дополнительных слов данных. Для этого значение регистра $sp уменьшается на 8 и становится равным 0x7FFFFFF4. Два дополнительных слова данных 0xAABBCCDD и 0x11223344 временно размещаются на стеке по адресам 7FFFFFF8 и 7FFFFFF4 соответственно.

2.1. Оберегаемые и не оберегаемые регистры стека.

В архитектуре MIPS регистры разделены на две категории: оберегаемые (англ.: preserved) и не оберегаемые (англ.: nonpreserved).

Оберегаемые регистры включают $s0-$s7 (отсюда их название: сохраняемые, англ.; saved).

Не оберегаемые регистры включают $t0- $t9 (отсюда их название: временные, анзл.; temporary).

Функция должна сохранять и восстанавливать любые оберегаемые регистры, с

которыми она собирается работать, но может свободно менять значения не оберегаемых регистров.

Если вызывающая функция содержит актуальные данные в не оберегаемых регистрах, она должна сохранять не оберегаемые регистры перед тем, как вызывать другую функцию, а затем их восстановить.

По этой причине оберегаемые регистры также называют сохраняемыми вызываемой функцией, а не оберегаемые регистры называют сохраняемыми вызывающей функцией.

Оберегаемые регистры

Не оберегаемые регистры

 

 

Сохраняемые регистры: $s0-$s7

Временные регистры: $t0-$t9

используют для хранения временных

используются для хранения локальных переменных

результатов перед тем, как присвоить эти

внутри функции, поэтому они должны быть сохранены.

значения локальным переменным.

 

Адрес возврата: $ra

 

Регистры аргументов: $a0-$a3

следует сохранять, чтобы функция знала,

перезаписываются в процессе вызова функции,

поэтому вызывающая функция должна

куда возвращаться.

сохранять их, если эти

 

значения могут понадобиться ей после

Указатель стека: $sp

завершения вызванной функции.

Возвращаемые значения: $v0-$v1

Сам указатель стека остаётся в сохранности потому,

очевидно, не следует оберегать, потому что в

что вызываемая функция перед завершением

них вызываемая функция возвращает свой

работы освобождает свой кадр стека, прибавляя к $sp

результат.

то же значение, которое вычла из него в начале.

 

Содержимое стека выше

 

 

указателя стека.

Стек ниже указателя стека.

 

 

Одно из важных свойств стека сохранение и восстановление значений регистров, используемых внутри функции. Функция производит вычисления и возвращает значения, но не должна приводить к неожиданным побочным эффектам. Она не должна менять значения никаких регистров внутри функции кроме регистра $v0, содержащего вычисляемое и возвращаемое значение.

Поэтому функция сохраняет значения регистров на стеке перед тем, как изменить их, и восстанавливает их из стека перед тем, как завершиться ее выполнение, а именно, совершает следующие шаги: 1. Выделяет пространство на стеке для сохранения значений одного или нескольких регистров. 2. Сохраняет значения регистров на стек. 3. Выполняет функцию, используя регистры стека. 4. Восстанавливает исходные значения регистров из стека. 5. Освобождает пространство на стеке.

2.2. ФУНКЦИЯ, СОХРАНЯЮЩАЯ РЕГИСТРЫ НА СТЕКЕ (сохраняет и восстанавливает регистры $t0, $t1 и $s0.)

# $s0 = result ре,гбудетистрразмещенрезультатпослевыполфункцениия

 

 

 

diffofsums.

 

diffofsums:

# шаг1:

 

 

 

 

 

 

 

 

addi $sp, $sp, −12

занять пространство на стеке для 3-х регистров ( 12:4=3).

 

sw $s0, 8($sp)

#

save $s0

on stack

Шаг2:

 

записьзначвререгинийменныхвпамятьстека:ров

 

 

sw $t0, 4($sp)

#save

$t0 on stack

 

 

$t0 вовторойадрес;

 

$s0 – вадрстека3 относительноуказателя;

 

sw $t1, 0($sp)

# save $t1 on stack

$t1 -

внулевойадресотносиуказателя. льно

 

 

add $t0, $a0, $a1

# $t0 = f + g

 

 

Шаг3 :вычислительоперациивыбраныеными

 

add $t1, $a2, $a3

# $t1 = h + i

 

 

 

 

 

регистрами.Получениерезультатаоперации.

 

 

sub $s0, $t0, $t1

# result−(h += (f + g)

i)

 

 

 

 

 

 

$v0

 

add $v0, $s0, $0

# сохранениерезультвелсохичинырующаняемыйегистр

Шаг4:

возвратинфоризпамятистекаврегистрыации:

 

lw $t1, 0($sp)

# restore $t1 from stack

 

 

lw $t0, 4($sp)

# restore $t0 from stack

$t1, $t0 , $s0 командой lw – чтениесловизпамятистека

 

lw $s0, 8($sp)

# restore $s0 from stack

записьихврегистровыйфайл

RF.

 

addi $sp, $sp, 12

# Шаг5

:освобождезанятогопространствапамятистекеие.

 

 

 

 

 

jr $ra

# возвратнаадрес

 

вызываемой функции diffofsums.

 

 

Вывод: в стеке были сохранены значения временных регистров $t1, $t0 , $s0

довыполненфункциия

и

значэтихрегнменялосьистровпомеревыполфункц,ното,чтоенбыловистекеиябылосохраненои

 

 

 

 

 

 

 

 

восстановленоизстекапослевыполфункц. ениия

данныерегистров

 

$t1, $t0 , $s0 навремявыполнениявычислительныхопераций.

 

 

Стекпростохранит

 

 

 

Изменение стека при вычислении функции.

12

стека

Пространство

 

 

Шаг 1: Выделение пространства на стеке для трёх слов регистров $s0,$t0,$t1, уменьшая указатель стека $sp на 12 (адреса F8,F4,F0). Рис. (а).

Шаг2: сохранение текущего значения $s0, $t0 и $t1 в выделенном пространстве. Рис.b.

Шаг3: выполнение основной часть функции, которая меняет значения этих трёх регистров, используя основную память компьютера, а не память стека.

Шаг4: восстановление значений регистров $s0, $t0 и $t1 из стека и освобождение пространства на стеке (рис. (с)) и возврат в вызывающую функцию main.

При возврате вызываемой функции, в регистре $v0 находится её результат.

В регистрах $s0, $t0, $t1 и $sp находятся те же значения, которые там и были до вызова функции.

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

$t1, $t0 , $s0 навремявыполнениявычислительных

операций.