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