Sign in Join
Wiki copytemporary

Writing portable code regarding the processor architecture/ru: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Writing portable code regarding the processor architecture/ru

OldNewLine
1+Существует ряд проблем, связанных с написанием кода, являющегося независимым от процессорной архитектуры. Одна из них - это порядок следования байтов, другая – разрядность процессора ([[32 bit|32]] или [[64 bit|64-битные]] ЦП).
2+
3+## Порядок следования байтов (ПСБ)
4+
5+Порядок следования байтов определяет, как ЦП будет хранить значения, имеющие размер больше одного [[Byte|байта]]. (т.е. 16/32/64-битные [[Integer|целые числа]]).
6+
7+Free Pascal поддерживает процессоры с двумя типами следования байтов:
8+
9+1. Порядок следования от младшего к старшему байту: longint(4) кодируется как 04 00 00 00 (*[little endian](http://en.wikipedia.org/wiki/Little_endian)*)
10+2. Порядок следования от старшего к младшему байту: longint(4) кодируется как 00 00 00 04 (*[big endian](http://en.wikipedia.org/wiki/Big_endian)*)
11+
12+Примечание:
13+
14+Процессоры со средним(смешаным) порядком байтов, известным также как смешанный порядок байтов, сегодня встречаются редко. Наиболее известным представителем процессоров со смешанным порядком байтов является, устаревший сегодня, [PDP-11](http://ru.wikipedia.org/wiki/PDP-11) производства компании DEC.
15+
16+Каждое семейство процессоров имеет свой порядок байтов, но, как правило, они либо от младшего к старшему, либо от старшего к младшему, в зависимости от архитектуры (ARM, PPC).
17+
18+Самыми известными представителями процессоров с порядком следования байтов от младшего к старшему, являются процессоры семейства x86, используемые в ПК, и его собратья x86-64. Типичными же представителями процессоров с порядком следования байтов от старшего к младшему, являются процессоры семейства PPC (см. примечание выше) и процессоры [m68k](http://ru.wikipedia.org/wiki/68k), использовавшиеся в миникомпьютерах [HP3000](http://en.wikipedia.org/wiki/HP3000), а также в мэйнфреймах, таких, как [IBM 370](http://ru.wikipedia.org/wiki/IBM_370) (серия Z).
19+
20+Поскольку спецификация TCP/IP предполагает, что все заголовки в структуре протокола должны храниться с порядком байтов от старшего к младшему, то данный порядок байтов иногда упоминается как «сетевой порядок следования байтов».
21+
22+Наиболее важен порядок байтов в следующих случаях:
23+
24+1. при обмене данными компьютерами с различными архитектурами ЦП
25+2. при доступе к большому количеству данных, например, представленных в виде массива целых чисел или байтов.
26+
27+Пример последнего:
28+
29+``` pascal
30+type
31+ Q = record
32+ case Boolean of
33+ True: (i: Integer);
34+ False: (p: array[1..4] of Byte);
35+ end;
36+
37+var
38+ x:^Q;
39+
40+begin
41+ // Указываем компилятору порядок следования байтов(ПСБ):
42+ {$IFDEF ENDIAN_LITTLE}
43+ Writeln('Программа скомпилирована для компьютеров с ПСБ от младшего к старшему (например Intel x86, ARMEL)');
44+ {$ENDIF}
45+ {$IFDEF ENDIAN_BIG}
46+ Writeln('Программа скомпилирована для компьютеров с ПСБ от старшего к младшему (например PowerPC, ARMEB)');
47+ {$ENDIF}
48+ New(x);
49+ x^.i := 5;
50+ if x^.p[1] = 5 then
51+ WriteLn(x^.p[1],' На вашей машине ПСБ от младшего к старшему')
52+ else
53+ if x^.p[4] = 5 then
54+ WriteLn(x^.p[1],' На вашей машине ПСБ от старшего к младшему')
55+ else
56+ WriteLn(x^.p[1],' ',x^.p[2],' ',x^.p[3],' ',x^.p[4],' Порядок следования байтов не определён');
57+ WriteLn;
58+
59+ { Сделаем паузу для просмотра результата }
60+
61+ Write('Нажмите Enter для выхода из программы ');
62+ ReadLn;
63+end.
64+```
65+
66+Данный пример на компьютерах с ПСБ от младшего к старшему выведет число 5 (т.к. число 5 хранится в памяти в виде 05 00 00 00). В то-же время, компьютеры с ПСБ от старшего к младшему (например, PowerMac), выведут 0 (поскольку число 5 хранится в памяти в виде 00 00 00 05).
67+
68+Для определения порядка следования байтов служат директивы компилятора ENDIAN_BIG и ENDIAN_LITTLE (или FPC_LITTLE_ENDIAN и FPC_BIG_ENDIAN, начиная с версии 1.9).
69+
70+### Изменение ПСБ
71+
72+Модуль system имеет ряд процедур для преобразования данных между порядком следования байтов от старшего к младшему и ЦП, на котором выполняется программа ([BEtoN](http://www.freepascal.org/docs-html/rtl/system/beton.html), [NtoBE](http://www.freepascal.org/docs-html/rtl/system/ntobe.html)). Соответствующие процедуры реализованы и для машин с ПСБ от младшего к старшему: [LEtoN](http://www.freepascal.org/docs-html/rtl/system/leton.html), [NtoLE](http://www.freepascal.org/docs-html/rtl/system/ntole.html). Имеются также процедуры для смешанного порядка байтов ([SwapEndian](http://www.freepascal.org/docs-html/rtl/system/swapendian.html)).
73+
74+Некоторые сетевые библиотеки, например, Synapse, имеют собственные реализации конвертации ПСБ между сетью и компьютером.
75+
76+## Согласование
77+
78+Некоторые процессоры могут неправильно выстроить данные в памяти. Это может привести к изменению размера типа данных запись (record), поэтому всегда используйте функцию sizeof для проверки размера записи.
79+
80+## 32 Bit и 64 Bit
81+
82+Для достижения максимальной совместимости со старым кодом, FPC не изменяет размер стандартных типов данных, например, [[Integer|integer]], [[longint]] или [[Word|word]] при переходе с 32-разрядного на 64-разрядный ЦП. Выражения вроде `longint(`[[pointer]]`(p))` приведут к ошибке на 64-разрядных процессорах. Для написания переносимого кода в FPC введены типы [[Ptrint|PtrInt]] и [[Ptruint|PtrUInt]] в модуле system, представляющие собой знаковые и беззнаковые целочисленные типы данных такого-же размера, как и указатель (Pointer).
83+
84+Имейте в виду, что смена размера типа "pointer" также влияет на размер записей, если Вы определите запись не фиксированного размера, а через процедуры [[new]] или [[getmem]] (\<x\>,[[sizeof]](\<x\>)).
85+
86+Это относится к открытым платформам Unix. В коммерческом мире существуют некоторые исключения, например Tru64 или ILP64.
87+
88+## Согласование вызовов
89+
90+В общем случае, старайтесь не полагаться на собственные знания. Лучше воспользуйтесь следующей таблицей:
91+
92+| Ключевое слово | ПСБ | Стек очищает | Выравнивание | Регистры сохранены? |
93+|----|----|----|----|----|
94+| нет | слева направо | функция | по умолчанию | нет |
95+| [[register|Register]] | слева направо | функция | по умолчанию | нет |
96+| [[cdecl|CDecl]] | справа налево | вызывающий | GCC выравнивание | только GCC регистры |
97+| [[interrupt|Interrupt]] | справа налево | функция | по умолчанию | да |
98+| [[pascal|Pascal]] | слева направо | функция | по умолчанию | нет |
99+| [[safecall|SafeCall]] | справа налево | функция | по умолчанию | только GCC регистры |
100+| [[stdcall|StdCall]] | справа налево | функция | GCC выравнивание | только GCC регистры |
101+| [[oldfpccall|OldFPCCall]] | справа налево | вызывающий | по умолчанию | нет |
102+
103+Более подробная информация: [\$CALLING](http://www.freepascal.org/docs-html/prog/progsu87.html).
104+
105+Ограничения по размеру параметров для различных архитектур ЦП:
106+
107+| Архитектура ЦП | Размер параметров | Размер локальных переменных |
108+|----------------|-------------------|-----------------------------|
109+| i386 | 64 КБ | нет лимита |
110+| AMD64/x86-64 | 64 КБ | нет лимита |
111+| Motorola 68000 | 32 КБ | 32 КБ |
112+| Motorola 68020 | 32 КБ | нет лимита |
113+| PPC | нет лимита | нет лимита |
114+| ARM | нет лимита | нет лимита |
115+| SPARC | нет лимита | нет лимита |
116+
117+### Мэйнфреймы
118+
119+Для архитектур IBM 370 и Z - серии смотрите подробности [[ZSeries|здесь]].
120+
121+### x86
122+
123+В процессорах x86 обычно все параметры передаются через стек. Однако, если функция вызывается в режиме совместимости с Delphi, то первые три параметра или параметры, имеющие один адрес, передаются через регистры EAX, EDX и ECX. Исключением из данного правила может являться процесс разработки ПО для ОС [[Target Darwin|Darwin]] и [[Portal:Mac|Mac OS X]].
124+
125+### ARM
126+
127+### PPC
128+
129+Архитектура PowerPC имеет большое количество регистров, что даёт возможность передать все аргументы функции через них за один вызов. Также, есть возможность использовать стек.
130+
131+Процессоры PowerPC используют стандарты AIX или SysV при вызовах функций. Смотрите подробнее [[PPC Calling conventions|здесь]].
132+
133+### 68K
134+
135+Процессоры 68K поддерживают согласование вызовов CDecl и Pascal. Более подробную информацию смотрите тут: [68K vs. PowerPC](http://physinfo-mac0.ulb.ac.be/divers_html/powerpc_programming_info/intro_to_ppc/ppc4_runtime2.html).
136+
137+После вызова процедуры или функции на этих ЦП, стек выглядит примерно так:
138+
139+| | |
140+|-----|----------------------------------|
141+| | возвращаемое значение |
142+| | первый параметр |
143+| | ... |
144+| | последний параметр |
145+| | статические ссылки (опционально) |
146+| | адрес возврата |
147+| A6 | предыдущие A6 |
148+| | локальные переменные |
149+| SP | сохраненные регистры |
150+| | |
151+
152+#### Ссылки по данной теме
153+
154+- [[THINK Pascal]] Руководство пользователя, Symantec Corporation, Cupertino, 1988
155+- Physinfo, Université libre de Bruxelles: [PowerPC Calling Conventions, 68K vs. PowerPC](http://physinfo-mac0.ulb.ac.be/divers_html/powerpc_programming_info/intro_to_ppc/ppc4_runtime2.html)
156+
157+---
158+*From the Free Pascal wiki, page "Writing portable code regarding the processor architecture/ru", as it stood on 2020-03-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history