1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
|
\documentclass[10pt,a4paper,oneside,openany]{memoir}
\newcommand{\DocShortTitle}{LibMCPU MELF ABI}
\input{libmcpu-doc-common.tex}
\hypersetup{
pdftitle={LibMCPU MELF ABI},
pdfsubject={Формат объектов и исполняемых файлов MCPU, контракт компоновщика и загрузчика}
}
\begin{document}
\DocTitlePage
{LibMCPU MELF ABI}
{Формат объектов и исполняемых файлов MCPU, контракт компоновщика (linker) и загрузчика (loader)}
{Самостоятельное справочное руководство; нумерация разделов начинается с 1}
\ManualIntro{Документ является самостоятельным описанием текущего MELF-контракта LibMCPU и намеренно не связан с номером выпуска пакета. Он фиксирует статический ABI v1, исторический explicit-preload ABI v2, frozen normal dynamic ABI v3 с SONAME/NEEDED, lifecycle, STACK/HEAP, MCPU static archives и partial ET_REL linking. HLL PROGRAM/MODEL classification и automatic CRT insertion описаны как linker layer над MELF container ABI.}
\begin{principle}
\textbf{MELF --- не системный ELF.} Формат намеренно использует сигнатуру \code{_ELF}, частное значение \code{e_machine=MCPU} и специфические для MCPU секции и заголовков сегментов (Program Headers). Ядро host-системы и системный \code{ld.so} не участвуют в запуске. \code{mcpu-ld} и \code{mcpu-run} являются частями одного целевого ABI.
\end{principle}
\tableofcontents
\clearpage
\section{Назначение и границы формата}
MELF хранит три вида файлов MCPU:
\begin{itemize}
\item перемещаемый объект (\term{relocatable object}{перемещаемый объект}) \code{ET_REL};
\item исполняемый образ (\term{executable}{исполняемый файл}) \code{ET_EXEC};
\item разделяемый объект (\term{shared object}{разделяемый объект}) \code{ET_DYN}, явно загружаемый при запуске программы.
\end{itemize}
От ELF заимствованы общие идеи заголовков Ehdr, Shdr и Phdr, таблиц символов и строк, а также relocation-записей RELA. Архитектурные пространства памяти, точки входа lifecycle и метаданные профиля целевой архитектуры определяются самим MCPU ABI.
Текущая реализация использует только MELF64. Имена и структуры MELF32 зарезервированы, но ABI v1, ABI v2 и ABI v3 их не принимают. C-структуры из \code{mcpu-elf.h} описывают логические поля, но не являются готовой сериализацией на диске (on-disk serialization): код записи и чтения явно кодирует и декодирует многобайтовые поля с учётом \code{EI_DATA}.
PROGRAM образует отдельную область с собственным порядком байтов: машинные поля MCPU внутри PROGRAM всегда записываются MSB-first независимо от \code{EI_DATA} контейнера.
\section{Идентификация, класс и e\_machine}
\subsection{Поле e\_ident}
\begin{center}
\begin{tabularx}{0.95\textwidth}{@{}L{28mm}L{28mm}Y@{}}
\toprule
\textbf{Поле} & \textbf{Значение} & \textbf{Смысл}\\
\midrule
MAG0..3 & \code{'_','E','L','F'} & сигнатура MELF; это не обычный \code{0x7fELF}\\
EI\_CLASS & 2 & \code{MELF_CLASS_64}\\
EI\_DATA & 1 или 2 & порядок байтов LSB/MSB для метаданных и объектов данных целевой архитектуры\\
EI\_VERSION & 1 & текущая версия формата\\
EI\_OSABI & 64 & \code{MELF_OSABI_MCPU}\\
EI\_ABIVERSION & 1, 2 или 3 & статический ABI v1 / исторический dynamic ABI v2 / frozen dynamic ABI v3\\
\bottomrule
\end{tabularx}
\end{center}
\subsection{e\_machine и e\_flags}
\code{e_machine = 0x4d43} (ASCII ``MC''). Это частное значение MELF, а не официальное значение системного ELF. В текущем ABI \code{e_flags=0}. Неизвестные биты загрузчик (loader) обязан отвергать, а не молча игнорировать.
\section{Типы файлов и версии ABI}
В MELF номер ABI относится не к версии инструмента, а к конкретному контракту файла. Текущий toolchain продолжает читать исторические ABI v1/v2 и выпускает ABI v1 для ET_REL/статического ET_EXEC и frozen ABI v3 для новых dynamic ET_EXEC/ET_DYN.
\begin{center}
\begin{tabularx}{0.96\textwidth}{@{}L{43mm}L{24mm}L{18mm}Y@{}}
\toprule
\textbf{Режим формирования} & \textbf{e\_type} & \textbf{ABI} & \textbf{Назначение}\\
\midrule
\code{mcpu-as} & ET\_REL & 1 & перемещаемый входной объект\\
\code{mcpu-ld -r} & ET\_REL & 1 & частично скомпонованный перемещаемый объект\\
\code{mcpu-ld} & ET\_EXEC & 1 & полностью статический исполняемый файл\\
исторический dynamic output & ET\_EXEC / ET\_DYN & 2 & explicit-preload startup ABI, сохраняемый загрузчиком для совместимости\\
\code{mcpu-ld --dynamic} & ET\_EXEC & 3 & главный startup-dynamic исполняемый файл с \code{.dynamic}\\
\code{mcpu-ld --shared} & ET\_DYN & 3 & shared object с обязательным SONAME и возможными NEEDED\\
ET\_CORE & зарезервировано & --- & пока не поддерживается\\
\bottomrule
\end{tabularx}
\end{center}
ABI v3 является frozen normal dynamic ABI. Его несовместимое изменение требует нового номера ABI. ABI v3 не меняет CPU ISA, CALL ABI, PTR64 или базовые типы RELA; он расширяет startup dynamic-link contract метаданными \code{.dynamic}, SONAME/NEEDED, поиском библиотек и детерминированным runtime symbol scope.
\section{Заголовок MELF64}
Сериализованный \code{MElf64_Ehdr} имеет размер 88 байт. Поля точек входа lifecycle содержат полные архитектурные \code{PTR64(PROGRAM,offset)}, а не смещения внутри файла.
\begin{longtable}{@{}L{32mm}L{20mm}L{102mm}@{}}
\toprule
\textbf{Поле} & \textbf{Размер} & \textbf{Смысл}\\
\midrule
\endfirsthead
\toprule
\textbf{Поле} & \textbf{Размер} & \textbf{Смысл}\\
\midrule
\endhead
\code{e_ident} & 16 & сигнатура, класс, порядок данных, версия, OSABI, версия ABI\\
\code{e_type} & 2 & ET\_REL / ET\_EXEC / ET\_DYN\\
\code{e_machine} & 2 & MCPU\\
\code{e_version} & 4 & \code{MELF_EV_CURRENT}\\
\code{e_entry} & 8 & обязательная точка входа исполняемого файла; всегда \code{_start}\\
\code{e_init_entry} & 8 & \code{_start}, если существует \code{.init}; иначе 0\\
\code{e_life_entry} & 8 & обязательный \code{_life}\\
\code{e_fini_entry} & 8 & необязательный \code{_fini}; иначе 0\\
\code{e_phoff} & 8 & смещение в файле до таблицы заголовков сегментов (Program Headers)\\
\code{e_shoff} & 8 & смещение в файле до таблицы заголовков секций (Section Headers)\\
\code{e_flags} & 4 & в текущем ABI равен 0\\
\code{e_ehsize} & 2 & 88\\
\code{e_phentsize} & 2 & 64 для MELF64\\
\code{e_phnum} & 2 & число записей заголовков сегментов\\
\code{e_shentsize} & 2 & 64 для MELF64\\
\code{e_shnum} & 2 & число записей заголовков секций\\
\code{e_shstrndx} & 2 & индекс секции \code{.shstrtab}\\
\bottomrule
\end{longtable}
У \code{ET_REL} окончательных адресов lifecycle ещё нет, поэтому четыре поля точек входа равны нулю. \code{ET_DYN} не является самостоятельной программой и также не имеет исполняемых точек входа lifecycle.
\section{Архитектурные адреса внутри MELF}
Для окончательно размещённых загружаемых секций (allocated sections) поле \code{sh_addr} содержит полный \code{PTR64(segment,final_offset)}. Используется следующая таблица селекторов (selectors):
\begin{center}
\begin{tabularx}{0.84\textwidth}{@{}L{26mm}L{18mm}Y@{}}
\toprule
\textbf{Пространство} & \textbf{SEG} & \textbf{Секции / роль}\\
\midrule
DATA & 0x0 & \code{.data}, \code{.bss}\\
STACK & 0x1 & только дескриптор времени выполнения; полезные данные объекта отсутствуют\\
PROGRAM & 0x2 & \code{.init}, \code{.text}, \code{.fini}\\
CONTROL & 0x3 & \code{.control}\\
INPUT & 0x4 & \code{.input}\\
OUTPUT & 0x5 & \code{.output}\\
TRACE & 0x6 & \code{.trace}\\
HEAP & 0x7 & только дескриптор времени выполнения; данных ассемблерного объекта нет\\
\bottomrule
\end{tabularx}
\end{center}
В \code{ET_REL} символы и секции используют смещения относительно своей секции и ещё не имеют окончательной базы процесса. В \code{ET_DYN} адреса также остаются относительными к модулю; окончательные базы PROGRAM и DATA назначает компоновщик запуска (startup linker).
\section{Секции и флаги секций}
MELF использует типы секций, близкие к ELF: \code{SHT_NULL}, \code{SHT_PROGBITS}, \code{SHT_SYMTAB}, \code{SHT_STRTAB}, \code{SHT_RELA}, \code{SHT_NOBITS}, \code{SHT_DYNSYM} и \code{SHT_DYNAMIC}.\par
Кроме того, определены два специфических для MCPU типа:
\begin{center}
\begin{tabularx}{0.82\textwidth}{@{}L{54mm}Y@{}}
\toprule
\textbf{Тип секции} & \textbf{Числовое значение}\\
\midrule
\code{SHT_MCPU_TARGET} & 0x70000000\\
\code{SHT_MCPU_LIFECYCLE} & 0x70000001\\
\bottomrule
\end{tabularx}
\end{center}
Загружаемые секции получают обычные признаки R/W/X через \code{SHF_WRITE/ALLOC/EXECINSTR}; тег архитектурного сегмента MCPU кодируется в процессорных битах флагов.
\begin{center}
\begin{tabularx}{0.94\textwidth}{@{}L{24mm}L{24mm}L{26mm}Y@{}}
\toprule
\textbf{Секция} & \textbf{Тип} & \textbf{Пространство} & \textbf{Атрибуты}\\
\midrule
.init & PROGBITS & PROGRAM & ALLOC + EXEC\\
.text & PROGBITS & PROGRAM & ALLOC + EXEC\\
.fini & PROGBITS & PROGRAM & ALLOC + EXEC\\
.data & PROGBITS & DATA & ALLOC + WRITE\\
.bss & NOBITS & DATA & ALLOC + WRITE\\
.control & PROGBITS & CONTROL & ALLOC, только чтение для guest-программы\\
.input & PROGBITS & INPUT & ALLOC, только чтение для guest-программы\\
.output & PROGBITS & OUTPUT & ALLOC + WRITE\\
.trace & PROGBITS & TRACE & ALLOC + WRITE\\
\bottomrule
\end{tabularx}
\end{center}
\code{sh_addralign} задаёт требование выравнивания guest-адреса. Значения 0/1 означают отсутствие специального требования, остальные допустимые значения являются степенями двойки. \code{SHT_NOBITS} занимает архитектурную память, но не содержит данных в файле.
\section{Объектная модель ET\_REL}
Ассемблер формирует символы со смещениями относительно секций и явные записи RELA. Типовой путь выглядит так:
\begin{center}
\begin{tikzpicture}[font=\sffamily\small,>=Stealth,node distance=4mm]
\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,minimum width=24mm] (src) {исходник .s};
\node[draw=McpuBlue,rounded corners,fill=McpuGreenBg,right=of src,minimum width=25mm] (as) {mcpu-as};
\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,right=of as,minimum width=31mm] (obj) {object.o / ET\_REL};
\node[draw=McpuBlue,rounded corners,fill=McpuGreenBg,right=of obj,minimum width=24mm] (ld) {mcpu-ld};
\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,right=of ld,minimum width=31mm] (exe) {ET\_EXEC};
\draw[->,thick] (src)--(as);
\draw[->,thick] (as)--(obj);
\draw[->,thick] (obj)--(ld);
\draw[->,thick] (ld)--(exe);
\end{tikzpicture}
\end{center}
В каждом \code{ET_REL}, включая результат \code{mcpu-ld -r}, имеется ровно одна \code{.mcpu.target}. Окончательная \code{.mcpu.lifecycle} ещё отсутствует: формирование lifecycle принадлежит компоновщику (linker), а в перемещаемом объекте представлено каноническими символами \code{_start}, \code{_life} и необязательным \code{_fini}.
\section{Таблицы символов ABI}
Запись MELF64 в таблице символов имеет размер 24 байта. Символ 0 --- полностью нулевая запись неопределённого символа. В \code{st_info} привязка (binding) хранится в старшей тетраде, тип --- в младшей.
Значения binding: LOCAL=0, GLOBAL=1, WEAK=2. Типы символов: NOTYPE, OBJECT, FUNC, SECTION, FILE. Для обычных символов времени запуска используется visibility DEFAULT; в подстановке символов при запуске (interposition) участвуют только имена DEFAULT GLOBAL/WEAK.
\subsection{st\_value в ET\_REL}
Для определённого символа \code{st_shndx} содержит индекс секции, а \code{st_value} --- байтовое смещение от её начала. Для неопределённого символа используется \code{SHN_UNDEF} и нулевое значение. Директива \code{.equ} остаётся механизмом абсолютных выражений времени ассемблирования и не обязана создавать запись MELF symbol table.
\subsection{Статическое разрешение символов}
LOCAL никогда не разрешается через границу object file. Сильный GLOBAL имеет приоритет над WEAK. Несколько сильных GLOBAL-определений являются ошибкой. Если сильное определение отсутствует, несколько WEAK-определений выбираются детерминированно по порядку входных файлов компоновщика. Неопределённый сильный GLOBAL после окончательной компоновки является ошибкой. При \code{mcpu-ld -r} такой символ может оставаться неопределённым и переносится вместе с RELA в новый ET_REL.
\subsection{Lifecycle-символы}
\code{_start} и \code{_life} обязательны как GLOBAL/FUNC для каждого исполняемого файла; \code{_fini} --- необязательный GLOBAL/FUNC. Lifecycle-символы не могут быть WEAK. Псевдометка исходного текста \code{_start_life} существует только в синтаксисе ассемблера и эквивалентна двум символам \code{_start} и \code{_life} с одним смещением в секции \code{.text}, когда \code{.init} отсутствует.
\section{RELA ABI}
Запись MELF64 RELA имеет размер 24 байта: \code{r_offset}, \code{r_info} и знаковый 64-битный \code{r_addend}. Базовое выражение relocation: \code{S + A}. Все текущие MCPU relocation исправляют ровно 8 байт.
\begin{longtable}{@{}L{38mm}L{28mm}L{30mm}L{58mm}@{}}
\toprule
\textbf{Relocation} & \textbf{Где находится поле} & \textbf{Цель} & \textbf{Записываемое значение}\\
\midrule
\endfirsthead
\toprule
\textbf{Relocation} & \textbf{Где находится поле} & \textbf{Цель} & \textbf{Записываемое значение}\\
\midrule
\endhead
R\_MCPU\_CODE64 & PROGRAM & PROGRAM & окончательное необработанное байтовое смещение PROGRAM\\
R\_MCPU\_DATA64 & PROGRAM & DATA/.bss & окончательное необработанное байтовое смещение DATA\\
R\_MCPU\_PTR64\_CODE & PROGRAM & загружаемый сегмент & PTR64(segment,offset) в порядке байтов машинного кода\\
R\_MCPU\_PTR64\_DATA & секция данных & загружаемый сегмент & PTR64 в представлении данных целевой архитектуры\\
R\_MCPU\_CPTR64\_DATA & секция данных & только PROGRAM & PTR64(PROGRAM,offset)\\
\bottomrule
\end{longtable}
В \code{ET_REL} поле \code{r_offset} является байтовым смещением внутри целевой секции, указанной через \code{sh_info}; \code{sh_link} указывает на таблицу символов. Все 8 байт исправляемого поля обязаны помещаться в сохранённой секции. Relocation непосредственно в область NOBITS запрещена: в файле нет байтов, которые можно исправить.
Relocation неопределённого WEAK-указателя с нулевым addend может дать канонический полностью нулевой NULL. Для необработанных CODE64/DATA64 такое молчаливое преобразование в zero запрещено, потому что offset 0 является допустимым архитектурным адресом.
\section{Частичная компоновка mcpu-ld -r}
Режим \code{mcpu-ld -r} объединяет несколько MELF \code{ET_REL} в один новый \code{ET_REL}. Это именно \term{partial link}{частичная компоновка}, а не построение исполняемого образа.
Для каждой одноимённой секции вклады входных объектов конкатенируются в порядке входа с соблюдением их \code{sh_addralign}. Значения определённых символов и \code{r_offset} пересчитываются в координаты объединённой секции. LOCAL-символы разных объектов остаются раздельными даже при одинаковом имени. Для GLOBAL/WEAK действует обычное правило силы: сильный GLOBAL заменяет WEAK; два сильных GLOBAL одного имени являются ошибкой.
RELA при \code{-r} не превращаются в окончательные архитектурные адреса. Они переносятся в выходной объект с новым section-relative offset и ссылкой на канонический символ результирующего ET_REL. Неопределённые GLOBAL/WEAK допускаются и могут быть разрешены последующей окончательной компоновкой.
\begin{McpuCommand}
mcpu-ld -r -o combined.o a.o b.o c.o
mcpu-ld --stack-size=64K -o program main.o combined.o
\end{McpuCommand}
STACK/HEAP, lifecycle-финализация, Program Headers, SONAME/NEEDED и runtime image в режиме \code{-r} не создаются. Поэтому \code{-r} взаимоисключён с \code{--dynamic}/\code{--shared}; опции размеров STACK/HEAP и \code{--soname} для него недопустимы.
\section{Статические библиотеки lib*.a}
Статическая библиотека MCPU не является новым типом MELF-файла. Это обычный UNIX \code{ar}-контейнер, чьи ordinary members являются независимыми текущими MELF \code{ET_REL}. Утилита \code{mcpu-ar} создаёт deterministic archives и при модификаторе \code{s} записывает настоящий System-V/GNU-style symbol index.
\begin{McpuCommand}
mcpu-ar rcs libmodel.a model.o solver.o helpers.o
mcpu-ar t libmodel.a
\end{McpuCommand}
При линковке из архива извлекается только member, определяющий текущий неразрешённый сильный GLOBAL. Неопределённый WEAK сам по себе member не вытягивает. После каждого извлечения текущий архив повторно сканируется до устойчивого состояния, поэтому новый member может породить ссылку на member, расположенный раньше в том же архиве. Уже пройденный отдельный \code{-l} archive автоматически после следующей библиотеки не пересматривается; повторное \code{-la} имеет реальный смысл.
Для ABI-v1 и для \code{-r} \code{-lfoo} ищет только \code{libfoo.a}. Для ABI-v3 \code{--dynamic}/\code{--shared} поиск является directory-major: в каждом каталоге сначала проверяется \code{libfoo.so}, затем \code{libfoo.a}. Статически извлечённые members становятся частью результирующего MELF и не создают \code{DT_NEEDED}.
\section{Метаданные профиля целевой архитектуры}
\code{.mcpu.target} обязательна в \code{ET_REL} и \code{ET_EXEC}; модули ABI v2/v3 несут тот же профиль совместимости. Запись имеет размер 64 байта, не является ALLOC и выровнена на 8.
\begin{longtable}{@{}L{38mm}L{18mm}L{94mm}@{}}
\toprule
\textbf{Поле} & \textbf{Смещение} & \textbf{Смысл}\\
\midrule
\endfirsthead
\toprule
\textbf{Поле} & \textbf{Смещение} & \textbf{Смысл}\\
\midrule
\endhead
mt\_version & 0 & версия структуры профиля, сейчас 1\\
mt\_size & 4 & размер записи, сейчас 64\\
mt\_isa\_revision & 8 & ревизия ISA, сейчас 1\\
mt\_abi\_revision & 12 & ревизия программного ABI, сейчас 1\\
mt\_program\_model & 16 & профиль ILP32/LP64/LLP64\\
mt\_data\_byte\_order & 20 & порядок байтов объектов данных; согласован с EI\_DATA\\
mt\_data\_word\_order & 24 & порядок слов LibMPU\\
mt\_integer\_model & 28 & дополнительный код (дополнительный код)\\
mt\_address\_model & 32 & PTR64 SEG4:OFF60\\
mt\_register\_model & 36 & REG24 / регистровый пул 512 KiB\\
mt\_real\_model & 40 & LibMPU\\
mt\_complex\_model & 44 & LibMPU\\
mt\_max\_align & 48 & максимальное обычное выравнивание ABI = 16\\
mt\_flags & 52 & пока 0\\
mt\_required\_features & 56 & пока 0\\
\bottomrule
\end{longtable}
Компоновщик требует совместимости профилей целевой архитектуры. Загрузчик повторно проверяет окончательный профиль до создания guest-областей памяти. Среда выполнения не исправляет несовместимый профиль и не конвертирует порядок байтов данных автоматически.
\section{Метаданные lifecycle}
Окончательный \code{ET_EXEC} содержит \code{.mcpu.lifecycle} фиксированного размера 32 байта. Запись описывает \textbf{семантику жизненного цикла}, но не дублирует адреса точек входа: единственным нормативным источником адресов остаётся Ehdr.
Флаги ABI v1 фиксируют: START обязателен, LIFE обязателен, INIT и FINI необязательны; \code{e_entry} указывает на START; без INIT START совпадает с LIFE; LIFE завершается END и может быть продолжен; штатный EXIT переходит в FINI; область запуска (startup area) остаётся действительной всё время жизни программы.
\begin{normative}
Метаданные lifecycle намеренно не содержат копий указателей на \code{_start/_life/_fini}. Благодаря этому в образе нет двух независимо перемещаемых источников истины. Загрузчик проверяет согласованность Ehdr и записи lifecycle, после чего использует числовые поля точек входа из Ehdr.
\end{normative}
\section{Таблица заголовков сегментов (Program Headers)}
Запись MELF64 Phdr имеет размер 64 байта и расширяет привычную ELF-подобную форму полем \code{p_maxsz}. \code{p_paddr=0}: отдельного пространства физических адресов у текущего MCPU ABI нет. \code{p_align} относится к выравниванию guest-адреса и файла, а не к размеру страницы host-системы.
\begin{center}
\begin{tabularx}{0.96\textwidth}{@{}L{28mm}L{34mm}L{24mm}Y@{}}
\toprule
\textbf{Пространство} & \textbf{p\_type} & \textbf{Флаги} & \textbf{Правило размеров}\\
\midrule
PROGRAM & PT\_LOAD & R|X & filesz=memsz=maxsz\\
DATA & PT\_LOAD & R|W & filesz <= memsz; maxsz=memsz\\
CONTROL & PT\_LOAD & R & сохранённый и runtime-размеры равны\\
INPUT & PT\_LOAD & R & сохранённый и runtime-размеры равны\\
OUTPUT & PT\_LOAD & R|W & сохранённый и runtime-размеры равны\\
TRACE & PT\_LOAD & R|W & сохранённый и runtime-размеры равны\\
STACK & PT\_MCPU\_STACK & R|W & filesz=0; memsz=maxsz\\
HEAP & PT\_MCPU\_HEAP & R|W & filesz=0; memsz <= maxsz\\
\bottomrule
\end{tabularx}
\end{center}
Для пространств, загружаемых из образа, \code{p_vaddr=PTR64(segment,0)} в координатах окончательного образа исполняемого файла или модуля. Дескриптор STACK обязателен в \code{ET_EXEC}; дескриптор HEAP необязателен. Округление host-mmap к размеру страницы не является частью ABI.
\section{Статический ET\_EXEC ABI v1}
Обычный \code{mcpu-ld} завершает всю работу времени компоновки до запуска:
\begin{enumerate}
\item проверяет профиль целевой архитектуры каждого \code{ET_REL};
\item размещает вклады секций с учётом \code{sh_addralign};
\item создаёт единственную 16-байтовую защитную нулевую область DATA (NULL guard) по смещениям 0..15;
\item разрешает символы GLOBAL/WEAK/UNDEF;
\item применяет все RELA с проверкой диапазона и сегмента;
\item проверяет обязательные определения lifecycle;
\item назначает окончательные PTR64-адреса секций и символов;
\item формирует окончательные заголовков сегментов (Program Headers) и метаданные.
\end{enumerate}
Исполняемый файл ABI v1 не нуждается в поиске символов при запуске. Любая попытка использовать \code{--ldpreload} или \code{MCPU_LD_PRELOAD} с ABI v1 является ошибкой, а не поводом неявно превратить программу в dynamic ABI.
\section{Точки входа lifecycle исполняемого файла}
\subsection{С секцией .init}
\code{_start} принадлежит \code{.init}; поля \code{e_entry} и \code{e_init_entry} указывают на \code{_start}. \code{_life} принадлежит \code{.text}, а \code{e_life_entry} указывает на \code{_life}. После \code{END} в INIT супервизор начинает повторяющиеся фазы LIFE.
\subsection{Без секции .init}
\code{_start} и \code{_life} обязаны находиться по одному адресу в \code{.text}. Псевдометка \code{_start_life:} создаёт именно эту пару символов. В окончательном исполняемом файле \code{e_init_entry=0} и \code{e_entry == e_life_entry}.
\subsection{FINI}
Если существует \code{.fini}/\code{_fini}, поле \code{e_fini_entry} указывает на него; иначе оно равно 0. Штатный \code{EXIT} после LIFE входит в FINI. Диагностическая остановка по внешнему лимиту шагов не имитирует \code{EXIT} и не обязана запускать FINI.
\subsection{Связь MELF lifecycle с HLL Runtime ABI}
Сам MELF container определяет машинные entry points \code{_start}, \code{_life} и optional \code{_fini}. Поверх этого container contract существующий \code{mcpu-ld} реализует HLL complete-program layer: strong GLOBAL/FUNC \code{main+fini} в одном defining ET_REL классифицирует PROGRAM, а \code{init+life+fini} --- MODEL. Linker автоматически добавляет соответствующий CRT из \code{<MCPU-root>/lib/mcpu/}; отсутствие обязательного CRT является fatal error. Raw low-level objects с собственными \code{_start/_life[/_fini]} продолжают линковаться без automatic CRT, но смешивать оба режима запрещено.
\begin{normative}
Это не меняет wire format MELF: HLL names являются linker policy над обычной symbol table, а окончательный ET_EXEC по-прежнему исполняется через нормативные lifecycle entry points. Loader не классифицирует HLL source form.
\end{normative}
Полный контракт HLL + CRT + MCPU Libc, включая \code{McpuStartup}, PRE_RUNTIME/RUNNING, internal Libc hooks и MODEL return namespace, приведён в \code{libmcpu-bytecode-architecture-ru.pdf}.
\section{Постоянная область запуска McpuStartup}
До первой guest-инструкции загрузчик строит в верхней части STACK структуру \code{McpuStartup}. Она имеет поле версии, поэтому имя C-типа намеренно не содержит суффикс V1.
\begin{center}
\begin{tabularx}{0.88\textwidth}{@{}L{20mm}L{30mm}L{18mm}Y@{}}
\toprule
\textbf{Смещение} & \textbf{Поле} & \textbf{Размер} & \textbf{Смысл}\\
\midrule
0x00 & version & 4 & \code{MCPU_STARTUP_VERSION_1}\\
0x04 & size & 4 & 32\\
0x08 & argc & 8 & число аргументов guest-программы\\
0x10 & argv & 8 & PTR64(STACK, массив argv)\\
0x18 & зарезервировано & 8 & 0\\
\bottomrule
\end{tabularx}
\end{center}
После заголовка располагается массив \code{argv[argc+1]} из PTR64, завершающий NULL, затем строки аргументов, завершённые NUL, и нулевое дополнение. \code{startup_base} выровнен на 16 байт. Начальное состояние: \code{PC=e_entry}, \code{SP=startup_base}, \code{FP=stack_size}. Искусственного CALL-frame для \code{_start} нет.
\section{Исторический MELF ABI v2}
ABI v2 ввёл \code{ET_DYN}, \code{.dynsym/.dynstr} и сохранённые runtime RELA, но не имел SONAME/NEEDED. Полный набор shared objects задавался явным \code{mcpu-run --ldpreload=a.so:b.so}; вся startup-компоновка завершалась до первой инструкции \code{_start}. ABI v2 остаётся читаемым для совместимости, тогда как текущие \code{mcpu-ld --dynamic}/\code{--shared} выпускают ABI v3.
\section{Frozen MELF ABI v3}
ABI v3 сохраняет image/symbol/RELA-модель ABI v2 и добавляет нормальную модель зависимостей. Каждый dynamic ABI-v3 \code{ET_EXEC}/\code{ET_DYN} содержит ровно одну не-ALLOC секцию \code{.dynamic} типа \code{SHT_DYNAMIC}, связанную через \code{sh_link} с \code{.dynstr}.
Запись \code{MElf64_Dyn} имеет размер 16 байт: знаковый 64-битный \code{d_tag} и беззнаковый 64-битный \code{d_val}. Текущие теги:
\begin{center}
\begin{tabularx}{0.82\textwidth}{@{}L{42mm}L{22mm}Y@{}}
\toprule
\textbf{Тег} & \textbf{Значение} & \textbf{Смысл}\\
\midrule
\code{DT_NULL} & 0 & обязательный единственный терминатор canonical stream\\
\code{DT_NEEDED} & 1 & offset имени требуемого SONAME в \code{.dynstr}\\
\code{DT_SONAME} & 14 & offset собственного SONAME shared object в \code{.dynstr}\\
\bottomrule
\end{tabularx}
\end{center}
После \code{DT_NULL} записей быть не должно. ABI-v3 \code{ET_DYN}, используемый как normal dependency, имеет ровно один SONAME. \code{ET_EXEC} не имеет собственного SONAME. Оба типа могут иметь ноль или более NEEDED в записанном порядке.
\section{SONAME, NEEDED и link-time -L/-l}
Имена development link, runtime identity и physical file разделены. Типичная установка:
\begin{McpuCode}
libfoo.so -> libfoo.so.1
libfoo.so.1 -> libfoo.so.1.2.3
libfoo.so.1.2.3 # DT_SONAME = libfoo.so.1
\end{McpuCode}
При \code{-lfoo} linker находит development name \code{libfoo.so}, полностью валидирует выбранный ABI-v3 ET_DYN, читает его SONAME и записывает в потребитель именно \code{DT_NEEDED [libfoo.so.1]}. Абсолютный путь, имя symlink и physical filename в NEEDED не попадают.
ABI-v3 dynamic output в каждом search directory предпочитает \code{libfoo.so}, затем \code{libfoo.a}. Если выбран archive, нужные ET_REL members встраиваются статически и никакого NEEDED для них нет. ABI-v1 и \code{-r} shared candidate не рассматривают.
\section{Поиск библиотек и runtime root}
\code{mcpu-ld} и \code{mcpu-run} используют общую relocatable root/config policy. Базовый system directory равен \code{<runtime-root>/lib}; конфигурационная цепочка в порядке роста приоритета:
\begin{McpuCode}
<runtime-root>/etc/mcpu-ld.conf
/etc/mcpu/mcpu-ld.conf
$HOME/.mcpu/etc/mcpu-ld.conf
\end{McpuCode}
Переменная конфигурации \code{MCPU_LD_SYSTEM_LIBRARY_PATH} заменяет system path; пустое значение отключает его. \code{--no-config} не читает config layers, но сохраняет executable-derived default. \code{--sys-root=PATH} подразумевает \code{--no-config} и использует \code{PATH/lib}. Для linker явные \code{-L} идут раньше system path; для runtime явный \code{--library-path} также имеет более высокий search priority.
\section{Рекурсивная загрузка NEEDED}
\code{mcpu-run} сначала читает прямые \code{DT_NEEDED} главного ET_EXEC, ищет каждый SONAME по runtime search policy, валидирует ABI-v3 ET_DYN и требует точного совпадения внутреннего \code{DT_SONAME} с запрошенным именем. Затем так же обрабатываются транзитивные NEEDED.
Граф зависимостей строится breadth-first и дедуплицируется по SONAME. Direct dependencies предшествуют transitive; siblings сохраняют порядок NEEDED слева направо. Цикл вида \code{A -> B -> A} допустим и завершается через предварительную регистрацию SONAME.
\section{.dynsym/.dynstr и runtime RELA}
\code{.dynsym/.dynstr} являются частью startup-link ABI, в отличие от developer/debug \code{.symtab/.strtab}. DEFAULT GLOBAL/WEAK участвуют в выборе определения; LOCAL никогда не входит в interposition namespace. Lifecycle-имена \code{_start/_life/_fini} принадлежат главному executable и не являются runtime-preemptible symbols.
Runtime \code{SHT_RELA} использует тот же \code{MElf64_Rela}. \code{sh_link} указывает на \code{.dynsym}, \code{sh_info} --- на allocated section с исправляемым полем, а \code{r_offset} остаётся offset относительно output section. Все runtime RELA выполняются до \code{_start}; lazy binding отсутствует.
\section{Детерминированный runtime symbol scope}
Для одного имени сначала сравнивается binding strength: GLOBAL всегда сильнее WEAK. Среди определений одинаковой силы действует scope:
\begin{enumerate}
\item explicit preload modules --- наивысший scope, внутри списка правый элемент имеет больший приоритет;
\item главный ET_EXEC;
\item normal DT_NEEDED graph в breadth-first, left-to-right порядке.
\end{enumerate}
Таким образом direct dependency выигрывает у конфликтующей transitive dependency той же силы, а первый sibling в NEEDED order выигрывает у следующего. Если GLOBAL нет вообще, тот же scope применяется к WEAK.
\code{MCPU_LD_PRELOAD} является environment counterpart для \code{--ldpreload}. Environment entries добавляются первыми, command-line entries --- после них; существующее rightmost-wins правило поэтому естественно делает command line сильнее environment. Эта переменная не является частью \code{mcpu-ld.conf} и не подавляется \code{--no-config}.
\section{Контракт ET_DYN}
ABI-v2/v3 \code{ET_DYN} содержит только library \code{.text/.data/.bss} плюс non-ALLOC metadata. Он не владеет \code{.init}, \code{.fini}, \code{.control}, \code{.input}, \code{.output}, \code{.trace}, lifecycle definitions, \code{PT_MCPU_STACK} или \code{PT_MCPU_HEAP}. STACK, HEAP и model spaces принадлежат главному \code{ET_EXEC}. Для ABI v3 normal shared object SONAME обязателен.
\section{LOCAL relocation внутри ET_DYN}
LOCAL-символ остаётся частным и неподменяемым, но окончательная process base модуля заранее неизвестна. Поэтому relocation внутри ET_DYN, которой нужен окончательный PROGRAM/DATA address, сохраняется как LOCAL runtime RELA. Startup linker разрешает её строго внутри исходного модуля и добавляет runtime base соответствующего сегмента. Эта коррекция является нормативной частью runtime relocation contract и полностью сохраняется в ABI v3.
\begin{center}
\begin{tikzpicture}[font=\sffamily\small,>=Stealth,node distance=7mm]
\node[draw=McpuBlue,rounded corners,fill=McpuBlueBg,minimum width=46mm] (so) {ET\_DYN после mcpu-ld};
\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,below=of so,minimum width=62mm] (rel) {LOCAL runtime RELA + module-relative symbol};
\node[draw=McpuGreen,rounded corners,fill=McpuGreenBg,below=of rel,minimum width=56mm] (run) {startup linker в mcpu-run};
\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,below=of run,minimum width=62mm] (final) {process PTR64 с PROGRAM/DATA base};
\draw[->,thick] (so)--(rel);
\draw[->,thick] (rel)--(run);
\draw[->,thick] (run)--(final);
\end{tikzpicture}
\end{center}
\section{Размещение образа процесса и единственный DATA guard}
У MCPU нет единого ELF-подобного смещения загрузки (load bias): PTR64 имеет независимые селекторы сегментов. Компоновщик запуска назначает отдельную базу для каждого архитектурного сегмента.
\begin{center}
\begin{tabularx}{0.9\textwidth}{@{}L{48mm}Y@{}}
\toprule
\textbf{Вклад} & \textbf{База}\\
\midrule
main PROGRAM & 0\\
lib1 PROGRAM & \code{align_up(main_program_end, lib1_align)}\\
lib2 PROGRAM & \code{align_up(lib1_program_end, lib2_align)}\\
main DATA & 0\\
первая DATA-библиотека & после окончательного DATA main; минимум 16, если DATA main отсутствует\\
\bottomrule
\end{tabularx}
\end{center}
В \code{ET_DYN} нет собственного DATA NULL guard. Во всём образе процесса существует ровно одна нулевая область offsets 0..15. Поэтому локальный символ библиотеки с относительным к модулю DATA offset 0 после размещения при запуске закономерно получает process offset 16 или больше.
\section{BSS и соотношение filesz/memsz}
\code{.bss} имеет тип \code{SHT_NOBITS}. Она участвует в расчёте адресов и увеличивает DATA \code{p_memsz}, но не увеличивает объём данных в файле \code{p_filesz}. Статический и startup-загрузчики сначала получают изначально обнулённую память, затем копируют сохранённые байты, поэтому NOBITS детерминированно начинается с нулей.
Для PROGRAM хранится только машинный код, поэтому \code{filesz=memsz}. Для DATA обычно \code{filesz < memsz}. LOCAL-ссылки из \code{ET_DYN} в DATA/.bss всё равно требуют перебазирования по базе модуля, даже если целевые байты относятся к NOBITS.
\section{Дескриптор STACK и командная строка}
Размер STACK является частью ABI исполняемого файла. Он задаётся компоновщиком через \code{--stack-size=N} и записывается в \code{PT_MCPU_STACK}; \code{mcpu-run} не может его переопределить. Разделяемые объекты ABI v2 не задают политику STACK.
Предпочтительный синтаксис запуска использует явный разделитель:
\begin{lstlisting}[language={}]
mcpu-run [runtime-options] -- executable [program-args...]
\end{lstlisting}
Все параметры после \code{--} передаются в guest \code{argv} без повторного разбора программой \code{mcpu-run}; текстовое имя исполняемого файла становится \code{argv[0]}. Старая форма без разделителя сохранена для совместимости.
\section{Дескриптор HEAP, _end и SYS\_brk}
Необязательный \code{PT_MCPU_HEAP} хранит начальный подготовленный размер в \code{p_memsz} и неизменяемый предел в \code{p_maxsz}; оба значения не меньше 16, причём max >= initial. Определяемый компоновщиком символ \code{_end=PTR64(HEAP,16)} является частным для исполняемого файла, неподменяемым и задаёт начальный и минимальный program break.
\code{SYS_brk} имеет номер 10. NULL-аргумент запрашивает текущее значение; HEAP PTR64 задаёт абсолютный новый break. В отличие от общего stable syscall rule \code{-MCPU_errno}, \code{SYS_brk} возвращает фактический текущий HEAP PTR64. При отклонённом запросе break не меняется. Shrink зануляет освобождённый диапазон, но не обязан уменьшать host-отображение памяти; последующий рост остаётся детерминированным. Guest PTR64 остаётся корректным при перемещении host backing, поскольку содержит segment+offset, а не host-адрес.
\section{Дисциплина проверки загрузчика}
Загрузчик сначала полностью проверяет структуру файла и только затем создаёт guest-области памяти. В частности проверяются:
\begin{itemize}
\item сигнатура, класс, порядок данных, версия, OSABI, ABI/machine, размеры заголовков и границы таблиц;
\item обязательные метаданные target/lifecycle и зарезервированные поля;
\item уникальность заголовков сегментов (Program Headers), права доступа, соотношения размеров, выравнивание и границы OFF60;
\item соответствие каждой ALLOC-секции её архитектурному сегменту;
\item selector/range точек входа lifecycle;
\item нулевые байты DATA guard в статическом исполняемом образе;
\item для ABI v2/v3 --- структура dynsym/RELA, диапазоны символов, границы исправляемых полей и семантика целевого сегмента; для ABI v3 дополнительно canonical .dynamic, SONAME/NEEDED и соответствие identity загруженного ET_DYN запрошенному SONAME.
\end{itemize}
\begin{principle}
\textbf{Загрузчик проверяет, но не «чинит».} Он не выводит lifecycle из названий секций, не создаёт недостающий guard, не меняет порядок байтов PROGRAM, не увеличивает STACK, не ослабляет HEAP limit и не переинтерпретирует несовместимый профиль целевой архитектуры. Компоновщик запуска ABI v2/v3 выполняет только явно определённые сохранённые relocation, dependency discovery и разрешение символов.
\end{principle}
\section{Режимы команды mcpu-ld}
\begin{lstlisting}[language={}]
# partial ET_REL
mcpu-ld -r -o combined.o a.o b.o
# статический ABI v1
mcpu-ld --stack-size=4096 --heap-size=64K --heap-limit=1M \
-L$HOME/.mcpu/lib -lmodel -o app main.o
# главный исполняемый файл frozen ABI v3
mcpu-ld --dynamic --stack-size=64K --no-heap \
-L$HOME/.mcpu/lib -lrk4 -o model pendulum.o
# shared object ABI v3
mcpu-ld --shared --soname=librk4.so.1 \
-o librk4.so.1.0.0 rk4.o
\end{lstlisting}
STACK/HEAP принадлежат только \code{ET_EXEC}. \code{--soname} допустим только для \code{--shared}. \code{-r} не создаёт executable/runtime metadata и использует для \code{-l} только static archives. Суффиксы размера K/KiB, M/MiB, G/GiB используют двоичные множители.
\section{Инструменты анализа и безопасного редактирования MELF}
Binary utilities работают поверх того же MELF contract и не создают отдельного container ABI.
\subsection{Read-only inspection}
\code{mcpu-readelf} показывает file/program/section headers, symbol tables, RELA, \code{.dynamic} и MCPU-specific metadata. \code{mcpu-nm} выводит \code{.symtab} или \code{.dynsym} и умеет читать static archives. \code{mcpu-objdump} объединяет section/relocation views с instruction disassembly; decoder общий с CPU runtime через \code{__cpu_decode_at()}, поэтому ISA не дублируется отдельным parser-ом.
\subsection{mcpu-strip}
Текущая policy намеренно консервативна. В ET\_REL ordinary \code{.symtab/.strtab} сохраняются, потому что они являются частью последующей link semantics. В ET\_EXEC/ET\_DYN ordinary non-ALLOC \code{SHT_SYMTAB} может быть удалена только если retained sections от неё не зависят; \code{.dynsym/.dynstr/.dynamic}, RELA, MCPU metadata и allocated image всегда сохраняются. Современные final-image writers уже компактны, поэтому для обычного ET\_EXEC/ET\_DYN strip часто является byte-for-byte no-op.
\subsection{mcpu-objcopy}
\code{mcpu-objcopy} выполняет только MELF-to-MELF structural copy/edit. Safe interface умеет выбирать/удалять sections и dump/add/update/rename для metadata, но запрещает разрушать allocated image, frozen dynamic metadata, runtime relocations и ET\_REL link-critical dependencies. Новая section через \code{--add-section} является non-ALLOC \code{SHT_PROGBITS}. Metadata tail может быть repacked, но program headers и runtime-visible PT\_LOAD bytes должны оставаться неизменными.
Flat binary, Intel HEX, S-record, VMA/LMA и firmware-image conversion намеренно отсутствуют: виртуальная MCPU исполняет MELF напрямую.
\subsection{Non-ALLOC debug metadata и frozen ABI v3}
\begin{normative}
Будущий debug format не обязан менять MELF ABI v3, если его sections остаются non-ALLOC, не входят в PT\_LOAD, не требуются loader/runtime для исполнения и могут быть полностью удалены без изменения guest-visible поведения. Версия такого debug format должна быть самостоятельной и не кодироваться повышением \code{EI_ABIVERSION} MELF.
\end{normative}
В ET\_REL debug sections при необходимости могут иметь link-time RELA к code/data symbols; такие relocations являются metadata link-editor contract и не должны становиться обязательными runtime relocations final ET\_EXEC/ET\_DYN.
\section{Правила совместимости}
\begin{enumerate}
\item Статический \code{ET_EXEC} ABI v1 и \code{ET_REL} ABI v1 остаются основой статического/разработческого пути; ABI-v1 executable отвергает preload.
\item Исторический ABI v2 остаётся читаемым и использует explicit-preload startup model без SONAME/NEEDED.
\item Frozen ABI v3 является текущим normal dynamic ABI. Несовместимое изменение \code{.dynamic}, NEEDED/SONAME, runtime scope или retained-relocation contract требует нового номера ABI.
\item Static \code{lib*.a} и \code{mcpu-ld -r} являются link-time механизмами над ABI-v1 ET_REL и не требуют ABI v4.
\item Ревизия ISA и CALL ABI остаются равны 1 независимо от версии контейнерного dynamic ABI.
\item Будущие расширения должны использовать явные version/feature поля, а не менять смысл зарезервированных битов или записей молча. Non-ALLOC debug metadata с самостоятельной версией формата не требует нового MELF ABI, пока loader/runtime semantics не зависят от неё.
\end{enumerate}
\appendix
\section{Размеры сериализованных записей}
\begin{center}
\begin{tabularx}{0.9\textwidth}{@{}L{48mm}L{22mm}Y@{}}
\toprule
\textbf{Запись} & \textbf{Байт} & \textbf{Назначение}\\
\midrule
MElf64\_Ehdr & 88 & заголовок файла\\
MElf64\_Shdr & 64 & заголовок секции\\
MElf64\_Sym & 24 & запись таблицы символов\\
MElf64\_Rela & 24 & запись RELA\\
MElf64\_Dyn & 16 & запись \code{.dynamic} ABI v3\\
MElf64\_Phdr & 64 & заголовок сегмента (Program Header) с \code{p_maxsz}\\
MElf\_McpuTarget & 64 & метаданные профиля целевой архитектуры\\
MElf\_McpuLifecycle & 32 & метаданные lifecycle\\
McpuStartup & 32 & заголовок области запуска (startup) в STACK guest-программы; это не сериализованные метаданные MELF\\
\bottomrule
\end{tabularx}
\end{center}
\section{Канонические имена секций}
\begin{center}
\begin{tabularx}{\textwidth}{@{}L{62mm}Y@{}}
\code{.init}, \code{.text}, \code{.fini} & Секции машинного кода PROGRAM.\\
\code{.data}, \code{.bss} & Объекты DATA; \code{.bss} имеет тип NOBITS.\\
\code{.control}, \code{.input}, \code{.output}, \code{.trace} & Модельные пространства, принадлежащие ET\_EXEC.\\
\code{.symtab}, \code{.strtab} & Информация о символах для разработки и статической компоновки.\\
\code{.dynsym}, \code{.dynstr} & Runtime symbol/string tables ABI v2/v3.\\
\code{.dynamic} & Non-ALLOC dependency metadata ABI v3: SONAME/NEEDED/NULL.\\
\code{.rela.init}, \code{.rela.text}, \code{.rela.fini} & Секции relocation для PROGRAM.\\
RELA секций данных & \code{.rela.data}, \code{.rela.control}, \code{.rela.input}, \code{.rela.output}, \code{.rela.trace}.\\
\code{.mcpu.target} & Обязательный профиль целевой архитектуры.\\
\code{.mcpu.lifecycle} & Окончательный lifecycle-контракт исполняемого файла.\\
\code{.shstrtab} & Таблица строк с именами секций.\\
\end{tabularx}
\end{center}
\section{Нормативная памятка frozen dynamic ABI v3}
\begin{normative}
\begin{itemize}
\item New dynamic output использует ABI v3; ABI v2 поддерживается как исторический explicit-preload input format.
\item ABI-v3 ET_DYN имеет обязательный SONAME и не владеет lifecycle, model spaces, STACK или HEAP.
\item ABI-v3 ET_EXEC/ET_DYN имеют canonical non-ALLOC \code{.dynamic}; NEEDED содержит SONAME, а не pathname или development symlink name.
\item Normal dependencies обнаруживаются рекурсивно по SONAME, deduplicate/cycle handling выполняются до guest execution.
\item GLOBAL сильнее WEAK; explicit preload имеет наивысший equal-strength scope и rightmost priority; затем main executable; затем breadth-first/left-to-right NEEDED graph.
\item LOCAL никогда не участвует в name interposition; нуждающиеся в process base LOCAL ET_DYN relocations сохраняются и rebased внутри исходного модуля.
\item Все runtime relocation и symbol resolution заканчиваются до \code{_start}; PLT/GOT, lazy binding, \code{dlopen()}, \code{dlsym()} и \code{dlclose()} отсутствуют.
\item Во всём process DATA существует один NULL guard; отдельный ET_DYN guard не создаётся.
\item Static archives и \code{mcpu-ld -r} работают на link-time поверх ET_REL и не меняют frozen ABI v3.
\end{itemize}
\end{normative}
\end{document}
|