32-разрядные соглашения о вызовах функции PowerPC
Когда функции (подпрограммы) вызывают другие функции (подпрограммы), они, возможно, должны передать параметры вызванным функциям. Вызванные функции получают доступ к тем параметрам как к параметрам. С другой стороны некоторые функции возвращают результат или возвращаемое значение к их вызывающим сторонам. И параметры и результаты могут быть переданы с помощью 32-разрядных регистров архитектуры PowerPC или стека этапа выполнения, в зависимости от типа данных включенных значений. Для успешной и эффективной передачи значений между подпрограммами и подпрограммами, GCC соблюдает строгие правила, когда это генерирует объектный код программы.
Эта статья описывает типы данных, которые могут использоваться для управления параметрами и результатами вызовов функции, как подпрограммы передают параметры подпрограммам, которые они вызывают, и как функции передают результаты своим вызывающим сторонам. Это также перечисляет регистры, доступные в 32-разрядной архитектуре PowerPC и сохраняется ли их значение после вызова функции.
Типы данных и выравнивание данных
Используя правильные типы данных для Ваших переменных и установки надлежащего выравнивания данных для Ваших данных может максимизировать производительность и мобильность Ваших программ. Выравнивание данных указывает, как данные размечаются в памяти.
Таблица 1 перечисляет ANSI C скалярные типы данных и их размеры и естественное выравнивание в этой среде.
Тип данных | Размер и естественное выравнивание (в байтах) |
---|---|
| 4 |
| 1 |
| 1 |
| 2 |
| 2 |
| 4 |
| 4 |
| 4 |
| 4 |
| 8 |
| 8 |
| 4 |
| 8 |
| 16* |
указатель | 4 |
(*) В OS X v10.4 и позже и GCC 4.0 и позже, размер long double
тип данных расширенной точности составляет 16 байтов (он составлен из двух 8 байтов, удваивается). В более ранних версиях OS X и GCC, long double
эквивалентно double
. Вы не должны использовать long double
введите при использовании GCC 4.0 или позже разработать или в программах, предназначенных для версий OS X ранее, чем 10,4.
Это некоторые важные подробные данные о 32-разрядной среде PowerPC:
Эта среда использует схему порядка байтов с обратным порядком байтов сохранить числовой и типы данных указателя. Т.е. старшие значащие байты идут сначала, сопровождаемые младшими значащими байтами.
Эта среда использует two's-дополнительное двоичное представление для типов данных целого числа со знаком.
Арифметика для 64-разрядных целочисленных типов данных должна быть синтезирована компилятором, так как 32-разрядная архитектура PowerPC не реализует 64-разрядные целочисленные математические операции.
float
иdouble
типы данных соответствуют представлению стандарта IEEE 754. Для диапазона значений и точного формата типов данных с плавающей точкой, посмотрите Численные данные PowerPC в Документации Производительности.
Это поддержка сред многократные режимы выравнивания данных. Выравнивание типов данных попадает в две категории:
Естественное выравнивание. Выравнивание типа данных, когда выделено в памяти или присвоенный адрес памяти.
Естественное выравнивание типа данных является своим размером. Таблица 1 показывает естественное выравнивание каждого типа данных, поддерживаемого этой средой.
Встраивание выравнивания. Выравнивание типа данных в составной структуре данных.
Например, выравнивание unsigned short
переменная на штабеле может отличаться от того из unsigned short
элемент встраивается в структуру данных.
Выравнивание встраивания для структур данных варьируется в зависимости от выбранного режима выравнивания. Обычно можно установить режим выравнивания с помощью параметров компилятора или #pragma
операторы. Необходимо считать совместимость и проблемы производительности описанными позже в этом разделе при выборе определенного режима выравнивания.
Это режимы выравнивания встраивания, доступные в 32-разрядной среде PowerPC:
Режим выравнивания питания получен на основании правил выравнивания, используемых IBM компилятор XLC для операционной системы ЭКС-АН-ПРОВАНСА. Это - режим выравнивания по умолчанию для версии архитектуры PowerPC GCC, используемого на ЭКС-АН-ПРОВАНСЕ и OS X. Поскольку этот режим, наиболее вероятно, будет совместим между компиляторами архитектуры PowerPC от различных поставщиков, он обычно используется со структурами данных, совместно использующимися различными программами.
Правила для выравнивания питания:
Выравнивание встраивания первого элемента в структуре данных равно естественному выравниванию элемента.
Для последующих элементов с естественным выравниванием меньше чем 4 байта выравнивание встраивания каждого элемента равно его естественному выравниванию.
Для последующих элементов, имеющих естественное выравнивание, больше, чем 4 байта, выравнивание встраивания равняется 4, если элемент не является a
vector
.Выравнивание встраивания для
vector
элементы всегда - 16 байтов.Выравнивание встраивания составного типа данных (структура массива или структура данных) определяется самым большим выравниванием встраивания его элементов.
Общий размер составного типа окружен к кратному числу его выравнивания встраивания и дополняется нулевыми байтами.
Поскольку естественное выравнивание
double
иlong long
типы данных больше, чем 4 байта, они могут не быть соответственно выровненные в режиме выравнивания питания. Когда к таким элементам данных получают доступ, любое неточное совмещение повреждает производительность. При использовании этих типов данных для любого элемента после того, как первый элемент, компилятор дополнит структуру для выравнивания элементов к следующему кратному числу их естественного выравнивания.Режим выравнивания Mac68K обычно используется с устаревшими структурами данных, наследованными от Mac OS 9 и более ранние системы. Новый код не должен должен быть использовать этот режим выравнивания кроме сохранить совместимость с более старыми структурами данных.
Правила для выравнивания Mac68K:
Выравнивание встраивания
char
тип данных составляет 1 байт.Выравнивание встраивания всех других типов данных (кроме
vector
) 2 байта.Выравнивание встраивания для
vector
тип данных составляет 16 байтов.Общий размер составного типа данных окружен к кратному числу 2 байтов.
Естественный режим выравнивания использует естественное выравнивание каждого типа данных как его выравнивание встраивания. Используйте этот режим выравнивания для получения самой высокой производительности при использовании
double
,long long
, иlong double
типы данных.Упакованный режим выравнивания не содержит дополнения выравнивания между элементами (выравнивание для всех типов данных составляет 1 байт). Используйте этот режим выравнивания при необходимости в структуре данных для использования как можно меньше памяти. Отметьте, однако, что упакованное выравнивание может значительно ниже производительность Вашего приложения.
Таблица 2 перечисляет выравнивание для полей структуры основополагающих типов данных и составных типов данных в поддерживаемых режимах выравнивания.
Тип данных | Выравнивание питания | Естественное выравнивание | Выравнивание Mac68K | Упакованное выравнивание |
---|---|---|---|---|
| 4 | 4 | 2 | 1 |
| 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 1 |
| 4 | 4 | 2 | 1 |
| 4 | 4 | 2 | 1 |
| 4 или 8 | 8 | 2 | 1 |
| 4 | 4 | 2 | 1 |
| 4 или 8 | 8 | 2 | 1 |
| 2 | 1 | ||
| 16 | 16 | 16 | 1 |
Составной объект (структура данных или массив) | 4, 8, или 16 | 1, 2, 4, 8, или 16 | 2 | 1 |
С GCC можно управлять выравниванием структуры данных путем добавления #pragma
операторы к Вашему исходному коду или при помощи параметров командной строки. Если Вы не указываете иначе, режим выравнивания питания используется.
Для установки режима выравнивания используйте gcc
флаги -malign-power
, -malign-mac68k
, и -malign-natural
. Для использования определенного режима выравнивания в структуре данных добавьте этот оператор как раз перед объявлением структуры данных:
#pragma option align=<mode> |
Замена <mode>
с power
, mac68k
, natural
, или packed
. Для восстановления предыдущего режима выравнивания использовать reset
как режим выравнивания в a #pragma
оператор:
#pragma option align=reset |
Вызовы функции
Этот раздел детализирует процесс вызова функции и передающих параметров ей, и как возвращаемые значения функций к их вызывающим сторонам.
Структура штабеля
Эта среда использует штабель, становящийся нисходящим и содержащий информацию о связи, локальные переменные и информацию о параметре функции, как показано на рисунке 1. (Чтобы помочь предотвратить выполнение вредоносного кода на штабеле, GCC защищает штабель от выполнения.)
Указатель вершины стека (SP) указывает на нижнюю часть штабеля. Штабель имеет фиксированный тип телосложения, который известен во время компиляции.
Стековый фрейм вызывающей подпрограммы включает область параметра и некоторую информацию о связи. Область параметра имеет параметры, которые вызывающая сторона передает вызванной функции или пространству для них, в зависимости от типа каждого параметра и доступности регистров (см. Передающие Параметры за подробные данные). Так как вызывающая подпрограмма может вызвать несколько функций в 32-разрядной среде PowerPC, область параметра является обычно достаточно большой для размещения самого большого списка аргументов всех функций вызовы вызывающей стороны. Это - ответственность вызывающей подпрограммы установить область параметра перед каждым вызовом функции. Вызванная функция ответственна за доступ к параметрам, помещенным в область параметра.
Первые 32 байта в области параметра соответствуют регистрам общего назначения GPR3 через GPR10. Когда данные помещены в регистр общего назначения и не дублированы в области параметра, соответствующий раздел в области параметра резервируется в случае, если вызванная функция должна скопировать значение в регистре к штабелю. Таблица 3 показывает корреспонденцию расположений области параметра к регистрам общего назначения, которые могут использоваться для передачи параметров.
Расположение стекового фрейма | Регистр |
---|---|
| GPR3 |
| GPR4 |
| GPR5 |
| GPR6 |
| GPR7 |
| GPR8 |
| GPR9 |
| GPR10 |
Когда параметры помещаются в область параметра или в GPR3 через GPR10, это правила выравнивания, соблюденные:
Все невекторные параметры выровненные на 4-байтовых границах.
Векторные параметры выровненные на 16-байтовых границах.
Несоставные параметры (т.е. параметры, которые не являются массивами или структурами данных) меньший, чем 4 байта занимают старшие байты своей 4-байтовой области.
Составные параметры (массивы, структуры и объединения) 1 или 2 байта в размере занимают байты младшего разряда своей 4-байтовой области. Им предшествуют путем дополнения к 4 байтам.
Это правило противоречиво с другими 32-разрядными двоичными интерфейсами PowerPC. В ЭКС-АН-ПРОВАНСЕ и Mac OS 9 (и ранее), дополняющие байты всегда следуют за структурой данных даже в случае составных параметров, меньших, чем 4 байта.
Составные параметры 3 байта или больше в размере занимают старшие байты своей 4-байтовой области. Они сопровождаются путем дополнения для создания кратного числа 4 байтов с дополнительными байтами, являющимися неопределенным.
Например, рассмотрите foo
функция, объявленная как это:
void foo(SInt32 i1, float f1, double d1, SInt16 s1, double d2, |
UInt8 c1, UInt16 s2, float f2, SInt32 i2); |
Таблица 4 показывает, как параметрами функции являются присвоенные расположения в области параметра. Присвоение принимает во внимание 4-байтовое выравнивание, требуемое для каждого параметра.
Параметр | Ввести | Расположение | Размер данных и дополняющий (в байтах) |
---|---|---|---|
|
|
| 4, 0 |
|
|
| 4, 0 |
|
|
| 8, 0 |
|
|
| 2, 2 |
|
|
| 8, 0 |
|
|
| 1, 3 |
|
|
| 2, 2 |
|
|
| 4, 0 |
|
|
| 4, 0 |
Область связи вызывающей подпрограммы содержит много значений, некоторые из которых сохраняются вызывающей подпрограммой и некоторыми вызванной функцией. Элементы в области связи:
Регистр ссылки (LR). Его значение сохраняется в
8(SP)
вызванной функцией, если это принимает решение сделать так. Регистр ссылки содержит обратный адрес инструкции, следующей за ответвлением и инструкцией ссылки.Регистр условия (CR). Его значение может быть сохранено в
4(SP)
вызванной функцией. Регистр условия содержит результаты операций сравнения. Как с регистром ссылки, вызванная процедура не требуется, чтобы сохранять это значение.Указатель вершины стека (SP). Его значение может быть сохранено в
0(SP)
вызванной функцией как часть ее стекового фрейма. Листовые функции не требуются, чтобы сохранять указатель вершины стека. Листовая функция является функцией, не вызывающей никакие другие функции.
Область связи наверху штабеля, смежного с указателем вершины стека. Это расположение необходимо так, чтобы вызывающая подпрограмма могла найти и восстановить значения, сохраненные там, и также позволить вызванной функции находить область параметра вызывающей стороны. Это размещение означает, что подпрограмма не может продвинуть и вытолкать параметры от штабеля, как только устанавливается стековый фрейм.
Стековый фрейм также включает пространство для локальных переменных вызванной функции. Однако некоторые регистры также доступны для использования вызванной функцией; посмотрите Сохранение Регистра для подробных данных. Если бы подпрограмма содержит больше локальных переменных, чем поместился бы в регистры, она использует дополнительное пространство на штабеле. Размер области локальной переменной определяется во время компиляции. Как только стековый фрейм выделяется, размер области локальной переменной не изменяется.
Прожурналы и эпилоги
Вызванная функция ответственна за выделение ее собственного стекового фрейма, удостоверяясь сохранять 16-байтовое выравнивание в штабеле. Эта работа выполняется разделом кода, названного Прологом, который компилятор помещает перед организацией подпрограммы. После организации подпрограммы компилятор помещает эпилог для восстановления процессора к состоянию, которым это было до вызова подпрограммы.
Сгенерированный компилятором код Пролога делает следующее:
Постепенно уменьшает указатель вершины стека для учета нового стекового фрейма и пишет предыдущее значение указателя вершины стека к его собственной области связи, гарантирующей, что штабель может быть восстановлен его исходному состоянию после возврата из вызова.
Важно, чтобы декремент и задачи обновления произошли атомарно (например, с
stwu
,stwux
,stdu
, илиstdux
) так, чтобы указатель вершины стека и обратный канал были в непротиворечивом состоянии. Иначе, асинхронные сигналы или прерывания могли повредить штабель.Сохраняет все энергонезависимые регистры с плавающей точкой и общего назначения в область сохраненных регистров. Обратите внимание на то, что, если вызванная функция не изменяет определенный энергонезависимый регистр, она не сохраняет его.
Сохраняет регистр ссылки и значения регистра условия в области связи вызывающей стороны, в случае необходимости.
Перечисление 1 показывает пример Пролога подпрограммы. Заметьте, что порядок этих действий отличается от порядка, ранее описанного.
Пролог перечисления 1 В качестве примера
linkageArea = 24 ; size in 32-bit PowerPC ABI |
params = 32 ; callee parameter area |
localVars = 0 ; callee local variables |
numGPRs = 0 ; volatile GPRs used by callee |
numFPRs = 0 ; volatile FPRs used by callee |
spaceToSave = linkageArea + params + localVars + 4*numGPRs + 8*numFPRs |
spaceToSaveAligned = ((spaceToSave+15) & (-16)) ; 16-byte-aligned stack |
_functionName: ; PROLOG |
mflr r0 ; extract return address |
stw r0, 8(SP) ; save the return address |
stwu SP, -spaceToSaveAligned(SP) ; skip over caller save area |
В конце подпрограммы сгенерированный компилятором эпилог делает следующее:
Восстанавливает энергонезависимые регистры с плавающей точкой и общего назначения, сохраненные в стековом фрейме.
Энергонезависимые регистры сохраняются в новом стековом фрейме, прежде чем указатель вершины стека будет обновлен только, когда они соответствуют в пространстве ниже указателя вершины стека, где новый стековый фрейм обычно выделялся бы, также известен как красная зона. Красная зона является по определению достаточно большой для содержания всех энергонезависимых регистров с плавающей точкой и общего назначения, но не энергонезависимых векторных регистров. Посмотрите Красную Зону для подробных данных.
Восстанавливает регистр условия и значения регистра ссылки, которые были сохранены в области связи.
Восстанавливает указатель вершины стека к его предыдущему значению.
Возвраты управляют к вызывающая подпрограмма с помощью адреса, сохраненного в регистре ссылки.
Перечисление 2 показывает эпилог в качестве примера.
Эпилог перечисления 2 В качестве примера
; EPILOG |
lwz r0, spaceToSaveAligned + 8(SP) ; get the return address |
mtlr r0 ; into the link register |
addi SP, SP, spaceToSaveAligned ; restore stack pointer |
blr ; and branch to the return address |
Регистр VRSAVE используется для указания, какие векторные регистры должны быть сохранены во время контекстного переключения процесса или потока. Перечисление 3 показывает Пролог в качестве примера, устанавливающий VRSAVE так, чтобы вектор зарегистрировался, V0 через V2 сохраняются. Перечисление 3 также включает эпилог, восстанавливающий VRSAVE к его предыдущему состоянию.
Использование перечисления 3 В качестве примера регистра VRSAVE
#define VRSAVE 256 // VRSAVE IS SPR# 256 |
_functionName: |
mfspr r2, VRSAVE ; get vector of live VRs |
oris r0, r2, 0xE000 ; set bits 0-2 since we use V0..V2 |
mtspr VRSAVE, r0 ; update live VR vector before using any VRs |
; Now, V0..V2 can be safely used. |
; Function body goes here. |
mtspr VRSAVE, r2 ; restore VRSAVE |
blr ; return to caller |
Красная зона
Пространство ниже указателя вершины стека, где новый стековый фрейм обычно выделялся бы подпрограммой, вызывают красной зоной. Красную зону, показанную на рисунке 2, считают частью текущего стекового фрейма. Эта область не изменяется асинхронными нажатиями, такими как сигналы или обработчики прерываний. Поэтому красная зона может использоваться в любой цели, пока новый стековый фрейм не должен быть добавлен к штабелю. Однако содержание красной зоны, как предполагается, уничтожается любым синхронным вызовом.
Например, потому что листовая функция не вызывает никакие другие функции — и, поэтому, не выделяет область параметра на штабеле — это может использовать красную зону. Кроме того, такая функция не должна использовать штабель для хранения локальных переменных; это должно сохранить только энергонезависимые регистры, которые это использует для локальных переменных. С тех пор, по определению, не больше, чем одна листовая функция активна в любое время в потоке, нет никакой возможности многократных листовых функций, конкурирующих за то же красное зональное пространство.
Листовая функция может или может не выделить стековый фрейм и постепенно уменьшить указатель вершины стека. Когда это не выделяет стековый фрейм, листовая функция хранит регистр ссылки и значения регистра условия в области связи подпрограммы, вызывающей его (если необходимый), и хранит значения любых энергонезависимых регистров, которые это использует в красной зоне. Эта оптимизация означает, что листовой Пролог функции и эпилог выполняют минимальную работу; они не должны устанавливать и приводить в нерабочее состояние стековый фрейм.
Размер красной зоны составляет 224 байта, который является достаточным количеством пространства для хранения значений девятнадцати 32-разрядных регистров общего назначения и восемнадцати 64-разрядных регистров с плавающей точкой, окруженных к самой близкой 16-байтовой границе. Если бы красное зональное использование функции листа превысило бы красный зональный размер, оно должно установить стековый фрейм, как функции, вызывающие другие функции, делают.
Передача параметров
На языке C функции могут объявить свои параметры с помощью одного из трех соглашений:
Типы всех параметров указаны в прототипе функции. Например:
int foo(int, short);
В этом случае тип параметров всей функции известен во время компиляции.
Прототип функции объявляет некоторые фиксированные параметры и некоторые нефиксированные параметры. Группу нефиксированных параметров также вызывают списком аргумента переменной. Например:
int foo(int, ...);
В этом случае, тип одного из параметров функции в известном во время компиляции. Тип нефиксированных параметров не известен.
Функция не имеет никакого прототипа или использует предANSI C объявление. Например:
int foo();
В этом случае тип параметров всей функции неизвестен во время компиляции.
Когда компилятор генерирует Пролог к вызову функции, это использует информацию от объявления функции, чтобы решить, как параметры передаются функции. Когда компилятор знает тип параметра, это передает его самым эффективным возможным способом. Но когда тип неизвестен, он передает параметр с помощью самого безопасного подхода, который может вовлечь помещающие данные и в регистры и в область параметра. Для вызванных функций для доступа к их параметрам правильно важно, чтобы они знали, когда параметры передаются в штабеле или в регистрах.
Параметры передаются в штабеле в регистрах, или и, в зависимости от их типов и, в зависимости от доступности регистров. Существует три типа регистров: общая цель, плавающая точка и вектор. Регистры общего назначения (GPRs) являются 32-разрядными регистрами, которые могут управлять интегральными значениями и указателями. Регистры с плавающей точкой (FPRs) являются 64-разрядными регистрами, которые могут управлять одинарной точностью и двойной точностью значения с плавающей точкой. Векторные регистры являются 128-разрядными регистрами, которые могут управлять 4 - 16 блоками данных параллельно.
Регистры, которые могут использоваться для передачи параметров вызванным функциям, являются регистрами общего назначения GPR3 через GPR10, регистры с плавающей точкой FPR1 через FPR13, и вектор регистрирует V2 через V13 (см. Сохранение Регистра для подробных данных). Эти регистры также известны как регистры параметра.
Как правило, вызванная подпрограмма получает параметры от регистров. Однако вызывающая сторона генерирует область параметра в стековом фрейме вызывающей стороны, который является достаточно большим для содержания всех параметров, переданных вызванной функции, независимо от того, сколько из параметров фактически передается в регистрах. (Можно думать об области параметра как о структуре данных, имеющей пространство для содержания всех параметров в данном вызове.) Существует несколько причин их, интригуйте:
Это предоставляет вызванной функции пространство в штабеле для хранения основанного на регистре параметра, если это хочет использовать один из регистров параметра в некоторой другой цели. Например, вызываемый может использовать, они располагают с интервалами для передачи параметров функции, которую это вызывает.
Функции со списками аргумента переменной должны часто получать доступ к своим параметрам от RAM, не от регистров. Такие функции должны зарезервировать 32 байта (8 регистров) в области параметра для содержания значений параметров.
Для упрощения отладки GCC пишет параметры из регистров параметра в область параметра в стековом фрейме. Это позволяет Вам видеть все параметры путем рассмотрения только области параметра.
Компилятор использует соблюдающие правила когда передающие параметры подпрограммам:
Параметры, тип которых известен во время компиляции, обрабатываются следующим образом:
Скаляр, элементы нес плавающей точкой помещаются в регистры общего назначения GPR3 через GPR10. Поскольку каждый регистр используется, вызывающая сторона выделяет соответствующий раздел регистра в области параметра, как описано в Структуре Штабеля. Когда регистры общего назначения исчерпываются, вызывающая сторона помещает скаляр, элементы нес плавающей точкой в области параметра.
Вызывающая сторона помещает параметры с плавающей точкой в регистры с плавающей точкой FPR1 через FPR13. Поскольку каждый регистр с плавающей точкой используется, вызывающая сторона пропускает один или несколько регистров общего назначения, на основе размера параметра. (Например, a
float
элемент заставляет один (4-байтовый) регистр общего назначения быть пропущенным. Adouble
элемент заставляет два регистра общего назначения быть пропущенными.), Когда регистры с плавающей точкой исчерпываются, вызывающая сторона помещает элементы с плавающей точкой в область параметра.Вызывающая сторона помещает структуры (
struct
элементы) только с одним несоставным элементом в регистрах с плавающей точкой или общего назначения, в зависимости от того, является ли элемент целым числом или значением с плавающей точкой. Например, вызывающая сторона помещает структуру, состоявшую из afloat
элемент в регистре с плавающей точкой, не регистре общего назначения. Когда регистры требуемого типа исчерпываются, структуры мест вызывающей стороны в области параметра.Места вызывающей стороны
vector
параметры в векторных регистрах V2 через V13. Для процедур с постоянным числом параметров присутствие векторов не влияет на выделение регистров общего назначения и регистров с плавающей точкой. Вызывающая сторона не выделяет площадь дляvector
элементы в области параметра его стекового фрейма, если числоvector
элементы превышают число применимых векторных регистров.Когда число параметров превышает число применимых регистров, вызывающая сторона помещает избыточные параметры в область параметра.
Параметры, тип которых не известен во время компиляции (функции со списками аргумента переменной или использованием предANSI C прототипы) обрабатываются следующим образом:
Вызывающая сторона помещает невекторные элементы и в регистры общего назначения и в регистры с плавающей точкой.
Поскольку компилятор не знает тип параметра, это не может определить, должен ли параметр быть передан в регистре общего назначения или в регистре с плавающей точкой. Поэтому вызывающие стороны помещают каждый параметр в регистр с плавающей точкой и соответствующие регистры общего назначения на основе размера параметра.
Места вызывающей стороны
vector
элементы в векторных регистрах и регистрах общего назначения (каждый векторный элемент требует четырех регистров общего назначения. Вызывающая сторона также выделяет площадь в области параметра, соответствующей используемым регистрам общего назначения.
Например, рассмотрите foo
функция, объявленная как это:
void foo(SInt32 i1, float f1, double d1, SInt16 s1, double d2, |
UInt8 c1, UInt16 s2, float f2, SInt32 i2); |
Вызывающая сторона помещает каждый параметр foo
в регистре общего назначения, регистре с плавающей точкой или области параметра, в зависимости от типа данных параметра и доступности регистра. Таблица 5 описывает этот процесс.
Параметр | Ввести | Помещенный в | Причина |
---|---|---|---|
|
| GPR3 | Несоставной объект, элемент нес плавающей точкой. |
|
| FPR1 | Элемент с плавающей точкой. GPR4 пропускается. |
|
| FPR2 | Двойная точность, элемент с плавающей точкой. GPR5 и GPR6 пропускаются. |
|
| GPR7 | Несоставной объект, элемент нес плавающей точкой. |
|
| FPR3 | Двойная точность, элемент с плавающей точкой. GPR8 и GPR9 пропускаются. |
|
| GPR10 | Несоставной объект, элемент нес плавающей точкой. |
|
|
| Никакие доступные регистры общего назначения. |
|
| FPR4 | Элемент с плавающей точкой. |
|
|
| Никакие доступные регистры общего назначения. |
Рисунок 3 иллюстрирует присвоение foo
параметры к регистрам и области параметра. Следует иметь в виду, что единственные параметры, помещенные в область параметра, s2
и i2
.
Вызванная функция может получить доступ к фиксированным параметрам, как обычно. Но это копирует регистры общего назначения в область параметра и получает доступ к значениям оттуда. Перечисление 4 показывает подпрограмму что доступы неопределенные параметры путем обхода через штабель.
Перечисление 4 процедура аргумента переменной
#include <stdarg.h> |
double dsum(int count, ...) { |
double sum = 0.0; |
double val; |
va_list arg; |
va_start(arg, count); |
while (count > 0) { |
val = va_arg(arg, double); |
sum += val; |
count--; |
} |
va_end(arg); |
return sum; |
} |
Возврат результатов
Следующий список описывает, куда возвращаемое значение функции передается вызывающей стороне.
Скаляры, меньшие, чем 4 байта (такой как
char
иshort
) помещаются в низкое слово GPR3. Высокое слово регистра не определено.Скаляры 4 байта в размере (такой как
long
,int
, и указатели, включая указатели массива), помещаются в GPR3.Значения типа
long long
возвращаются в высоком слове GPR3 и низком слове GPR4.Значения с плавающей точкой помещаются в FPR1.
Составные значения (такой как
struct
иunion
) и значения, больше, чем 4 байта, помещаются в расположение, на которое указывает GPR3. Посмотрите Передающие Параметры для получения дополнительной информации.
Сохранение регистра
Таблица 6 перечисляет 32-разрядные регистры архитектуры PowerPC, используемые в этой среде и их энергозависимости в вызовах функции. Регистры, которые должны сохранить их значение после вызова функции, вызывают энергонезависимые.
Ввести | Имя | Сохраненный | Примечания |
---|---|---|---|
Регистр общего назначения | GPR0 | Нет | |
GPR1 | Да | Используемый в качестве указателя вершины стека для хранения параметров и других временных элементов данных. | |
GPR2 | Нет | Доступный для общего использования. | |
GPR3 | Нет | Вызывающая сторона передает значения параметров вызванной процедуре в GPR3 через GPR10. Вызывающая сторона может также передать адрес хранению, куда вызываемый помещает его возвращаемое значение в этот регистр. | |
GPR4–GPR10 | Нет | Используемый вызывающими сторонами для передачи значений параметров вызванным функциям (см. примечания для GPR3). | |
GPR11 | Да во вложенных функциях. Нет в листовых функциях. | Во вложенных функциях вызывающая сторона передает свой стековый фрейм вложенной функции в этом регистре. В листовых функциях регистр доступен. Для получения дополнительной информации на вложенных функциях, см. документацию GCC. Этот регистр также используется ленивыми тупиками в динамической генерации кода для указания на ленивый указатель. | |
GPR12 | Нет | Набор к адресу цели ответвления перед непрямым вызовом динамической генерации кода. Этот регистр не установлен для функции, вызванной непосредственно; поэтому, функции, которые могут быть вызваны непосредственно, не должны зависеть от этого регистра, устанавливаемого правильно. Посмотрите Мужественные Темы Программирования для получения дополнительной информации. | |
GPR13–GPR31 | Да | ||
Регистр с плавающей точкой | FPR0 | Нет | |
FPR1–FPR13 | Нет | Используемый для передачи параметров с плавающей точкой в вызовах функции. | |
FPR14–FPR31 | Да | ||
Векторный регистр | V0–V19 | Нет | Вызывающая сторона передает векторные параметры в V2 к V13 во время вызова функции. |
V20–V31 | Да | ||
Векторный регистр специального назначения | VRSAVE | Да | 32-разрядный регистр специального назначения. Каждый бит в этом регистре указывает, должен ли соответствующий векторный регистр быть сохранен во время контекстного переключения процесса или потока. |
Регистр ссылки | LR | Нет | Хранит обратный адрес вызывающей подпрограммы который названный текущей подпрограммой. |
Регистр количества | CTR | Нет | |
Регистр исключения фиксированной точки | XER | Нет | |
Поля регистра условия | CR0, CR1 | Нет | |
CR2–CR4 | Да | ||
CR5–CR7 | Нет |