fpc/compiler/ogbase.pas
Jonas Maebe 6432c82c01 * don't pass property as var-parameter to val()
git-svn-id: trunk@20137 -
2012-01-21 16:54:57 +00:00

2863 lines
94 KiB
ObjectPascal

{
Copyright (c) 1998-2006 by Peter Vreman
Contains the base stuff for binary object file writers
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit ogbase;
{$i fpcdefs.inc}
interface
uses
{ common }
cutils,
cclasses,
{ targets }
systems,globtype,
{ outputwriters }
owbase,
{ assembler }
aasmbase;
type
TObjSection = class;
TObjData = class;
TExeSection = class;
TExeSymbol = class;
TObjRelocationType = (
{ Relocation to absolute address }
RELOC_ABSOLUTE,
{$ifdef x86_64}
{ 32bit Relocation to absolute address }
RELOC_ABSOLUTE32,
{ 64 bit coff only }
RELOC_RELATIVE_1,
RELOC_RELATIVE_2,
RELOC_RELATIVE_3,
RELOC_RELATIVE_4,
RELOC_RELATIVE_5,
{ PIC }
RELOC_GOTPCREL,
RELOC_PLT32,
{$endif x86_64}
{$ifdef i386}
{ PIC }
RELOC_GOTPC,
RELOC_GOT32,
RELOC_PLT32,
{$endif i386}
{$ifdef arm}
RELOC_RELATIVE_24,
{$endif arm}
{ Relative relocation }
RELOC_RELATIVE,
{ PECoff (Windows) RVA relocation }
RELOC_RVA,
{ PECoff (Windows) section relocation, required by DWARF2 debug info }
RELOC_SECREL32,
{ Generate a 0 value at the place of the relocation,
this is used to remove unused vtable entries }
RELOC_ZERO,
{ No relocation is needed. It is used in ARM object files.
Also internal linker use this reloc to make virtual (not real)
links to some sections }
RELOC_NONE,
{ Darwin relocation, using PAIR }
RELOC_PIC_PAIR
);
{$ifndef x86_64}
const
RELOC_ABSOLUTE32 = RELOC_ABSOLUTE;
{$endif x86_64}
const
{ stab types }
N_GSYM = $20;
N_STSYM = 38; { initialized const }
N_LCSYM = 40; { non initialized variable}
N_Function = $24; { function or const }
N_TextLine = $44;
N_DataLine = $46;
N_BssLine = $48;
N_RSYM = $40; { register variable }
N_LSYM = $80;
N_tsym = 160;
N_SourceFile = $64;
N_IncludeFile = $84;
N_BINCL = $82;
N_EINCL = $A2;
N_LBRAC = $C0;
N_EXCL = $C2;
N_RBRAC = $E0;
{ GNU extensions }
debuglinkname='.gnu_debuglink';
type
TObjSectionOption = (
{ Has Data available in the file }
oso_Data,
{ Is loaded into memory }
oso_load,
{ Not loaded into memory }
oso_noload,
{ Read only }
oso_readonly,
{ Read/Write }
oso_write,
{ Contains executable instructions }
oso_executable,
{ Never discard section }
oso_keep,
{ Special common symbols }
oso_common,
{ Contains debug info and can be stripped }
oso_debug,
{ Contains only strings }
oso_strings
);
TObjSectionOptions = set of TObjSectionOption;
TObjSymbol = class(TFPHashObject)
public
bind : TAsmsymbind;
typ : TAsmsymtype;
{ Current assemble pass, used to detect duplicate labels }
pass : byte;
objsection : TObjSection;
symidx : longint;
offset,
size : aword;
{ Used for external and common solving during linking }
exesymbol : TExeSymbol;
{ Darwin asm is using indirect symbols resolving }
indsymbol : TObjSymbol;
constructor create(AList:TFPHashObjectList;const AName:string);
function address:aword;
procedure SetAddress(apass:byte;aobjsec:TObjSection;abind:TAsmsymbind;atyp:Tasmsymtype);
end;
{ Stabs is common for all targets }
TObjStabEntry=packed record
strpos : longint;
ntype : byte;
nother : byte;
ndesc : word;
nvalue : longint;
end;
PObjStabEntry=^TObjStabEntry;
TObjRelocation = class
DataOffset,
orgsize : aword; { original size of the symbol to Relocate, required for COFF }
symbol : TObjSymbol;
objsection : TObjSection; { only used if symbol=nil }
typ : TObjRelocationType;
constructor CreateSymbol(ADataOffset:aword;s:TObjSymbol;Atyp:TObjRelocationType);
constructor CreateSymbolSize(ADataOffset:aword;s:TObjSymbol;Aorgsize:aword;Atyp:TObjRelocationType);
constructor CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType);
end;
TObjSection = class(TFPHashObject)
private
FData : TDynamicArray;
FSecOptions : TObjSectionOptions;
FCachedFullName : pshortstring;
procedure SetSecOptions(Aoptions:TObjSectionOptions);
public
ObjData : TObjData;
SecSymIdx : longint; { index for the section in symtab }
SecAlign : shortint; { alignment of the section }
{ section Data }
Size,
DataPos,
MemPos : aword;
DataAlignBytes : shortint;
{ Relocations (=references) to other sections }
ObjRelocations : TFPObjectList;
{ Symbols this defines }
ObjSymbolDefines : TFPObjectList;
{ executable linking }
ExeSection : TExeSection;
USed : Boolean;
VTRefList : TFPObjectList;
constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);virtual;
destructor destroy;override;
function write(const d;l:aword):aword;
function writestr(const s:string):aword;
function WriteZeros(l:longword):aword;
function setmempos(mpos:qword):qword;
procedure setDatapos(var dpos:aword);
procedure alloc(l:aword);
procedure addsymReloc(ofs:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
procedure addsectionReloc(ofs:aword;aobjsec:TObjSection;Reloctype:TObjRelocationType);
procedure AddSymbolDefine(p:TObjSymbol);
procedure FixupRelocs;virtual;
procedure ReleaseData;
function FullName:string;
property Data:TDynamicArray read FData;
property SecOptions:TObjSectionOptions read FSecOptions write SetSecOptions;
end;
TObjSectionClass = class of TObjSection;
TString80 = string[80];
TObjData = class(TLinkedListItem)
private
FName : TString80;
FCurrObjSec : TObjSection;
FObjSectionList : TFPHashObjectList;
FCObjSection : TObjSectionClass;
{ Symbols that will be defined in this object file }
FObjSymbolList : TFPHashObjectList;
FCachedAsmSymbolList : TFPObjectList;
{ Special info sections that are written to during object generation }
FStabsObjSec,
FStabStrObjSec : TObjSection;
procedure section_reset(p:TObject;arg:pointer);
procedure section_afteralloc(p:TObject;arg:pointer);
procedure section_afterwrite(p:TObject;arg:pointer);
protected
property CObjSection:TObjSectionClass read FCObjSection write FCObjSection;
public
CurrPass : byte;
ImageBase : aword;
constructor create(const n:string);virtual;
destructor destroy;override;
{ Sections }
function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;virtual;
function sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;virtual;
function sectiontype2align(atype:TAsmSectiontype):shortint;virtual;
function createsection(atype:TAsmSectionType;const aname:string='';aorder:TAsmSectionOrder=secorder_default):TObjSection;
function createsection(const aname:string;aalign:shortint;aoptions:TObjSectionOptions;DiscardDuplicate:boolean=true):TObjSection;virtual;
procedure CreateDebugSections;virtual;
function findsection(const aname:string):TObjSection;
procedure setsection(asec:TObjSection);
{ Symbols }
function createsymbol(const aname:string):TObjSymbol;
function symboldefine(asmsym:TAsmSymbol):TObjSymbol;
function symboldefine(const aname:string;abind:TAsmsymbind;atyp:Tasmsymtype):TObjSymbol;
function symbolref(asmsym:TAsmSymbol):TObjSymbol;
function symbolref(const aname:string):TObjSymbol;
procedure ResetCachedAsmSymbols;
{ Allocation }
procedure alloc(len:aword);
procedure allocalign(len:shortint);
procedure writebytes(const Data;len:aword);
procedure writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);virtual;abstract;
procedure beforealloc;virtual;
procedure beforewrite;virtual;
procedure afteralloc;virtual;
procedure afterwrite;virtual;
procedure resetsections;
property Name:TString80 read FName;
property CurrObjSec:TObjSection read FCurrObjSec;
property ObjSymbolList:TFPHashObjectList read FObjSymbolList;
property ObjSectionList:TFPHashObjectList read FObjSectionList;
property StabsSec:TObjSection read FStabsObjSec write FStabsObjSec;
property StabStrSec:TObjSection read FStabStrObjSec write FStabStrObjSec;
end;
TObjDataClass = class of TObjData;
TObjOutput = class
private
FCObjData : TObjDataClass;
protected
{ writer }
FWriter : TObjectwriter;
function writeData(Data:TObjData):boolean;virtual;abstract;
property CObjData : TObjDataClass read FCObjData write FCObjData;
public
constructor create(AWriter:TObjectWriter);virtual;
destructor destroy;override;
function newObjData(const n:string):TObjData;
function startObjectfile(const fn:string):boolean;
function writeobjectfile(Data:TObjData):boolean;
procedure exportsymbol(p:TObjSymbol);
property Writer:TObjectWriter read FWriter;
end;
TObjOutputClass=class of TObjOutput;
TObjInput = class
private
FCObjData : TObjDataClass;
protected
{ reader }
FReader : TObjectReader;
InputFileName : string;
property CObjData : TObjDataClass read FCObjData write FCObjData;
public
constructor create;virtual;
destructor destroy;override;
function newObjData(const n:string):TObjData;
function ReadObjData(AReader:TObjectreader;Data:TObjData):boolean;virtual;abstract;
procedure inputerror(const s : string);
end;
TObjInputClass=class of TObjInput;
TVTableEntry=record
ObjRelocation : TObjRelocation;
orgreloctype : TObjRelocationType;
Enabled,
Used : Boolean;
end;
PVTableEntry=^TVTableEntry;
TExeVTable = class
private
procedure CheckIdx(VTableIdx:longint);
public
ExeSymbol : TExeSymbol;
EntryCnt : Longint;
EntryArray : PVTableEntry;
Consolidated : Boolean;
ChildList : TFPObjectList;
constructor Create(AExeSymbol:TExeSymbol);
destructor Destroy;override;
procedure AddChild(vt:TExeVTable);
procedure AddEntry(VTableIdx:Longint);
procedure SetVTableSize(ASize:longint);
function VTableRef(VTableIdx:Longint):TObjRelocation;
end;
TSymbolState = (symstate_undefined,symstate_defined,symstate_common);
TExeSymbol = class(TFPHashObject)
ObjSymbol : TObjSymbol;
ExeSection : TExeSection;
State : TSymbolState;
{ Used for vmt references optimization }
VTable : TExeVTable;
end;
TExeSection = class(TFPHashObject)
private
FSecSymIdx : longint;
FObjSectionList : TFPObjectList;
public
Size,
DataPos,
MemPos : aword;
SecAlign : shortint;
SecOptions : TObjSectionOptions;
constructor create(AList:TFPHashObjectList;const AName:string);virtual;
destructor destroy;override;
procedure AddObjSection(objsec:TObjSection);
property ObjSectionList:TFPObjectList read FObjSectionList;
property SecSymIdx:longint read FSecSymIdx write FSecSymIdx;
end;
TExeSectionClass=class of TExeSection;
TStaticLibrary = class(TFPHashObject)
private
FArReader : TObjectReader;
FObjInputClass : TObjInputClass;
public
constructor create(AList:TFPHashObjectList;const AName:string;AReader:TObjectReader;AObjInputClass:TObjInputClass);
destructor destroy;override;
property ArReader:TObjectReader read FArReader;
property ObjInputClass:TObjInputClass read FObjInputClass;
end;
TImportLibrary = class(TFPHashObject)
private
FImportSymbolList : TFPHashObjectList;
public
constructor create(AList:TFPHashObjectList;const AName:string);
destructor destroy;override;
property ImportSymbolList:TFPHashObjectList read FImportSymbolList;
end;
TImportSymbol = class(TFPHashObject)
private
FOrdNr : longint;
FIsVar : boolean;
FMangledName : string;
public
constructor create(AList:TFPHashObjectList;const AName,AMangledName:string;AOrdNr:longint;AIsVar:boolean);
property OrdNr: longint read FOrdNr;
property MangledName: string read FMangledName;
property IsVar: boolean read FIsVar;
end;
TExeWriteMode = (ewm_exefull,ewm_dbgonly,ewm_exeonly);
TExeOutput = class
private
{ ExeSectionList }
FCObjData : TObjDataClass;
FCExeSection : TExeSectionClass;
FCurrExeSec : TExeSection;
FExeSectionList : TFPHashObjectList;
Fzeronr : longint;
Fvaluesnr : longint;
{ Symbols }
FExeSymbolList : TFPHashObjectList;
FUnresolvedExeSymbols : TFPObjectList;
FExternalObjSymbols,
FCommonObjSymbols : TFPObjectList;
FEntryName : string;
FExeVTableList : TFPObjectList;
{ Objects }
FObjDataList : TFPObjectList;
{ Position calculation }
FImageBase : aword;
FCurrMemPos : qword;
procedure SetCurrMemPos(const AValue: qword);
protected
{ writer }
FExeWriteMode : TExeWriteMode;
FWriter : TObjectwriter;
commonObjSection : TObjSection;
internalObjData : TObjData;
EntrySym : TObjSymbol;
SectionDataAlign,
SectionMemAlign : aword;
function writeData:boolean;virtual;abstract;
property CExeSection:TExeSectionClass read FCExeSection write FCExeSection;
property CObjData:TObjDataClass read FCObjData write FCObjData;
procedure Order_ObjSectionList(ObjSectionList : TFPObjectList; const aPattern:string);virtual;
public
CurrDataPos : aword;
MaxMemPos : qword;
IsSharedLibrary : boolean;
constructor create;virtual;
destructor destroy;override;
function FindExeSection(const aname:string):TExeSection;
procedure AddObjData(ObjData:TObjData);
procedure Load_Start;virtual;
procedure Load_EntryName(const aname:string);virtual;
procedure Load_Symbol(const aname:string);virtual;
procedure Load_ProvideSymbol(const aname:string);virtual;
procedure Load_IsSharedLibrary;
procedure Load_ImageBase(const avalue:string);
procedure Order_Start;virtual;
procedure Order_End;virtual;
procedure Order_ExeSection(const aname:string);virtual;
procedure Order_Align(const avalue:string);virtual;
procedure Order_Zeros(const avalue:string);virtual;
procedure Order_Values(bytesize : aword; const avalue:string);virtual;
procedure Order_Symbol(const aname:string);virtual;
procedure Order_ProvideSymbol(const aname:string);virtual;
procedure Order_EndExeSection;virtual;
procedure Order_ObjSection(const aname:string);virtual;
procedure MemPos_Start;virtual;
procedure MemPos_Header;virtual;
procedure MemPos_ExeSection(const aname:string);virtual;
procedure MemPos_EndExeSection;virtual;
procedure DataPos_Start;virtual;
procedure DataPos_Header;virtual;
procedure DataPos_ExeSection(const aname:string);virtual;
procedure DataPos_EndExeSection;virtual;
procedure DataPos_Symbols;virtual;
procedure BuildVTableTree(VTInheritList,VTEntryList:TFPObjectList);
procedure PackUnresolvedExeSymbols(const s:string);
procedure ResolveSymbols(StaticLibraryList:TFPHashObjectList);
procedure PrintMemoryMap;
procedure FixupSymbols;
procedure FixupRelocations;
procedure MergeStabs;
procedure RemoveUnreferencedSections;
procedure RemoveEmptySections;
procedure RemoveDebugInfo;
procedure GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);virtual;
procedure GenerateDebugLink(const dbgname:string;dbgcrc:cardinal);
function WriteExeFile(const fn:string):boolean;
procedure ParseScript (linkscript:TCmdStrList); virtual;
property Writer:TObjectWriter read FWriter;
property ExeSectionList:TFPHashObjectList read FExeSectionList;
property ObjDataList:TFPObjectList read FObjDataList;
property ExeSymbolList:TFPHashObjectList read FExeSymbolList;
property UnresolvedExeSymbols:TFPObjectList read FUnresolvedExeSymbols;
property ExternalObjSymbols:TFPObjectList read FExternalObjSymbols;
property CommonObjSymbols:TFPObjectList read FCommonObjSymbols;
property ExeVTableList:TFPObjectList read FExeVTableList;
property EntryName:string read FEntryName write FEntryName;
property ImageBase:aword read FImageBase write FImageBase;
property CurrExeSec:TExeSection read FCurrExeSec;
property ExeWriteMode:TExeWriteMode read FExeWriteMode write FExeWriteMode;
property CurrMemPos:qword read FCurrMemPos write SetCurrMemPos;
end;
TExeOutputClass=class of TExeOutput;
var
exeoutput : TExeOutput;
implementation
uses
SysUtils,
globals,verbose,fmodule,ogmap;
const
SectionDataMaxGrow = 4096;
{$ifdef MEMDEBUG}
var
memobjsymbols,
memobjsections : TMemDebug;
{$endif MEMDEBUG}
{*****************************************************************************
TObjSymbol
*****************************************************************************}
constructor TObjSymbol.create(AList:TFPHashObjectList;const AName:string);
begin;
inherited create(AList,AName);
bind:=AB_EXTERNAL;
typ:=AT_NONE;
symidx:=-1;
size:=0;
offset:=0;
objsection:=nil;
end;
function TObjSymbol.address:aword;
begin
if assigned(objsection) then
result:=offset+objsection.mempos
else
result:=0;
end;
procedure TObjSymbol.SetAddress(apass:byte;aobjsec:TObjSection;abind:TAsmsymbind;atyp:Tasmsymtype);
begin
if not(abind in [AB_GLOBAL,AB_LOCAL,AB_COMMON,AB_IMPORT]) then
internalerror(200603016);
if not assigned(aobjsec) then
internalerror(200603017);
if (bind in [AB_EXTERNAL,AB_LAZY]) or
{ Put all COMMON to GLOBAL in step 3 of
TExeOutput.ResolveSymbols }
((abind=AB_GLOBAL) and (bind=AB_COMMON)) then
begin
{ Do not change the AB_TYPE of common symbols yet }
{ This will be done in FixupSymbols }
if (pass<>0) or (bind<>AB_COMMON) then
bind:=abind;
typ:=atyp;
end
else
begin
if pass=apass then
begin
Message1(asmw_e_duplicate_label,name);
exit;
end;
end;
pass:=apass;
{ Code can never grow after a pass }
if assigned(objsection) and
(objsection=aobjsec) and
(aobjsec.size>offset) then
internalerror(200603014);
objsection:=aobjsec;
offset:=aobjsec.size;
end;
{****************************************************************************
TObjRelocation
****************************************************************************}
constructor TObjRelocation.CreateSymbol(ADataOffset:aword;s:TObjSymbol;Atyp:TObjRelocationType);
begin
if not assigned(s) then
internalerror(200603034);
DataOffset:=ADataOffset;
Symbol:=s;
OrgSize:=0;
ObjSection:=nil;
Typ:=Atyp;
end;
constructor TObjRelocation.CreateSymbolSize(ADataOffset:aword;s:TObjSymbol;Aorgsize:aword;Atyp:TObjRelocationType);
begin
if not assigned(s) then
internalerror(200603035);
DataOffset:=ADataOffset;
Symbol:=s;
OrgSize:=Aorgsize;
ObjSection:=nil;
Typ:=Atyp;
end;
constructor TObjRelocation.CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType);
begin
if not assigned(aobjsec) then
internalerror(200603036);
DataOffset:=ADataOffset;
Symbol:=nil;
OrgSize:=0;
ObjSection:=aobjsec;
Typ:=Atyp;
end;
{****************************************************************************
TObjSection
****************************************************************************}
constructor TObjSection.create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);
begin
inherited Create(AList,Aname);
{ Data }
Size:=0;
Datapos:=0;
mempos:=0;
FData:=Nil;
{ Setting the secoptions allocates Data if needed }
secoptions:=Aoptions;
secalign:=Aalign;
secsymidx:=0;
{ relocation }
ObjRelocations:=TFPObjectList.Create(true);
ObjSymbolDefines:=TFPObjectList.Create(false);
VTRefList:=TFPObjectList.Create(false);
end;
destructor TObjSection.destroy;
begin
if assigned(Data) then
Data.Free;
stringdispose(FCachedFullName);
ObjRelocations.Free;
ObjSymbolDefines.Free;
VTRefList.Free;
inherited destroy;
end;
procedure TObjSection.SetSecOptions(Aoptions:TObjSectionOptions);
begin
FSecOptions:=FSecOptions+AOptions;
if (oso_Data in secoptions) and
not assigned(FData) then
FData:=TDynamicArray.Create(SectionDataMaxGrow);
end;
function TObjSection.write(const d;l:aword):aword;
begin
result:=size;
if assigned(Data) then
begin
if Size<>Data.size then
internalerror(200602281);
Data.write(d,l);
inc(Size,l);
end
else
internalerror(200602289);
end;
function TObjSection.writestr(const s:string):aword;
begin
result:=Write(s[1],length(s));
end;
function TObjSection.WriteZeros(l:longword):aword;
var
empty : array[0..1023] of byte;
begin
if l>sizeof(empty) then
internalerror(200404082);
if l>0 then
begin
fillchar(empty,l,0);
result:=Write(empty,l);
end
else
result:=Size;
end;
procedure TObjSection.setDatapos(var dpos:aword);
begin
if oso_Data in secoptions then
begin
{ get aligned Datapos }
Datapos:=align(dpos,secalign);
Dataalignbytes:=Datapos-dpos;
{ return updated Datapos }
dpos:=Datapos+size;
end
else
Datapos:=dpos;
end;
function TObjSection.setmempos(mpos:qword):qword;
begin
mempos:=align(mpos,secalign);
{ return updated mempos }
result:=mempos+size;
end;
procedure TObjSection.alloc(l:aword);
begin
inc(size,l);
end;
procedure TObjSection.addsymReloc(ofs:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
begin
ObjRelocations.Add(TObjRelocation.CreateSymbol(ofs,p,reloctype));
end;
procedure TObjSection.addsectionReloc(ofs:aword;aobjsec:TObjSection;Reloctype:TObjRelocationType);
begin
ObjRelocations.Add(TObjRelocation.CreateSection(ofs,aobjsec,reloctype));
end;
procedure TObjSection.AddSymbolDefine(p:TObjSymbol);
begin
if p.bind<>AB_GLOBAL then
exit;
ObjSymbolDefines.Add(p);
end;
procedure TObjSection.FixupRelocs;
begin
end;
procedure TObjSection.ReleaseData;
begin
if assigned(FData) then
begin
FData.free;
FData:=nil;
end;
ObjRelocations.free;
ObjRelocations:=nil;
ObjSymbolDefines.Free;
ObjSymbolDefines:=nil;
if assigned(FCachedFullName) then
begin
stringdispose(FCachedFullName);
FCachedFullName:=nil;
end;
end;
function TObjSection.FullName:string;
begin
if not assigned(FCachedFullName) then
begin
if assigned(ObjData) then
FCachedFullName:=stringdup(ObjData.Name+'('+Name+')')
else
FCachedFullName:=stringdup(Name);
end;
result:=FCachedFullName^;
end;
{****************************************************************************
TObjData
****************************************************************************}
constructor TObjData.create(const n:string);
begin
inherited create;
FName:=ExtractFileName(n);
FObjSectionList:=TFPHashObjectList.Create(true);
FStabsObjSec:=nil;
FStabStrObjSec:=nil;
{ symbols }
FObjSymbolList:=TFPHashObjectList.Create(true);
FCachedAsmSymbolList:=TFPObjectList.Create(false);
{ section class type for creating of new sections }
FCObjSection:=TObjSection;
end;
destructor TObjData.destroy;
begin
{ Symbols }
{$ifdef MEMDEBUG}
MemObjSymbols.Start;
{$endif}
ResetCachedAsmSymbols;
FCachedAsmSymbolList.free;
FObjSymbolList.free;
{$ifdef MEMDEBUG}
MemObjSymbols.Stop;
{$endif}
{ Sections }
{$ifdef MEMDEBUG}
MemObjSections.Start;
{$endif}
FObjSectionList.free;
{$ifdef MEMDEBUG}
MemObjSections.Stop;
{$endif}
inherited destroy;
end;
function TObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
const
secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
'code',
'Data',
'Data',
'roData',
'bss',
'threadvar',
'pdata',
'stub',
'data_nonlazy',
'data_lazy',
'init_func',
'term_func',
'stab','stabstr',
'iData2','iData4','iData5','iData6','iData7','eData',
'eh_frame',
'debug_frame','debug_info','debug_line','debug_abbrev',
'fpc',
'toc',
'init',
'fini',
'objc_class',
'objc_meta_class',
'objc_cat_cls_meth',
'objc_cat_inst_meth',
'objc_protocol',
'objc_string_object',
'objc_cls_meth',
'objc_inst_meth',
'objc_cls_refs',
'objc_message_refs',
'objc_symbols',
'objc_category',
'objc_class_vars',
'objc_instance_vars',
'objc_module_info',
'objc_class_names',
'objc_meth_var_types',
'objc_meth_var_names',
'objc_selector_strs',
'objc_protocol_ext',
'objc_class_ext',
'objc_property',
'objc_image_info',
'objc_cstring_object',
'objc_sel_fixup',
'__DATA,__objc_data',
'__DATA,__objc_const',
'.objc_superrefs',
'__DATA, __datacoal_nt,coalesced',
'.objc_classlist',
'.objc_nlclasslist',
'.objc_catlist',
'.obcj_nlcatlist',
'.objc_protolist'
);
var
sep : string[3];
begin
if aname<>'' then
begin
case aorder of
secorder_begin :
sep:='.b_';
secorder_end :
sep:='.z_';
else
sep:='.n_';
end;
result:=secnames[atype]+sep+aname
end
else
result:=secnames[atype];
end;
function TObjData.sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;
const
secoptions : array[TAsmSectiontype] of TObjSectionOptions = ([],
{user} [oso_Data,oso_load,oso_write,oso_keep],
{code} [oso_Data,oso_load,oso_readonly,oso_executable,oso_keep],
{Data} [oso_Data,oso_load,oso_write,oso_keep],
{ TODO: Fix sec_rodata be read-only-with-relocs}
{roData} [oso_Data,oso_load,oso_write,oso_keep],
{ TODO: Fix sec_rodata_norel be read-only/constant}
{roData_norel} [oso_Data,oso_load,oso_write,oso_keep],
{bss} [oso_load,oso_write,oso_keep],
{threadvar} [oso_load,oso_write
{$ifdef FPC_USE_TLS_DIRECTORY}
,oso_keep
{$endif FPC_USE_TLS_DIRECTORY}
],
{pdata} [oso_data,oso_load,oso_readonly {$ifndef x86_64},oso_keep{$endif}],
{stub} [oso_Data,oso_load,oso_readonly,oso_executable],
{data_nonlazy} [oso_Data,oso_load,oso_write],
{data_lazy} [oso_Data,oso_load,oso_write],
{init_func} [oso_Data,oso_load],
{term_func} [oso_Data,oso_load],
{stab} [oso_Data,oso_noload,oso_debug],
{stabstr} [oso_Data,oso_noload,oso_strings,oso_debug],
{iData2} [oso_Data,oso_load,oso_write],
{iData4} [oso_Data,oso_load,oso_write],
{iData5} [oso_Data,oso_load,oso_write],
{iData6} [oso_Data,oso_load,oso_write],
{iData7} [oso_Data,oso_load,oso_write],
{eData} [oso_Data,oso_load,oso_readonly],
{eh_frame} [oso_Data,oso_load,oso_readonly],
{debug_frame} [oso_Data,oso_noload,oso_debug],
{debug_info} [oso_Data,oso_noload,oso_debug],
{debug_line} [oso_Data,oso_noload,oso_debug],
{debug_abbrev} [oso_Data,oso_noload,oso_debug],
{fpc} [oso_Data,oso_load,oso_write,oso_keep],
{toc} [oso_Data,oso_load,oso_readonly],
{init} [oso_Data,oso_load,oso_readonly,oso_executable,oso_keep],
{fini} [oso_Data,oso_load,oso_readonly,oso_executable,oso_keep],
{objc_class} [oso_data,oso_load],
{objc_meta_class} [oso_data,oso_load],
{objc_cat_cls_meth} [oso_data,oso_load],
{objc_cat_inst_meth} [oso_data,oso_load],
{objc_protocol} [oso_data,oso_load],
{objc_string_object} [oso_data,oso_load],
{objc_cls_meth} [oso_data,oso_load],
{objc_inst_meth} [oso_data,oso_load],
{objc_cls_refs} [oso_data,oso_load],
{objc_message_refs} [oso_data,oso_load],
{objc_symbols} [oso_data,oso_load],
{objc_category} [oso_data,oso_load],
{objc_class_vars} [oso_data,oso_load],
{objc_instance_vars} [oso_data,oso_load],
{objc_module_info} [oso_data,oso_load],
{objc_class_names} [oso_data,oso_load],
{objc_meth_var_types} [oso_data,oso_load],
{objc_meth_var_names} [oso_data,oso_load],
{objc_selector_strs} [oso_data,oso_load],
{objc_protocol_ext} [oso_data,oso_load],
{objc_class_ext} [oso_data,oso_load],
{objc_property} [oso_data,oso_load],
{objc_image_info} [oso_data,oso_load],
{objc_cstring_object} [oso_data,oso_load],
{objc_sel_fixup} [oso_data,oso_load],
{sec_objc_data} [oso_data,oso_load],
{sec_objc_const} [oso_data,oso_load],
{sec_objc_sup_refs} [oso_data,oso_load],
{sec_data_coalesced} [oso_data,oso_load],
{sec_objc_classlist} [oso_data,oso_load],
{sec_objc_nlclasslist} [oso_data,oso_load],
{sec_objc_catlist} [oso_data,oso_load],
{sec_objc_nlcatlist} [oso_data,oso_load],
{sec_objc_protolist'} [oso_data,oso_load]
);
begin
result:=secoptions[atype];
end;
function TObjData.sectiontype2align(atype:TAsmSectiontype):shortint;
begin
case atype of
sec_stabstr,sec_debug_info,sec_debug_line,sec_debug_abbrev:
result:=1;
sec_code,
sec_bss,
sec_data:
result:=16;
{ For idata (at least idata2) it must be 4 bytes, because
an entry is always (also in win64) 20 bytes and aligning
on 8 bytes will insert 4 bytes between the entries resulting
in a corrupt idata section.
Same story with .pdata, it has 4-byte elements which should
be packed without gaps. }
sec_idata2,sec_idata4,sec_idata5,sec_idata6,sec_idata7,sec_pdata:
result:=4;
else
result:=sizeof(pint);
end;
end;
function TObjData.createsection(atype:TAsmSectionType;const aname:string;aorder:TAsmSectionOrder):TObjSection;
begin
result:=createsection(sectionname(atype,aname,aorder),sectiontype2align(atype),sectiontype2options(atype));
end;
function TObjData.createsection(const aname:string;aalign:shortint;aoptions:TObjSectionOptions;DiscardDuplicate:boolean):TObjSection;
begin
if DiscardDuplicate then
result:=TObjSection(FObjSectionList.Find(aname))
else
result:=nil;
if not assigned(result) then
begin
result:=CObjSection.create(FObjSectionList,aname,aalign,aoptions);
result.ObjData:=self;
end;
FCurrObjSec:=result;
end;
procedure TObjData.CreateDebugSections;
begin
end;
function TObjData.FindSection(const aname:string):TObjSection;
begin
result:=TObjSection(FObjSectionList.Find(aname));
end;
procedure TObjData.setsection(asec:TObjSection);
begin
if asec.ObjData<>self then
internalerror(200403041);
FCurrObjSec:=asec;
end;
function TObjData.createsymbol(const aname:string):TObjSymbol;
begin
result:=TObjSymbol(FObjSymbolList.Find(aname));
if not assigned(result) then
result:=TObjSymbol.Create(FObjSymbolList,aname);
end;
function TObjData.symboldefine(asmsym:TAsmSymbol):TObjSymbol;
begin
if assigned(asmsym) then
begin
if not assigned(asmsym.cachedObjSymbol) then
begin
result:=symboldefine(asmsym.name,asmsym.bind,asmsym.typ);
asmsym.cachedObjSymbol:=result;
FCachedAsmSymbolList.add(asmsym);
end
else
begin
result:=TObjSymbol(asmsym.cachedObjSymbol);
result.SetAddress(CurrPass,CurrObjSec,asmsym.bind,asmsym.typ);
{ Register also in TObjSection }
CurrObjSec.AddSymbolDefine(result);
end;
end
else
result:=nil;
end;
function TObjData.symboldefine(const aname:string;abind:TAsmsymbind;atyp:Tasmsymtype):TObjSymbol;
begin
if not assigned(CurrObjSec) then
internalerror(200603051);
result:=CreateSymbol(aname);
{ Register also in TObjSection }
CurrObjSec.AddSymbolDefine(result);
result.SetAddress(CurrPass,CurrObjSec,abind,atyp);
end;
function TObjData.symbolref(asmsym:TAsmSymbol):TObjSymbol;
begin
if assigned(asmsym) then
begin
if not assigned(asmsym.cachedObjSymbol) then
begin
result:=symbolref(asmsym.name);
asmsym.cachedObjSymbol:=result;
FCachedAsmSymbolList.add(asmsym);
end
else
result:=TObjSymbol(asmsym.cachedObjSymbol);
end
else
result:=nil;
end;
function TObjData.symbolref(const aname:string):TObjSymbol;
begin
if not assigned(CurrObjSec) then
internalerror(200603052);
result:=CreateSymbol(aname);
end;
procedure TObjData.ResetCachedAsmSymbols;
var
i : longint;
begin
for i:=0 to FCachedAsmSymbolList.Count-1 do
tasmsymbol(FCachedAsmSymbolList[i]).cachedObjSymbol:=nil;
FCachedAsmSymbolList.Clear;
end;
procedure TObjData.writebytes(const Data;len:aword);
begin
if not assigned(CurrObjSec) then
internalerror(200402251);
CurrObjSec.write(Data,len);
end;
procedure TObjData.alloc(len:aword);
begin
if not assigned(CurrObjSec) then
internalerror(200402252);
CurrObjSec.alloc(len);
end;
procedure TObjData.allocalign(len:shortint);
begin
if not assigned(CurrObjSec) then
internalerror(200402253);
CurrObjSec.alloc(align(CurrObjSec.size,len)-CurrObjSec.size);
end;
procedure TObjData.section_afteralloc(p:TObject;arg:pointer);
begin
with TObjSection(p) do
alloc(align(size,secalign)-size);
end;
procedure TObjData.section_afterwrite(p:TObject;arg:pointer);
begin
with TObjSection(p) do
begin
if assigned(Data) then
writezeros(align(size,secalign)-size);
end;
end;
procedure TObjData.section_reset(p:TObject;arg:pointer);
begin
with TObjSection(p) do
begin
Size:=0;
Datapos:=0;
mempos:=0;
end;
end;
procedure TObjData.beforealloc;
begin
{ create stabs sections if debugging }
if assigned(StabsSec) then
begin
StabsSec.Alloc(sizeof(TObjStabEntry));
StabStrSec.Alloc(1);
end;
end;
procedure TObjData.beforewrite;
var
s : string[1];
hstab : TObjStabEntry;
begin
{ create stabs sections if debugging }
if assigned(StabsSec) then
begin
{ Create dummy HdrSym stab, it will be overwritten in AfterWrite }
fillchar(hstab,sizeof(hstab),0);
StabsSec.Write(hstab,sizeof(hstab));
{ start of stabstr }
s:=#0;
StabStrSec.write(s[1],length(s));
end;
end;
procedure TObjData.afteralloc;
begin
FObjSectionList.ForEachCall(@section_afteralloc,nil);
end;
procedure TObjData.afterwrite;
var
s : string[1];
hstab : TObjStabEntry;
begin
FObjSectionList.ForEachCall(@section_afterwrite,nil);
{ For the stab section we need an HdrSym which can now be
calculated more easily }
if assigned(StabsSec) then
begin
{ end of stabstr }
s:=#0;
StabStrSec.write(s[1],length(s));
{ header stab }
hstab.strpos:=1;
hstab.ntype:=0;
hstab.nother:=0;
hstab.ndesc:=(StabsSec.Size div sizeof(TObjStabEntry))-1;
hstab.nvalue:=StabStrSec.Size;
StabsSec.Data.seek(0);
StabsSec.Data.write(hstab,sizeof(hstab));
end;
end;
procedure TObjData.resetsections;
begin
FObjSectionList.ForEachCall(@section_reset,nil);
end;
{****************************************************************************
TObjOutput
****************************************************************************}
constructor TObjOutput.create(AWriter:TObjectWriter);
begin
FWriter:=AWriter;
CObjData:=TObjData;
end;
destructor TObjOutput.destroy;
begin
inherited destroy;
end;
function TObjOutput.newObjData(const n:string):TObjData;
begin
result:=CObjData.create(n);
if (cs_use_lineinfo in current_settings.globalswitches) or
(cs_debuginfo in current_settings.moduleswitches) then
result.CreateDebugSections;
end;
function TObjOutput.startObjectfile(const fn:string):boolean;
begin
result:=false;
{ start the writer already, so the .a generation can initialize
the position of the current objectfile }
if not FWriter.createfile(fn) then
Comment(V_Fatal,'Can''t create object '+fn);
result:=true;
end;
function TObjOutput.writeobjectfile(Data:TObjData):boolean;
begin
if errorcount=0 then
result:=writeData(Data)
else
result:=true;
{ close the writer }
FWriter.closefile;
end;
procedure TObjOutput.exportsymbol(p:TObjSymbol);
begin
{ export globals and common symbols, this is needed
for .a files }
if p.bind in [AB_GLOBAL,AB_COMMON] then
FWriter.writesym(p.name);
end;
{****************************************************************************
TExeVTable
****************************************************************************}
constructor TExeVTable.Create(AExeSymbol:TExeSymbol);
begin
ExeSymbol:=AExeSymbol;
if ExeSymbol.State=symstate_undefined then
internalerror(200604012);
ChildList:=TFPObjectList.Create(false);
end;
destructor TExeVTable.Destroy;
begin
ChildList.Free;
if assigned(EntryArray) then
Freemem(EntryArray);
end;
procedure TExeVTable.CheckIdx(VTableIdx:longint);
var
OldEntryCnt : longint;
begin
if VTableIdx>=EntryCnt then
begin
OldEntryCnt:=EntryCnt;
EntryCnt:=VTableIdx+1;
ReAllocMem(EntryArray,EntryCnt*sizeof(TVTableEntry));
FillChar(EntryArray[OldEntryCnt],(EntryCnt-OldEntryCnt)*sizeof(TVTableEntry),0);
end;
end;
procedure TExeVTable.AddChild(vt:TExeVTable);
begin
ChildList.Add(vt);
end;
procedure TExeVTable.AddEntry(VTableIdx:Longint);
var
i : longint;
objreloc : TObjRelocation;
vtblentryoffset : aword;
begin
CheckIdx(VTableIdx);
vtblentryoffset:=ExeSymbol.ObjSymbol.Offset+longword(VTableIdx)*sizeof(pint);
{ Find and disable relocation }
for i:=0 to ExeSymbol.ObjSymbol.ObjSection.ObjRelocations.Count-1 do
begin
objreloc:=TObjRelocation(ExeSymbol.ObjSymbol.ObjSection.ObjRelocations[i]);
if objreloc.dataoffset=vtblentryoffset then
begin
EntryArray[VTableIdx].ObjRelocation:=objreloc;
EntryArray[VTableIdx].OrgRelocType:=objreloc.typ;
objreloc.typ:=RELOC_ZERO;
break;
end;
end;
if not assigned(EntryArray[VTableIdx].ObjRelocation) then
internalerror(200604011);
end;
procedure TExeVTable.SetVTableSize(ASize:longint);
begin
if EntryCnt<>0 then
internalerror(200603313);
EntryCnt:=ASize div sizeof(pint);
EntryArray:=AllocMem(EntryCnt*sizeof(TVTableEntry));
end;
function TExeVTable.VTableRef(VTableIdx:Longint):TObjRelocation;
begin
result:=nil;
CheckIdx(VTableIdx);
if EntryArray[VTableIdx].Used then
exit;
{ Restore relocation if available }
if assigned(EntryArray[VTableIdx].ObjRelocation) then
begin
EntryArray[VTableIdx].ObjRelocation.typ:=EntryArray[VTableIdx].OrgRelocType;
result:=EntryArray[VTableIdx].ObjRelocation;
end;
EntryArray[VTableIdx].Used:=true;
end;
{****************************************************************************
TExeSection
****************************************************************************}
constructor TExeSection.create(AList:TFPHashObjectList;const AName:string);
begin
inherited create(AList,AName);
Size:=0;
MemPos:=0;
DataPos:=0;
FSecSymIdx:=0;
FObjSectionList:=TFPObjectList.Create(false);
end;
destructor TExeSection.destroy;
begin
ObjSectionList.Free;
inherited destroy;
end;
procedure TExeSection.AddObjSection(objsec:TObjSection);
begin
ObjSectionList.Add(objsec);
if (SecOptions<>[]) then
begin
{ Only if the section contains (un)initialized data the
data flag must match. This check is not needed if the
section is empty for a symbol allocation }
if (objsec.size>0) and
((oso_Data in SecOptions)<>(oso_Data in objsec.SecOptions)) then
Comment(V_Error,'Incompatible section options');
end
else
begin
{ inherit section options }
SecAlign:=objsec.SecAlign;
SecOptions:=SecOptions+objsec.SecOptions;
end;
{ relate ObjSection to ExeSection, and mark it Used by default }
objsec.ExeSection:=self;
objsec.Used:=true;
end;
{****************************************************************************
TStaticLibrary
****************************************************************************}
constructor TStaticLibrary.create(AList:TFPHashObjectList;const AName:string;AReader:TObjectReader;AObjInputClass:TObjInputClass);
begin
inherited create(AList,AName);
FArReader:=AReader;
FObjInputClass:=AObjInputClass;
end;
destructor TStaticLibrary.destroy;
begin
ArReader.Free;
inherited destroy;
end;
{****************************************************************************
TImportLibrary
****************************************************************************}
constructor TImportLibrary.create(AList:TFPHashObjectList;const AName:string);
begin
inherited create(AList,AName);
FImportSymbolList:=TFPHashObjectList.Create(true);
end;
destructor TImportLibrary.destroy;
begin
ImportSymbolList.Free;
inherited destroy;
end;
{****************************************************************************
TImportSymbol
****************************************************************************}
constructor TImportSymbol.create(AList:TFPHashObjectList;
const AName,AMangledName:string;AOrdNr:longint;AIsVar:boolean);
begin
inherited Create(AList, AName);
FOrdNr:=AOrdNr;
FIsVar:=AIsVar;
FMangledName:=AMangledName;
{ Replace ? and @ in import name, since GNU AS does not allow these characters in symbol names. }
{ This allows to import VC++ mangled names from DLLs. }
if target_info.system in systems_all_windows then
begin
Replace(FMangledName,'?','__q$$');
{$ifdef arm}
{ @ symbol is not allowed in ARM assembler only }
Replace(FMangledName,'@','__a$$');
{$endif arm}
end;
end;
{****************************************************************************
TExeOutput
****************************************************************************}
constructor TExeOutput.create;
begin
{ init writer }
FWriter:=TObjectwriter.create;
FExeWriteMode:=ewm_exefull;
{ object files }
FObjDataList:=TFPObjectList.Create(true);
{ symbols }
FExeSymbolList:=TFPHashObjectList.Create(true);
FUnresolvedExeSymbols:=TFPObjectList.Create(false);
FExternalObjSymbols:=TFPObjectList.Create(false);
FCommonObjSymbols:=TFPObjectList.Create(false);
FExeVTableList:=TFPObjectList.Create(false);
FEntryName:='start';
{ sections }
FExeSectionList:=TFPHashObjectList.Create(true);
FImageBase:=0;
{$ifdef cpu16bitaddr}
SectionMemAlign:=$10;
SectionDataAlign:=$10;
{$else cpu16bitaddr}
SectionMemAlign:=$1000;
SectionDataAlign:=$200;
{$endif cpu16bitaddr}
FCExeSection:=TExeSection;
FCObjData:=TObjData;
end;
destructor TExeOutput.destroy;
begin
FExeSymbolList.free;
UnresolvedExeSymbols.free;
ExternalObjSymbols.free;
CommonObjSymbols.free;
ExeVTableList.free;
FExeSectionList.free;
ObjDatalist.free;
FWriter.free;
inherited destroy;
end;
function TExeOutput.WriteExeFile(const fn:string):boolean;
begin
result:=false;
if FWriter.createfile(fn) then
begin
{ Only write the .o if there are no errors }
if errorcount=0 then
result:=writedata
else
result:=true;
{ close the writer }
FWriter.closefile;
end
else
Comment(V_Fatal,'Can''t create executable '+fn);
end;
procedure TExeOutput.ParseScript (linkscript:TCmdStrList);
begin
end;
function TExeOutput.FindExeSection(const aname:string):TExeSection;
begin
result:=TExeSection(ExeSectionList.Find(aname));
end;
procedure TExeOutput.AddObjData(ObjData:TObjData);
begin
if ObjData.classtype<>FCObjData then
Comment(V_Error,'Invalid input object format for '+ObjData.name+' got '+ObjData.classname+' expected '+FCObjData.classname);
ObjDataList.Add(ObjData);
end;
procedure TExeOutput.Load_Start;
begin
ObjDataList.Clear;
{ Globals defined in the linker script }
if not assigned(internalObjData) then
internalObjData:=CObjData.create('*Internal*');
AddObjData(internalObjData);
{ Common Data section }
commonObjSection:=internalObjData.createsection(sec_bss,'');
end;
procedure TExeOutput.Load_EntryName(const aname:string);
begin
FEntryName:=aname;
end;
procedure TExeOutput.Load_IsSharedLibrary;
begin
IsSharedLibrary:=true;
end;
procedure TExeOutput.Load_ImageBase(const avalue:string);
var
code : integer;
objsec : TObjSection;
objsym : TObjSymbol;
exesym : TExeSymbol;
begin
val(avalue,FImageBase,code);
if code<>0 then
Comment(V_Error,'Invalid number '+avalue);
{ Create __image_base__ symbol, create the symbol
in a section with adress 0 and at offset 0 }
objsec:=internalObjData.createsection('*__image_base__',0,[]);
internalObjData.setsection(objsec);
objsym:=internalObjData.SymbolDefine('__image_base__',AB_GLOBAL,AT_FUNCTION);
exesym:=texesymbol.Create(FExeSymbolList,objsym.name);
exesym.ObjSymbol:=objsym;
end;
procedure TExeOutput.Load_Symbol(const aname:string);
begin
internalObjData.createsection('*'+aname,0,[]);
internalObjData.SymbolDefine(aname,AB_GLOBAL,AT_FUNCTION);
end;
procedure TExeOutput.Load_ProvideSymbol(const aname:string);
begin
if assigned(ExeSymbolList.Find(aname)) then
exit;
internalObjData.createsection('*'+aname,0,[]);
// Use AB_COMMON to avoid muliple defined complaints
internalObjData.SymbolDefine(aname,AB_COMMON,AT_DATA);
end;
procedure TExeOutput.Order_Start;
begin
end;
procedure TExeOutput.Order_End;
begin
internalObjData.afterwrite;
end;
procedure TExeOutput.Order_ExeSection(const aname:string);
var
sec : TExeSection;
begin
sec:=FindExeSection(aname);
if not assigned(sec) then
sec:=CExeSection.create(ExeSectionList,aname);
{ Clear ExeSection contents }
FCurrExeSec:=sec;
end;
procedure TExeOutput.Order_EndExeSection;
begin
if not assigned(CurrExeSec) then
internalerror(200602184);
FCurrExeSec:=nil;
end;
procedure TExeOutput.Order_ObjSection(const aname:string);
var
i,j : longint;
ObjData : TObjData;
objsec : TObjSection;
TmpObjSectionList : TFPObjectList;
begin
if not assigned(CurrExeSec) then
internalerror(200602181);
TmpObjSectionList:=TFPObjectList.Create(false);
for i:=0 to ObjDataList.Count-1 do
begin
ObjData:=TObjData(ObjDataList[i]);
for j:=0 to ObjData.ObjSectionList.Count-1 do
begin
objsec:=TObjSection(ObjData.ObjSectionList[j]);
if (not objsec.Used) and
MatchPattern(aname,objsec.name) then
TmpObjSectionList.Add(objsec);
end;
end;
{ Order list if needed }
Order_ObjSectionList(TmpObjSectionList,aname);
{ Add the (ordered) list to the current ExeSection }
for i:=0 to TmpObjSectionList.Count-1 do
begin
objsec:=TObjSection(TmpObjSectionList[i]);
CurrExeSec.AddObjSection(objsec);
end;
TmpObjSectionList.Free;
end;
procedure TExeOutput.Order_ObjSectionList(ObjSectionList : TFPObjectList; const aPattern:string);
begin
end;
procedure TExeOutput.Order_Symbol(const aname:string);
var
ObjSection : TObjSection;
begin
ObjSection:=internalObjData.findsection('*'+aname);
if not assigned(ObjSection) then
internalerror(200603041);
CurrExeSec.AddObjSection(ObjSection);
end;
procedure TExeOutput.Order_ProvideSymbol(const aname:string);
var
ObjSection : TObjSection;
begin
ObjSection:=internalObjData.findsection('*'+aname);
if not assigned(ObjSection) then
internalerror(200603041);
{ Only include this section if the symbol doesn't
exist otherwisee }
if not assigned(ExeSymbolList.Find(aname)) then
CurrExeSec.AddObjSection(ObjSection);
end;
procedure TExeOutput.Order_Align(const avalue:string);
var
code : integer;
alignval : shortint;
objsec : TObjSection;
begin
val(avalue,alignval,code);
if code<>0 then
Comment(V_Error,'Invalid number '+avalue);
if alignval<=0 then
exit;
{ Create an empty section with the required aligning }
inc(Fzeronr);
objsec:=internalObjData.createsection('*align'+tostr(Fzeronr),alignval,CurrExeSec.SecOptions+[oso_Data,oso_keep]);
CurrExeSec.AddObjSection(objsec);
end;
procedure TExeOutput.Order_Zeros(const avalue:string);
var
zeros : array[0..1023] of byte;
code : integer;
len : longint;
objsec : TObjSection;
begin
val(avalue,len,code);
if code<>0 then
Comment(V_Error,'Invalid number '+avalue);
if len<=0 then
exit;
if len>sizeof(zeros) then
internalerror(200602254);
fillchar(zeros,len,0);
inc(Fzeronr);
objsec:=internalObjData.createsection('*zeros'+tostr(Fzeronr),0,CurrExeSec.SecOptions+[oso_Data,oso_keep]);
internalObjData.writebytes(zeros,len);
CurrExeSec.AddObjSection(objsec);
end;
procedure TExeOutput.Order_Values(bytesize : aword; const avalue:string);
const
MAXVAL = 128;
var
bytevalues : array[0..MAXVAL-1] of byte;
twobytevalues : array[0..MAXVAL-1] of word;
fourbytevalues : array[0..MAXVAL-1] of dword;
eightbytevalues : array[0..MAXVAL-1] of qword;
allvals, oneval : string;
len, commapos : longint;
indexpos, code : integer;
anumval : qword;
signedval : int64;
objsec : TObjSection;
begin
indexpos:=0;
allvals:=avalue;
repeat
commapos:=pos(',',allvals);
if commapos>0 then
begin
oneval:=trim(copy(allvals,1,commapos-1));
allvals:=copy(allvals,commapos+1,length(allvals));
end
else
begin
oneval:=trim(allvals);
allvals:='';
end;
if oneval<>'' then
begin
if oneval[1]='-' then
begin
val(oneval,signedval,code);
anumval:=qword(signedval);
end
else
val(oneval,anumval,code);
if code<>0 then
Comment(V_Error,'Invalid number '+avalue)
else
begin
if (indexpos<MAXVAL) then
begin
if source_info.endian<>target_info.endian then
swapendian(anumval);
{ No range checking here }
if bytesize=1 then
bytevalues[indexpos]:=byte(anumval)
else if bytesize=2 then
twobytevalues[indexpos]:=word(anumval)
else if bytesize=4 then
fourbytevalues[indexpos]:=dword(anumval)
else if bytesize=8 then
eightbytevalues[indexpos]:=anumval;
inc(indexpos);
end
else
Comment(V_Error,'Buffer overrun in Order_values');
end;
end;
until allvals='';
if indexpos=0 then
begin
Comment(V_Error,'Invalid number '+avalue);
exit;
end;
if indexpos=MAXVAL then
begin
Comment(V_Error,'Too many values '+avalue);
internalerror(200602254);
end;
len:=bytesize*indexpos;
inc(Fvaluesnr);
objsec:=internalObjData.createsection('*values'+tostr(Fvaluesnr),0,CurrExeSec.SecOptions+[oso_Data,oso_keep]);
if bytesize=1 then
internalObjData.writebytes(bytevalues,len)
else if bytesize=2 then
internalObjData.writebytes(twobytevalues,len)
else if bytesize=4 then
internalObjData.writebytes(fourbytevalues,len)
else if bytesize=8 then
internalObjData.writebytes(eightbytevalues,len);
CurrExeSec.AddObjSection(objsec);
end;
procedure TExeOutput.MemPos_Start;
begin
CurrMemPos:=0;
end;
procedure TExeOutput.MemPos_Header;
begin
end;
procedure TExeOutput.MemPos_ExeSection(const aname:string);
var
i : longint;
objsec : TObjSection;
begin
{ Section can be removed }
FCurrExeSec:=FindExeSection(aname);
if not assigned(CurrExeSec) then
exit;
{ Alignment of ExeSection }
CurrMemPos:=align(CurrMemPos,SectionMemAlign);
CurrExeSec.MemPos:=CurrMemPos;
{ set position of object ObjSections }
for i:=0 to CurrExeSec.ObjSectionList.Count-1 do
begin
objsec:=TObjSection(CurrExeSec.ObjSectionList[i]);
CurrMemPos:=objsec.setmempos(CurrMemPos);
end;
{ calculate size of the section }
CurrExeSec.Size:=CurrMemPos-CurrExeSec.MemPos;
end;
procedure TExeOutput.MemPos_EndExeSection;
begin
if not assigned(CurrExeSec) then
exit;
FCurrExeSec:=nil;
end;
procedure TExeOutput.DataPos_Start;
begin
end;
procedure TExeOutput.DataPos_Header;
begin
end;
procedure TExeOutput.DataPos_ExeSection(const aname:string);
var
i : longint;
objsec : TObjSection;
begin
{ Section can be removed }
FCurrExeSec:=FindExeSection(aname);
if not assigned(CurrExeSec) then
exit;
{ don't write normal section if writing only debug info }
if (ExeWriteMode=ewm_dbgonly) and
not(oso_debug in CurrExeSec.SecOptions) then
exit;
if (oso_Data in currexesec.SecOptions) then
begin
CurrDataPos:=align(CurrDataPos,SectionDataAlign);
CurrExeSec.DataPos:=CurrDataPos;
end;
{ set position of object ObjSections }
for i:=0 to CurrExeSec.ObjSectionList.Count-1 do
begin
objsec:=TObjSection(CurrExeSec.ObjSectionList[i]);
if (oso_Data in objsec.SecOptions) then
begin
if not(oso_Data in currexesec.SecOptions) then
internalerror(200603043);
if not assigned(objsec.Data) then
internalerror(200603044);
objsec.setDatapos(CurrDataPos);
end;
end;
end;
procedure TExeOutput.DataPos_EndExeSection;
begin
if not assigned(CurrExeSec) then
exit;
FCurrExeSec:=nil;
end;
procedure TExeOutput.DataPos_Symbols;
var
i : longint;
sym : TExeSymbol;
begin
{ Removing unused symbols }
for i:=0 to ExeSymbolList.Count-1 do
begin
sym:=TExeSymbol(ExeSymbolList[i]);
if not sym.ObjSymbol.objsection.Used then
ExeSymbolList[i]:=nil;
end;
ExeSymbolList.Pack;
end;
procedure TExeOutput.BuildVTableTree(VTInheritList,VTEntryList:TFPObjectList);
var
hs : string;
code : integer;
i,k,
vtableidx : longint;
vtableexesym,
childexesym,
parentexesym : TExeSymbol;
objsym : TObjSymbol;
begin
{ Build inheritance tree from VTINHERIT }
for i:=0 to VTInheritList.Count-1 do
begin
objsym:=TObjSymbol(VTInheritList[i]);
hs:=objsym.name;
{ VTINHERIT_<ChildVMTName>$$<ParentVMTName> }
Delete(hs,1,Pos('_',hs));
k:=Pos('$$',hs);
if k=0 then
internalerror(200603311);
childexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,1,k-1)));
parentexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,k+2,length(hs)-k-1)));
if not assigned(childexesym) or
not assigned(parentexesym)then
internalerror(200603312);
if not assigned(childexesym.vtable) then
begin
childexesym.vtable:=TExeVTable.Create(childexesym);
ExeVTableList.Add(childexesym.vtable);
end;
if not assigned(parentexesym.vtable) then
begin
parentexesym.vtable:=TExeVTable.Create(parentexesym);
ExeVTableList.Add(parentexesym.vtable);
end;
childexesym.vtable.SetVTableSize(childexesym.ObjSymbol.Size);
if parentexesym<>childexesym then
parentexesym.vtable.AddChild(childexesym.vtable);
end;
{ Find VTable entries from VTENTRY }
for i:=0 to VTEntryList.Count-1 do
begin
objsym:=TObjSymbol(VTEntryList[i]);
hs:=objsym.name;
{ VTENTRY_<VTableName>$$<Index> }
Delete(hs,1,Pos('_',hs));
k:=Pos('$$',hs);
if k=0 then
internalerror(200603319);
vtableexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,1,k-1)));
val(Copy(hs,k+2,length(hs)-k-1),vtableidx,code);
if (code<>0) then
internalerror(200603318);
if not assigned(vtableexesym) then
internalerror(2006033110);
vtableexesym.vtable.AddEntry(vtableidx);
end;
end;
procedure TExeOutput.PackUnresolvedExeSymbols(const s:string);
var
i : longint;
exesym : TExeSymbol;
begin
{ Generate a list of Unresolved External symbols }
for i:=0 to UnresolvedExeSymbols.count-1 do
begin
exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
if exesym.State<>symstate_undefined then
UnresolvedExeSymbols[i]:=nil;
end;
UnresolvedExeSymbols.Pack;
Comment(V_Debug,'Number of unresolved externals '+s+' '+tostr(UnresolvedExeSymbols.Count));
end;
procedure TExeOutput.ResolveSymbols(StaticLibraryList:TFPHashObjectList);
var
ObjData : TObjData;
exesym : TExeSymbol;
objsym,
commonsym : TObjSymbol;
objinput : TObjInput;
StaticLibrary : TStaticLibrary;
firstarchive,
firstcommon : boolean;
i,j : longint;
VTEntryList,
VTInheritList : TFPObjectList;
procedure LoadObjDataSymbols(ObjData:TObjData);
var
j : longint;
hs : string;
exesym : TExeSymbol;
objsym : TObjSymbol;
begin
for j:=0 to ObjData.ObjSymbolList.Count-1 do
begin
objsym:=TObjSymbol(ObjData.ObjSymbolList[j]);
{ From the local symbols we are only interressed in the
VTENTRY and VTINHERIT symbols }
if objsym.bind=AB_LOCAL then
begin
if cs_link_opt_vtable in current_settings.globalswitches then
begin
hs:=objsym.name;
if (hs[1]='V') then
begin
if Copy(hs,1,5)='VTREF' then
begin
if not assigned(objsym.ObjSection.VTRefList) then
objsym.ObjSection.VTRefList:=TFPObjectList.Create(false);
objsym.ObjSection.VTRefList.Add(objsym);
end
else if Copy(hs,1,7)='VTENTRY' then
VTEntryList.Add(objsym)
else if Copy(hs,1,9)='VTINHERIT' then
VTInheritList.Add(objsym);
end;
end;
continue;
end;
{ Search for existing exesymbol }
exesym:=texesymbol(FExeSymbolList.Find(objsym.name));
if not assigned(exesym) then
begin
exesym:=texesymbol.Create(FExeSymbolList,objsym.name);
exesym.ObjSymbol:=objsym;
end;
objsym.ExeSymbol:=exesym;
case objsym.bind of
AB_GLOBAL :
begin
if exesym.State<>symstate_defined then
begin
exesym.ObjSymbol:=objsym;
exesym.State:=symstate_defined;
end
else
Comment(V_Error,'Multiple defined symbol '+objsym.name);
end;
AB_EXTERNAL :
begin
ExternalObjSymbols.add(objsym);
{ Register unresolved symbols only the first time they
are registered }
if exesym.ObjSymbol=objsym then
UnresolvedExeSymbols.Add(exesym);
end;
AB_COMMON :
begin
if exesym.State=symstate_undefined then
begin
exesym.ObjSymbol:=objsym;
exesym.State:=symstate_common;
end;
CommonObjSymbols.add(objsym);
end;
end;
end;
end;
begin
VTEntryList:=TFPObjectList.Create(false);
VTInheritList:=TFPObjectList.Create(false);
{
The symbol resolving is done in 3 steps:
1. Register symbols from objects
2. Find symbols in static libraries
3. Define stil undefined common symbols
}
{ Step 1, Register symbols from objects }
for i:=0 to ObjDataList.Count-1 do
begin
ObjData:=TObjData(ObjDataList[i]);
LoadObjDataSymbols(ObjData);
end;
PackUnresolvedExeSymbols('in objects');
{ Step 2, Find unresolved symbols in the libraries }
firstarchive:=true;
for i:=0 to StaticLibraryList.Count-1 do
begin
StaticLibrary:=TStaticLibrary(StaticLibraryList[i]);
{ Process list of Unresolved External symbols, we need
to use a while loop because the list can be extended when
we load members from the library. }
j:=0;
while (j<UnresolvedExeSymbols.count) do
begin
exesym:=TExeSymbol(UnresolvedExeSymbols[j]);
{ Check first if the symbol is still undefined }
if exesym.State=symstate_undefined then
begin
if StaticLibrary.ArReader.OpenFile(exesym.name) then
begin
if assigned(exemap) then
begin
if firstarchive then
begin
exemap.Add('');
exemap.Add('Archive member included because of file (symbol)');
exemap.Add('');
firstarchive:=false;
end;
exemap.Add(StaticLibrary.ArReader.FileName+' - '+
{exesym.ObjSymbol.ObjSection.FullName+}
'('+exesym.Name+')');
end;
objinput:=StaticLibrary.ObjInputClass.Create;
objdata:=objinput.newObjData(StaticLibrary.ArReader.FileName);
objinput.ReadObjData(StaticLibrary.ArReader,objdata);
objinput.free;
AddObjData(objdata);
LoadObjDataSymbols(objdata);
StaticLibrary.ArReader.CloseFile;
end;
end;
inc(j);
end;
end;
PackUnresolvedExeSymbols('after static libraries');
{ Step 3, Match common symbols or add to the globals }
firstcommon:=true;
for i:=0 to CommonObjSymbols.count-1 do
begin
objsym:=TObjSymbol(CommonObjSymbols[i]);
if objsym.exesymbol.State=symstate_defined then
begin
if objsym.exesymbol.ObjSymbol.size<>objsym.size then
Comment(V_Debug,'Size of common symbol '+objsym.name+' is different, expected '+tostr(objsym.size)+' got '+tostr(objsym.exesymbol.ObjSymbol.size));
end
else
begin
{ allocate new objsymbol in .bss of *COMMON* and assign
it to the exesymbol }
if firstcommon then
begin
if assigned(exemap) then
exemap.AddCommonSymbolsHeader;
firstcommon:=false;
end;
internalObjData.setsection(commonObjSection);
internalObjData.allocalign(var_align(objsym.size));
commonsym:=internalObjData.symboldefine(objsym.name,AB_GLOBAL,AT_FUNCTION);
commonsym.size:=objsym.size;
internalObjData.alloc(objsym.size);
if assigned(exemap) then
exemap.AddCommonSymbol(commonsym);
{ Assign to the exesymbol }
objsym.exesymbol.objsymbol:=commonsym;
objsym.exesymbol.state:=symstate_defined;
end;
end;
PackUnresolvedExeSymbols('after defining COMMON symbols');
{ Find entry symbol and print in map }
exesym:=texesymbol(ExeSymbolList.Find(EntryName));
if assigned(exesym) then
begin
EntrySym:=exesym.ObjSymbol;
if assigned(exemap) then
begin
exemap.Add('');
exemap.Add('Entry symbol '+EntryName);
end;
end
else
Comment(V_Error,'Entrypoint '+EntryName+' not defined');
{ Generate VTable tree }
if cs_link_opt_vtable in current_settings.globalswitches then
BuildVTableTree(VTInheritList,VTEntryList);
VTInheritList.Free;
VTEntryList.Free;
end;
procedure TExeOutput.GenerateDebugLink(const dbgname:string;dbgcrc:cardinal);
var
debuglink : array[0..1023] of byte;
len : longint;
objsec : TObjSection;
exesec : TExeSection;
begin
{ From the gdb manual chapter 15. GDB Files:
* A filename, with any leading directory components removed, followed by a zero byte,
* zero to three bytes of padding, as needed to reach the next four-byte boundary within the section, and
* a four-byte CRC checksum, stored in the same endianness used for the executable file itself. The checksum is computed
on the debugging information file's full contents by the function given below, passing zero as the crc argument.
}
fillchar(debuglink,sizeof(debuglink),0);
len:=0;
move(dbgname[1],debuglink[len],length(dbgname));
inc(len,length(dbgname)+1);
len:=align(len,4);
if source_info.endian<>target_info.endian then
SwapEndian(dbgcrc);
move(dbgcrc,debuglink[len],sizeof(cardinal));
inc(len,4);
{ Add section }
exesec:=FindExeSection(debuglinkname);
if not assigned(exesec) then
exesec:=CExeSection.create(ExeSectionList,debuglinkname);
exesec.SecOptions:=[oso_data,oso_keep];
exesec.SecAlign:=4;
objsec:=internalObjData.createsection(exesec.name,0,exesec.SecOptions);
internalObjData.writebytes(debuglink,len);
exesec.AddObjSection(objsec);
end;
procedure TExeOutput.GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);
begin
end;
procedure TExeOutput.PrintMemoryMap;
var
exesec : TExeSection;
objsec : TObjSection;
objsym : TObjSymbol;
i,j,k : longint;
begin
if not assigned(exemap) then
exit;
exemap.AddMemoryMapHeader(ImageBase);
for i:=0 to ExeSectionList.Count-1 do
begin
exesec:=TExeSection(ExeSectionList[i]);
exemap.AddMemoryMapExeSection(exesec);
for j:=0 to exesec.ObjSectionList.count-1 do
begin
objsec:=TObjSection(exesec.ObjSectionList[j]);
exemap.AddMemoryMapObjectSection(objsec);
for k:=0 to objsec.ObjSymbolDefines.Count-1 do
begin
objsym:=TObjSymbol(objsec.ObjSymbolDefines[k]);
exemap.AddMemoryMapSymbol(objsym);
end;
end;
end;
end;
procedure TExeOutput.FixupSymbols;
procedure UpdateSymbol(objsym:TObjSymbol);
begin
objsym.bind:=objsym.ExeSymbol.ObjSymbol.bind;
objsym.offset:=objsym.ExeSymbol.ObjSymbol.offset;
objsym.size:=objsym.ExeSymbol.ObjSymbol.size;
objsym.typ:=objsym.ExeSymbol.ObjSymbol.typ;
objsym.ObjSection:=objsym.ExeSymbol.ObjSymbol.ObjSection;
end;
var
i : longint;
objsym : TObjSymbol;
exesym : TExeSymbol;
begin
{ Print list of Unresolved External symbols }
for i:=0 to UnresolvedExeSymbols.count-1 do
begin
exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
if exesym.State<>symstate_defined then
Comment(V_Error,'Undefined symbol: '+exesym.name);
end;
{ Update ImageBase to ObjData so it can access from ObjSymbols }
for i:=0 to ObjDataList.Count-1 do
TObjData(ObjDataList[i]).imagebase:=imagebase;
{
Fixing up symbols is done in the following steps:
1. Update common references
2. Update external references
}
{ Step 1, Update commons }
for i:=0 to CommonObjSymbols.count-1 do
begin
objsym:=TObjSymbol(CommonObjSymbols[i]);
if objsym.bind<>AB_COMMON then
internalerror(200606241);
UpdateSymbol(objsym);
end;
{ Step 2, Update externals }
for i:=0 to ExternalObjSymbols.count-1 do
begin
objsym:=TObjSymbol(ExternalObjSymbols[i]);
if objsym.bind<>AB_EXTERNAL then
internalerror(200606242);
UpdateSymbol(objsym);
end;
end;
procedure TExeOutput.MergeStabs;
var
stabexesec,
stabstrexesec : TExeSection;
relocsec,
currstabsec,
currstabstrsec,
mergedstabsec,
mergedstabstrsec : TObjSection;
hstabreloc,
currstabreloc : TObjRelocation;
i,j : longint;
currstabrelocidx,
mergestabcnt,
stabcnt : longword;
skipstab : boolean;
skipfun : boolean;
hstab : TObjStabEntry;
stabrelocofs : longword;
buf : array[0..1023] of byte;
bufend,
bufsize : longint;
begin
stabexesec:=FindExeSection('.stab');
stabstrexesec:=FindExeSection('.stabstr');
if (stabexesec=nil) or
(stabstrexesec=nil) or
(stabexesec.ObjSectionlist.count=0) then
exit;
{ Create new stabsection }
stabRelocofs:=pbyte(@hstab.nvalue)-pbyte(@hstab);
mergedstabsec:=internalObjData.CreateSection(sec_stab,'');
mergedstabstrsec:=internalObjData.CreateSection(sec_stabstr,'');
{ write stab for hdrsym }
fillchar(hstab,sizeof(TObjStabEntry),0);
mergedstabsec.write(hstab,sizeof(TObjStabEntry));
mergestabcnt:=1;
{ .stabstr starts with a #0 }
buf[0]:=0;
mergedstabstrsec.write(buf[0],1);
skipfun:=false;
{ Copy stabs and corresponding Relocations }
for i:=0 to stabexesec.ObjSectionList.Count-1 do
begin
currstabsec:=TObjSection(stabexesec.ObjSectionList[i]);
currstabstrsec:=currstabsec.ObjData.findsection('.stabstr');
if assigned(currstabstrsec) then
begin
stabcnt:=currstabsec.Data.size div sizeof(TObjStabEntry);
currstabsec.Data.seek(0);
currstabrelocidx:=0;
for j:=0 to stabcnt-1 do
begin
hstabreloc:=nil;
skipstab:=false;
currstabsec.Data.read(hstab,sizeof(TObjStabEntry));
{ Only include first hdrsym stab }
if hstab.ntype=0 then
skipstab:=true;
if skipfun then
begin
{ Skip all stabs for function body until N_RBRAC }
skipfun:=hstab.ntype<>N_RBRAC;
skipstab:=true;
end;
if not skipstab then
begin
{ Find corresponding Relocation }
currstabreloc:=nil;
while (currstabrelocidx<longword(currstabsec.ObjRelocations.Count)) do
begin
currstabreloc:=TObjRelocation(currstabsec.ObjRelocations[currstabrelocidx]);
if assigned(currstabreloc) and
(currstabreloc.dataoffset>=longword(j)*sizeof(TObjStabEntry)+stabrelocofs) then
break;
inc(currstabrelocidx);
end;
if assigned(currstabreloc) and
(currstabreloc.dataoffset=longword(j)*sizeof(TObjStabEntry)+stabrelocofs) then
begin
hstabReloc:=currstabReloc;
inc(currstabrelocidx);
end;
{ Check if the stab is refering to a removed section }
if assigned(hstabreloc) then
begin
if assigned(hstabreloc.Symbol) then
relocsec:=hstabreloc.Symbol.ObjSection
else
relocsec:=hstabreloc.ObjSection;
if not assigned(relocsec) then
internalerror(200603302);
if not relocsec.Used then
begin
skipstab:=true;
if (hstab.ntype=N_Function) and (hstab.strpos<>0) then
begin
currstabstrsec.Data.seek(hstab.strpos);
bufsize:=currstabstrsec.Data.read(buf,sizeof(buf));
bufend:=indexbyte(buf,bufsize,Ord(':'));
if (bufend<>-1) and (bufend<bufsize-1) and (buf[bufend+1]=Ord('F')) then
skipfun:=true;
end;
end;
end;
end;
if not skipstab then
begin
{ Copy string in stabstr }
if hstab.strpos<>0 then
begin
currstabstrsec.Data.seek(hstab.strpos);
hstab.strpos:=mergedstabstrsec.Size;
repeat
bufsize:=currstabstrsec.Data.read(buf,sizeof(buf));
bufend:=indexbyte(buf,bufsize,0);
if bufend=-1 then
bufend:=bufsize
else
begin
{ include the #0 }
inc(bufend);
end;
mergedstabstrsec.write(buf,bufend);
until (buf[bufend-1]=0) or (bufsize<sizeof(buf));
end;
{ Copy and Update the relocation }
if assigned(hstabreloc) then
begin
hstabreloc.Dataoffset:=mergestabcnt*sizeof(TObjStabEntry)+stabRelocofs;
{ Remove from List without freeing the object }
currstabsec.ObjRelocations.List[currstabrelocidx-1]:=nil;
mergedstabsec.ObjRelocations.Add(hstabreloc);
end;
{ Write updated stab }
mergedstabsec.write(hstab,sizeof(hstab));
inc(mergestabcnt);
end;
end;
end;
{ Unload stabs }
if assigned(currstabstrsec) then
begin
currstabstrsec.Used:=False;
currstabstrsec.ReleaseData;
end;
currstabsec.Used:=false;
currstabsec.ReleaseData;
end;
{ Generate new HdrSym }
if mergedstabsec.Size>0 then
begin
hstab.strpos:=1;
hstab.ntype:=0;
hstab.nother:=0;
hstab.ndesc:=word(mergestabcnt-1);
hstab.nvalue:=mergedstabstrsec.Size;
mergedstabsec.Data.seek(0);
mergedstabsec.Data.write(hstab,sizeof(hstab));
end;
{ Replace all sections with our combined stabsec }
stabexesec.ObjSectionList.Clear;
stabstrexesec.ObjSectionList.Clear;
stabexesec.AddObjSection(mergedstabsec);
stabstrexesec.AddObjSection(mergedstabstrsec);
end;
procedure TExeOutput.RemoveEmptySections;
var
i, j : longint;
exesec : TExeSection;
doremove : boolean;
begin
for i:=0 to ExeSectionList.Count-1 do
begin
exesec:=TExeSection(ExeSectionList[i]);
doremove:=not(oso_keep in exesec.SecOptions) and
(
(exesec.ObjSectionlist.count=0) or
(
(cs_link_strip in current_settings.globalswitches) and
not(cs_link_separate_dbg_file in current_settings.globalswitches) and
(oso_debug in exesec.SecOptions)
)
);
if not doremove then
begin
{ Check if section has no actual data }
doremove:=true;
for j:=0 to exesec.ObjSectionList.Count-1 do
if TObjSection(exesec.ObjSectionList[j]).Size<>0 then
begin
doremove:=false;
break;
end;
end;
if doremove and not (RelocSection and (exesec.Name='.reloc')) then
begin
Comment(V_Debug,'Deleting empty section '+exesec.name);
ExeSectionList[i]:=nil;
end;
end;
ExeSectionList.Pack;
end;
procedure TExeOutput.RemoveDebugInfo;
var
i : longint;
exesec : TExeSection;
begin
for i:=0 to ExeSectionList.Count-1 do
begin
exesec:=TExeSection(ExeSectionList[i]);
if (oso_debug in exesec.SecOptions) then
ExeSectionList[i]:=nil;
end;
ExeSectionList.Pack;
end;
procedure TExeOutput.RemoveUnreferencedSections;
var
ObjSectionWorkList : TFPObjectList;
procedure AddToObjSectionWorkList(aobjsec:TObjSection);
begin
if not aobjsec.Used then
begin
aobjsec.Used:=true;
ObjSectionWorkList.Add(aobjsec);
end;
end;
procedure DoReloc(objreloc:TObjRelocation);
var
objsym : TObjSymbol;
refobjsec : TObjSection;
begin
{ Disabled Relocation to 0 }
if objreloc.typ=RELOC_ZERO then
exit;
if assigned(objreloc.symbol) then
begin
objsym:=objreloc.symbol;
if objsym.bind<>AB_LOCAL then
begin
if not(assigned(objsym.exesymbol) and
(objsym.exesymbol.State=symstate_defined)) then
internalerror(200603063);
objsym:=objsym.exesymbol.objsymbol;
end;
if not assigned(objsym.objsection) then
internalerror(200603062);
refobjsec:=objsym.objsection;
end
else
if assigned(objreloc.objsection) then
refobjsec:=objreloc.objsection
else
internalerror(200603316);
if assigned(exemap) then
begin
objsym:=objreloc.symbol;
if assigned(objsym) then
exemap.Add(' References '+objsym.name+' in '
+refobjsec.fullname)
else
exemap.Add(' References '+refobjsec.fullname);
end;
AddToObjSectionWorkList(refobjsec);
end;
procedure DoVTableRef(vtable:TExeVTable;VTableIdx:longint);
var
i : longint;
objreloc : TObjRelocation;
begin
objreloc:=vtable.VTableRef(VTableIdx);
if assigned(objreloc) then
begin
{ Process the relocation now if the ObjSection is
already processed and marked as used. Otherwise we leave it
unprocessed. It'll then be resolved when the ObjSection is
changed to Used }
if vtable.ExeSymbol.ObjSymbol.ObjSection.Used then
DoReloc(objreloc);
end;
{ This recursive walking is done here instead of
in TExeVTable.VTableRef because we can now process
all needed relocations }
for i:=0 to vtable.ChildList.Count-1 do
DoVTableRef(TExeVTable(vtable.ChildList[i]),VTableIdx);
end;
var
hs : string;
i,j,k : longint;
exesec : TExeSection;
objdata : TObjData;
objsec : TObjSection;
objsym : TObjSymbol;
code : integer;
vtableidx : longint;
vtableexesym : TExeSymbol;
begin
ObjSectionWorkList:=TFPObjectList.Create(false);
if assigned(exemap) then
exemap.AddHeader('Removing unreferenced sections');
{ Initialize by marking all sections unused and
adding the sections with oso_keep flags to the ObjSectionWorkList }
for i:=0 to ObjDataList.Count-1 do
begin
ObjData:=TObjData(ObjDataList[i]);
for j:=0 to ObjData.ObjSectionList.Count-1 do
begin
objsec:=TObjSection(ObjData.ObjSectionList[j]);
objsec.Used:=false;
{ TODO: remove debug section always keep}
if oso_debug in objsec.secoptions then
objsec.Used:=true;
if (oso_keep in objsec.secoptions) then
begin
AddToObjSectionWorkList(objsec);
if objsec.name='.fpc.n_links' then
objsec.Used:=false;
end;
end;
end;
AddToObjSectionWorkList(entrysym.exesymbol.objsymbol.objsection);
{ Process all sections, add new sections to process based
on the symbol references }
while ObjSectionWorkList.Count>0 do
begin
objsec:=TObjSection(ObjSectionWorkList.Last);
if assigned(exemap) then
exemap.Add('Keeping '+objsec.FullName+' '+ToStr(objsec.ObjRelocations.Count)+' references');
ObjSectionWorkList.Delete(ObjSectionWorkList.Count-1);
{ Process Relocations }
for i:=0 to objsec.ObjRelocations.count-1 do
DoReloc(TObjRelocation(objsec.ObjRelocations[i]));
{ Process Virtual Entry calls }
if cs_link_opt_vtable in current_settings.globalswitches then
begin
for i:=0 to objsec.VTRefList.count-1 do
begin
objsym:=TObjSymbol(objsec.VTRefList[i]);
hs:=objsym.name;
Delete(hs,1,Pos('_',hs));
k:=Pos('$$',hs);
if k=0 then
internalerror(200603314);
vtableexesym:=texesymbol(FExeSymbolList.Find(Copy(hs,1,k-1)));
val(Copy(hs,k+2,length(hs)-k-1),vtableidx,code);
if (code<>0) then
internalerror(200603317);
if not assigned(vtableexesym) then
internalerror(200603315);
if not assigned(vtableexesym.vtable) then
internalerror(200603316);
DoVTableRef(vtableexesym.vtable,vtableidx);
end;
end;
end;
ObjSectionWorkList.Free;
ObjSectionWorkList:=nil;
{ Remove unused objsections from ExeSectionList }
for i:=0 to ExeSectionList.Count-1 do
begin
exesec:=TExeSection(ExeSectionList[i]);
for j:=0 to exesec.ObjSectionlist.count-1 do
begin
objsec:=TObjSection(exesec.ObjSectionlist[j]);
if not objsec.used then
begin
if assigned(exemap) then
exemap.Add('Removing '+objsec.FullName);
exesec.ObjSectionlist[j]:=nil;
objsec.ReleaseData;
end;
end;
exesec.ObjSectionlist.Pack;
end;
end;
procedure TExeOutput.FixupRelocations;
var
i,j : longint;
exesec : TExeSection;
objsec : TObjSection;
begin
for i:=0 to ExeSectionList.Count-1 do
begin
exesec:=TExeSection(ExeSectionList[i]);
if not assigned(exesec) then
continue;
for j:=0 to exesec.ObjSectionlist.count-1 do
begin
objsec:=TObjSection(exesec.ObjSectionlist[j]);
if not objsec.Used then
internalerror(200603301);
objsec.FixupRelocs;
end;
end;
end;
procedure TExeOutput.SetCurrMemPos(const AValue: qword);
begin
if AValue>MaxMemPos then
Message1(link_f_executable_too_big, target_os_string);
FCurrMemPos:=AValue;
end;
{****************************************************************************
TObjInput
****************************************************************************}
constructor TObjInput.create;
begin
end;
destructor TObjInput.destroy;
begin
inherited destroy;
end;
function TObjInput.newObjData(const n:string):TObjData;
begin
result:=CObjData.create(n);
end;
procedure TObjInput.inputerror(const s : string);
begin
Comment(V_Error,s+' while reading '+InputFileName);
end;
{$ifdef MEMDEBUG}
initialization
memobjsymbols:=TMemDebug.create('ObjSymbols');
memobjsymbols.stop;
memobjsections:=TMemDebug.create('ObjSections');
memobjsections.stop;
finalization
memobjsymbols.free;
memobjsections.free;
{$endif MEMDEBUG}
end.