Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Промежуточный отчёт по ассемблеру(main frame).docx
Скачиваний:
4
Добавлен:
28.08.2019
Размер:
188.13 Кб
Скачать

Выход из функции

Вызываемая функция завершается, освобождая авто переменные, восстанавливая регистры, освобождая параметры стека и, наконец, выполняя команду RET, которая выталкивает адрес возврата от стека адреса возврата.

Возвращаемые значения

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

Для обоих соглашений о вызовах, следующие подробности имеют место:

  • стек адреса возврата (RSTACK) и стек данных (CSTACK) два отдельный стека. RSTACK использует внутренний порт Ввода - вывода SP, который объявлен в ioxxx.h файлы для включения, поставляемые с программой.

  • struct и union имеющие больше чем 4 байта передаются используя указатель, этот указатель возвращается через регистр

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

Использование регистров для возвращения значений

Для обоих соглашений о вызовах, регистры, доступные для возвращения значений - R16-R19.

Возвращаемоезначение

Используемыерегистры

8-bit

R16

16-bit

R17:R16

24-bit

R18:R17:R16

32-bit

R19:R18:R17:R16

Размер возвращенного указателя зависит от используемой модели памяти;

Соответствующие регистраторы используются соответственно.

Обработка Стека

Обычно, это - ответственность вызываемой функции, чтобы чистить стек. Единственное исключение - для функций с переменным списком параметров типаprintf — для которого обработка стека является ответственностью вызывающей программы, чтобы чистить стек.

Обработка адреса возврата

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

Как правило возврат функции использует команду RET.

Ограничение для специальных типов функций

Функции обработки прерываний

Функции обработки прерываний отличаются от обычных функций C по этому:

  • Если используется, флажки и рабочие регистраторы сохранены

  • вызовы функций обработки прерываний сделаны через векторы прерывания; прямые вызовы не позволяются

  • нет аргументов для передачи в функции обработки прерываний

  • возврат из функции обработки прерываний использует команду RETI.

Функции Монитора

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

Примеры

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

Пример 1

Предположим, что мы имеем следующее объявление функции:

intadd1(int);

Эта функция берет один параметр из регистров R17:R16, и возвращает значение к вызывающей её программе в регистрах R17:R16.

Следующая подпрограмма ассемблера совместима с объявлением; возвратит значение, которое является на один больше чем значение передаваемого параметра:

SUBI R16,FF

SBCI R17,FF

Пример 2

Этот пример показывает, как структуры передаются через стек. Предположим, что мы имеем следующие объявление:

struct a_struct { int a; int b; int c;};

int a_function(struct a_struct x, int y);

Функция запроса должна резервировать шесть байтов на вершине стека и копировать содержание struct к тому местоположению. Целочисленный параметр y передается в регистрах R17:R16. Возвращаемое значение передается назад к вызывающей программе в регистрах R17:R16.

Пример 3

Функция возвращающая struct.

structa_struct { int a; };

structa_structa_function(int x);

Функция запроса должна распределить местоположение памяти для возвращаемого значения и передавать указатель на неё как скрытый первый параметр. Указатель на местоположение, где возвращаемое значение должно быть сохранено, передается в первой паре регистра/регистров, которая является R16, R17:R16, и R18:R17:R16 для Tiny, Small, и Large модели памяти соответственно. Параметр x передается в R19:R18, R19:R18, и R21:R20 Tiny, Small, и Large модели памяти соответственно.

Предположим, что функция вместо того как объявляли, возвращает указатель на структуру:

structa_struct * a_function(int x);

В этом случае, возвращаемое значение - скаляр, так не имеется никакого скрытого параметра. Параметр x пропускают в R17:R16. Возвращаемое значение возвращено в R16, R17:R16, и R18:R17:R16 для Tiny, Small, и Large модели памяти соответственно.

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

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

CFI директивы обеспечат C-SPY информацией относительно состояния функции(й) запроса. Наиболее важный из этого - адрес возврата, и значение указателя вершины стека при входе подпрограммы ассемблера или функции. По этим данным C-SPY может восстанавливать состояние для функции вызова, и таким образом раскручивать стек.

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

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

  • имя блока описания доступных ресурсов, которые будут прослежены

  • общий блок, соответствующий соглашению о вызовах

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