Difference between revisions of "Writing portable code regarding the processor architecture/ru"
m (Fixed syntax highlighting) |
|||
(3 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
{{Editing Writing portable code regarding the processor architecture}} | {{Editing Writing portable code regarding the processor architecture}} | ||
− | Существует ряд проблем связанных с написанием кода, являющегося | + | Существует ряд проблем, связанных с написанием кода, являющегося независимым от процессорной архитектуры. Одна из них - это порядок следования байтов, другая – разрядность процессора ([[32 bit|32]] или [[64 bit|64-битные]] ЦП). |
== Порядок следования байтов (ПСБ) == | == Порядок следования байтов (ПСБ) == | ||
− | Порядок следования байтов определяет, как будет хранить | + | Порядок следования байтов определяет, как ЦП будет хранить значения, имеющие размер больше одного [[Byte|байта]]. (т.е. 16/32/64-битные [[Integer|целые числа]]). |
Free Pascal поддерживает процессоры с двумя типами следования байтов: | Free Pascal поддерживает процессоры с двумя типами следования байтов: | ||
Line 14: | Line 14: | ||
Примечание: | Примечание: | ||
− | Процессоры со средним(смешаным) порядком байтов, | + | Процессоры со средним(смешаным) порядком байтов, известным также как смешанный порядок байтов, сегодня встречаются редко. Наиболее известным представителем процессоров со смешанным порядком байтов является, устаревший сегодня, [http://ru.wikipedia.org/wiki/PDP-11 PDP-11] производства компании DEC. |
− | Каждое семейство процессоров | + | Каждое семейство процессоров имеет свой порядок байтов, но, как правило, они либо от младшего к старшему, либо от старшего к младшему, в зависимости от архитектуры (ARM, PPC). |
− | + | Самыми известными представителями процессоров с порядком следования байтов от младшего к старшему, являются процессоры семейства x86, используемые в ПК, и его собратья x86-64. Типичными же представителями процессоров с порядком следования байтов от старшего к младшему, являются процессоры семейства PPC (см. примечание выше) и процессоры [http://ru.wikipedia.org/wiki/68k m68k], использовавшиеся в миникомпьютерах [http://en.wikipedia.org/wiki/HP3000 HP3000], а также в мэйнфреймах, таких, как [http://ru.wikipedia.org/wiki/IBM_370 IBM 370] (серия Z). | |
Поскольку спецификация TCP/IP предполагает, что все заголовки в структуре протокола должны храниться с порядком байтов от старшего к младшему, то данный порядок байтов иногда упоминается как «сетевой порядок следования байтов». | Поскольку спецификация TCP/IP предполагает, что все заголовки в структуре протокола должны храниться с порядком байтов от старшего к младшему, то данный порядок байтов иногда упоминается как «сетевой порядок следования байтов». | ||
Line 30: | Line 30: | ||
Пример последнего: | Пример последнего: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang=pascal> |
type | type | ||
Q = record | Q = record | ||
Line 67: | Line 67: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Данный пример на компьютерах с ПСБ от младшего к старшему выведет число 5 (т.к. число 5 хранится в памяти в виде 05 00 00 00). В то же время, компьютеры с ПСБ от старшего к младшему (например, PowerMac) выведут 0 (поскольку число 5 хранится в памяти в виде 00 00 00 05). | + | Данный пример на компьютерах с ПСБ от младшего к старшему выведет число 5 (т.к. число 5 хранится в памяти в виде 05 00 00 00). В то-же время, компьютеры с ПСБ от старшего к младшему (например, PowerMac), выведут 0 (поскольку число 5 хранится в памяти в виде 00 00 00 05). |
− | Для определения порядка следования байтов | + | Для определения порядка следования байтов служат директивы компилятора ENDIAN_BIG и ENDIAN_LITTLE (или FPC_LITTLE_ENDIAN и FPC_BIG_ENDIAN, начиная с версии 1.9). |
=== Изменение ПСБ === | === Изменение ПСБ === | ||
− | Модуль system имеет ряд процедур для преобразования данных между порядком следования байтов от старшего к младшему и ЦП, на | + | Модуль system имеет ряд процедур для преобразования данных между порядком следования байтов от старшего к младшему и ЦП, на котором выполняется программа ([http://www.freepascal.org/docs-html/rtl/system/beton.html BEtoN], [http://www.freepascal.org/docs-html/rtl/system/ntobe.html NtoBE]). Соответствующие процедуры реализованы и для машин с ПСБ от младшего к старшему: [http://www.freepascal.org/docs-html/rtl/system/leton.html LEtoN], [http://www.freepascal.org/docs-html/rtl/system/ntole.html NtoLE]. Имеются также процедуры для смешанного порядка байтов ([http://www.freepascal.org/docs-html/rtl/system/swapendian.html SwapEndian]). |
− | Некоторые сетевые библиотеки, например Synapse имеют собственные реализации конвертации ПСБ между сетью и компьютером. | + | Некоторые сетевые библиотеки, например, Synapse, имеют собственные реализации конвертации ПСБ между сетью и компьютером. |
== Согласование == | == Согласование == | ||
− | Некоторые процессоры могут | + | Некоторые процессоры могут неправильно выстроить данные в памяти. Это может привести к изменению размера типа данных запись (record), поэтому всегда используйте функцию sizeof для проверки размера записи. |
== 32 Bit и 64 Bit == | == 32 Bit и 64 Bit == | ||
− | Для достижения максимальной совместимости со старым кодом, FPC не изменяет размер стандартных типов данных, например | + | Для достижения максимальной совместимости со старым кодом, FPC не изменяет размер стандартных типов данных, например, <tt>[[Integer|integer]]</tt>, <tt>[[longint]]</tt> или <tt>[[Word|word]]</tt> при переходе с 32-разрядного на 64-разрядный ЦП. Выражения вроде <tt>longint([[pointer]](p))</tt> приведут к ошибке на 64-разрядных процессорах. Для написания переносимого кода в FPC введены типы <tt>[[Ptrint|PtrInt]]</tt> и <tt>[[Ptruint|PtrUInt]]</tt> в модуле system, представляющие собой знаковые и беззнаковые целочисленные типы данных такого-же размера, как и указатель (Pointer). |
− | Имейте в виду, что смена размера типа "pointer" | + | Имейте в виду, что смена размера типа "pointer" также влияет на размер записей, если Вы определите запись не фиксированного размера, а через процедуры [[new]] или [[getmem]] (<x>,[[sizeof]](<x>)). |
− | Это относится к открытым платформам Unix. В коммерческом мире | + | Это относится к открытым платформам Unix. В коммерческом мире существуют некоторые исключения, например Tru64 или ILP64. |
== Согласование вызовов == | == Согласование вызовов == | ||
− | В общем | + | В общем случае, старайтесь не полагаться на собственные знания. Лучше воспользуйтесь следующей таблицей: |
{| class="wikitable" | {| class="wikitable" | ||
Line 96: | Line 96: | ||
! Ключевое слово !! ПСБ !! Стек очищает !! Выравнивание !! Регистры сохранены? | ! Ключевое слово !! ПСБ !! Стек очищает !! Выравнивание !! Регистры сохранены? | ||
|- | |- | ||
− | | нет || | + | | нет || слева направо || функция || по умолчанию || нет |
|- | |- | ||
− | | [[register|Register]] || | + | | [[register|Register]] || слева направо || функция || по умолчанию || нет |
|- | |- | ||
− | | [[cdecl|CDecl]] || | + | | [[cdecl|CDecl]] || справа налево || вызывающий || GCC выравнивание || только GCC регистры |
|- | |- | ||
− | | [[interrupt|Interrupt]] || | + | | [[interrupt|Interrupt]] || справа налево || функция || по умолчанию || да |
|- | |- | ||
− | | [[pascal|Pascal]] || | + | | [[pascal|Pascal]] || слева направо || функция || по умолчанию || нет |
|- | |- | ||
− | | [[safecall|SafeCall]] || | + | | [[safecall|SafeCall]] || справа налево || функция || по умолчанию || только GCC регистры |
|- | |- | ||
− | | [[stdcall|StdCall]] || | + | | [[stdcall|StdCall]] || справа налево || функция || GCC выравнивание || только GCC регистры |
|- | |- | ||
− | | [[oldfpccall|OldFPCCall]] || | + | | [[oldfpccall|OldFPCCall]] || справа налево || вызывающий || по умолчанию || нет |
|} | |} | ||
Более подробная информация: [http://www.freepascal.org/docs-html/prog/progsu87.html $CALLING]. | Более подробная информация: [http://www.freepascal.org/docs-html/prog/progsu87.html $CALLING]. | ||
− | Ограничения | + | Ограничения по размеру параметров для различных архитектур ЦП: |
{| class="wikitable" | {| class="wikitable" | ||
Line 136: | Line 136: | ||
|} | |} | ||
=== Мэйнфреймы === | === Мэйнфреймы === | ||
− | Для архитектур IBM 370 и Z - серии | + | Для архитектур IBM 370 и Z - серии смотрите подробности [[ZSeries|здесь]]. |
=== x86 === | === x86 === | ||
− | В процессорах x86 | + | В процессорах x86 обычно все параметры передаются через стек. Однако, если функция вызывается в режиме совместимости с Delphi, то первые три параметра или параметры, имеющие один адрес, передаются через регистры EAX, EDX и ECX. Исключением из данного правила может являться процесс разработки ПО для ОС [[Target Darwin|Darwin]] и [[Portal:Mac|Mac OS X]]. |
=== ARM === | === ARM === | ||
=== PPC === | === PPC === | ||
− | Архитектура PowerPC имеет большое количество регистров, что даёт возможность | + | Архитектура PowerPC имеет большое количество регистров, что даёт возможность передать все аргументы функции через них за один вызов. Также, есть возможность использовать стек. |
− | Процессоры PowerPC | + | Процессоры PowerPC используют стандарты AIX или SysV при вызовах функций. Смотрите подробнее [[PPC Calling conventions|здесь]]. |
=== 68K === | === 68K === | ||
− | Процессоры 68K поддерживают CDecl и Pascal | + | Процессоры 68K поддерживают согласование вызовов CDecl и Pascal. Более подробную информацию смотрите тут: [http://physinfo-mac0.ulb.ac.be/divers_html/powerpc_programming_info/intro_to_ppc/ppc4_runtime2.html 68K vs. PowerPC]. |
− | + | После вызова процедуры или функции на этих ЦП, стек выглядит примерно так: | |
{| border="1" class="wikitable" | {| border="1" class="wikitable" | ||
Line 177: | Line 177: | ||
* Physinfo, Université libre de Bruxelles: [http://physinfo-mac0.ulb.ac.be/divers_html/powerpc_programming_info/intro_to_ppc/ppc4_runtime2.html PowerPC Calling Conventions, 68K vs. PowerPC] | * Physinfo, Université libre de Bruxelles: [http://physinfo-mac0.ulb.ac.be/divers_html/powerpc_programming_info/intro_to_ppc/ppc4_runtime2.html PowerPC Calling Conventions, 68K vs. PowerPC] | ||
{{Data types}} | {{Data types}} | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |
Latest revision as of 12:39, 4 March 2020
│
English (en) │
Bahasa Indonesia (id) │
русский (ru) │
Существует ряд проблем, связанных с написанием кода, являющегося независимым от процессорной архитектуры. Одна из них - это порядок следования байтов, другая – разрядность процессора (32 или 64-битные ЦП).
Порядок следования байтов (ПСБ)
Порядок следования байтов определяет, как ЦП будет хранить значения, имеющие размер больше одного байта. (т.е. 16/32/64-битные целые числа).
Free Pascal поддерживает процессоры с двумя типами следования байтов:
- Порядок следования от младшего к старшему байту: longint(4) кодируется как 04 00 00 00 (little endian)
- Порядок следования от старшего к младшему байту: longint(4) кодируется как 00 00 00 04 (big endian)
Примечание:
Процессоры со средним(смешаным) порядком байтов, известным также как смешанный порядок байтов, сегодня встречаются редко. Наиболее известным представителем процессоров со смешанным порядком байтов является, устаревший сегодня, PDP-11 производства компании DEC.
Каждое семейство процессоров имеет свой порядок байтов, но, как правило, они либо от младшего к старшему, либо от старшего к младшему, в зависимости от архитектуры (ARM, PPC).
Самыми известными представителями процессоров с порядком следования байтов от младшего к старшему, являются процессоры семейства x86, используемые в ПК, и его собратья x86-64. Типичными же представителями процессоров с порядком следования байтов от старшего к младшему, являются процессоры семейства PPC (см. примечание выше) и процессоры m68k, использовавшиеся в миникомпьютерах HP3000, а также в мэйнфреймах, таких, как IBM 370 (серия Z).
Поскольку спецификация TCP/IP предполагает, что все заголовки в структуре протокола должны храниться с порядком байтов от старшего к младшему, то данный порядок байтов иногда упоминается как «сетевой порядок следования байтов».
Наиболее важен порядок байтов в следующих случаях:
- при обмене данными компьютерами с различными архитектурами ЦП
- при доступе к большому количеству данных, например, представленных в виде массива целых чисел или байтов.
Пример последнего:
type
Q = record
case Boolean of
True: (i: Integer);
False: (p: array[1..4] of Byte);
end;
var
x:^Q;
begin
// Указываем компилятору порядок следования байтов(ПСБ):
{$IFDEF ENDIAN_LITTLE}
Writeln('Программа скомпилирована для компьютеров с ПСБ от младшего к старшему (например Intel x86, ARMEL)');
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Writeln('Программа скомпилирована для компьютеров с ПСБ от старшего к младшему (например PowerPC, ARMEB)');
{$ENDIF}
New(x);
x^.i := 5;
if x^.p[1] = 5 then
WriteLn(x^.p[1],' На вашей машине ПСБ от младшего к старшему')
else
if x^.p[4] = 5 then
WriteLn(x^.p[1],' На вашей машине ПСБ от старшего к младшему')
else
WriteLn(x^.p[1],' ',x^.p[2],' ',x^.p[3],' ',x^.p[4],' Порядок следования байтов не определён');
WriteLn;
{ Сделаем паузу для просмотра результата }
Write('Нажмите Enter для выхода из программы ');
ReadLn;
end.
Данный пример на компьютерах с ПСБ от младшего к старшему выведет число 5 (т.к. число 5 хранится в памяти в виде 05 00 00 00). В то-же время, компьютеры с ПСБ от старшего к младшему (например, PowerMac), выведут 0 (поскольку число 5 хранится в памяти в виде 00 00 00 05).
Для определения порядка следования байтов служат директивы компилятора ENDIAN_BIG и ENDIAN_LITTLE (или FPC_LITTLE_ENDIAN и FPC_BIG_ENDIAN, начиная с версии 1.9).
Изменение ПСБ
Модуль system имеет ряд процедур для преобразования данных между порядком следования байтов от старшего к младшему и ЦП, на котором выполняется программа (BEtoN, NtoBE). Соответствующие процедуры реализованы и для машин с ПСБ от младшего к старшему: LEtoN, NtoLE. Имеются также процедуры для смешанного порядка байтов (SwapEndian).
Некоторые сетевые библиотеки, например, Synapse, имеют собственные реализации конвертации ПСБ между сетью и компьютером.
Согласование
Некоторые процессоры могут неправильно выстроить данные в памяти. Это может привести к изменению размера типа данных запись (record), поэтому всегда используйте функцию sizeof для проверки размера записи.
32 Bit и 64 Bit
Для достижения максимальной совместимости со старым кодом, FPC не изменяет размер стандартных типов данных, например, integer, longint или word при переходе с 32-разрядного на 64-разрядный ЦП. Выражения вроде longint(pointer(p)) приведут к ошибке на 64-разрядных процессорах. Для написания переносимого кода в FPC введены типы PtrInt и PtrUInt в модуле system, представляющие собой знаковые и беззнаковые целочисленные типы данных такого-же размера, как и указатель (Pointer).
Имейте в виду, что смена размера типа "pointer" также влияет на размер записей, если Вы определите запись не фиксированного размера, а через процедуры new или getmem (<x>,sizeof(<x>)).
Это относится к открытым платформам Unix. В коммерческом мире существуют некоторые исключения, например Tru64 или ILP64.
Согласование вызовов
В общем случае, старайтесь не полагаться на собственные знания. Лучше воспользуйтесь следующей таблицей:
Ключевое слово | ПСБ | Стек очищает | Выравнивание | Регистры сохранены? |
---|---|---|---|---|
нет | слева направо | функция | по умолчанию | нет |
Register | слева направо | функция | по умолчанию | нет |
CDecl | справа налево | вызывающий | GCC выравнивание | только GCC регистры |
Interrupt | справа налево | функция | по умолчанию | да |
Pascal | слева направо | функция | по умолчанию | нет |
SafeCall | справа налево | функция | по умолчанию | только GCC регистры |
StdCall | справа налево | функция | GCC выравнивание | только GCC регистры |
OldFPCCall | справа налево | вызывающий | по умолчанию | нет |
Более подробная информация: $CALLING.
Ограничения по размеру параметров для различных архитектур ЦП:
Архитектура ЦП | Размер параметров | Размер локальных переменных |
---|---|---|
i386 | 64 КБ | нет лимита |
AMD64/x86-64 | 64 КБ | нет лимита |
Motorola 68000 | 32 КБ | 32 КБ |
Motorola 68020 | 32 КБ | нет лимита |
PPC | нет лимита | нет лимита |
ARM | нет лимита | нет лимита |
SPARC | нет лимита | нет лимита |
Мэйнфреймы
Для архитектур IBM 370 и Z - серии смотрите подробности здесь.
x86
В процессорах x86 обычно все параметры передаются через стек. Однако, если функция вызывается в режиме совместимости с Delphi, то первые три параметра или параметры, имеющие один адрес, передаются через регистры EAX, EDX и ECX. Исключением из данного правила может являться процесс разработки ПО для ОС Darwin и Mac OS X.
ARM
PPC
Архитектура PowerPC имеет большое количество регистров, что даёт возможность передать все аргументы функции через них за один вызов. Также, есть возможность использовать стек.
Процессоры PowerPC используют стандарты AIX или SysV при вызовах функций. Смотрите подробнее здесь.
68K
Процессоры 68K поддерживают согласование вызовов CDecl и Pascal. Более подробную информацию смотрите тут: 68K vs. PowerPC.
После вызова процедуры или функции на этих ЦП, стек выглядит примерно так:
возвращаемое значение | |
первый параметр | |
... | |
последний параметр | |
статические ссылки (опционально) | |
адрес возврата | |
A6 | предыдущие A6 |
локальные переменные | |
SP | сохраненные регистры |
Ссылки по данной теме
- THINK Pascal Руководство пользователя, Symantec Corporation, Cupertino, 1988
- Physinfo, Université libre de Bruxelles: PowerPC Calling Conventions, 68K vs. PowerPC
simple data types |
|
---|---|
complex data types |