Общие сведения
Размеры и выравнивания базовых типов данных C++:
Имя типа | Размер в словах процессора | Количество значимых бит | Выравнивание типа данных в памяти |
char | |||
short | |||
int | |||
long | |||
void * | |||
float | |||
double | |||
long double |
Примечание: размер типа данных совпадает с выравниванием данного типа в памяти.
Архитектурные особенности:
Обращение в память для чтения 64-х битного длинного слова возможно только по четному адресу.
Важное следствие: вызов функции возможен, только когда регистр указатель стека имеет четное значение. Данное требование усугубляется, если в процессе выполнения программы могут происходить прерывания, поскольку в момент прихода прерывания указатель стек должен иметь чётное значение. Прерывание может прийти в любое момент, когда регистр PC (счётчик команд) чётный, отсюда правило – к началу выполнения любой команды, размещённой по чётному адресу указатель стека должен быть чётным.
Передаваемые параметры функций
Все параметры функции передаются через стек. Для базовых типов данных в стеке передается сам параметр. Для структурных типов данных (структуры, классы, объединения) в стеке передается указатель на структуру.
Компилятор может порождать дополнительные, неявные параметры для функций. Для функций, возвращающих структурный тип данных, добавляется параметр - указатель на область стека в которой располагается структура. Если у функции имеется такой параметр, то он предшествует всем остальным явным и неявным параметрам. Для функций членов класса компилятор порождает неявный параметр - указатель на объект класса (this). Такой параметр предшествует всем явным параметрам. Если у функции имеется два неявных параметра - указатель на возвращаемую структуру и указатель this, то первым параметром является указатель на возвращаемую структуру, вторым указатель this, затем идут явные параметры.
|
Параметры размещаются в стеке начиная с последнего, т.е. первый параметр имеет наибольший адрес, последний параметр имеет наименьший адрес.
Выравнивание параметров в памяти соответствует обычному выравниванию переменных такого типа. При этом в стеке могут образовываться неиспользуемые места. Такие неиспользуемые места имеют размер 1 слово и располагаются по четным адресам. Поскольку, при выполнении инструкции перехода к подпрограмме, указатель стека должен иметь четное значение, выравнивание параметров производится относительно места в стеке, где располагаются PC и PSW при переходе к подпрограмме.
Примеры:
1. Расположение в стеке параметров функции f(int a, long b, int c) на момент входа в функцию (адрес растет вверх):
Текущий указатель стека |
PSW |
PC |
a |
Неиспользуемое место |
Старшая часть b |
Младшая часть b |
c |
2. Расположение в стеке параметров функции g(int a, int b, long c, int d) на момент входа в функцию (адрес растет вверх):
Текущий указатель стека |
PSW |
PC |
a |
b |
Старшая часть c |
Младшая часть c |
d |
Замечание: Следует обратить внимание, что параметры размером в 1 слово всегда выравниваются на больший адрес и соответственно пустые места всегда занимают часть длинного слова с меньшим адресом. Такое выравнивание гарантирует, что расположение параметра в стеке не зависит от последующих параметров. Это особенно важно для функций с переменным числом параметров, когда функция обращаясь к своему параметру не знает о типе и вообще о существовании следующего параметра.
|
Алгоритм 1. Вычисление расположения параметров функции в стеке и занимаемого ими размера:
1. Установить переменную РАЗМЕР в 0. Эта переменная содержит размер, занимаемый параметрами в стеке.
2. Взять очередной параметр из списка параметров в направлении от первого параметра к последнему. Если список параметров полностью просмотрен, то закончить работу.
3. Если параметр имеет размер 2 слова (long, то принять в качестве смещения параметра РАЗМЕР + 2; РАЗМЕР += 2. Перейти к шагу 2.
4. В данном случае параметр имеет размер 1 слово (int). Принять в качестве смещения параметра РАЗМЕР + 1; РАЗМЕР += 1. После этого взять следующий параметр из списка. Если список полностью просмотрен, то закончить работу.
5. Если следующий параметр имеет размер 1 (ситуация int,int), то в качестве смещения второго параметра взять РАЗМЕР + 1; РАЗМЕР += 1. Перейти к шагу 2.
6. В данном случае мы имеем первый параметр размера 1 слово и второй параметр размером 2 слова (ситуация int, long). Добавляется одно слово выравнивания по смещению РАЗМЕР + 1. В качестве смещения второго параметра взять РАЗМЕР + 3; РАЗМЕР += 3. Перейти к шагу 2.
В результате работы данного алгоритма вычисляется смещение каждого параметра относительно места в стеке, где при вызове функции располагается PC, и общий размер места в стеке занимаемого параметрами.
|
Например, для функции f из примера 1 параметр a имеет смещение 1, слова заполнения между параметрами a и b имеет смещение 2, параметр b - смещение 4, параметр c - смещение 5. Параметры занимают 5 слов в стеке (адрес растет вверх):
Смещение | |
Текущий указатель стека | |
PSW | |
PC | |
a | |
Неиспользуемое место | |
Старшая часть b | |
Младшая часть b | |
c |
Алгоритм 2. Заполнение стека параметрами при вызове функции:
1. Составляем полный список параметров функции, включая неявно добавленные компилятором
2. Вычисляем размер, занимаемый параметрами функции в стеке, и смещения параметров. Вычисление производится с помощью алгоритма 1.
3. Если размер, занимаемый параметрами в стеке, нечетный, то выравниваем вершину стека на нечетный адрес. Если размер, занимаемый параметрами в стеке, четный, то выравниваем вершину стека на четный адрес.
4. Заносим параметры в стек, добавляя в нужных местах слова заполнения.
5. Производим вызов функции. Шаг 3 гарантирует нам, что вершина стека перед вызовом функции будет иметь четной адрес.