1 {
2     Copyright (c) 1998-2006 by Peter Vreman
3 
4     Contains the base stuff for binary object file writers
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20  ****************************************************************************
21 }
22 unit ogbase;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28     uses
29       { common }
30       cutils,
31       cclasses,
32       { targets }
33       systems,globtype,
34       { outputwriters }
35       owbase,
36       { assembler }
37       aasmbase,
38       cpuinfo;
39 
40     type
41       TObjSection = class;
42       TObjData = class;
43 
44       TExeSection = class;
45       TExeSymbol  = class;
46       TExeOutput  = class;
47 
48       TObjRelocationType = (
49          { Relocation to absolute address }
50          RELOC_ABSOLUTE,
51 {$ifdef x86_64}
52          { 32bit Relocation to absolute address }
53          RELOC_ABSOLUTE32,
54          { 64 bit coff only }
55          RELOC_RELATIVE_1,
56          RELOC_RELATIVE_2,
57          RELOC_RELATIVE_3,
58          RELOC_RELATIVE_4,
59          RELOC_RELATIVE_5,
60          { PIC }
61          RELOC_GOTPCREL,
62          RELOC_PLT32,
63 {$endif x86_64}
64 {$ifdef i386}
65          { PIC }
66          RELOC_GOTPC,
67          RELOC_GOT32,
68          RELOC_PLT32,
69 {$endif i386}
70 {$ifdef i8086}
71          RELOC_ABSOLUTE32,
72          RELOC_RELATIVE32,
73          RELOC_FARPTR,
74          RELOC_FARPTR_RELATIVEOFFSET,
75          RELOC_FARPTR48,
76          RELOC_FARPTR48_RELATIVEOFFSET,
77          RELOC_SEG,
78          RELOC_SEGREL,
79          RELOC_DGROUP,
80          RELOC_DGROUPREL,
81          RELOC_FARDATASEG,
82          RELOC_FARDATASEGREL,
83 {$endif i8086}
84 {$ifdef arm}
85          RELOC_RELATIVE_24,
86          RELOC_RELATIVE_CALL,
87          RELOC_RELATIVE_24_THUMB,
88          RELOC_RELATIVE_CALL_THUMB,
89          RELOC_GOT32,
90 {$endif arm}
91          { Relative relocation }
92          RELOC_RELATIVE,
93          { PECoff (Windows) RVA relocation }
94          RELOC_RVA,
95          { PECoff (Windows) section relocation, required by DWARF2 debug info }
96          RELOC_SECREL32,
97          { Generate a 0 value at the place of the relocation,
98            this is used to remove unused vtable entries }
99          RELOC_ZERO,
100          { No relocation is needed. It is used in ARM object files.
101            Also internal linker use this reloc to make virtual (not real)
102            links to some sections }
103          RELOC_NONE,
104          { Darwin relocation, using PAIR }
105          RELOC_PIC_PAIR,
106          { Relative to GOT/gp }
107          RELOC_GOTOFF,
108          { Untranslated target-specific value }
109          RELOC_RAW
110       );
111 
112 {$if defined(x86_64)}
113     { no special aliases for x86_64 }
114 {$elseif defined(i8086)}
115     const
116       RELOC_ABSOLUTE16 = RELOC_ABSOLUTE;
117       RELOC_RELATIVE16 = RELOC_RELATIVE;
118 {$else}
119     const
120       RELOC_ABSOLUTE32 = RELOC_ABSOLUTE;
121 {$endif}
122 
123     const
124       { stab types }
125       N_GSYM = $20;
126       N_STSYM = 38;     { initialized const }
127       N_LCSYM = 40;     { non initialized variable}
128       N_Function = $24; { function or const }
129       N_TextLine = $44;
130       N_DataLine = $46;
131       N_BssLine = $48;
132       N_RSYM = $40;     { register variable }
133       N_LSYM = $80;
134       N_tsym = 160;
135       N_SourceFile = $64;
136       N_IncludeFile = $84;
137       N_BINCL = $82;
138       N_EINCL = $A2;
139       N_LBRAC = $C0;
140       N_EXCL  = $C2;
141       N_RBRAC = $E0;
142 
143       { GNU extensions }
144       debuglinkname='.gnu_debuglink';
145 
146       { TObjRelocation.flags }
147       { 'ftype' field contains platform-specific value }
148       rf_raw = 1;
149       { relocation must be added to dynamic list }
150       rf_dynamic = 2;
151       { relocation target is absent/irrelevant (e.g. R_ARM_V4BX) }
152       rf_nosymbol = 4;
153 
154     type
155       TObjSectionOption = (
156        { Has Data available in the file }
157        oso_Data,
158        { Is loaded into memory }
159        oso_load,
160        { Writable }
161        oso_write,
162        { Contains executable instructions }
163        oso_executable,
164        { Never discard section }
165        oso_keep,
166        { Procedure Linkage Table specific treatment }
167        oso_plt,
168        { Contains debug info and can be stripped }
169        oso_debug,
170        { Contains only strings }
171        oso_strings,
172        { Must be cloned when writing separate debug file }
173        oso_debug_copy,
174        { Has relocations with explicit addends (ELF-specific) }
175        oso_rela_relocs,
176        { Supports bss-like allocation of data, even though it is written in file (i.e. also has oso_Data) }
177        oso_sparse_data,
178        { Section to support the resolution of multiple symbols with the same name }
179        oso_comdat
180      );
181 
182      TObjSectionOptions = set of TObjSectionOption;
183 
184      TObjSectionComdatSelection = (
185        { Section is not a COMDAT section }
186        oscs_none,
187        { Select any of the symbols }
188        oscs_any,
189        { Select any symbol, but abort if they differ in size }
190        oscs_same_size,
191        { Select any symbol, but abort if they differ in size or content }
192        oscs_exact_match,
193        { Select the symbol only if the associated symbol is linked as well }
194        oscs_associative,
195        { Select the largest symbol }
196        oscs_largest
197      );
198 
199 {$ifdef i8086}
200      { allow 32-bit sections on i8086. Useful for the dwarf debug info, as well
201        as to allow linking 32-bit obj modules. }
202      TObjSectionOfs = LongWord;
203 {$else i8086}
204      TObjSectionOfs = PUInt;
205 {$endif i8086}
206 
207      TObjSectionGroup = class;
208 
209      TObjSymbol = class(TFPHashObject)
210      public
211        bind       : TAsmsymbind;
212        typ        : TAsmsymtype;
213        { Current assemble pass, used to detect duplicate labels }
214        pass       : byte;
215        { how the symbol is referenced (target-specific bitfield) }
216        refs       : byte;
217        symidx     : longint;
218        objsection : TObjSection;
219        offset,
220        size       : TObjSectionOfs;
221        { Used for external and common solving during linking }
222        exesymbol  : TExeSymbol;
223 
224        { Darwin asm is using indirect symbols resolving }
225        indsymbol  : TObjSymbol;
226 
227        { Used by the OMF object format and its complicated relocation records }
228        group: TObjSectionGroup;
229 {$ifdef ARM}
230        ThumbFunc : boolean;
231 {$endif ARM}
232 
233        constructor create(AList:TFPHashObjectList;const AName:string);
addressnull234        function  address:qword;
235        procedure SetAddress(apass:byte;aobjsec:TObjSection;abind:TAsmsymbind;atyp:Tasmsymtype);
ObjDatanull236        function  ObjData: TObjData;
237        { string representation for the linker map file }
AddressStrnull238        function  AddressStr(AImageBase: qword): string;virtual;
239      end;
240      TObjSymbolClass = class of TObjSymbol;
241 
242      { Stabs is common for all targets }
243      TObjStabEntry=packed record
244         strpos  : longint;
245         ntype   : byte;
246         nother  : byte;
247         ndesc   : word;
248         nvalue  : longint;
249      end;
250      PObjStabEntry=^TObjStabEntry;
251 
252      TObjRelocation = class
253      private
GetTypenull254         function GetType:TObjRelocationType;
255         procedure SetType(v:TObjRelocationType);
256      public
257         DataOffset,
258         orgsize    : TObjSectionOfs;  { COFF: original size of the symbol to relocate }
259                                       { ELF: explicit addend }
260         symbol     : TObjSymbol;
261         objsection : TObjSection; { only used if symbol=nil }
262         group      : TObjSectionGroup; { only used if symbol=nil and objsection=nil }
263         ftype      : byte;
264         size       : byte;
265         flags      : byte;
266         constructor CreateSymbol(ADataOffset:TObjSectionOfs;s:TObjSymbol;Atyp:TObjRelocationType);
267         constructor CreateSection(ADataOffset:TObjSectionOfs;aobjsec:TObjSection;Atyp:TObjRelocationType);
268         constructor CreateGroup(ADataOffset:TObjSectionOfs;grp:TObjSectionGroup;Atyp:TObjRelocationType);
269         constructor CreateRaw(ADataOffset:TObjSectionOfs;s:TObjSymbol;ARawType:byte);
TargetNamenull270         function TargetName:TSymStr;
271         property typ: TObjRelocationType read GetType write SetType;
272      end;
273 
274      TObjSection = class(TFPHashObject)
275      private
276        FData       : TDynamicArray;
277        FSecOptions : TObjSectionOptions;
278        FComdatSelection : TObjSectionComdatSelection;
279        FCachedFullName : pshortstring;
280        FSizeLimit : TObjSectionOfs;
281        procedure SetSecOptions(Aoptions:TObjSectionOptions);
282        procedure SectionTooLargeError;
283      public
284        ObjData    : TObjData;
285        index      : longword;  { index of section in section headers }
286        SecSymIdx  : longint;   { index for the section in symtab }
287        SecAlign   : longint;   { alignment of the section }
288        { section Data }
289        Size,
290        DataPos    : TObjSectionOfs;
291        MemPos     : qword;
292        Group      : TObjSectionGroup;
293        AssociativeSection : TObjSection;
294        ComdatSelection : TObjSectionComdatSelection;
295        DataAlignBytes : shortint;
296        { Relocations (=references) to other sections }
297        ObjRelocations : TFPObjectList;
298        { executable linking }
299        ExeSection  : TExeSection;
300        USed        : Boolean;
301        VTRefList : TFPObjectList;
302        constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);virtual;
303        destructor  destroy;override;
writenull304        function  write(const d;l:TObjSectionOfs):TObjSectionOfs;
305        { writes string plus zero byte }
writestrnull306        function  writestr(const s:string):TObjSectionOfs;
WriteZerosnull307        function  WriteZeros(l:longword):TObjSectionOfs;
308        { writes content of s without null termination }
WriteBytesnull309        function  WriteBytes(const s:string):TObjSectionOfs;
310        procedure writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);virtual;
setmemposnull311        function  setmempos(mpos:qword):qword;
312        procedure setDatapos(var dpos:TObjSectionOfs);
313        procedure alloc(l:TObjSectionOfs);
314        procedure addsymReloc(ofs:TObjSectionOfs;p:TObjSymbol;Reloctype:TObjRelocationType);
315        procedure addsectionReloc(ofs:TObjSectionOfs;aobjsec:TObjSection;Reloctype:TObjRelocationType);
316        procedure addrawReloc(ofs:TObjSectionOfs;p:TObjSymbol;RawReloctype:byte);
317        procedure ReleaseData;
FullNamenull318        function  FullName:string;
319        { string representation for the linker map file }
MemPosStrnull320        function  MemPosStr(AImageBase: qword): string;virtual;
321        property  Data:TDynamicArray read FData;
322        property  SecOptions:TObjSectionOptions read FSecOptions write SetSecOptions;
323        property  SizeLimit:TObjSectionOfs read FSizeLimit write FSizeLimit;
324      end;
325      TObjSectionClass = class of TObjSection;
326 
327      TObjSectionGroup = class(TFPHashObject)
328      public
329        index: longword;  { index of group in group headers }
330        members: array of TObjSection;
331        iscomdat: boolean;
332      end;
333      TObjSectionGroupClass = class of TObjSectionGroup;
334 
335      TString80 = string[80];
336 
337      TObjSymbolList = class(TFPHashObjectList)
338      public
339        Owner: TObjData;
340      end;
341 
342 {$ifdef i8086}
343      { on i8086 we use a longint, to support 32-bit relocations as well (e.g.
344        for allowing 386+ instructions with 32-bit addresses in inline asm code) }
345      TRelocDataInt = longint;
346 {$else i8086}
347      TRelocDataInt = aint;
348 {$endif i8086}
349 
350      TObjData = class(TLinkedListItem)
351      private
352        FCurrObjSec : TObjSection;
353        FObjSectionList  : TFPHashObjectList;
354        FCObjSymbol      : TObjSymbolClass;
355        FCObjSection     : TObjSectionClass;
356        FCObjSectionGroup: TObjSectionGroupClass;
357        { Symbols that will be defined in this object file }
358        FObjSymbolList    : TObjSymbolList;
359        FCachedAsmSymbolList : TFPObjectList;
360        { Special info sections that are written to during object generation }
361        FStabsObjSec,
362        FStabStrObjSec : TObjSection;
363        FGroupsList : TFPHashObjectList;
364        FCPUType : tcputype;
365        procedure section_reset(p:TObject;arg:pointer);
366        procedure section_afteralloc(p:TObject;arg:pointer);
367        procedure section_afterwrite(p:TObject;arg:pointer);
368      protected
369        FName       : TString80;
370        property CObjSection:TObjSectionClass read FCObjSection write FCObjSection;
371        property CObjSectionGroup: TObjSectionGroupClass read FCObjSectionGroup write FCObjSectionGroup;
372      public
373        CurrPass  : byte;
374        ExecStack : boolean;
375 {$ifdef ARM}
376        ThumbFunc : boolean;
377 {$endif ARM}
378        constructor create(const n:string);virtual;
379        destructor  destroy;override;
380        { Sections }
sectionnamenull381        function  sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;virtual;abstract;
sectiontype2optionsnull382        function  sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;virtual;
sectiontype2alignnull383        function  sectiontype2align(atype:TAsmSectiontype):longint;virtual;
createsectionnull384        function  createsection(atype:TAsmSectionType;const aname:string='';aorder:TAsmSectionOrder=secorder_default):TObjSection;virtual;
createsectionnull385        function  createsection(const aname:string;aalign:longint;aoptions:TObjSectionOptions;DiscardDuplicate:boolean=true):TObjSection;virtual;
createsectiongroupnull386        function  createsectiongroup(const aname:string):TObjSectionGroup;
387        procedure CreateDebugSections;virtual;
findsectionnull388        function  findsection(const aname:string):TObjSection;
389        procedure setsection(asec:TObjSection);
390        { Symbols }
createsymbolnull391        function  createsymbol(const aname:string):TObjSymbol;
symboldefinenull392        function  symboldefine(asmsym:TAsmSymbol):TObjSymbol;
symboldefinenull393        function  symboldefine(const aname:string;abind:TAsmsymbind;atyp:Tasmsymtype):TObjSymbol;
symbolrefnull394        function  symbolref(asmsym:TAsmSymbol):TObjSymbol;
symbolrefnull395        function  symbolref(const aname:string):TObjSymbol;
396        procedure ResetCachedAsmSymbols;
397        { Allocation }
398        procedure alloc(len:aword);
399        procedure allocalign(len:longint);
400        procedure writebytes(const Data;len:aword);
401        procedure writeReloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);virtual;abstract;
402        procedure beforealloc;virtual;
403        procedure beforewrite;virtual;
404        procedure afteralloc;virtual;
405        procedure afterwrite;virtual;
406        procedure resetsections;
407        procedure layoutsections(var datapos:TObjSectionOfs);
408        property Name:TString80 read FName;
409        property CurrObjSec:TObjSection read FCurrObjSec;
410        property ObjSymbolList:TObjSymbolList read FObjSymbolList;
411        property ObjSectionList:TFPHashObjectList read FObjSectionList;
412        property GroupsList:TFPHashObjectList read FGroupsList;
413        property StabsSec:TObjSection read FStabsObjSec write FStabsObjSec;
414        property StabStrSec:TObjSection read FStabStrObjSec write FStabStrObjSec;
415        property CObjSymbol: TObjSymbolClass read FCObjSymbol write FCObjSymbol;
416        { Current CPU type for the internal asm writer.
417          Instructions, not supported by the given CPU should produce an error.
418          A value of 'cpu_none' means no restrictions (all instructions should be accepted) }
419        property CPUType : tcputype read FCPUType write FCPUType;
420      end;
421      TObjDataClass = class of TObjData;
422 
423      TObjOutput = class
424       private
425         FCObjData : TObjDataClass;
426       protected
427         { writer }
428         FWriter    : TObjectwriter;
writeDatanull429         function  writeData(Data:TObjData):boolean;virtual;abstract;
430         property CObjData : TObjDataClass read FCObjData write FCObjData;
431         procedure WriteSectionContent(Data:TObjData);
432       public
433         constructor create(AWriter:TObjectWriter);virtual;
434         destructor  destroy;override;
newObjDatanull435         function  newObjData(const n:string):TObjData;
startObjectfilenull436         function  startObjectfile(const fn:string):boolean;
writeobjectfilenull437         function  writeobjectfile(Data:TObjData):boolean;
438         procedure exportsymbol(p:TObjSymbol);
439         property Writer:TObjectWriter read FWriter;
440       end;
441       TObjOutputClass=class of TObjOutput;
442 
443       TObjInput = class
444       private
445         FCObjData : TObjDataClass;
446       protected
447         { reader }
448         FReader    : TObjectReader;
449         InputFileName : string;
450         property CObjData : TObjDataClass read FCObjData write FCObjData;
451         procedure ReadSectionContent(Data:TObjData);
452       public
453         constructor create;virtual;
ReadObjDatanull454         function  ReadObjData(AReader:TObjectreader;out Data:TObjData):boolean;virtual;abstract;
CanReadObjDatanull455         class function CanReadObjData(AReader:TObjectreader):boolean;virtual;
456         procedure inputerror(const s : string);
457       end;
458       TObjInputClass=class of TObjInput;
459 
460       TVTableEntry=record
461         ObjRelocation : TObjRelocation;
462         orgreloctype,
463         orgrelocflags : byte;
464         Enabled,
465         Used  : Boolean;
466       end;
467       PVTableEntry=^TVTableEntry;
468 
469       TExeVTable = class
470       private
471         procedure CheckIdx(VTableIdx:longint);
472       public
473         ExeSymbol    : TExeSymbol;
474         EntryCnt     : Longint;
475         EntryArray   : PVTableEntry;
476         Consolidated : Boolean;
477         ChildList    : TFPObjectList;
478         constructor Create(AExeSymbol:TExeSymbol);
479         destructor Destroy;override;
480         procedure AddChild(vt:TExeVTable);
481         procedure AddEntry(VTableIdx:Longint);
482         procedure SetVTableSize(ASize:longint);
VTableRefnull483         function  VTableRef(VTableIdx:Longint):TObjRelocation;
484       end;
485 
486       TSymbolState = (
487         symstate_undefined,
488         symstate_undefweak,  // undefined but has only weak refs - don't complain
489         symstate_defined,
490         symstate_defweak,
491         symstate_common,
492         symstate_dynamic     // a matching symbol has been seen in .so
493       );
494 
495       TExeSymbol = class(TFPHashObject)
496         ObjSymbol  : TObjSymbol;
497         State      : TSymbolState;
498         used       : boolean;
499         { Used for vmt references optimization }
500         VTable     : TExeVTable;
501         { fields for ELF linking }
502         gotoffset  : aword;
503         dynindex   : aword;
504         { A thunk used to redirect some references to symbol (like absolute
505           jumps/calls to PIC code).
506           This probably is also needed for ARM/Thumb interworking and alike.
507           TODO: consider reusing objsymbol.indsymbol for this purpose }
508 {$ifdef mips}
509         stubsymbol : TObjSymbol;
510 {$endif mips}
511       end;
512 
513       TExeSection = class(TFPHashObject)
514       private
515         FSecSymIdx : longint;
516         FObjSectionList : TFPObjectList;
517       public
518         Size,
519         DataPos,
520         MemPos     : qword;
521         SecAlign   : longint;
522         Disabled   : boolean;
523         SecOptions : TObjSectionOptions;
524         constructor create(AList:TFPHashObjectList;const AName:string);virtual;
525         destructor  destroy;override;
526         procedure AddObjSection(objsec:TObjSection;ignoreprops:boolean=false);virtual;
527         property ObjSectionList:TFPObjectList read FObjSectionList;
528         property SecSymIdx:longint read FSecSymIdx write FSecSymIdx;
529       end;
530       TExeSectionClass=class of TExeSection;
531 
532       TlibKind = (lkArchive,lkObject,lkGroup);
533 
534       TStaticLibrary = class(TObject)
535       private
536         FName : TCmdStr;
537         FPayload : TObject;                 { lkArchive: TObjectReader }
538                                             { lkObject:  TObjData      }
539                                             { lkGroup:   TFPObjectList }
540         FObjInputClass : TObjInputClass;
541         FKind: TlibKind;
542         FAsNeeded : Boolean;
543         function GetArReader:TObjectReader;
544         function GetGroupMembers:TFPObjectList;
545         function GetObjData:TObjData;
546       public
547         constructor create(const AName:TCmdStr;AReader:TObjectReader;AObjInputClass:TObjInputClass);
548         constructor create_object(AObjData:TObjData);
549         constructor create_group;
550         destructor  destroy;override;
551         property ArReader:TObjectReader read GetArReader;
552         property ObjInputClass:TObjInputClass read FObjInputClass;
553         property GroupMembers:TFPObjectList read GetGroupMembers;
554         property ObjData:TObjData read GetObjData;
555         property AsNeeded:Boolean read FAsNeeded write FAsNeeded;
556         property Kind:TLibKind read FKind;
557       end;
558 
559       TImportLibrary = class(TFPHashObject)
560       private
561         FImportSymbolList : TFPHashObjectList;
562       public
563         constructor create(AList:TFPHashObjectList;const AName:string);
564         destructor  destroy;override;
565         property ImportSymbolList:TFPHashObjectList read FImportSymbolList;
566       end;
567 
568       TImportSymbol = class(TFPHashObject)
569       private
570         FOrdNr  : longint;
571         FIsVar  : boolean;
572         FMangledName : string;
573         FCachedExeSymbol: TExeSymbol;
574       public
575         constructor create(AList:TFPHashObjectList;const AName,AMangledName:string;AOrdNr:longint;AIsVar:boolean);
576         property OrdNr: longint read FOrdNr;
577         property MangledName: string read FMangledName;
578         property IsVar: boolean read FIsVar;
579         property CachedExeSymbol: TExeSymbol read FCachedExeSymbol write FCachedExeSymbol;
580       end;
581 
582       TExeWriteMode = (ewm_exefull,ewm_dbgonly,ewm_exeonly);
583 
584       TExeOutput = class
585       private
586         { ExeSectionList }
587         FCObjSymbol       : TObjSymbolClass;
588         FCObjData         : TObjDataClass;
589         FCExeSection      : TExeSectionClass;
590         FCurrExeSec       : TExeSection;
591         FExeSectionList   : TFPHashObjectList;
592         Fzeronr           : longint;
593         Fvaluesnr         : longint;
594         { Symbols }
595         FExeSymbolList    : TFPHashObjectList;
596         FUnresolvedExeSymbols : TFPObjectList;
597         FExternalObjSymbols,
598         FCommonObjSymbols   : TFPObjectList;
599         FProvidedObjSymbols : TFPObjectList;
600         FIndirectObjSymbols : TFPObjectList;
601         FEntryName          : string;
602         FExeVTableList     : TFPObjectList;
603         { Objects }
604         FObjDataList  : TFPObjectList;
605         { Position calculation }
606         FImageBase    : aword;
607         FCurrMemPos       : qword;
608         procedure SetCurrMemPos(const AValue: qword);
609       protected
610         { writer }
611         FExeWriteMode : TExeWriteMode;
612         FWriter : TObjectwriter;
613         commonObjSection : TObjSection;
614         internalObjData : TObjData;
615         EntrySym  : TObjSymbol;
616         SectionDataAlign,
617         SectionMemAlign : aword;
618         ComdatGroups : TFPHashList;
619         FixedSectionAlign : boolean;
620         AllowUndefinedSymbols : boolean;
621         function  writeData:boolean;virtual;abstract;
622         property CExeSection:TExeSectionClass read FCExeSection write FCExeSection;
623         property CObjData:TObjDataClass read FCObjData write FCObjData;
624         property CObjSymbol:TObjSymbolClass read FCObjSymbol write FCObjSymbol;
625         procedure Order_ObjSectionList(ObjSectionList : TFPObjectList; const aPattern:string);virtual;
626         procedure WriteExeSectionContent;
627         procedure DoRelocationFixup(objsec:TObjSection);virtual;abstract;
628         function MemAlign(exesec: TExeSection): longword;
629         function DataAlign(exesec: TExeSection): longword;
630         procedure ReplaceExeSectionList(newlist: TFPList);
631       public
632         CurrDataPos  : aword;
633         MaxMemPos    : qword;
634         IsSharedLibrary : boolean;
635         ExecStack    : boolean;
636         constructor create;virtual;
637         destructor  destroy;override;
638         function  FindExeSection(const aname:string):TExeSection;
639         procedure AddObjData(ObjData:TObjData);
640         procedure Load_Start;virtual;
641         procedure Load_EntryName(const aname:string);virtual;
642         procedure Load_Symbol(const aname:string);virtual;
643         procedure Load_ProvideSymbol(const aname:string);virtual;
644         procedure Load_IsSharedLibrary;
645         procedure Load_ImageBase(const avalue:string);
646         procedure Load_DynamicObject(ObjData:TObjData;asneeded:boolean);virtual;
647         procedure Order_Start;virtual;
648         procedure Order_End;virtual;
649         procedure Order_ExeSection(const aname:string);virtual;
650         procedure Order_Align(const avalue:string);virtual;
651         procedure Order_Zeros(const avalue:string);virtual;
652         procedure Order_Values(bytesize : aword; const avalue:string);virtual;
653         procedure Order_Symbol(const aname:string);virtual;
654         procedure Order_ProvideSymbol(const aname:string);virtual;
655         procedure Order_EndExeSection;virtual;
656         procedure Order_ObjSection(const aname:string);virtual;
657         procedure MemPos_Start;virtual;
658         procedure MemPos_Header;virtual;
659         procedure MemPos_ExeSection(exesec:TExeSection);
660         procedure MemPos_ExeSection(const aname:string);virtual;
661         procedure MemPos_EndExeSection;virtual;
662         procedure DataPos_Start;virtual;
663         procedure DataPos_Header;virtual;
664         procedure DataPos_ExeSection(exesec:TExeSection);
665         procedure DataPos_ExeSection(const aname:string);virtual;
666         procedure DataPos_EndExeSection;virtual;
667         procedure DataPos_Symbols;virtual;
668         procedure BuildVTableTree(VTInheritList,VTEntryList:TFPObjectList);
669         procedure PackUnresolvedExeSymbols(const s:string);
670         procedure ResolveSymbols(StaticLibraryList:TFPObjectList);
671         procedure PrintMemoryMap;
672         procedure FixupSymbols;
673         procedure FixupRelocations;virtual;
674         procedure RemoveUnusedExeSymbols;
675         procedure MergeStabs;
676         procedure MarkEmptySections;
677         procedure RemoveUnreferencedSections;
678         procedure RemoveDisabledSections;
679         procedure RemoveDebugInfo;
680         procedure MarkTargetSpecificSections(WorkList:TFPObjectList);virtual;
681         procedure AfterUnusedSectionRemoval;virtual;
682         procedure GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);virtual;
683         procedure GenerateDebugLink(const dbgname:string;dbgcrc:cardinal);
684         function WriteExeFile(const fn:string):boolean;
685         procedure ParseScript (linkscript:TCmdStrList); virtual;
686         property Writer:TObjectWriter read FWriter;
687         property ExeSectionList:TFPHashObjectList read FExeSectionList;
688         property ObjDataList:TFPObjectList read FObjDataList;
689         property ExeSymbolList:TFPHashObjectList read FExeSymbolList;
690         property UnresolvedExeSymbols:TFPObjectList read FUnresolvedExeSymbols;
691         property ExternalObjSymbols:TFPObjectList read FExternalObjSymbols;
692         property CommonObjSymbols:TFPObjectList read FCommonObjSymbols;
693         property IndirectObjSymbols:TFPObjectList read FIndirectObjSymbols;
694         property ExeVTableList:TFPObjectList read FExeVTableList;
695         property EntryName:string read FEntryName write FEntryName;
696         property ImageBase:aword read FImageBase write FImageBase;
697         property CurrExeSec:TExeSection read FCurrExeSec;
698         property ExeWriteMode:TExeWriteMode read FExeWriteMode write FExeWriteMode;
699         property CurrMemPos:qword read FCurrMemPos write SetCurrMemPos;
700       end;
701       TExeOutputClass=class of TExeOutput;
702 
703     const
704       SectionDataMaxGrow = 4096;
705 
706     var
707       exeoutput : TExeOutput;
708 
709     function align_aword(v:aword;a:longword):aword;
710     function align_qword(v:qword;a:longword):qword;
711     function align_objsecofs(v:TObjSectionOfs;a:longword):TObjSectionOfs;
712 
713 implementation
714 
715     uses
716       SysUtils,
717       globals,verbose,ogmap;
718 
719 {$ifdef MEMDEBUG}
720     var
721       memobjsymbols,
722       memobjsections : TMemDebug;
723 {$endif MEMDEBUG}
724 
725 {*****************************************************************************
726                                  Helpers
727 *****************************************************************************}
728 
729     function align_aword(v:aword;a:longword):aword;
730       begin
731         if a<=1 then
732           result:=v
733         else
734           result:=((v+a-1) div a) * a;
735       end;
736 
737 
738     function align_qword(v:qword;a:longword):qword;
739       begin
740         if a<=1 then
741           result:=v
742         else
743           result:=((v+a-1) div a) * a;
744       end;
745 
746 
747     function align_objsecofs(v:TObjSectionOfs;a:longword):TObjSectionOfs;
748       begin
749         if a<=1 then
750           result:=v
751         else
752           result:=((v+a-1) div a) * a;
753       end;
754 
755 
756     procedure MaybeSwapStab(var v:TObjStabEntry);
757       begin
758         if source_info.endian<>target_info.endian then
759           begin
760             v.strpos:=SwapEndian(v.strpos);
761             v.nvalue:=SwapEndian(v.nvalue);
762             v.ndesc:=SwapEndian(v.ndesc);
763           end;
764       end;
765 
766 {*****************************************************************************
767                                  TObjSymbol
768 *****************************************************************************}
769 
770     constructor TObjSymbol.create(AList:TFPHashObjectList;const AName:string);
771       begin
772         inherited create(AList,AName);
773         bind:=AB_EXTERNAL;
774         typ:=AT_NONE;
775         symidx:=-1;
776         size:=0;
777         offset:=0;
778         objsection:=nil;
779       end;
780 
781 
782     function TObjSymbol.address:qword;
783       begin
784         if assigned(objsection) then
785           result:=offset+objsection.mempos
786         else
787           result:=0;
788       end;
789 
790 
791     procedure TObjSymbol.SetAddress(apass:byte;aobjsec:TObjSection;abind:TAsmsymbind;atyp:Tasmsymtype);
792       begin
793         if not(abind in [AB_GLOBAL,AB_LOCAL,AB_COMMON,AB_IMPORT]) then
794           internalerror(200603016);
795         if not assigned(aobjsec) then
796           internalerror(200603017);
797         if (bind in [AB_EXTERNAL,AB_LAZY]) or
798           { Put all COMMON to GLOBAL in step 3 of
799             TExeOutput.ResolveSymbols }
800            ((abind=AB_GLOBAL) and (bind=AB_COMMON)) then
801           begin
802             { Do not change the AB_TYPE of common symbols yet }
803             { This will be done in FixupSymbols }
804             if (pass<>0) or (bind<>AB_COMMON) then
805               bind:=abind;
806             typ:=atyp;
807           end
808         else
809           begin
810             if pass=apass then
811               begin
812                 Message1(asmw_e_duplicate_label,name);
813                 exit;
814               end;
815           end;
816         pass:=apass;
817         { Code can never grow after a pass }
818         if assigned(objsection) and
819            (objsection=aobjsec) and
820            (aobjsec.size>offset) then
821           internalerror(200603014);
822         objsection:=aobjsec;
823         offset:=aobjsec.size;
824       end;
825 
826 
827     function TObjSymbol.ObjData: TObjData;
828       begin
829         result:=(OwnerList as TObjSymbolList).Owner;
830       end;
831 
832 
833     function TObjSymbol.AddressStr(AImageBase: qword): string;
834       begin
835         Result:='0x'+HexStr(address+Aimagebase,sizeof(pint)*2);
836       end;
837 
838 {****************************************************************************
839                               TObjRelocation
840 ****************************************************************************}
841 
842     constructor TObjRelocation.CreateSymbol(ADataOffset:TObjSectionOfs;s:TObjSymbol;Atyp:TObjRelocationType);
843       begin
844         if not assigned(s) then
845           internalerror(200603034);
846         DataOffset:=ADataOffset;
847         Symbol:=s;
848         OrgSize:=0;
849         Group:=nil;
850         ObjSection:=nil;
851         ftype:=ord(Atyp);
852       end;
853 
854 
855     constructor TObjRelocation.CreateSection(ADataOffset:TObjSectionOfs;aobjsec:TObjSection;Atyp:TObjRelocationType);
856       begin
857         if not assigned(aobjsec) then
858           internalerror(200603036);
859         DataOffset:=ADataOffset;
860         Symbol:=nil;
861         OrgSize:=0;
862         Group:=nil;
863         ObjSection:=aobjsec;
864         ftype:=ord(Atyp);
865       end;
866 
867 
868     constructor TObjRelocation.CreateGroup(ADataOffset:TObjSectionOfs;grp:TObjSectionGroup;Atyp:TObjRelocationType);
869       begin
870         if not assigned(grp) then
871           internalerror(2015111201);
872         DataOffset:=ADataOffset;
873         Symbol:=nil;
874         ObjSection:=nil;
875         OrgSize:=0;
876         Group:=grp;
877         ftype:=ord(Atyp);
878       end;
879 
880 
881     constructor TObjRelocation.CreateRaw(ADataOffset:TObjSectionOfs;s:TObjSymbol;ARawType:byte);
882       begin
883         { nil symbol is allowed here }
884         DataOffset:=ADataOffset;
885         Symbol:=s;
886         ObjSection:=nil;
887         Group:=nil;
888         orgsize:=0;
889         ftype:=ARawType;
890         flags:=rf_raw;
891       end;
892 
893 
894     function TObjRelocation.GetType:TObjRelocationType;
895       begin
896         if (flags and rf_raw)=0 then
897           result:=TObjRelocationType(ftype)
898         else
899           result:=RELOC_RAW;
900       end;
901 
902 
903     procedure TObjRelocation.SetType(v:TObjRelocationType);
904       begin
905         ftype:=ord(v);
906         flags:=flags and (not rf_raw);
907       end;
908 
909 
910     function TObjRelocation.TargetName:TSymStr;
911       begin
912         if assigned(symbol) then
913           if symbol.typ=AT_SECTION then
914             result:=symbol.objsection.name
915           else
916             result:=symbol.Name
917         else
918           result:=objsection.Name;
919       end;
920 
921 {****************************************************************************
922                               TObjSection
923 ****************************************************************************}
924 
925     constructor TObjSection.create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);
926       begin
927         inherited Create(AList,Aname);
928         { Data }
929         Size:=0;
930         Datapos:=0;
931         mempos:=0;
932         FData:=Nil;
933 {$ifdef i8086}
934         FSizeLimit:=high(word);
935 {$else i8086}
936         FSizeLimit:=high(TObjSectionOfs);
937 {$endif i8086}
938         { Setting the secoptions allocates Data if needed }
939         secoptions:=Aoptions;
940         secalign:=Aalign;
941         secsymidx:=0;
942         { relocation }
943         ObjRelocations:=TFPObjectList.Create(true);
944         VTRefList:=TFPObjectList.Create(false);
945       end;
946 
947 
948     destructor TObjSection.destroy;
949       begin
950         if assigned(Data) then
951           Data.Free;
952         stringdispose(FCachedFullName);
953         ObjRelocations.Free;
954         VTRefList.Free;
955         inherited destroy;
956       end;
957 
958 
959     procedure TObjSection.SetSecOptions(Aoptions:TObjSectionOptions);
960       begin
961         FSecOptions:=FSecOptions+AOptions;
962         if (oso_Data in secoptions) and
963            not assigned(FData) then
964           FData:=TDynamicArray.Create(SectionDataMaxGrow);
965       end;
966 
967 
968     procedure TObjSection.SectionTooLargeError;
969       begin
970         if oso_executable in SecOptions then
971           Message(asmw_f_code_segment_too_large)
972         else
973           Message(asmw_f_data_segment_too_large);
974       end;
975 
976 
977     function TObjSection.write(const d;l:TObjSectionOfs):TObjSectionOfs;
978       begin
979         result:=size;
980         if assigned(Data) then
981           begin
982             if Size<>Data.size then
983               internalerror(200602281);
984 {$ifndef cpu64bitalu}
985             if (qword(size)+l)>SizeLimit then
986               SectionTooLargeError;
987 {$endif}
988             Data.write(d,l);
989             inc(Size,l);
990           end
991         else
992           internalerror(200602289);
993       end;
994 
995 
996     function TObjSection.writestr(const s:string):TObjSectionOfs;
997       var
998         b: byte;
999       begin
1000         result:=Write(s[1],length(s));
1001         b:=0;
1002         Write(b,1);
1003       end;
1004 
1005 
1006     function TObjSection.WriteBytes(const s:string):TObjSectionOfs;
1007       begin
1008         result:=Write(s[1],length(s));
1009       end;
1010 
1011 
1012     function TObjSection.WriteZeros(l:longword):TObjSectionOfs;
1013       var
1014         empty : array[0..1023] of byte;
1015       begin
1016         result:=Size;
1017         if l>sizeof(empty) then
1018           begin
1019             fillchar(empty,sizeof(empty),0);
1020             while l>sizeof(empty) do
1021               begin
1022                 Write(empty,sizeof(empty));
1023                 Dec(l,sizeof(empty));
1024               end;
1025             if l>0 then
1026               Write(empty,l);
1027           end
1028         else if l>0 then
1029           begin
1030             fillchar(empty,l,0);
1031             Write(empty,l);
1032           end;
1033       end;
1034 
1035 
1036     { Writes relocation to (section+offset) without need to have a symbol at that location.
1037       Not an abstract method because not every backend needs this functionality. }
1038     procedure TObjSection.writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);
1039       begin
1040         InternalError(2012081501);
1041       end;
1042 
1043 
1044     procedure TObjSection.setDatapos(var dpos:TObjSectionOfs);
1045       begin
1046         if oso_Data in secoptions then
1047           begin
1048             { get aligned Datapos }
1049             Datapos:=align_aword(dpos,secalign);
1050             Dataalignbytes:=Datapos-dpos;
1051             { return updated Datapos }
1052             dpos:=Datapos+size;
1053           end
1054         else
1055           Datapos:=dpos;
1056       end;
1057 
1058 
1059     function TObjSection.setmempos(mpos:qword):qword;
1060       begin
1061         mempos:=align_qword(mpos,secalign);
1062         { return updated mempos }
1063         result:=mempos+size;
1064       end;
1065 
1066 
1067     procedure TObjSection.alloc(l:TObjSectionOfs);
1068       begin
1069 {$ifndef cpu64bitalu}
1070         if (qword(size)+l)>SizeLimit then
1071           SectionTooLargeError;
1072 {$endif}
1073         if oso_sparse_data in SecOptions then
1074           WriteZeros(l)
1075         else
1076           inc(size,l);
1077       end;
1078 
1079 
1080     procedure TObjSection.addsymReloc(ofs:TObjSectionOfs;p:TObjSymbol;Reloctype:TObjRelocationType);
1081       begin
1082         ObjRelocations.Add(TObjRelocation.CreateSymbol(ofs,p,reloctype));
1083       end;
1084 
1085 
1086     procedure TObjSection.addsectionReloc(ofs:TObjSectionOfs;aobjsec:TObjSection;Reloctype:TObjRelocationType);
1087       begin
1088         ObjRelocations.Add(TObjRelocation.CreateSection(ofs,aobjsec,reloctype));
1089       end;
1090 
1091 
1092     procedure TObjSection.addrawReloc(ofs:TObjSectionOfs;p:TObjSymbol;RawReloctype:byte);
1093       begin
1094         ObjRelocations.Add(TObjRelocation.CreateRaw(ofs,p,RawReloctype));
1095       end;
1096 
1097 
1098     procedure TObjSection.ReleaseData;
1099       begin
1100         if assigned(FData) then
1101           begin
1102             FData.free;
1103             FData:=nil;
1104           end;
1105         ObjRelocations.free;
1106         ObjRelocations:=nil;
1107         if assigned(FCachedFullName) then
1108           begin
1109             stringdispose(FCachedFullName);
1110             FCachedFullName:=nil;
1111           end;
1112       end;
1113 
1114 
1115     function  TObjSection.FullName:string;
1116       begin
1117         if not assigned(FCachedFullName) then
1118           begin
1119             if assigned(ObjData) then
1120               FCachedFullName:=stringdup(ObjData.Name+'('+Name+')')
1121             else
1122               FCachedFullName:=stringdup(Name);
1123           end;
1124         result:=FCachedFullName^;
1125       end;
1126 
1127 
1128     function  TObjSection.MemPosStr(AImageBase: qword): string;
1129       begin
1130         result:='0x'+HexStr(mempos+AImageBase,sizeof(pint)*2);
1131       end;
1132 
1133 
1134 {****************************************************************************
1135                                 TObjData
1136 ****************************************************************************}
1137 
1138     constructor TObjData.create(const n:string);
1139       begin
1140         inherited create;
1141         FName:=ExtractFileName(n);
1142         FObjSectionList:=TFPHashObjectList.Create(true);
1143         FStabsObjSec:=nil;
1144         FStabStrObjSec:=nil;
1145         { symbols }
1146         FCObjSymbol:=TObjSymbol;
1147         FObjSymbolList:=TObjSymbolList.Create(true);
1148         FObjSymbolList.Owner:=Self;
1149         FCachedAsmSymbolList:=TFPObjectList.Create(false);
1150         { section class type for creating of new sections }
1151         FCObjSection:=TObjSection;
1152         FCObjSectionGroup:=TObjSectionGroup;
1153 {$ifdef ARM}
1154         ThumbFunc:=false;
1155 {$endif ARM}
1156       end;
1157 
1158 
1159     destructor TObjData.destroy;
1160       begin
1161         { Symbols }
1162 {$ifdef MEMDEBUG}
1163         MemObjSymbols.Start;
1164 {$endif}
1165         ResetCachedAsmSymbols;
1166         FCachedAsmSymbolList.free;
1167         FObjSymbolList.free;
1168 {$ifdef MEMDEBUG}
1169         MemObjSymbols.Stop;
1170 {$endif}
1171         GroupsList.free;
1172 
1173         { Sections }
1174 {$ifdef MEMDEBUG}
1175         MemObjSections.Start;
1176 {$endif}
1177         FObjSectionList.free;
1178 {$ifdef MEMDEBUG}
1179         MemObjSections.Stop;
1180 {$endif}
1181         inherited destroy;
1182       end;
1183 
1184 
1185     function TObjData.sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;
1186       const
1187         secoptions : array[TAsmSectiontype] of TObjSectionOptions = ([],
1188           {user} [oso_Data,oso_load,oso_write],
1189           {code} [oso_Data,oso_load,oso_executable],
1190           {Data} [oso_Data,oso_load,oso_write],
1191 { Readonly data with relocations must be initially writable for some targets.
1192   Moreover, e.g. for ELF it depends on whether the executable is linked statically or
1193   dynamically. Here we declare it writable, target-specific descendants must provide
1194   further handling. }
1195           {roData} [oso_Data,oso_load,oso_write],
1196           {roData_norel} [oso_Data,oso_load],
1197           {bss} [oso_load,oso_write],
1198           {threadvar} [oso_load,oso_write],
1199           {pdata} [oso_data,oso_load],
1200           {stub} [oso_Data,oso_load,oso_executable],
1201           {data_nonlazy}  [oso_Data,oso_load,oso_write],
1202           {data_lazy} [oso_Data,oso_load,oso_write],
1203           {init_func} [oso_Data,oso_load],
1204           {term_func} [oso_Data,oso_load],
1205           {stab} [oso_Data,oso_debug],
1206           {stabstr} [oso_Data,oso_strings,oso_debug],
1207           {iData2} [oso_Data,oso_load,oso_write],
1208           {iData4} [oso_Data,oso_load,oso_write],
1209           {iData5} [oso_Data,oso_load,oso_write],
1210           {iData6} [oso_Data,oso_load,oso_write],
1211           {iData7} [oso_Data,oso_load,oso_write],
1212           {eData} [oso_Data,oso_load],
1213           {eh_frame} [oso_Data,oso_load],
1214           {debug_frame} [oso_Data,oso_debug],
1215           {debug_info} [oso_Data,oso_debug],
1216           {debug_line} [oso_Data,oso_debug],
1217           {debug_abbrev} [oso_Data,oso_debug],
1218           {debug_aranges} [oso_Data,oso_debug],
1219           {debug_ranges} [oso_Data,oso_debug],
1220           {fpc} [oso_Data,oso_load,oso_write],
1221           {toc} [oso_Data,oso_load],
1222           {init} [oso_Data,oso_load,oso_executable],
1223           {fini} [oso_Data,oso_load,oso_executable],
1224           {objc_class} [oso_data,oso_load],
1225           {objc_meta_class} [oso_data,oso_load],
1226           {objc_cat_cls_meth} [oso_data,oso_load],
1227           {objc_cat_inst_meth} [oso_data,oso_load],
1228           {objc_protocol} [oso_data,oso_load],
1229           {objc_string_object} [oso_data,oso_load],
1230           {objc_cls_meth} [oso_data,oso_load],
1231           {objc_inst_meth} [oso_data,oso_load],
1232           {objc_cls_refs} [oso_data,oso_load],
1233           {objc_message_refs} [oso_data,oso_load],
1234           {objc_symbols} [oso_data,oso_load],
1235           {objc_category} [oso_data,oso_load],
1236           {objc_class_vars} [oso_data,oso_load],
1237           {objc_instance_vars} [oso_data,oso_load],
1238           {objc_module_info} [oso_data,oso_load],
1239           {objc_class_names} [oso_data,oso_load],
1240           {objc_meth_var_types} [oso_data,oso_load],
1241           {objc_meth_var_names} [oso_data,oso_load],
1242           {objc_selector_strs} [oso_data,oso_load],
1243           {objc_protocol_ext} [oso_data,oso_load],
1244           {objc_class_ext} [oso_data,oso_load],
1245           {objc_property} [oso_data,oso_load],
1246           {objc_image_info} [oso_data,oso_load],
1247           {objc_cstring_object} [oso_data,oso_load],
1248           {objc_sel_fixup} [oso_data,oso_load],
1249           {sec_objc_data} [oso_data,oso_load],
1250           {sec_objc_const} [oso_data,oso_load],
1251           {sec_objc_sup_refs} [oso_data,oso_load],
1252           {sec_data_coalesced} [oso_data,oso_load],
1253           {sec_objc_classlist} [oso_data,oso_load],
1254           {sec_objc_nlclasslist} [oso_data,oso_load],
1255           {sec_objc_catlist} [oso_data,oso_load],
1256           {sec_objc_nlcatlist} [oso_data,oso_load],
1257           {sec_objc_protolist'} [oso_data,oso_load],
1258           {stack} [oso_load,oso_write],
1259           {heap} [oso_load,oso_write]
1260         );
1261       begin
1262         result:=secoptions[atype];
1263       end;
1264 
1265 
TObjData.sectiontype2alignnull1266     function TObjData.sectiontype2align(atype:TAsmSectiontype):longint;
1267       begin
1268         case atype of
1269           sec_stabstr,sec_debug_info,sec_debug_line,sec_debug_abbrev,sec_debug_aranges,sec_debug_ranges:
1270             result:=1;
1271           sec_code,
1272           sec_bss,
1273           sec_data:
1274             result:=16;
1275           { For idata (at least idata2) it must be 4 bytes, because
1276             an entry is always (also in win64) 20 bytes and aligning
1277             on 8 bytes will insert 4 bytes between the entries resulting
1278             in a corrupt idata section.
1279             Same story with .pdata, it has 4-byte elements which should
1280             be packed without gaps. }
1281           sec_idata2,sec_idata4,sec_idata5,sec_idata6,sec_idata7,sec_pdata:
1282             result:=4;
1283           else
1284             result:=sizeof(pint);
1285         end;
1286       end;
1287 
1288 
TObjData.createsectionnull1289     function TObjData.createsection(atype:TAsmSectionType;const aname:string;aorder:TAsmSectionOrder):TObjSection;
1290       begin
1291         result:=createsection(sectionname(atype,aname,aorder),sectiontype2align(atype),sectiontype2options(atype));
1292       end;
1293 
1294 
TObjData.createsectionnull1295     function TObjData.createsection(const aname:string;aalign:longint;aoptions:TObjSectionOptions;DiscardDuplicate:boolean):TObjSection;
1296       begin
1297         if DiscardDuplicate then
1298           result:=TObjSection(FObjSectionList.Find(aname))
1299         else
1300           result:=nil;
1301         if not assigned(result) then
1302           begin
1303             result:=CObjSection.create(FObjSectionList,aname,aalign,aoptions);
1304             result.ObjData:=self;
1305           end;
1306         FCurrObjSec:=result;
1307       end;
1308 
1309 
TObjData.CreateSectionGroupnull1310     function TObjData.CreateSectionGroup(const aname:string):TObjSectionGroup;
1311       begin
1312         if FGroupsList=nil then
1313           FGroupsList:=TFPHashObjectList.Create(true);
1314         result:=CObjSectionGroup.Create(FGroupsList,aname);
1315       end;
1316 
1317 
1318     procedure TObjData.CreateDebugSections;
1319       begin
1320       end;
1321 
1322 
TObjData.FindSectionnull1323     function TObjData.FindSection(const aname:string):TObjSection;
1324       begin
1325         result:=TObjSection(FObjSectionList.Find(aname));
1326       end;
1327 
1328 
1329     procedure TObjData.setsection(asec:TObjSection);
1330       begin
1331         if asec.ObjData<>self then
1332           internalerror(200403041);
1333         FCurrObjSec:=asec;
1334       end;
1335 
1336 
TObjData.createsymbolnull1337     function TObjData.createsymbol(const aname:string):TObjSymbol;
1338       begin
1339         result:=TObjSymbol(FObjSymbolList.Find(aname));
1340         if not assigned(result) then
1341           result:=CObjSymbol.Create(FObjSymbolList,aname);
1342 
1343 {$ifdef ARM}
1344         result.ThumbFunc:=ThumbFunc;
1345         ThumbFunc:=false;
1346 {$endif ARM}
1347       end;
1348 
1349 
TObjData.symboldefinenull1350     function TObjData.symboldefine(asmsym:TAsmSymbol):TObjSymbol;
1351       begin
1352         if assigned(asmsym) then
1353           begin
1354             if asmsym.typ = AT_NONE then
1355               InternalError(2018062800);
1356 
1357             if not assigned(asmsym.cachedObjSymbol) then
1358               begin
1359                 result:=symboldefine(asmsym.name,asmsym.bind,asmsym.typ);
1360                 asmsym.cachedObjSymbol:=result;
1361                 FCachedAsmSymbolList.add(asmsym);
1362               end
1363             else
1364               begin
1365                 result:=TObjSymbol(asmsym.cachedObjSymbol);
1366                 result.SetAddress(CurrPass,CurrObjSec,asmsym.bind,asmsym.typ);
1367               end;
1368           end
1369         else
1370           result:=nil;
1371       end;
1372 
1373 
TObjData.symboldefinenull1374     function TObjData.symboldefine(const aname:string;abind:TAsmsymbind;atyp:Tasmsymtype):TObjSymbol;
1375       begin
1376         if not assigned(CurrObjSec) then
1377           internalerror(200603051);
1378         result:=CreateSymbol(aname);
1379         result.SetAddress(CurrPass,CurrObjSec,abind,atyp);
1380       end;
1381 
1382 
TObjData.symbolrefnull1383     function TObjData.symbolref(asmsym:TAsmSymbol):TObjSymbol;
1384       var
1385         s:string;
1386       begin
1387         if assigned(asmsym) then
1388           begin
1389             if not assigned(asmsym.cachedObjSymbol) then
1390               begin
1391                 s:=asmsym.name;
1392                 result:=TObjSymbol(FObjSymbolList.Find(s));
1393                 if result=nil then
1394                   begin
1395                     result:=CObjSymbol.Create(FObjSymbolList,s);
1396                     if asmsym.bind=AB_WEAK_EXTERNAL then
1397                       result.bind:=AB_WEAK_EXTERNAL;
1398                   end;
1399                 asmsym.cachedObjSymbol:=result;
1400                 FCachedAsmSymbolList.add(asmsym);
1401               end
1402             else
1403               result:=TObjSymbol(asmsym.cachedObjSymbol);
1404             { The weak bit could have been removed from asmsym. }
1405             if (asmsym.bind=AB_EXTERNAL) and (result.bind=AB_WEAK_EXTERNAL) then
1406               result.bind:=AB_EXTERNAL;
1407           end
1408         else
1409           result:=nil;
1410       end;
1411 
1412 
TObjData.symbolrefnull1413     function TObjData.symbolref(const aname:string):TObjSymbol;
1414       begin
1415         if not assigned(CurrObjSec) then
1416           internalerror(200603052);
1417         result:=CreateSymbol(aname);
1418       end;
1419 
1420 
1421     procedure TObjData.ResetCachedAsmSymbols;
1422       var
1423         i  : longint;
1424       begin
1425         for i:=0 to FCachedAsmSymbolList.Count-1 do
1426           tasmsymbol(FCachedAsmSymbolList[i]).cachedObjSymbol:=nil;
1427         FCachedAsmSymbolList.Clear;
1428       end;
1429 
1430 
1431     procedure TObjData.writebytes(const Data;len:aword);
1432       begin
1433         if not assigned(CurrObjSec) then
1434           internalerror(200402251);
1435         CurrObjSec.write(Data,len);
1436       end;
1437 
1438 
1439     procedure TObjData.alloc(len:aword);
1440       begin
1441         if not assigned(CurrObjSec) then
1442           internalerror(200402252);
1443         CurrObjSec.alloc(len);
1444       end;
1445 
1446 
1447     procedure TObjData.allocalign(len:longint);
1448       begin
1449         if not assigned(CurrObjSec) then
1450           internalerror(200402253);
1451         CurrObjSec.alloc(align_objsecofs(CurrObjSec.size,len)-CurrObjSec.size);
1452       end;
1453 
1454 
1455     procedure TObjData.section_afteralloc(p:TObject;arg:pointer);
1456       begin
1457         with TObjSection(p) do
1458           alloc(align_objsecofs(size,secalign)-size);
1459       end;
1460 
1461 
1462     procedure TObjData.section_afterwrite(p:TObject;arg:pointer);
1463       begin
1464         with TObjSection(p) do
1465           begin
1466             if assigned(Data) then
1467               writezeros(align_objsecofs(size,secalign)-size);
1468           end;
1469       end;
1470 
1471 
1472     procedure TObjData.section_reset(p:TObject;arg:pointer);
1473       begin
1474         with TObjSection(p) do
1475           begin
1476             Size:=0;
1477             Datapos:=0;
1478             mempos:=0;
1479             if assigned(Data) then
1480               Data.reset;
1481           end;
1482       end;
1483 
1484 
1485     procedure TObjData.beforealloc;
1486       begin
1487         FCPUType:=current_settings.cputype;
1488         { create stabs sections if debugging }
1489         if assigned(StabsSec) then
1490           begin
1491             StabsSec.Alloc(sizeof(TObjStabEntry));
1492             StabStrSec.Alloc(1);
1493           end;
1494       end;
1495 
1496 
1497     procedure TObjData.beforewrite;
1498       begin
1499         FCPUType:=current_settings.cputype;
1500         { create stabs sections if debugging }
1501         if assigned(StabsSec) then
1502          begin
1503            { Create dummy HdrSym stab, it will be overwritten in AfterWrite }
1504            StabsSec.WriteZeros(sizeof(TObjStabEntry));
1505            { start of stabstr }
1506            StabStrSec.writeZeros(1);
1507          end;
1508       end;
1509 
1510 
1511     procedure TObjData.afteralloc;
1512       begin
1513         FObjSectionList.ForEachCall(@section_afteralloc,nil);
1514       end;
1515 
1516 
1517     procedure TObjData.afterwrite;
1518       var
1519         hstab : TObjStabEntry;
1520       begin
1521         FObjSectionList.ForEachCall(@section_afterwrite,nil);
1522         { For the stab section we need an HdrSym which can now be
1523           calculated more easily }
1524         if assigned(StabsSec) then
1525           begin
1526             { end of stabstr }
1527             StabStrSec.writeZeros(1);
1528             { header stab }
1529             hstab.strpos:=1;
1530             hstab.ntype:=0;
1531             hstab.nother:=0;
1532 {$push}{$R-}
1533             { for jwawindows.pas, this causes an range check error, it contains too much stab symbols }
1534             hstab.ndesc:=(StabsSec.Size div sizeof(TObjStabEntry))-1;
1535 {$pop}
1536             hstab.nvalue:=StabStrSec.Size;
1537             MaybeSwapStab(hstab);
1538             StabsSec.Data.seek(0);
1539             StabsSec.Data.write(hstab,sizeof(hstab));
1540           end;
1541       end;
1542 
1543 
1544     procedure TObjData.resetsections;
1545       begin
1546         FObjSectionList.ForEachCall(@section_reset,nil);
1547       end;
1548 
1549 
1550     procedure TObjData.layoutsections(var DataPos:TObjSectionOfs);
1551       var
1552         i: longint;
1553       begin
1554         for i:=0 to FObjSectionList.Count-1 do
1555           TObjSection(FObjSectionList[i]).setDatapos(DataPos);
1556       end;
1557 
1558 
1559 {****************************************************************************
1560                                 TObjOutput
1561 ****************************************************************************}
1562 
1563     constructor TObjOutput.create(AWriter:TObjectWriter);
1564       begin
1565         FWriter:=AWriter;
1566         CObjData:=TObjData;
1567       end;
1568 
1569 
1570     destructor TObjOutput.destroy;
1571       begin
1572         inherited destroy;
1573       end;
1574 
1575 
TObjOutput.newObjDatanull1576     function TObjOutput.newObjData(const n:string):TObjData;
1577       begin
1578         result:=CObjData.create(n);
1579         if (cs_use_lineinfo in current_settings.globalswitches) or
1580            (cs_debuginfo in current_settings.moduleswitches) then
1581           result.CreateDebugSections;
1582       end;
1583 
1584 
TObjOutput.startObjectfilenull1585     function TObjOutput.startObjectfile(const fn:string):boolean;
1586       begin
1587         result:=false;
1588         { start the writer already, so the .a generation can initialize
1589           the position of the current objectfile }
1590         if not FWriter.createfile(fn) then
1591          Comment(V_Fatal,'Can''t create object '+fn);
1592         result:=true;
1593       end;
1594 
1595 
TObjOutput.writeobjectfilenull1596     function TObjOutput.writeobjectfile(Data:TObjData):boolean;
1597       begin
1598         if errorcount=0 then
1599          result:=writeData(Data)
1600         else
1601          result:=true;
1602         { close the writer }
1603         FWriter.closefile;
1604       end;
1605 
1606 
1607     procedure TObjOutput.exportsymbol(p:TObjSymbol);
1608       begin
1609         { export globals and common symbols, this is needed
1610           for .a files }
1611         if p.bind in [AB_GLOBAL,AB_COMMON] then
1612          FWriter.writesym(p.name);
1613       end;
1614 
1615     procedure TObjOutput.WriteSectionContent(Data:TObjData);
1616       var
1617         i:longint;
1618         sec:TObjSection;
1619       begin
1620         for i:=0 to Data.ObjSectionList.Count-1 do
1621           begin
1622             sec:=TObjSection(Data.ObjSectionList[i]);
1623             if (oso_data in sec.SecOptions) then
1624               begin
1625                 if sec.Data=nil then
1626                   internalerror(200403073);
1627                 FWriter.writezeros(sec.dataalignbytes);
1628                 if sec.Datapos<>FWriter.ObjSize then
1629                   internalerror(200604031);
1630                 FWriter.writearray(sec.data);
1631               end;
1632           end;
1633       end;
1634 
1635 {****************************************************************************
1636                                  TExeVTable
1637 ****************************************************************************}
1638 
1639     constructor TExeVTable.Create(AExeSymbol:TExeSymbol);
1640       begin
1641         ExeSymbol:=AExeSymbol;
1642         if ExeSymbol.State=symstate_undefined then
1643           internalerror(200604012);
1644         ChildList:=TFPObjectList.Create(false);
1645       end;
1646 
1647 
1648     destructor TExeVTable.Destroy;
1649       begin
1650         ChildList.Free;
1651         if assigned(EntryArray) then
1652           Freemem(EntryArray);
1653       end;
1654 
1655 
1656     procedure TExeVTable.CheckIdx(VTableIdx:longint);
1657       var
1658         OldEntryCnt : longint;
1659       begin
1660         if VTableIdx>=EntryCnt then
1661           begin
1662             OldEntryCnt:=EntryCnt;
1663             EntryCnt:=VTableIdx+1;
1664             ReAllocMem(EntryArray,EntryCnt*sizeof(TVTableEntry));
1665             FillChar(EntryArray[OldEntryCnt],(EntryCnt-OldEntryCnt)*sizeof(TVTableEntry),0);
1666           end;
1667       end;
1668 
1669 
1670     procedure TExeVTable.AddChild(vt:TExeVTable);
1671       begin
1672         ChildList.Add(vt);
1673       end;
1674 
1675 
1676     procedure TExeVTable.AddEntry(VTableIdx:Longint);
1677       var
1678         i : longint;
1679         objreloc : TObjRelocation;
1680         vtblentryoffset : aword;
1681       begin
1682         CheckIdx(VTableIdx);
1683         vtblentryoffset:=ExeSymbol.ObjSymbol.Offset+longword(VTableIdx)*sizeof(pint);
1684         { Find and disable relocation }
1685         for i:=0 to ExeSymbol.ObjSymbol.ObjSection.ObjRelocations.Count-1 do
1686           begin
1687             objreloc:=TObjRelocation(ExeSymbol.ObjSymbol.ObjSection.ObjRelocations[i]);
1688             if objreloc.dataoffset=vtblentryoffset then
1689               begin
1690                 EntryArray[VTableIdx].ObjRelocation:=objreloc;
1691                 EntryArray[VTableIdx].OrgRelocType:=objreloc.ftype;
1692                 EntryArray[VTableIdx].OrgRelocFlags:=objreloc.flags;
1693                 objreloc.typ:=RELOC_ZERO;
1694                 objreloc.flags:=objreloc.flags or rf_nosymbol;
1695                 break;
1696               end;
1697           end;
1698         if not assigned(EntryArray[VTableIdx].ObjRelocation) then
1699           internalerror(200604011);
1700       end;
1701 
1702 
1703     procedure TExeVTable.SetVTableSize(ASize:longint);
1704       begin
1705         if EntryCnt<>0 then
1706           internalerror(200603313);
1707         EntryCnt:=ASize div sizeof(pint);
1708         EntryArray:=AllocMem(EntryCnt*sizeof(TVTableEntry));
1709       end;
1710 
1711 
TExeVTable.VTableRefnull1712     function TExeVTable.VTableRef(VTableIdx:Longint):TObjRelocation;
1713       begin
1714         result:=nil;
1715         CheckIdx(VTableIdx);
1716         if EntryArray[VTableIdx].Used then
1717           exit;
1718         { Restore relocation if available }
1719         if assigned(EntryArray[VTableIdx].ObjRelocation) then
1720           begin
1721             EntryArray[VTableIdx].ObjRelocation.ftype:=EntryArray[VTableIdx].OrgRelocType;
1722             EntryArray[VTableIdx].ObjRelocation.flags:=EntryArray[VTableIdx].OrgRelocFlags;
1723             result:=EntryArray[VTableIdx].ObjRelocation;
1724           end;
1725         EntryArray[VTableIdx].Used:=true;
1726       end;
1727 
1728 
1729 {****************************************************************************
1730                                 TExeSection
1731 ****************************************************************************}
1732 
1733     constructor TExeSection.create(AList:TFPHashObjectList;const AName:string);
1734       begin
1735         inherited create(AList,AName);
1736         Size:=0;
1737         MemPos:=0;
1738         DataPos:=0;
1739         FSecSymIdx:=0;
1740         FObjSectionList:=TFPObjectList.Create(false);
1741       end;
1742 
1743 
1744     destructor TExeSection.destroy;
1745       begin
1746         ObjSectionList.Free;
1747         inherited destroy;
1748       end;
1749 
1750 
1751     procedure TExeSection.AddObjSection(objsec:TObjSection;ignoreprops:boolean);
1752       begin
1753         ObjSectionList.Add(objsec);
1754         { relate ObjSection to ExeSection, and mark it Used by default }
1755         objsec.ExeSection:=self;
1756         objsec.Used:=true;
1757         if ignoreprops then
1758           exit;
1759         if (SecOptions<>[]) then
1760           begin
1761             { Only if the section contains (un)initialized data the
1762               data flag must match. }
1763             if ((oso_Data in SecOptions)<>(oso_Data in objsec.SecOptions)) then
1764               Comment(V_Error,'Incompatible section options');
1765           end
1766         else
1767           begin
1768             { inherit section options }
1769             SecOptions:=SecOptions+objsec.SecOptions;
1770           end;
1771         SecAlign:=max(objsec.SecAlign,SecAlign);
1772       end;
1773 
1774 
1775 {****************************************************************************
1776                                 TStaticLibrary
1777 ****************************************************************************}
1778 
1779     constructor TStaticLibrary.create(const AName:TCmdStr;AReader:TObjectReader;AObjInputClass:TObjInputClass);
1780       begin
1781         FName:=AName;
1782         FPayload:=AReader;
1783         FObjInputClass:=AObjInputClass;
1784         FKind:=lkArchive;
1785       end;
1786 
1787 
1788     constructor TStaticLibrary.create_object(AObjData:TObjData);
1789       begin
1790         FPayload:=AObjData;
1791         FKind:=lkObject;
1792       end;
1793 
1794 
1795     constructor TStaticLibrary.create_group;
1796       begin
1797         FPayload:=TFPObjectList.Create(true);
1798         FKind:=lkGroup;
1799       end;
1800 
1801 
1802     destructor TStaticLibrary.destroy;
1803       begin
1804         FPayload.Free;
1805         inherited destroy;
1806       end;
1807 
1808 
TStaticLibrary.GetArReadernull1809     function TStaticLibrary.GetArReader: TObjectReader;
1810       begin
1811         if (FKind<>lkArchive) then
1812           InternalError(2012071501);
1813         result:=TObjectReader(FPayload);
1814       end;
1815 
1816 
TStaticLibrary.GetGroupMembersnull1817     function TStaticLibrary.GetGroupMembers: TFPObjectList;
1818       begin
1819         if (FKind<>lkGroup) then
1820           InternalError(2012071502);
1821         result:=TFPObjectList(FPayload);
1822       end;
1823 
1824 
TStaticLibrary.GetObjDatanull1825     function TStaticLibrary.GetObjData: TObjData;
1826       begin
1827         if (FKind<>lkObject) then
1828           InternalError(2012071503);
1829         result:=TObjData(FPayload);
1830       end;
1831 
1832 {****************************************************************************
1833                                 TImportLibrary
1834 ****************************************************************************}
1835 
1836     constructor TImportLibrary.create(AList:TFPHashObjectList;const AName:string);
1837       begin
1838         inherited create(AList,AName);
1839         FImportSymbolList:=TFPHashObjectList.Create(true);
1840       end;
1841 
1842 
1843     destructor TImportLibrary.destroy;
1844       begin
1845         ImportSymbolList.Free;
1846         inherited destroy;
1847       end;
1848 
1849 
1850 {****************************************************************************
1851                                 TImportSymbol
1852 ****************************************************************************}
1853 
1854     constructor TImportSymbol.create(AList:TFPHashObjectList;
1855             const AName,AMangledName:string;AOrdNr:longint;AIsVar:boolean);
1856       begin
1857         inherited Create(AList, AName);
1858         FOrdNr:=AOrdNr;
1859         FIsVar:=AIsVar;
1860         FMangledName:=AMangledName;
1861         { Replace ? and @ in import name, since GNU AS does not allow these characters in symbol names. }
1862         { This allows to import VC++ mangled names from DLLs. }
1863         if target_info.system in systems_all_windows then
1864           begin
1865             Replace(FMangledName,'?','__q$$');
1866 {$ifdef arm}
1867             { @ symbol is not allowed in ARM assembler only }
1868             Replace(FMangledName,'@','__a$$');
1869 {$endif arm}
1870           end;
1871       end;
1872 
1873 
1874 {****************************************************************************
1875                                 TExeOutput
1876 ****************************************************************************}
1877 
1878     constructor TExeOutput.create;
1879       begin
1880         { init writer }
1881         FWriter:=TObjectwriter.create;
1882         FExeWriteMode:=ewm_exefull;
1883         { object files }
1884         FObjDataList:=TFPObjectList.Create(true);
1885         { symbols }
1886         FExeSymbolList:=TFPHashObjectList.Create(true);
1887         FUnresolvedExeSymbols:=TFPObjectList.Create(false);
1888         FExternalObjSymbols:=TFPObjectList.Create(false);
1889         FCommonObjSymbols:=TFPObjectList.Create(false);
1890         FProvidedObjSymbols:=TFPObjectList.Create(false);
1891         FIndirectObjSymbols:=TFPObjectList.Create(false);
1892         FExeVTableList:=TFPObjectList.Create(false);
1893         ComdatGroups:=TFPHashList.Create;
1894         { sections }
1895         FExeSectionList:=TFPHashObjectList.Create(true);
1896         FImageBase:=0;
1897 {$ifdef cpu16bitaddr}
1898         SectionMemAlign:=$10;
1899         SectionDataAlign:=$10;
1900 {$else cpu16bitaddr}
1901         SectionMemAlign:=$1000;
1902         SectionDataAlign:=$200;
1903 {$endif cpu16bitaddr}
1904         FixedSectionAlign:=True;
1905         FCExeSection:=TExeSection;
1906         FCObjData:=TObjData;
1907         FCObjSymbol:=TObjSymbol;
1908       end;
1909 
1910 
1911     destructor TExeOutput.destroy;
1912       begin
1913         FExeSymbolList.free;
1914         UnresolvedExeSymbols.free;
1915         ExternalObjSymbols.free;
1916         FProvidedObjSymbols.free;
1917         FIndirectObjSymbols.free;
1918         CommonObjSymbols.free;
1919         ExeVTableList.free;
1920         FExeSectionList.free;
1921         ComdatGroups.free;
1922         ObjDatalist.free;
1923         FWriter.free;
1924         inherited destroy;
1925       end;
1926 
1927 
TExeOutput.MemAlignnull1928     function TExeOutput.MemAlign(exesec:TExeSection):longword;
1929       begin
1930         if FixedSectionAlign then
1931           result:=SectionMemAlign
1932         else
1933           result:=exesec.SecAlign;
1934       end;
1935 
1936 
TExeOutput.DataAlignnull1937     function TExeOutput.DataAlign(exesec:TExeSection):longword;
1938       begin
1939         if FixedSectionAlign then
1940           result:=SectionDataAlign
1941         else
1942           result:=exesec.SecAlign;
1943       end;
1944 
1945 
TExeOutput.WriteExeFilenull1946     function TExeOutput.WriteExeFile(const fn:string):boolean;
1947       begin
1948         result:=false;
1949         if FWriter.createfile(fn) then
1950          begin
1951            { Only write the .o if there are no errors }
1952            if errorcount=0 then
1953              result:=writedata
1954            else
1955              result:=true;
1956            { close the writer }
1957            FWriter.closefile;
1958          end
1959         else
1960          Comment(V_Fatal,'Can''t create executable '+fn);
1961       end;
1962 
1963 
1964     procedure TExeOutput.ParseScript (linkscript:TCmdStrList);
1965       begin
1966       end;
1967 
1968 
TExeOutput.FindExeSectionnull1969     function  TExeOutput.FindExeSection(const aname:string):TExeSection;
1970       begin
1971         result:=TExeSection(ExeSectionList.Find(aname));
1972       end;
1973 
1974 
1975     procedure TExeOutput.AddObjData(ObjData:TObjData);
1976       begin
1977         if ObjData.classtype<>FCObjData then
1978           Comment(V_Error,'Invalid input object format for '+ObjData.name+' got '+ObjData.classname+' expected '+FCObjData.classname);
1979         ObjDataList.Add(ObjData);
1980         ExecStack:=ExecStack or ObjData.ExecStack;
1981       end;
1982 
1983 
1984     procedure TExeOutput.Load_Start;
1985       begin
1986         ObjDataList.Clear;
1987         { Globals defined in the linker script }
1988         if not assigned(internalObjData) then
1989           internalObjData:=CObjData.create('*Internal*');
1990         AddObjData(internalObjData);
1991         { Common Data section }
1992         commonObjSection:=internalObjData.createsection(sec_bss,'');
1993       end;
1994 
1995 
1996     procedure TExeOutput.Load_EntryName(const aname:string);
1997       begin
1998         FEntryName:=aname;
1999       end;
2000 
2001 
2002     procedure TExeOutput.Load_IsSharedLibrary;
2003       begin
2004         IsSharedLibrary:=true;
2005       end;
2006 
2007 
2008     procedure TExeOutput.Load_ImageBase(const avalue:string);
2009       var
2010         code : integer;
2011         objsec : TObjSection;
2012         objsym : TObjSymbol;
2013         exesym : TExeSymbol;
2014       begin
2015         val(avalue,FImageBase,code);
2016         if code<>0 then
2017           Comment(V_Error,'Invalid number '+avalue);
2018         { Create __image_base__ symbol, create the symbol
2019           in a section with adress 0 and at offset 0 }
2020         objsec:=internalObjData.createsection('*__image_base__',0,[]);
2021         internalObjData.setsection(objsec);
2022         objsym:=internalObjData.SymbolDefine('__image_base__',AB_GLOBAL,AT_DATA);
2023         exesym:=texesymbol.Create(FExeSymbolList,objsym.name);
2024         exesym.ObjSymbol:=objsym;
2025       end;
2026 
2027 
2028     procedure TExeOutput.Load_Symbol(const aname:string);
2029       begin
2030         internalObjData.createsection('*'+aname,0,[]);
2031         internalObjData.SymbolDefine(aname,AB_GLOBAL,AT_DATA);
2032       end;
2033 
2034     procedure TExeOutput.Load_ProvideSymbol(const aname:string);
2035       begin
2036         if assigned(ExeSymbolList.Find(aname)) then
2037           exit;
2038         internalObjData.createsection('*'+aname,0,[]);
2039         // Use AB_COMMON to avoid muliple defined complaints
2040         internalObjData.SymbolDefine(aname,AB_COMMON,AT_DATA);
2041       end;
2042 
2043 
2044     procedure TExeOutput.Load_DynamicObject(ObjData:TObjData;asneeded:boolean);
2045       begin
2046       end;
2047 
2048 
2049     procedure TExeOutput.Order_Start;
2050       begin
2051       end;
2052 
2053 
2054     procedure TExeOutput.Order_End;
2055       begin
2056         internalObjData.afterwrite;
2057       end;
2058 
2059 
2060     procedure TExeOutput.Order_ExeSection(const aname:string);
2061       var
2062         sec : TExeSection;
2063       begin
2064         sec:=FindExeSection(aname);
2065         if not assigned(sec) then
2066           sec:=CExeSection.create(ExeSectionList,aname);
2067         { Clear ExeSection contents }
2068         FCurrExeSec:=sec;
2069       end;
2070 
2071 
2072     procedure TExeOutput.Order_EndExeSection;
2073       begin
2074         if not assigned(CurrExeSec) then
2075           internalerror(200602184);
2076         FCurrExeSec:=nil;
2077       end;
2078 
2079 
2080     procedure TExeOutput.Order_ObjSection(const aname:string);
2081       var
2082         i,j     : longint;
2083         ObjData : TObjData;
2084         objsec  : TObjSection;
2085         TmpObjSectionList : TFPObjectList;
2086       begin
2087         if not assigned(CurrExeSec) then
2088           internalerror(200602181);
2089         TmpObjSectionList:=TFPObjectList.Create(false);
2090         for i:=0 to ObjDataList.Count-1 do
2091           begin
2092             ObjData:=TObjData(ObjDataList[i]);
2093             for j:=0 to ObjData.ObjSectionList.Count-1 do
2094               begin
2095                 objsec:=TObjSection(ObjData.ObjSectionList[j]);
2096                 if (not objsec.Used) and
2097                    MatchPattern(aname,objsec.name) then
2098                   TmpObjSectionList.Add(objsec);
2099               end;
2100           end;
2101         { Order list if needed }
2102         Order_ObjSectionList(TmpObjSectionList,aname);
2103         { Add the (ordered) list to the current ExeSection }
2104         for i:=0 to TmpObjSectionList.Count-1 do
2105           begin
2106             objsec:=TObjSection(TmpObjSectionList[i]);
2107             CurrExeSec.AddObjSection(objsec);
2108           end;
2109         TmpObjSectionList.Free;
2110       end;
2111 
2112 
2113     procedure TExeOutput.Order_ObjSectionList(ObjSectionList : TFPObjectList; const aPattern:string);
2114       begin
2115       end;
2116 
2117 
2118     procedure TExeOutput.Order_Symbol(const aname:string);
2119       var
2120         objsym: TObjSymbol;
2121       begin
2122         objsym:=TObjSymbol(internalObjData.ObjSymbolList.Find(aname));
2123         if (objsym=nil) or (objsym.ObjSection.ObjData<>internalObjData) then
2124           internalerror(200603041);
2125         CurrExeSec.AddObjSection(objsym.ObjSection,True);
2126       end;
2127 
2128     procedure TExeOutput.Order_ProvideSymbol(const aname:string);
2129       var
2130         objsym : TObjSymbol;
2131         exesym : TExeSymbol;
2132       begin
2133         objsym:=TObjSymbol(internalObjData.ObjSymbolList.Find(aname));
2134         if (objsym=nil) or (objsym.ObjSection.ObjData<>internalObjData) then
2135           internalerror(200603041);
2136         exesym:=TExeSymbol(ExeSymbolList.Find(aname));
2137         if not assigned(exesym) then
2138           internalerror(201206301);
2139         { Only include this section if it actually resolves
2140           the symbol }
2141         if exesym.objsymbol=objsym then
2142           CurrExeSec.AddObjSection(objsym.ObjSection,True);
2143       end;
2144 
2145 
2146     procedure TExeOutput.Order_Align(const avalue:string);
2147       var
2148         code     : integer;
2149         alignval : shortint;
2150         objsec   : TObjSection;
2151       begin
2152         val(avalue,alignval,code);
2153         if code<>0 then
2154           Comment(V_Error,'Invalid number '+avalue);
2155         if alignval<=0 then
2156           exit;
2157         { Create an empty section with the required aligning }
2158         inc(Fzeronr);
2159         objsec:=internalObjData.createsection('*align'+tostr(Fzeronr),alignval,CurrExeSec.SecOptions+[oso_Data,oso_keep]);
2160         CurrExeSec.AddObjSection(objsec);
2161       end;
2162 
2163 
2164     procedure TExeOutput.Order_Zeros(const avalue:string);
2165       var
2166         zeros : array[0..1023] of byte;
2167         code  : integer;
2168         len   : longint;
2169         objsec : TObjSection;
2170       begin
2171         val(avalue,len,code);
2172         if code<>0 then
2173           Comment(V_Error,'Invalid number '+avalue);
2174         if len<=0 then
2175           exit;
2176         if len>sizeof(zeros) then
2177           internalerror(200602254);
2178         fillchar(zeros,len,0);
2179         inc(Fzeronr);
2180         objsec:=internalObjData.createsection('*zeros'+tostr(Fzeronr),0,CurrExeSec.SecOptions+[oso_Data,oso_keep]);
2181         internalObjData.writebytes(zeros,len);
2182         CurrExeSec.AddObjSection(objsec);
2183       end;
2184 
2185     procedure TExeOutput.Order_Values(bytesize : aword; const avalue:string);
2186       const
2187         MAXVAL = 128;
2188       var
2189         bytevalues : array[0..MAXVAL-1] of byte;
2190         twobytevalues : array[0..MAXVAL-1] of word;
2191         fourbytevalues : array[0..MAXVAL-1] of dword;
2192         eightbytevalues : array[0..MAXVAL-1] of qword;
2193         allvals, oneval : string;
2194         len, commapos : longint;
2195         indexpos, code  : integer;
2196         anumval : qword;
2197         signedval : int64;
2198         objsec : TObjSection;
2199       begin
2200         indexpos:=0;
2201         allvals:=avalue;
2202         { avoid warnings }
2203         bytevalues[0]:=0;
2204         twobytevalues[0]:=0;
2205         fourbytevalues[0]:=0;
2206         eightbytevalues[0]:=0;
2207         repeat
2208           commapos:=pos(',',allvals);
2209           if commapos>0 then
2210             begin
2211               oneval:=trim(copy(allvals,1,commapos-1));
2212               allvals:=copy(allvals,commapos+1,length(allvals));
2213             end
2214           else
2215             begin
2216               oneval:=trim(allvals);
2217               allvals:='';
2218             end;
2219           if oneval<>'' then
2220             begin
2221               if oneval[1]='-' then
2222                 begin
2223                   val(oneval,signedval,code);
2224                   anumval:=qword(signedval);
2225                 end
2226               else
2227                 val(oneval,anumval,code);
2228               if code<>0 then
2229                 Comment(V_Error,'Invalid number '+avalue)
2230               else
2231                 begin
2232                   if (indexpos<MAXVAL) then
2233                     begin
2234                       if source_info.endian<>target_info.endian then
2235                         swapendian(anumval);
2236                       { No range checking here }
2237 
2238                       if bytesize=1 then
2239                         bytevalues[indexpos]:=byte(anumval)
2240                       else if bytesize=2 then
2241                         twobytevalues[indexpos]:=word(anumval)
2242                       else if bytesize=4 then
2243                         fourbytevalues[indexpos]:=dword(anumval)
2244                       else if bytesize=8 then
2245                         eightbytevalues[indexpos]:=anumval;
2246                       inc(indexpos);
2247                     end
2248                   else
2249                     Comment(V_Error,'Buffer overrun in Order_values');
2250                 end;
2251             end;
2252         until allvals='';
2253         if indexpos=0 then
2254           begin
2255             Comment(V_Error,'Invalid number '+avalue);
2256             exit;
2257           end;
2258         if indexpos=MAXVAL then
2259           begin
2260             Comment(V_Error,'Too many values '+avalue);
2261             internalerror(200602254);
2262           end;
2263         len:=bytesize*indexpos;
2264         inc(Fvaluesnr);
2265         objsec:=internalObjData.createsection('*values'+tostr(Fvaluesnr),0,CurrExeSec.SecOptions+[oso_Data,oso_keep]);
2266         if bytesize=1 then
2267           internalObjData.writebytes(bytevalues,len)
2268         else if bytesize=2 then
2269           internalObjData.writebytes(twobytevalues,len)
2270         else if bytesize=4 then
2271           internalObjData.writebytes(fourbytevalues,len)
2272         else if bytesize=8 then
2273           internalObjData.writebytes(eightbytevalues,len);
2274         CurrExeSec.AddObjSection(objsec);
2275       end;
2276 
2277 
2278     procedure TExeOutput.MemPos_Start;
2279       begin
2280         CurrMemPos:=0;
2281         RemoveDisabledSections;
2282       end;
2283 
2284 
2285     procedure TExeOutput.MemPos_Header;
2286       begin
2287       end;
2288 
2289 
2290     procedure TExeOutput.MemPos_ExeSection(exesec:TExeSection);
2291       var
2292         i      : longint;
2293         objsec : TObjSection;
2294       begin
2295         { Alignment of ExeSection }
2296         CurrMemPos:=align_qword(CurrMemPos,MemAlign(exesec));
2297         exesec.MemPos:=CurrMemPos;
2298 
2299         { set position of object ObjSections }
2300         for i:=0 to exesec.ObjSectionList.Count-1 do
2301           begin
2302             objsec:=TObjSection(exesec.ObjSectionList[i]);
2303             CurrMemPos:=objsec.setmempos(CurrMemPos);
2304           end;
2305 
2306         { calculate size of the section }
2307         exesec.Size:=CurrMemPos-exesec.MemPos;
2308       end;
2309 
2310 
2311     procedure TExeOutput.MemPos_ExeSection(const aname:string);
2312       begin
2313         { Section can be removed }
2314         FCurrExeSec:=FindExeSection(aname);
2315         if not assigned(CurrExeSec) then
2316           exit;
2317 
2318         MemPos_ExeSection(CurrExeSec);
2319       end;
2320 
2321 
2322     procedure TExeOutput.MemPos_EndExeSection;
2323       begin
2324         if not assigned(CurrExeSec) then
2325           exit;
2326         FCurrExeSec:=nil;
2327       end;
2328 
2329 
2330     procedure TExeOutput.DataPos_Start;
2331       begin
2332       end;
2333 
2334 
2335     procedure TExeOutput.DataPos_Header;
2336       begin
2337       end;
2338 
2339 
2340     procedure TExeOutput.DataPos_ExeSection(exesec:TExeSection);
2341       begin
2342         { don't write normal section if writing only debug info }
2343         if (ExeWriteMode=ewm_dbgonly) and
2344            (exesec.SecOptions*[oso_debug,oso_debug_copy]=[]) then
2345           exit;
2346 
2347         if (oso_Data in exesec.SecOptions) then
2348           begin
2349             CurrDataPos:=align_aword(CurrDataPos,DataAlign(exesec));
2350             exesec.DataPos:=CurrDataPos;
2351             CurrDataPos:=CurrDataPos+exesec.Size;
2352           end;
2353       end;
2354 
2355 
2356     procedure TExeOutput.DataPos_ExeSection(const aname:string);
2357       begin
2358         { Section can be removed }
2359         FCurrExeSec:=FindExeSection(aname);
2360         if not assigned(CurrExeSec) then
2361           exit;
2362         DataPos_ExeSection(CurrExeSec);
2363       end;
2364 
2365 
2366     procedure TExeOutput.DataPos_EndExeSection;
2367       begin
2368         if not assigned(CurrExeSec) then
2369           exit;
2370         FCurrExeSec:=nil;
2371       end;
2372 
2373 
2374     procedure TExeOutput.DataPos_Symbols;
2375       begin
2376       end;
2377 
2378 
2379     procedure TExeOutput.BuildVTableTree(VTInheritList,VTEntryList:TFPObjectList);
2380       var
2381         hs : string;
2382         code : integer;
2383         i,k,
2384         vtableidx : longint;
2385         vtableexesym,
2386         childexesym,
2387         parentexesym : TExeSymbol;
2388         objsym : TObjSymbol;
2389       begin
2390         { Build inheritance tree from VTINHERIT }
2391         for i:=0 to VTInheritList.Count-1 do
2392           begin
2393             objsym:=TObjSymbol(VTInheritList[i]);
2394             hs:=objsym.name;
2395             { VTINHERIT_<ChildVMTName>$$<ParentVMTName> }
2396             Delete(hs,1,Pos('_',hs));
2397             k:=Pos('$$',hs);
2398             if k=0 then
2399               internalerror(200603311);
2400             childexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,1,k-1)));
2401             parentexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,k+2,length(hs)-k-1)));
2402             if not assigned(childexesym) or
2403                not assigned(parentexesym)then
2404               internalerror(200603312);
2405             if not assigned(childexesym.vtable) then
2406               begin
2407                 childexesym.vtable:=TExeVTable.Create(childexesym);
2408                 ExeVTableList.Add(childexesym.vtable);
2409               end;
2410             if not assigned(parentexesym.vtable) then
2411               begin
2412                 parentexesym.vtable:=TExeVTable.Create(parentexesym);
2413                 ExeVTableList.Add(parentexesym.vtable);
2414               end;
2415             childexesym.vtable.SetVTableSize(childexesym.ObjSymbol.Size);
2416             if parentexesym<>childexesym then
2417               parentexesym.vtable.AddChild(childexesym.vtable);
2418           end;
2419 
2420         { Find VTable entries from VTENTRY }
2421         for i:=0 to VTEntryList.Count-1 do
2422           begin
2423             objsym:=TObjSymbol(VTEntryList[i]);
2424             hs:=objsym.name;
2425             { VTENTRY_<VTableName>$$<Index> }
2426             Delete(hs,1,Pos('_',hs));
2427             k:=Pos('$$',hs);
2428             if k=0 then
2429               internalerror(200603319);
2430             vtableexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,1,k-1)));
2431             val(Copy(hs,k+2,length(hs)-k-1),vtableidx,code);
2432             if (code<>0) then
2433               internalerror(200603318);
2434             if not assigned(vtableexesym) then
2435               internalerror(2006033110);
2436             vtableexesym.vtable.AddEntry(vtableidx);
2437           end;
2438       end;
2439 
2440 
2441     procedure TExeOutput.PackUnresolvedExeSymbols(const s:string);
2442       var
2443         i : longint;
2444         exesym : TExeSymbol;
2445       begin
2446         { Generate a list of Unresolved External symbols }
2447         for i:=0 to UnresolvedExeSymbols.count-1 do
2448           begin
2449             exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
2450             if not (exesym.State in [symstate_undefined,symstate_undefweak]) then
2451               UnresolvedExeSymbols[i]:=nil;
2452           end;
2453         UnresolvedExeSymbols.Pack;
2454         Comment(V_Debug,'Number of unresolved externals '+s+' '+tostr(UnresolvedExeSymbols.Count));
2455       end;
2456 
2457 
2458     procedure TExeOutput.ResolveSymbols(StaticLibraryList:TFPObjectList);
2459       var
2460         ObjData   : TObjData;
2461         exesym    : TExeSymbol;
2462         objsym,
2463         commonsym : TObjSymbol;
2464         firstarchive,
2465         firstcommon : boolean;
2466         i         : longint;
2467         VTEntryList,
2468         VTInheritList : TFPObjectList;
2469 
2470         procedure LoadObjDataSymbols(ObjData:TObjData);
2471         var
2472           j      : longint;
2473           hs     : string;
2474           exesym : TExeSymbol;
2475           objsym : TObjSymbol;
2476           grp    : TObjSectionGroup;
2477         begin
2478           for j:=0 to ObjData.ObjSymbolList.Count-1 do
2479             begin
2480               objsym:=TObjSymbol(ObjData.ObjSymbolList[j]);
2481               { From the local symbols we are only interressed in the
2482                 VTENTRY and VTINHERIT symbols }
2483               if objsym.bind=AB_LOCAL then
2484                 begin
2485                   if cs_link_opt_vtable in current_settings.globalswitches then
2486                     begin
2487                       hs:=objsym.name;
2488                       if (hs[1]='V') then
2489                         begin
2490                           if Copy(hs,1,5)='VTREF' then
2491                             begin
2492                               if not assigned(objsym.ObjSection.VTRefList) then
2493                                 objsym.ObjSection.VTRefList:=TFPObjectList.Create(false);
2494                               objsym.ObjSection.VTRefList.Add(objsym);
2495                             end
2496                           else if Copy(hs,1,7)='VTENTRY' then
2497                             VTEntryList.Add(objsym)
2498                           else if Copy(hs,1,9)='VTINHERIT' then
2499                             VTInheritList.Add(objsym);
2500                         end;
2501                     end;
2502                   continue;
2503                 end;
2504 
2505               { If this symbol comes from COMDAT group, see if a group with
2506                 matching signature is already included. }
2507               if assigned(objsym.objsection) and
2508                  assigned(objsym.objsection.group) then
2509                 begin
2510                   grp:=objsym.objsection.group;
2511                   if grp.IsComdat then
2512                     begin
2513                       if ComdatGroups.Find(grp.name)=nil then
2514                         ComdatGroups.Add(grp.name,grp)
2515                       else
2516                         begin
2517                           { Undefine the symbol, causing relocations to it from same
2518                             objdata to be redirected to the symbol in the actually
2519                             linked group. }
2520                           if objsym.bind=AB_GLOBAL then
2521                             objsym.bind:=AB_EXTERNAL;
2522                           { AB_WEAK_EXTERNAL remains unchanged }
2523                           objsym.objsection:=nil;
2524                         end;
2525                     end;
2526                 end;
2527 
2528               { Search for existing exesymbol }
2529               exesym:=texesymbol(FExeSymbolList.Find(objsym.name));
2530               if not assigned(exesym) then
2531                 begin
2532                   exesym:=texesymbol.Create(FExeSymbolList,objsym.name);
2533                   exesym.ObjSymbol:=objsym;
2534                 end;
2535               objsym.ExeSymbol:=exesym;
2536               case objsym.bind of
2537                 AB_GLOBAL :
2538                   begin
2539                     if exesym.State<>symstate_defined then
2540                       begin
2541                         exesym.ObjSymbol:=objsym;
2542                         exesym.State:=symstate_defined;
2543                       end
2544                     else
2545                       if (oso_comdat in exesym.ObjSymbol.objsection.SecOptions) and
2546                          (oso_comdat in objsym.objsection.SecOptions) then
2547                         begin
2548                           if exesym.ObjSymbol.objsection.ComdatSelection=objsym.objsection.ComdatSelection then
2549                             begin
2550                               case objsym.objsection.ComdatSelection of
2551                                 oscs_none:
2552                                   Message1(link_e_duplicate_symbol,objsym.name);
2553                                 oscs_any:
2554                                   Message1(link_d_comdat_discard_any,objsym.name);
2555                                 oscs_same_size:
2556                                   if exesym.ObjSymbol.size<>objsym.size then
2557                                     Message1(link_e_comdat_size_differs,objsym.name)
2558                                   else
2559                                     Message1(link_d_comdat_discard_size,objsym.name);
2560                                 oscs_exact_match:
2561                                   if (exesym.ObjSymbol.size<>objsym.size) and not exesym.ObjSymbol.objsection.Data.equal(objsym.objsection.Data) then
2562                                     Message1(link_e_comdat_content_differs,objsym.name)
2563                                   else
2564                                     Message1(link_d_comdat_discard_content,objsym.name);
2565                                 oscs_associative:
2566                                   { this is handled in a different way }
2567                                   Message1(link_e_duplicate_symbol,objsym.name);
2568                                 oscs_largest:
2569                                   if objsym.size>exesym.ObjSymbol.size then
2570                                     begin
2571                                       Message1(link_d_comdat_replace_size,objsym.name);
2572                                       exesym.ObjSymbol.exesymbol:=nil;
2573                                       exesym.ObjSymbol:=objsym;
2574                                     end;
2575                               end;
2576                             end
2577                           else
2578                             Message1(link_e_comdat_selection_differs,objsym.name);
2579                         end
2580                       else
2581                         { specific error if ComDat flags are different? }
2582                         Message1(link_e_duplicate_symbol,objsym.name);
2583                   end;
2584                 AB_EXTERNAL :
2585                   begin
2586                     ExternalObjSymbols.add(objsym);
2587                     { Register unresolved symbols only the first time they
2588                       are registered }
2589                     if exesym.ObjSymbol=objsym then
2590                       UnresolvedExeSymbols.Add(exesym)
2591                     { Normal reference removes any existing "weakness" }
2592                     else if exesym.state=symstate_undefweak then
2593                       begin
2594                         exesym.state:=symstate_undefined;
2595                         exesym.ObjSymbol:=objsym;
2596                       end;
2597                   end;
2598                 AB_COMMON :
2599                   begin
2600                     { A COMMON definition overrides weak one.
2601                       Also select the symbol with largest size. }
2602                     if (exesym.State in [symstate_undefined,symstate_undefweak,symstate_defweak]) or
2603                        ((exesym.State=symstate_common) and (objsym.size>exesym.ObjSymbol.size)) then
2604                       begin
2605                         exesym.ObjSymbol:=objsym;
2606                         exesym.State:=symstate_common;
2607                       end;
2608                     if assigned(objsym.objsection) and
2609                       (objsym.objsection.objdata=internalObjData) then
2610                       FProvidedObjSymbols.add(objsym)
2611                     else
2612                       CommonObjSymbols.add(objsym);
2613                   end;
2614                 AB_WEAK_EXTERNAL :
2615                   begin
2616                     if objsym.objsection=nil then          { a weak reference }
2617                       begin
2618                         ExternalObjSymbols.add(objsym);
2619                         if exesym.ObjSymbol=objsym then
2620                           begin
2621                             UnresolvedExeSymbols.Add(exesym);
2622                             exesym.state:=symstate_undefweak;
2623                           end;
2624                       end
2625                     else                                   { a weak definition }
2626                       begin
2627                         if exesym.State in [symstate_undefined,symstate_undefweak] then
2628                           begin
2629                             exesym.ObjSymbol:=objsym;
2630                             exesym.state:=symstate_defweak;
2631                           end;
2632                       end;
2633                   end;
2634               end;
2635             end;
2636         end;
2637 
2638         procedure LoadLibrary(lib:TStaticLibrary);
2639           var
2640             j,k,oldcount: longint;
2641             members: TFPObjectList;
2642             exesym: TExeSymbol;
2643             objinput: TObjInput;
2644           begin
2645             case lib.Kind of
2646               lkArchive:
2647                 begin
2648                   { Process list of Unresolved External symbols, we need
2649                     to use a while loop because the list can be extended when
2650                     we load members from the library. }
2651                   j:=0;
2652                   while (j<UnresolvedExeSymbols.count) do
2653                     begin
2654                       exesym:=TExeSymbol(UnresolvedExeSymbols[j]);
2655                       { Check first if the symbol is still undefined }
2656                       if (exesym.State=symstate_undefined) then
2657                         begin
2658                           if lib.ArReader.OpenFile(exesym.name) then
2659                             begin
2660                               if assigned(exemap) then
2661                                 begin
2662                                   if firstarchive then
2663                                     begin
2664                                       exemap.Add('');
2665                                       exemap.Add('Archive member included because of file (symbol)');
2666                                       exemap.Add('');
2667                                       firstarchive:=false;
2668                                     end;
2669                                   exemap.Add(lib.ArReader.FileName+' - '+
2670                                     {exesym.ObjSymbol.ObjSection.FullName+}
2671                                     '('+exesym.Name+')');
2672                                 end;
2673                               objinput:=lib.ObjInputClass.Create;
2674                               objinput.ReadObjData(lib.ArReader,objdata);
2675                               objinput.free;
2676                               AddObjData(objdata);
2677                               LoadObjDataSymbols(objdata);
2678                               lib.ArReader.CloseFile;
2679                             end;
2680                          end;
2681                       inc(j);
2682                     end;
2683                 end;
2684 
2685               lkGroup:
2686                 begin
2687                   { repeatedly process members of the group until no new
2688                     unresolved symbols appear }
2689                   members:=lib.GroupMembers;
2690                   repeat
2691                     oldcount:=UnresolvedExeSymbols.count;
2692                     for k:=0 to members.Count-1 do
2693                       LoadLibrary(TStaticLibrary(members[k]));
2694                   until UnresolvedExeSymbols.count=oldcount;
2695                 end;
2696               lkObject:
2697                 { TODO: ownership of objdata }
2698                 //if lib.objdata.is_dynamic then
2699                   Load_DynamicObject(lib.objdata,lib.AsNeeded);
2700                 {else
2701                   begin
2702                     AddObjData(lib.objdata);
2703                     LoadObjDataSymbols(lib.objdata);
2704                   end;}
2705             end;
2706           end;
2707 
2708       begin
2709         VTEntryList:=TFPObjectList.Create(false);
2710         VTInheritList:=TFPObjectList.Create(false);
2711 
2712         {
2713           The symbol resolving is done in 4 steps:
2714            1. Register symbols from objects
2715            2. Find symbols in static libraries
2716            3. Define symbols PROVIDEd by the link script
2717            4. Define still undefined common symbols
2718         }
2719 
2720         { Step 1, Register symbols from objects }
2721         for i:=0 to ObjDataList.Count-1 do
2722           begin
2723             ObjData:=TObjData(ObjDataList[i]);
2724             LoadObjDataSymbols(ObjData);
2725           end;
2726         PackUnresolvedExeSymbols('in objects');
2727 
2728         { Step 2, Find unresolved symbols in the libraries }
2729         firstarchive:=true;
2730         for i:=0 to StaticLibraryList.Count-1 do
2731           LoadLibrary(TStaticLibrary(StaticLibraryList[i]));
2732 
2733         PackUnresolvedExeSymbols('after static libraries');
2734 
2735         { Step 3, handle symbols provided in script }
2736         for i:=0 to FProvidedObjSymbols.count-1 do
2737           begin
2738             objsym:=TObjSymbol(FProvidedObjSymbols[i]);
2739             if objsym.exesymbol.State=symstate_defined then
2740               continue;
2741             objsym.exesymbol.objsymbol:=objsym;
2742             objsym.bind:=AB_GLOBAL;
2743             objsym.exesymbol.State:=symstate_defined;
2744           end;
2745         PackUnresolvedExeSymbols('after defining symbols provided by link script');
2746 
2747         { Step 4, Match common symbols or add to the globals }
2748         firstcommon:=true;
2749         for i:=0 to CommonObjSymbols.count-1 do
2750           begin
2751             objsym:=TObjSymbol(CommonObjSymbols[i]);
2752             if objsym.exesymbol.State=symstate_defined then
2753               begin
2754                 if objsym.exesymbol.ObjSymbol.size<>objsym.size then
2755                   Comment(V_Debug,'Size of common symbol '+objsym.name+' is different, expected '+tostr(objsym.size)+' got '+tostr(objsym.exesymbol.ObjSymbol.size));
2756               end
2757             else
2758               begin
2759                 { allocate new objsymbol in .bss of *COMMON* and assign
2760                   it to the exesymbol }
2761                 if firstcommon then
2762                   begin
2763                     if assigned(exemap) then
2764                       exemap.AddCommonSymbolsHeader;
2765                     firstcommon:=false;
2766                   end;
2767                 internalObjData.setsection(commonObjSection);
2768                 { TODO: support alignment of common symbols (ELF targets at least),
2769                   increase commonObjSection.SecAlign if necessary here. }
2770                 internalObjData.allocalign(used_align(size_2_align(objsym.size),0,commonObjSection.SecAlign));
2771                 commonsym:=internalObjData.symboldefine(objsym.name,AB_GLOBAL,AT_DATA);
2772                 commonsym.size:=objsym.size;
2773                 internalObjData.alloc(objsym.size);
2774                 if assigned(exemap) then
2775                   exemap.AddCommonSymbol(objsym);
2776                 { Assign to the exesymbol }
2777                 objsym.exesymbol.objsymbol:=commonsym;
2778                 objsym.exesymbol.state:=symstate_defined;
2779               end;
2780           end;
2781         PackUnresolvedExeSymbols('after defining COMMON symbols');
2782 
2783         { Find entry symbol and print in map }
2784         if (EntryName<>'') then
2785           begin
2786             exesym:=texesymbol(ExeSymbolList.Find(EntryName));
2787             if assigned(exesym) then
2788               begin
2789                 EntrySym:=exesym.ObjSymbol;
2790                 if assigned(exemap) then
2791                   begin
2792                     exemap.Add('');
2793                     exemap.Add('Entry symbol '+EntryName);
2794                   end;
2795               end
2796             else
2797               Comment(V_Error,'Entrypoint '+EntryName+' not defined');
2798           end;
2799 
2800         { Generate VTable tree }
2801         if cs_link_opt_vtable in current_settings.globalswitches then
2802           BuildVTableTree(VTInheritList,VTEntryList);
2803         VTInheritList.Free;
2804         VTEntryList.Free;
2805       end;
2806 
2807 
2808     procedure TExeOutput.GenerateDebugLink(const dbgname:string;dbgcrc:cardinal);
2809       var
2810         debuglink : array[0..1023] of byte;
2811         len   : longint;
2812         objsec : TObjSection;
2813         exesec : TExeSection;
2814       begin
2815         { From the gdb manual  chapter 15. GDB Files:
2816 
2817            * A filename, with any leading directory components removed, followed by a zero byte,
2818            * zero to three bytes of padding, as needed to reach the next four-byte boundary within the section, and
2819            * a four-byte CRC checksum, stored in the same endianness used for the executable file itself. The checksum is computed
2820              on the debugging information file's full contents by the function given below, passing zero as the crc argument.
2821         }
2822         fillchar(debuglink,sizeof(debuglink),0);
2823         len:=0;
2824         move(dbgname[1],debuglink[len],length(dbgname));
2825         inc(len,length(dbgname)+1);
2826         len:=align(len,4);
2827         if source_info.endian<>target_info.endian then
2828           SwapEndian(dbgcrc);
2829         move(dbgcrc,debuglink[len],sizeof(cardinal));
2830         inc(len,4);
2831         { Add section }
2832         exesec:=FindExeSection(debuglinkname);
2833         if not assigned(exesec) then
2834           exesec:=CExeSection.create(ExeSectionList,debuglinkname);
2835         exesec.SecOptions:=[oso_data,oso_keep];
2836         exesec.SecAlign:=4;
2837         objsec:=internalObjData.createsection(exesec.name,1,exesec.SecOptions);
2838         internalObjData.writebytes(debuglink,len);
2839         exesec.AddObjSection(objsec);
2840       end;
2841 
2842 
2843     procedure TExeOutput.GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);
2844       begin
2845       end;
2846 
2847 
2848     procedure TExeOutput.MarkTargetSpecificSections(WorkList:TFPObjectList);
2849       begin
2850       end;
2851 
2852 
2853     procedure TExeOutput.AfterUnusedSectionRemoval;
2854       begin
2855       end;
2856 
2857 
ByAddressnull2858     function ByAddress(item1,item2:pointer):longint;
2859       var
2860         sym1:TObjSymbol absolute item1;
2861         sym2:TObjSymbol absolute item2;
2862       begin
2863         if sym1.address>sym2.address then
2864           result:=1
2865         else if sym1.address<sym2.address then
2866           result:=-1
2867         else
2868           result:=0;
2869       end;
2870 
2871 
2872     procedure TExeOutput.PrintMemoryMap;
2873       var
2874         exesec : TExeSection;
2875         objsec : TObjSection;
2876         objsym : TObjSymbol;
2877         i,j,k,m: longint;
2878         list   : TFPList;
2879         flag   : boolean;
2880       begin
2881         if not assigned(exemap) then
2882           exit;
2883         { create a list of symbols sorted by address }
2884         list:=TFPList.Create;
2885         for i:=0 to ExeSymbolList.Count-1 do
2886           list.Add(TExeSymbol(ExeSymbolList[i]).ObjSymbol);
2887         list.Sort(@ByAddress);
2888 
2889         exemap.AddMemoryMapHeader(ImageBase);
2890         k:=0;
2891         for i:=0 to ExeSectionList.Count-1 do
2892           begin
2893             exesec:=TExeSection(ExeSectionList[i]);
2894             exemap.AddMemoryMapExeSection(exesec);
2895             for j:=0 to exesec.ObjSectionList.count-1 do
2896               begin
2897                 objsec:=TObjSection(exesec.ObjSectionList[j]);
2898                 exemap.AddMemoryMapObjectSection(objsec);
2899 
2900                 while (k<list.Count) and (TObjSymbol(list[k]).Address<objsec.MemPos) do
2901                   inc(k);
2902                 while (k<list.Count)  do
2903                   begin
2904                     objsym:=TObjSymbol(list[k]);
2905                     if objsym.address>objsec.MemPos+objsec.Size then
2906                       break;
2907                     if objsym.objsection=objsec then
2908                       exemap.AddMemoryMapSymbol(objsym)
2909                     else
2910                       begin
2911                         { Got a symbol with address falling into current section, but
2912                           belonging to a different section. This may happen for zero-length
2913                           sections because symbol list is sorted by address but not by section.
2914                           Do some look-ahead in this case. }
2915                         m:=k+1;
2916                         flag:=false;
2917                         while (m<list.Count) and (TObjSymbol(list[m]).Address=objsym.address) do
2918                           begin
2919                             if TObjSymbol(list[m]).objsection=objsec then
2920                               begin
2921                                 flag:=true;
2922                                 list.Exchange(k,m);
2923                                 exemap.AddMemoryMapSymbol(TObjSymbol(list[k]));
2924                                 break;
2925                               end;
2926                             inc(m);
2927                           end;
2928                         if not flag then
2929                           break;
2930                       end;
2931                     inc(k);
2932                   end;
2933               end;
2934           end;
2935         list.Free;
2936       end;
2937 
2938 
2939     procedure TExeOutput.FixupSymbols;
2940 
2941         procedure UpdateSymbol(objsym:TObjSymbol);
2942         begin
2943           objsym.bind:=objsym.ExeSymbol.ObjSymbol.bind;
2944           objsym.offset:=objsym.ExeSymbol.ObjSymbol.offset;
2945           objsym.size:=objsym.ExeSymbol.ObjSymbol.size;
2946           objsym.typ:=objsym.ExeSymbol.ObjSymbol.typ;
2947           objsym.ObjSection:=objsym.ExeSymbol.ObjSymbol.ObjSection;
2948           objsym.group:=objsym.ExeSymbol.ObjSymbol.group;
2949         end;
2950 
2951       var
2952         i      : longint;
2953         objsym : TObjSymbol;
2954         exesym : TExeSymbol;
2955       begin
2956         { Print list of Unresolved External symbols }
2957         if not AllowUndefinedSymbols then
2958           for i:=0 to UnresolvedExeSymbols.count-1 do
2959             begin
2960               exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
2961               if (exesym.State=symstate_undefined) then
2962                 Comment(V_Error,'Undefined symbol: '+exesym.name);
2963             end;
2964 
2965         {
2966           Fixing up symbols is done in the following steps:
2967            1. Update common references
2968            2. Update external references
2969 
2970            Symbols with objsection<>nil are removed from the lists,
2971            remaining ones can be processed later by calling this method again.
2972         }
2973 
2974         { Step 1, Update commons. Preserve the original symbol size and bind,
2975           this is needed for correct relocation of DJCOFF files. }
2976         for i:=0 to CommonObjSymbols.count-1 do
2977           begin
2978             objsym:=TObjSymbol(CommonObjSymbols[i]);
2979             if objsym.bind<>AB_COMMON then
2980               internalerror(200606241);
2981 
2982             objsym.ObjSection:=objsym.ExeSymbol.ObjSymbol.ObjSection;
2983             objsym.offset:=objsym.ExeSymbol.ObjSymbol.offset;
2984             objsym.typ:=objsym.ExeSymbol.ObjSymbol.typ;
2985           end;
2986 
2987         { Step 2, Update externals }
2988         for i:=0 to ExternalObjSymbols.count-1 do
2989           begin
2990             objsym:=TObjSymbol(ExternalObjSymbols[i]);
2991             if not (objsym.bind in [AB_EXTERNAL,AB_WEAK_EXTERNAL]) then
2992               internalerror(200606242);
2993             UpdateSymbol(objsym);
2994             { Collect symbols that resolve to indirect functions,
2995               they will need additional target-specific processing. }
2996             if objsym.typ=AT_GNU_IFUNC then
2997               IndirectObjSymbols.Add(objsym)
2998             else if assigned(objsym.objsection) then
2999               ExternalObjSymbols[i]:=nil;
3000           end;
3001         CommonObjSymbols.Clear;
3002         ExternalObjSymbols.Pack;
3003       end;
3004 
3005 
3006     procedure TExeOutput.MergeStabs;
3007       var
3008         stabexesec,
3009         stabstrexesec : TExeSection;
3010         relocsec,
3011         currstabsec,
3012         currstabstrsec,
3013         mergedstabsec,
3014         mergedstabstrsec : TObjSection;
3015         hstabreloc,
3016         currstabreloc : TObjRelocation;
3017         i,j : longint;
3018         currstabrelocidx,
3019         mergestabcnt,
3020         stabcnt : longword;
3021         skipstab : boolean;
3022         skipfun : boolean;
3023         hstab   : TObjStabEntry;
3024         stabrelocofs : longword;
3025         buf     : array[0..1023] of byte;
3026         bufend,
3027         bufsize  : longint;
3028       begin
3029         stabexesec:=FindExeSection('.stab');
3030         stabstrexesec:=FindExeSection('.stabstr');
3031         if (stabexesec=nil) or
3032            (stabstrexesec=nil) or
3033            (stabexesec.ObjSectionlist.count=0) then
3034           exit;
3035         { Create new stabsection }
3036         stabRelocofs:=pbyte(@hstab.nvalue)-pbyte(@hstab);
3037         mergedstabsec:=internalObjData.CreateSection(sec_stab,'');
3038         mergedstabstrsec:=internalObjData.CreateSection(sec_stabstr,'');
3039 
3040         { write stab for hdrsym }
3041         mergedstabsec.writeZeros(sizeof(TObjStabEntry));
3042         mergestabcnt:=1;
3043 
3044         { .stabstr starts with a #0 }
3045         buf[0]:=0;
3046         mergedstabstrsec.write(buf[0],1);
3047 
3048         skipfun:=false;
3049         { Copy stabs and corresponding Relocations }
3050         for i:=0 to stabexesec.ObjSectionList.Count-1 do
3051           begin
3052             currstabsec:=TObjSection(stabexesec.ObjSectionList[i]);
3053             currstabstrsec:=currstabsec.ObjData.findsection('.stabstr');
3054             if assigned(currstabstrsec) then
3055               begin
3056                 stabcnt:=currstabsec.Data.size div sizeof(TObjStabEntry);
3057                 currstabsec.Data.seek(0);
3058                 currstabrelocidx:=0;
3059                 for j:=0 to stabcnt-1 do
3060                   begin
3061                     hstabreloc:=nil;
3062                     skipstab:=false;
3063                     currstabsec.Data.read(hstab,sizeof(TObjStabEntry));
3064                     MaybeSwapStab(hstab);
3065                     { Only include first hdrsym stab }
3066                     if hstab.ntype=0 then
3067                       skipstab:=true;
3068                     if skipfun then
3069                       begin
3070                         { Skip all stabs for function body until N_RBRAC }
3071                         skipfun:=hstab.ntype<>N_RBRAC;
3072                         skipstab:=true;
3073                       end;
3074                     if not skipstab then
3075                       begin
3076                         { Find corresponding Relocation }
3077                         currstabreloc:=nil;
3078                         while (currstabrelocidx<longword(currstabsec.ObjRelocations.Count)) do
3079                           begin
3080                             currstabreloc:=TObjRelocation(currstabsec.ObjRelocations[currstabrelocidx]);
3081                             if assigned(currstabreloc) and
3082                                (currstabreloc.dataoffset>=longword(j)*sizeof(TObjStabEntry)+stabrelocofs) then
3083                               break;
3084                             inc(currstabrelocidx);
3085                           end;
3086                         if assigned(currstabreloc) and
3087                            (currstabreloc.dataoffset=longword(j)*sizeof(TObjStabEntry)+stabrelocofs) then
3088                           begin
3089                             hstabReloc:=currstabReloc;
3090                             inc(currstabrelocidx);
3091                           end;
3092 
3093                         { Check if the stab is refering to a removed section }
3094                         if assigned(hstabreloc) then
3095                           begin
3096                             if assigned(hstabreloc.Symbol) then
3097                               relocsec:=hstabreloc.Symbol.ObjSection
3098                             else
3099                               relocsec:=hstabreloc.ObjSection;
3100                             if not assigned(relocsec) then
3101                               internalerror(200603302);
3102                             if not relocsec.Used then
3103                               begin
3104                                 skipstab:=true;
andnull3105                                 if (hstab.ntype=N_Function) and (hstab.strpos<>0) then
3106                                   begin
3107                                     currstabstrsec.Data.seek(hstab.strpos);
3108                                     bufsize:=currstabstrsec.Data.read(buf,sizeof(buf));
3109                                     bufend:=indexbyte(buf,bufsize,Ord(':'));
3110                                     if (bufend<>-1) and (bufend<bufsize-1) and (buf[bufend+1]=Ord('F')) then
3111                                       skipfun:=true;
3112                                   end;
3113                               end;
3114                           end;
3115                       end;
3116                     if not skipstab then
3117                       begin
3118                         { Copy string in stabstr }
3119                         if hstab.strpos<>0 then
3120                           begin
3121                             currstabstrsec.Data.seek(hstab.strpos);
3122                             hstab.strpos:=mergedstabstrsec.Size;
3123                             repeat
3124                               bufsize:=currstabstrsec.Data.read(buf,sizeof(buf));
3125                               bufend:=indexbyte(buf,bufsize,0);
3126                               if bufend=-1 then
3127                                 bufend:=bufsize
3128                               else
3129                                 begin
3130                                   { include the #0 }
3131                                   inc(bufend);
3132                                 end;
3133                               mergedstabstrsec.write(buf,bufend);
3134                             until (buf[bufend-1]=0) or (bufsize<sizeof(buf));
3135                           end;
3136                         { Copy and Update the relocation }
3137                         if assigned(hstabreloc) then
3138                           begin
3139                             hstabreloc.Dataoffset:=mergestabcnt*sizeof(TObjStabEntry)+stabRelocofs;
3140                             { Remove from List without freeing the object }
3141                             currstabsec.ObjRelocations.List[currstabrelocidx-1]:=nil;
3142                             mergedstabsec.ObjRelocations.Add(hstabreloc);
3143                           end;
3144                         { Write updated stab }
3145                         MaybeSwapStab(hstab);
3146                         mergedstabsec.write(hstab,sizeof(hstab));
3147                         inc(mergestabcnt);
3148                       end;
3149                   end;
3150               end;
3151 
3152             { Unload stabs }
3153             if assigned(currstabstrsec) then
3154               begin
3155                 currstabstrsec.Used:=False;
3156                 currstabstrsec.ReleaseData;
3157               end;
3158             currstabsec.Used:=false;
3159             currstabsec.ReleaseData;
3160           end;
3161 
3162         { Generate new HdrSym }
3163         if mergedstabsec.Size>0 then
3164           begin
3165             hstab.strpos:=1;
3166             hstab.ntype:=0;
3167             hstab.nother:=0;
3168             hstab.ndesc:=word(mergestabcnt-1);
3169             hstab.nvalue:=mergedstabstrsec.Size;
3170             MaybeSwapStab(hstab);
3171             mergedstabsec.Data.seek(0);
3172             mergedstabsec.Data.write(hstab,sizeof(hstab));
3173           end;
3174 
3175         { Replace all sections with our combined stabsec }
3176         stabexesec.ObjSectionList.Clear;
3177         stabstrexesec.ObjSectionList.Clear;
3178         stabexesec.AddObjSection(mergedstabsec);
3179         stabstrexesec.AddObjSection(mergedstabstrsec);
3180       end;
3181 
3182 
3183     procedure TExeOutput.MarkEmptySections;
3184       var
3185         i, j   : longint;
3186         exesec : TExeSection;
3187         doremove : boolean;
3188       begin
3189         for i:=0 to ExeSectionList.Count-1 do
3190           begin
3191             exesec:=TExeSection(ExeSectionList[i]);
3192 
3193             doremove:=not(oso_keep in exesec.SecOptions) and
3194                 (
3195                  (exesec.ObjSectionlist.count=0) or
3196                  (
3197                   (cs_link_strip in current_settings.globalswitches) and
3198                   not(cs_link_separate_dbg_file in current_settings.globalswitches) and
3199                   (oso_debug in exesec.SecOptions)
3200                  )
3201                 );
3202             if not doremove then
3203               begin
3204                { Check if section has no actual data }
3205                 doremove:=true;
3206                 for j:=0 to exesec.ObjSectionList.Count-1 do
3207                   if TObjSection(exesec.ObjSectionList[j]).Size<>0 then
3208                     begin
3209                       doremove:=false;
3210                       break;
3211                     end;
3212               end;
3213             if doremove then
3214               begin
3215                 Comment(V_Debug,'Disabling empty section '+exesec.name);
3216                 exesec.Disabled:=true;
3217               end;
3218           end;
3219       end;
3220 
3221 
3222     procedure TExeOutput.RemoveDisabledSections;
3223       var
3224         i: longint;
3225         exesec: TExeSection;
3226       begin
3227         for i:=0 to ExeSectionList.Count-1 do
3228           begin
3229             exesec:=TExeSection(ExeSectionList[i]);
3230             if exesec.Disabled then
3231               ExeSectionList[i]:=nil;
3232           end;
3233         ExeSectionList.Pack;
3234       end;
3235 
3236 
3237     procedure TExeOutput.RemoveDebugInfo;
3238       var
3239         i      : longint;
3240         exesec : TExeSection;
3241       begin
3242         for i:=0 to ExeSectionList.Count-1 do
3243           begin
3244             exesec:=TExeSection(ExeSectionList[i]);
3245             if (oso_debug in exesec.SecOptions) then
3246               ExeSectionList[i]:=nil;
3247           end;
3248         ExeSectionList.Pack;
3249       end;
3250 
3251 
3252     procedure TExeOutput.RemoveUnreferencedSections;
3253       var
3254         ObjSectionWorkList : TFPObjectList;
3255 
3256         procedure AddToObjSectionWorkList(aobjsec:TObjSection);
3257         begin
3258           if not aobjsec.Used then
3259             begin
3260               aobjsec.Used:=true;
3261               ObjSectionWorkList.Add(aobjsec);
3262             end;
3263         end;
3264 
3265         procedure DoReloc(objreloc:TObjRelocation);
3266         var
3267           objsym : TObjSymbol;
3268           refobjsec : TObjSection;
3269           refgrp : TObjSectionGroup;
3270         begin
3271           { Disabled Relocation to 0  }
3272           if (objreloc.flags and rf_nosymbol)<>0 then
3273             exit;
3274           refobjsec:=nil;
3275           refgrp:=nil;
3276           if assigned(objreloc.symbol) then
3277             begin
3278               objsym:=objreloc.symbol;
3279               if objsym.bind<>AB_LOCAL then
3280                 begin
3281                   if not assigned(objsym.exesymbol) then
3282                     internalerror(200603063);
3283                   objsym.exesymbol.used:=true;
3284                   objsym:=objsym.exesymbol.objsymbol;
3285                 end;
3286               if not assigned(objsym.objsection) then
3287                 exit
3288               else
3289                 refobjsec:=objsym.objsection;
3290             end
3291           else if assigned(objreloc.objsection) then
3292             refobjsec:=objreloc.objsection
3293           else if assigned(objreloc.group) then
3294             refgrp:=objreloc.group
3295           else
3296             internalerror(200603316);
3297           if assigned(exemap) then
3298             begin
3299               objsym:=objreloc.symbol;
3300               if assigned(objsym) and (objsym.typ<>AT_SECTION) then
3301                 exemap.Add('  References  '+objsym.name+' in '
3302                   +refobjsec.fullname)
3303               else if assigned(refobjsec) then
3304                 exemap.Add('  References '+refobjsec.fullname)
3305               else if assigned(refgrp) then
3306                 exemap.Add('  References '+refgrp.Name)
3307               else
3308                 internalerror(200603316);
3309             end;
3310           if assigned(refobjsec) then
3311             AddToObjSectionWorkList(refobjsec);
3312         end;
3313 
3314         procedure DoVTableRef(vtable:TExeVTable;VTableIdx:longint);
3315         var
3316           i : longint;
3317           objreloc : TObjRelocation;
3318         begin
3319           objreloc:=vtable.VTableRef(VTableIdx);
3320           if assigned(objreloc) then
3321             begin
3322               { Process the relocation now if the ObjSection is
3323                 already processed and marked as used. Otherwise we leave it
3324                 unprocessed. It'll then be resolved when the ObjSection is
3325                 changed to Used }
3326               if vtable.ExeSymbol.ObjSymbol.ObjSection.Used then
3327                 DoReloc(objreloc);
3328             end;
3329           { This recursive walking is done here instead of
3330             in TExeVTable.VTableRef because we can now process
3331             all needed relocations }
3332           for i:=0 to vtable.ChildList.Count-1 do
3333             DoVTableRef(TExeVTable(vtable.ChildList[i]),VTableIdx);
3334         end;
3335 
3336         procedure ProcessWorkList;
3337         var
3338           hs        : string;
3339           i,k       : longint;
3340           objsec    : TObjSection;
3341           objsym    : TObjSymbol;
3342           code      : integer;
3343           vtableidx : longint;
3344           vtableexesym : TExeSymbol;
3345         begin
3346           while ObjSectionWorkList.Count>0 do
3347             begin
3348               objsec:=TObjSection(ObjSectionWorkList.Last);
3349               if assigned(exemap) then
3350                 exemap.Add('Keeping '+objsec.FullName+' '+ToStr(objsec.ObjRelocations.Count)+' references');
3351               ObjSectionWorkList.Delete(ObjSectionWorkList.Count-1);
3352 
3353               { Process Relocations }
3354               for i:=0 to objsec.ObjRelocations.count-1 do
3355                 DoReloc(TObjRelocation(objsec.ObjRelocations[i]));
3356 
3357               { Process Virtual Entry calls }
3358               if cs_link_opt_vtable in current_settings.globalswitches then
3359                 begin
3360                   for i:=0 to objsec.VTRefList.count-1 do
3361                     begin
3362                       objsym:=TObjSymbol(objsec.VTRefList[i]);
3363                       hs:=objsym.name;
3364                       Delete(hs,1,Pos('_',hs));
3365                       k:=Pos('$$',hs);
3366                       if k=0 then
3367                         internalerror(200603314);
3368                       vtableexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,1,k-1)));
3369                       val(Copy(hs,k+2,length(hs)-k-1),vtableidx,code);
3370                       if (code<>0) then
3371                         internalerror(200603317);
3372                       if not assigned(vtableexesym) then
3373                         internalerror(200603315);
3374                       if not assigned(vtableexesym.vtable) then
3375                         internalerror(200603316);
3376                       DoVTableRef(vtableexesym.vtable,vtableidx);
3377                     end;
3378                 end;
3379             end;
3380 
3381         end;
3382 
3383       var
3384         i,j       : longint;
3385         exesec    : TExeSection;
3386         objdata   : TObjData;
3387         objsec    : TObjSection;
3388       begin
3389         ObjSectionWorkList:=TFPObjectList.Create(false);
3390 
3391         if assigned(exemap) then
3392           exemap.AddHeader('Removing unreferenced sections');
3393 
3394         { Initialize by marking all sections unused and
3395           adding the sections with oso_keep flags to the ObjSectionWorkList }
3396         for i:=0 to ObjDataList.Count-1 do
3397           begin
3398             ObjData:=TObjData(ObjDataList[i]);
3399             for j:=0 to ObjData.ObjSectionList.Count-1 do
3400               begin
3401                 objsec:=TObjSection(ObjData.ObjSectionList[j]);
3402                 objsec.Used:=false;
3403 { TODO: remove debug section always keep}
3404                 if oso_debug in objsec.secoptions then
3405                   objsec.Used:=true;
3406                 if (oso_keep in objsec.secoptions) then
3407                   begin
3408                     AddToObjSectionWorkList(objsec);
3409                     if objsec.name='.fpc.n_links' then
3410                       objsec.Used:=false;
3411                   end;
3412               end;
3413           end;
3414         if assigned(entrysym) then
3415           AddToObjSectionWorkList(entrysym.exesymbol.objsymbol.objsection);
3416 
3417         { Process all sections, add new sections to process based
3418           on the symbol references  }
3419         ProcessWorkList;
3420 
3421         { Handle stuff like .pdata, i.e. sections that are not referenced
3422           but must be included if sections they reference are included.
3423           Loop is necessary because .pdata can reference (via .xdata)
3424           more text sections, VMTs of exception classes, etc. }
3425         repeat
3426           MarkTargetSpecificSections(ObjSectionWorkList);
3427           if (ObjSectionWorkList.Count=0) then
3428             break;
3429           ProcessWorkList;
3430         until False;
3431 
3432         ObjSectionWorkList.Free;
3433         ObjSectionWorkList:=nil;
3434 
3435         { Remove unused objsections from ExeSectionList }
3436         for i:=0 to ExeSectionList.Count-1 do
3437           begin
3438             exesec:=TExeSection(ExeSectionList[i]);
3439             for j:=0 to exesec.ObjSectionlist.count-1 do
3440               begin
3441                 objsec:=TObjSection(exesec.ObjSectionlist[j]);
3442                 if not objsec.used then
3443                   begin
3444                     if assigned(exemap) then
3445                       exemap.Add('Removing '+objsec.FullName);
3446                     exesec.ObjSectionlist[j]:=nil;
3447                     objsec.ReleaseData;
3448                   end;
3449               end;
3450             exesec.ObjSectionlist.Pack;
3451           end;
3452       end;
3453 
3454 
3455     procedure TExeOutput.FixupRelocations;
3456       var
3457         i,j     : longint;
3458         exesec  : TExeSection;
3459         objsec  : TObjSection;
3460       begin
3461         for i:=0 to ExeSectionList.Count-1 do
3462           begin
3463             exesec:=TExeSection(ExeSectionList[i]);
3464             if not assigned(exesec) then
3465               continue;
3466             for j:=0 to exesec.ObjSectionlist.count-1 do
3467               begin
3468                 objsec:=TObjSection(exesec.ObjSectionlist[j]);
3469                 if not objsec.Used then
3470                   internalerror(200603301);
3471                 if (objsec.ObjRelocations.Count>0) and
3472                    not assigned(objsec.data) then
3473                   internalerror(200205183);
3474                 DoRelocationFixup(objsec);
3475                 {for size = 0 data is not valid PM }
3476                 if assigned(objsec.data) and (objsec.data.size<>objsec.size) then
3477                   internalerror(2010092801);
3478               end;
3479           end;
3480       end;
3481 
3482 
3483     procedure TExeOutput.RemoveUnusedExeSymbols;
3484       var
3485         i : longint;
3486         sym : TExeSymbol;
3487       begin
3488         { Removing unused symbols }
3489         for i:=0 to ExeSymbolList.Count-1 do
3490           begin
3491             sym:=TExeSymbol(ExeSymbolList[i]);
3492             { an unresolved weak symbol has objsection=nil }
3493             if assigned(sym.ObjSymbol.objsection) and
3494               (not sym.ObjSymbol.objsection.Used) then
3495               ExeSymbolList[i]:=nil;
3496           end;
3497         ExeSymbolList.Pack;
3498       end;
3499 
3500 
3501     procedure TExeOutput.SetCurrMemPos(const AValue: qword);
3502       begin
3503         if AValue>MaxMemPos then
3504           Message1(link_f_executable_too_big, target_os_string);
3505         FCurrMemPos:=AValue;
3506       end;
3507 
3508 
3509     procedure TExeOutput.WriteExeSectionContent;
3510       var
3511         exesec : TExeSection;
3512         objsec : TObjSection;
3513         i,j    : longint;
3514         dpos,pad: aword;
3515       begin
3516         for j:=0 to ExeSectionList.Count-1 do
3517           begin
3518             exesec:=TExeSection(ExeSectionList[j]);
3519             { don't write normal section if writing only debug info }
3520             if (ExeWriteMode=ewm_dbgonly) and
3521                (exesec.SecOptions*[oso_debug,oso_debug_copy]=[]) then
3522               continue;
3523 
3524             if oso_data in exesec.SecOptions then
3525               begin
3526                 if exesec.DataPos<FWriter.Size then
3527                   InternalError(2012103001);
3528                 FWriter.Writezeros(exesec.DataPos-FWriter.Size);
3529                 for i:=0 to exesec.ObjSectionList.Count-1 do
3530                   begin
3531                     objsec:=TObjSection(exesec.ObjSectionList[i]);
3532                     if oso_data in objsec.secoptions then
3533                       begin
3534                         if not assigned(objsec.data) then
3535                           internalerror(200603042);
3536                         dpos:=objsec.MemPos-exesec.MemPos+exesec.DataPos;
3537                         pad:=dpos-FWriter.Size;
3538                         { objsection must be within SecAlign bytes from the previous one }
3539                         if (dpos<FWriter.Size) or
3540                           (pad>=max(objsec.SecAlign,1)) then
3541                           internalerror(200602251);
3542                         FWriter.writeZeros(pad);
3543                         FWriter.writearray(objsec.data);
3544                       end;
3545                   end;
3546               end;
3547           end;
3548       end;
3549 
3550 
3551     procedure TExeOutput.ReplaceExeSectionList(newlist: TFPList);
3552       var
3553         tmp: TFPHashObjectList;
3554         i: longint;
3555       begin
3556         tmp:=TFPHashObjectList.Create(true);
3557         for i:=0 to newlist.count-1 do
3558           TFPHashObject(newlist[i]).ChangeOwner(tmp);
3559         { prevent destruction of existing sections }
3560         for i:=0 to ExeSectionList.count-1 do
3561           ExeSectionList.List[i]:=nil;
3562         FExeSectionList.Free;
3563         FExeSectionList:=tmp;
3564       end;
3565 
3566 
3567 {****************************************************************************
3568                                 TObjInput
3569 ****************************************************************************}
3570 
3571     constructor TObjInput.create;
3572       begin
3573       end;
3574 
3575 
3576     procedure TObjInput.inputerror(const s : string);
3577       begin
3578         Comment(V_Error,s+' while reading '+InputFileName);
3579       end;
3580 
3581 
TObjInput.CanReadObjDatanull3582     class function TObjInput.CanReadObjData(AReader:TObjectReader):boolean;
3583       begin
3584         result:=false;
3585       end;
3586 
3587 
3588     procedure TObjInput.ReadSectionContent(Data:TObjData);
3589       var
3590         i: longint;
3591         sec: TObjSection;
3592       begin
3593         for i:=0 to Data.ObjSectionList.Count-1 do
3594           begin
3595             sec:=TObjSection(Data.ObjSectionList[i]);
3596             { Skip debug sections }
3597             if (oso_debug in sec.SecOptions) and
3598                (cs_link_strip in current_settings.globalswitches) and
3599                not(cs_link_separate_dbg_file in current_settings.globalswitches) then
3600               continue;
3601 
3602             if assigned(sec.Data) then
3603               begin
3604                 FReader.Seek(sec.datapos);
3605                 if not FReader.ReadArray(sec.data,sec.Size) then
3606                   begin
3607                     InputError('Can''t read object data');
3608                     exit;
3609                   end;
3610               end;
3611           end;
3612       end;
3613 
3614 
3615 {$ifdef MEMDEBUG}
3616 initialization
3617   memobjsymbols:=TMemDebug.create('ObjSymbols');
3618   memobjsymbols.stop;
3619   memobjsections:=TMemDebug.create('ObjSections');
3620   memobjsections.stop;
3621 
3622 finalization
3623   memobjsymbols.free;
3624   memobjsections.free;
3625 {$endif MEMDEBUG}
3626 end.
3627