| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303 | {    Copyright (c) 1998-2006 by Peter Vreman    Contains the binary elf writer    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 ogelf;{$i fpcdefs.inc}interface    uses       { common }       cclasses,globtype,       { target }       systems,       { assembler }       aasmbase,assemble,       { ELF definitions }       elfbase,       { output }       ogbase,       owbase;    type{$ifdef cpu64bitaddr}      TElfsechdr = TElf64sechdr;{$else cpu64bitaddr}      TElfsechdr = TElf32sechdr;{$endif cpu64bitaddr}       TElfObjSection = class(TObjSection)       public          shstridx,          shtype,          shflags,          shlink,          shinfo,          shentsize : longint;          constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);override;          constructor create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:longint;Aentsize:longint);          constructor create_reloc(aobjdata:TObjData;const Aname:string;allocflag:boolean);          procedure writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);override;       end;       TElfSymtabKind = (esk_obj,esk_exe,esk_dyn);       TElfSymtab = class(TElfObjSection)       public         kind: TElfSymtabKind;         fstrsec: TObjSection;         symidx: longint;         tlsbase: aword;         constructor create(aObjData:TObjData;aKind:TElfSymtabKind);reintroduce;         procedure writeSymbol(objsym:TObjSymbol;nameidx:longword=0);         procedure writeInternalSymbol(avalue:aword;astridx:longword;ainfo:byte;ashndx:word);       end;       TElfObjData = class(TObjData)       public         ident: TElfIdent;         flags: longword;{$ifdef mips}         gp_value: longword;{$endif mips}         constructor create(const n:string);override;         function  sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;         procedure CreateDebugSections;override;         procedure writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);override;       end;       TElfObjectOutput = class(tObjOutput)       private         symtabsect: TElfSymtab;         shstrtabsect: TElfObjSection;         procedure createrelocsection(s:TElfObjSection;data:TObjData);         procedure createshstrtab(data:TObjData);         procedure createsymtab(data: TObjData);         procedure writesectionheader(s:TElfObjSection);         procedure section_write_symbol(p:TObject;arg:pointer);         procedure section_count_sections(p:TObject;arg:pointer);         procedure section_create_relocsec(p:TObject;arg:pointer);         procedure section_write_sechdr(p:TObject;arg:pointer);       protected         function writedata(data:TObjData):boolean;override;       public         constructor Create(AWriter:TObjectWriter);override;       end;       TElfAssembler = class(tinternalassembler)         constructor create(info: pasminfo; smart:boolean);override;       end;       PSectionRec=^TSectionRec;       TSectionRec=record         sec: TObjSection;         relocpos: aword;         relocs: longint;         relentsize: longint;       end;       TElfsecheaderarray=array of TElfsechdr;       TObjSymbolClass=class of TObjSymbol;       TElfObjInput=class(TObjInput)       private         FSecTbl: PSectionRec;         FSymTbl: PPointer;         FLoaded: PBoolean;         shdrs: TElfsecheaderarray;         nsects: longword;         shoffset: aword;         shstrndx: longword;         symtabndx: longword;         shstrtab: TAnsiCharDynarray;         strtab: TAnsiCharDynarray;         shstrtablen: longword;         strtablen: longword;         symtaboffset: aword;         syms: longword;         localsyms: longword;         symversions: TWordDynArray;         dynobj: boolean;         CObjSymbol: TObjSymbolClass;         verdefs: TFPHashObjectList;         function LoadHeader(out objdata:TObjData):boolean;         procedure LoadSection(const shdr:TElfsechdr;index:longint;objdata:TObjData);         procedure LoadRelocations(const secrec:TSectionRec);         procedure LoadSymbols(objdata:TObjData;count,locals:longword);         procedure LoadDynamic(const shdr:TElfsechdr;objdata:TObjData);       public         constructor Create;override;         destructor Destroy;override;         function  ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;override;         class function CanReadObjData(AReader:TObjectreader):boolean;override;         function CreateSection(const shdr:TElfsechdr;index:longint;objdata:TObjData;           out secname:string):TElfObjSection;         function ReadBytes(offs:longint;out buf;len:longint):boolean;       end;       TElfVersionDef = class(TFPHashObject)       public         index: longword;       end;       TElfDynamicObjData = class(TElfObjData)       private         FVersionDefs: TFPHashObjectList;       public         soname_strofs: longword;         vernaux_count: longword;         constructor create(const n:string);override;         destructor destroy;override;         property versiondefs:TFPHashObjectList read FVersionDefs;       end;       TVersionedObjSymbol = class(TObjSymbol)       private         FVersion: TElfVersionDef;       public         property version: TElfVersionDef read FVersion write FVersion;       end;       TRelocNameProc=function(reltyp:byte):string;       TEncodeRelocProc=function(objrel:TObjRelocation):byte;       TLoadRelocProc=procedure(objrel:TObjRelocation);       TLoadSectionProc=function(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean;       TEncodeFlagsProc=function:longword;       TDynamicReloc=(         dr_relative,         dr_glob_dat,         dr_jump_slot,         dr_copy,         dr_irelative       );       TElfTarget=record         max_page_size: longword;         exe_image_base: longword;         machine_code: word;         relocs_use_addend: boolean;         dyn_reloc_codes: array[TDynamicReloc] of byte;         relocname: TRelocNameProc;         encodereloc: TEncodeRelocProc;         loadreloc: TLoadRelocProc;         loadsection: TLoadSectionProc;         encodeflags: TEncodeFlagsProc;       end;       TElfExeSection=class(TExeSection)       public         secshidx  : longword; { index of the section header }         shstridx,         shtype,         shflags,         shlink,         shinfo,         shentsize : longword;         procedure AddObjSection(objsec:TObjSection;ignoreprops:boolean=false);override;       end;       TElfSegment=class       public         ptype: longword;         pflags: longword;         DataPos: aword;         DataSize: aword;         MemPos: aword;         MemSize: aword;         align: longword;         //physaddr: aword;         FSectionList: TFPObjectList;         constructor Create(atype,aflags,aalign:longword);         destructor Destroy; override;         procedure Add(exesec:TExeSection);       end;       TElfExeOutput=class(TExeOutput)       private         segmentlist: TFPObjectList;         textseg,         dataseg,         noteseg,         phdrseg: TElfSegment;         shstrtabsect: TElfObjSection;         symtab: TElfSymtab;         shoffset: aword;         gotwritten: boolean;         { dynamic linking }         dynsymnames: Plongword;         dynsymtable: TElfSymtab;         interpobjsec: TObjSection;         FInterpreter: pshortstring;         verneedcount,         verdefcount: longword;         symversec,         verdefsec,         verneedsec,         hashobjsec: TElfObjSection;         neededlist: TFPHashList;         dyncopysyms: TFPObjectList;         preinitarraysec,         initarraysec,         finiarraysec: TObjSection;         function AttachSection(objsec:TObjSection):TElfExeSection;         function CreateSegment(atype,aflags,aalign:longword):TElfSegment;         procedure WriteHeader;         procedure WriteDynamicSymbolsHash;         procedure WriteVersionSections;         procedure WriteDynamicTags;         procedure FinishDynamicTags;         procedure exesection_write_header(p:TObject;arg:Pointer);         procedure segment_write_header(p:TObject;arg:Pointer);         procedure mempos_segment(seg:TElfSegment);         procedure datapos_segment(seg:TElfSegment);         procedure MapSectionsToSegments;         procedure WriteStaticSymtable;         procedure WriteShstrtab;         procedure FixupSectionLinks;         procedure InitDynlink;         procedure OrderOrphanSections;       protected         dynamiclink: boolean;         hastextrelocs: boolean;         gotsymbol: TObjSymbol;         dynsymlist: TFPObjectList;         dynamicsec,         gotobjsec: TObjSection;         dynbssobjsec,         pltobjsec,         gotpltobjsec,         pltrelocsec,         ipltrelocsec,         dynrelocsec: TElfObjSection;         dynreloclist: TFPObjectList;         tlsseg: TElfSegment;         relative_reloc_count: longint;         gotsize: aword;         dynrelsize: aword;         procedure PrepareGOT;virtual;         function AllocGOTSlot(objsym: TObjSymbol):boolean;virtual;         procedure CreateGOTSection;virtual;         procedure make_dynamic_if_undefweak(exesym:TExeSymbol);         procedure WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword);         procedure CreatePLT;virtual;         procedure WriteFirstPLTEntry;virtual;abstract;         procedure WritePLTEntry(exesym:TExeSymbol);virtual;         procedure WriteIndirectPLTEntry(exesym:TExeSymbol);virtual;         procedure WriteTargetDynamicTags;virtual;         procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);virtual;abstract;         procedure ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);         procedure ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);         procedure WriteDynTag(aTag:longword;aValue:longword);         procedure WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword=0);         procedure Do_Mempos;virtual;       public         constructor Create;override;         destructor Destroy;override;         procedure Load_Start;override;         procedure Load_DynamicObject(ObjData:TObjData;asneeded:boolean);override;         procedure Order_Start;override;         procedure Order_end;override;         procedure AfterUnusedSectionRemoval;override;         procedure MemPos_Start;override;         procedure MemPos_ExeSection(const aname:string);override;         procedure DataPos_Start;override;         procedure DataPos_ExeSection(const aname:string);override;         function writeData:boolean;override;         procedure GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);override;         property interpreter:pshortstring read FInterpreter write FInterpreter;       end;     var       ElfExeOutputClass: TExeOutputClass;       ElfTarget: TElfTarget;     const       { Bits of TObjSymbol.refs field }       symref_plt = 1;       symref_from_text = 2;implementation      uses        SysUtils,        verbose,        export,expunix,        cutils,globals,fmodule,owar;    const      symbolresize = 200*18;{$ifdef cpu64bitaddr}      const        ELFCLASS = ELFCLASS64;      type        telfheader = telf64header;        telfreloc = telf64reloc;        telfsymbol = telf64symbol;        telfproghdr = telf64proghdr;        telfdyn = telf64dyn;      function ELF_R_INFO(sym:longword;typ:byte):qword;inline;        begin          result:=(qword(sym) shl 32) or typ;        end;{$else cpu64bitaddr}      const        ELFCLASS = ELFCLASS32;      type        telfheader = telf32header;        telfreloc = telf32reloc;        telfsymbol = telf32symbol;        telfproghdr = telf32proghdr;        telfdyn = telf32dyn;      function ELF_R_INFO(sym:longword;typ:byte):longword;inline;        begin          result:=(sym shl 8) or typ;        end;{$endif cpu64bitaddr}{****************************************************************************                                Helpers****************************************************************************}    procedure encodesechdrflags(aoptions:TObjSectionOptions;out AshType:longint;out Ashflags:longint);      begin        { Section Type }        if oso_strings in aoptions then          AshType:=SHT_STRTAB        else if not(oso_data in aoptions) then          AshType:=SHT_NOBITS        else if oso_note in aoptions then          AshType:=SHT_NOTE        else if oso_arm_attributes in aoptions then          AshType:=SHT_ARM_ATTRIBUTES        else          AshType:=SHT_PROGBITS;        { Section Flags }        Ashflags:=0;        if oso_load in aoptions then          Ashflags:=Ashflags or SHF_ALLOC;        if oso_executable in aoptions then          Ashflags:=Ashflags or SHF_EXECINSTR;        if oso_write in aoptions then          Ashflags:=Ashflags or SHF_WRITE;        if oso_threadvar in aoptions then          Ashflags:=Ashflags or SHF_TLS;      end;    procedure decodesechdrflags(AshType:longint;Ashflags:longint;out aoptions:TObjSectionOptions);      begin        aoptions:=[];        { Section Type }        if AshType<>SHT_NOBITS then          include(aoptions,oso_data);        if AshType=SHT_STRTAB then          include(aoptions,oso_strings);        { Section Flags }        if Ashflags and SHF_ALLOC<>0 then          include(aoptions,oso_load);        if Ashflags and SHF_WRITE<>0 then          include(aoptions,oso_write);        if Ashflags and SHF_EXECINSTR<>0 then          include(aoptions,oso_executable);        if Ashflags and SHF_TLS<>0 then          include(aoptions,oso_threadvar);      end;{****************************************************************************                               TElfObjSection****************************************************************************}    constructor TElfObjSection.create(AList:TFPHashObjectList;const Aname:string;Aalign:longint;Aoptions:TObjSectionOptions);      begin        inherited create(AList,Aname,Aalign,aoptions);        index:=0;        shstridx:=0;        encodesechdrflags(aoptions,shtype,shflags);        shlink:=0;        shinfo:=0;        if name='.stab' then          shentsize:=sizeof(TObjStabEntry);      end;    constructor TElfObjSection.create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:longint;Aentsize:longint);      var        aoptions : TObjSectionOptions;      begin        decodesechdrflags(Ashtype,Ashflags,aoptions);        inherited create(aobjdata.ObjSectionList,Aname,Aalign,aoptions);        objdata:=aobjdata;        index:=0;        shstridx:=0;        shtype:=AshType;        shflags:=AshFlags;        shentsize:=Aentsize;      end;    const      relsec_prefix:array[boolean] of string[5] = ('.rel','.rela');      relsec_shtype:array[boolean] of longword = (SHT_REL,SHT_RELA);    constructor TElfObjSection.create_reloc(aobjdata:TObjData;const Aname:string;allocflag:boolean);      begin        create_ext(aobjdata,          relsec_prefix[ElfTarget.relocs_use_addend]+aname,          relsec_shtype[ElfTarget.relocs_use_addend],          SHF_ALLOC*ord(allocflag),          sizeof(pint),          (2+ord(ElfTarget.relocs_use_addend))*sizeof(pint));      end;    procedure TElfObjSection.writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);      var        reloc: TObjRelocation;      begin        reloc:=TObjRelocation.CreateSection(Size,aTarget,reltype);        reloc.size:=len;        ObjRelocations.Add(reloc);        if reltype=RELOC_RELATIVE then{ ARM does not require this adjustment, other CPUs must be checked }{$if defined(i386) or defined(x86_64)}          dec(offset,len){$endif i386 or x86_64}        else if reltype<>RELOC_ABSOLUTE then          InternalError(2012062401);        if ElfTarget.relocs_use_addend then          begin            reloc.orgsize:=offset;            offset:=0;          end;        write(offset,len);      end;{****************************************************************************                            TElfObjData****************************************************************************}    constructor TElfObjData.create(const n:string);      begin        inherited create(n);        CObjSection:=TElfObjSection;      end;    function TElfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;      const        secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',          { TODO: sec_rodata is still writable }          '.text','.data','.data','.rodata','.bss','.threadvar',          '.pdata',          '.text', { darwin stubs }          '__DATA,__nl_symbol_ptr',          '__DATA,__la_symbol_ptr',          '__DATA,__mod_init_func',          '__DATA,__mod_term_func',          '.stab','.stabstr',          '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',          '.eh_frame',          '.debug_frame','.debug_info','.debug_line','.debug_abbrev','.debug_aranges','.debug_ranges','.debug_loc','.debug_loclists',          '.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',          '.stack',          '.heap',          '.gcc_except_table',          '.ARM.attributes'        );      var        sep : string[3];        secname : string;      begin        { section type user gives the user full controll on the section name }        if atype=sec_user then          result:=aname        else          begin            secname:=secnames[atype];            if (atype=sec_fpc) and (Copy(aname,1,3)='res') then              begin                result:=secname+'.'+aname;                exit;              end;            if atype=sec_threadvar then              begin                if (target_info.system in (systems_windows+systems_wince)) then                  secname:='.tls'                else if (target_info.system in systems_linux) then                  secname:='.tbss';              end;            if create_smartlink_sections and (aname<>'') then              begin                case aorder of                  secorder_begin :                    sep:='.b_';                  secorder_end :                    sep:='.z_';                  else                    sep:='.n_';                end;                result:=secname+sep+aname              end            else              result:=secname;          end;      end;    procedure TElfObjData.CreateDebugSections;      begin        if target_dbg.id=dbg_stabs then          begin            stabssec:=createsection(sec_stab);            stabstrsec:=createsection(sec_stabstr);          end;      end;    procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);      type         multi = record          case integer of          0 : (ba : array[0..sizeof(aint)-1] of byte);          1 : (b : byte);          2 : (w : word);          4 : (d : dword);          8 : (q : qword);        end;      var        symaddr : aint;        ba : multi;        b : byte;        objreloc: TObjRelocation;      begin        if CurrObjSec=nil then          internalerror(200403292);        objreloc:=nil;        if assigned(p) then         begin           { real address of the symbol }           symaddr:=p.address;           { Local ObjSymbols can be resolved already or need a section reloc }           if (p.bind=AB_LOCAL) and              (reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}{$ifdef arm},RELOC_RELATIVE_24,RELOC_RELATIVE_CALL{$endif arm}]) then             begin{$ifdef ARM}               if (reltype in [RELOC_RELATIVE_24,RELOC_RELATIVE_CALL]) and                  (p.objsection=CurrObjSec) then                 begin                   data:=aint((data and $ff000000) or (((((data and $ffffff) shl 2)+(symaddr-CurrObjSec.Size)) shr 2) and $FFFFFF)); // TODO: Check overflow                 end               else{$endif ARM}               { For a reltype relocation in the same section the                 value can be calculated }               if (p.objsection=CurrObjSec) and                  (reltype=RELOC_RELATIVE) then                 inc(data,symaddr-len-CurrObjSec.Size)               else                 begin                   objreloc:=TObjRelocation.CreateSection(CurrObjSec.Size,p.objsection,reltype);                   CurrObjSec.ObjRelocations.Add(objreloc);                   inc(data,symaddr);                 end;             end           else             begin               objreloc:=TObjRelocation.CreateSymbol(CurrObjSec.Size,p,reltype);               CurrObjSec.ObjRelocations.Add(objreloc);               { If target is a local label and it isn't handled above,                 patch its type in order to get it written to symtable.                 This may happen e.g. when taking address of Pascal label in PIC mode. }               if (p.bind=AB_LOCAL) and (p.typ=AT_LABEL) then                 p.typ:=AT_ADDR;            end;         end;        if assigned(objreloc) then          begin            objreloc.size:=len;            { RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX] need special handling              this is done in x86/aasmcpu unit }            if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}               {$ifdef x86_64}, RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX,RELOC_TLSGD{$endif}] then              dec(data,len);            if ElfTarget.relocs_use_addend then              begin                objreloc.orgsize:=aword(data);                data:=0;              end;          end;        if target_info.endian<>source_info.endian then          begin            ba.q:=0;            if (len<=sizeof(data)) then              case len of                1 : ba.b:=byte(data);                2 : begin                      ba.w:=word(data);                      ba.w:=swapendian(ba.w);                    end;                4 : begin                      ba.d:=dword(data);                      ba.d:=swapendian(ba.d);                    end;                8 : begin                      ba.q:=qword(data);                      ba.q:=swapendian(ba.q);                    end;              else                internalerror(2024012501);              end;            CurrObjSec.write(ba,len);          end        else          CurrObjSec.write(data,len);      end;{****************************************************************************                            TElfDynamicObjData****************************************************************************}    constructor TElfDynamicObjData.create(const n:string);      begin        inherited Create(n);        FVersionDefs:=TFPHashObjectList.create(true);        { Default symversions with indices 0 and 1 }        TElfVersionDef.create(FVersionDefs,'*local*');        TElfVersionDef.create(FVersionDefs,'*global*');      end;    destructor TElfDynamicObjData.destroy;      begin        FVersionDefs.free;        inherited Destroy;      end;{****************************************************************************                            TElfSymtab****************************************************************************}    const      symsecnames: array[boolean] of string[8] = ('.symtab','.dynsym');      strsecnames: array[boolean] of string[8] = ('.strtab','.dynstr');      symsectypes: array[boolean] of longword  = (SHT_SYMTAB,SHT_DYNSYM);      symsecattrs: array[boolean] of longword  = (0,SHF_ALLOC);    constructor TElfSymtab.create(aObjData:TObjData;aKind:TElfSymtabKind);      var        dyn:boolean;      begin        dyn:=(aKind=esk_dyn);        create_ext(aObjData,symsecnames[dyn],symsectypes[dyn],symsecattrs[dyn],sizeof(pint),sizeof(TElfSymbol));        fstrsec:=TElfObjSection.create_ext(aObjData,strsecnames[dyn],SHT_STRTAB,symsecattrs[dyn],1,0);        fstrsec.writezeros(1);        writezeros(sizeof(TElfSymbol));        symidx:=1;        shinfo:=1;        kind:=aKind;      end;    procedure TElfSymtab.writeInternalSymbol(avalue:aword;astridx:longword;ainfo:byte;ashndx:word);      var        elfsym:TElfSymbol;      begin        fillchar(elfsym,sizeof(elfsym),0);        elfsym.st_value:=avalue;        elfsym.st_name:=astridx;        elfsym.st_info:=ainfo;        elfsym.st_shndx:=ashndx;        inc(symidx);        inc(shinfo);        MaybeSwapElfSymbol(elfsym);        write(elfsym,sizeof(elfsym));      end;    procedure TElfSymtab.writeSymbol(objsym:TObjSymbol;nameidx:longword);      var        elfsym:TElfSymbol;      begin        fillchar(elfsym,sizeof(elfsym),0);        if nameidx=0 then          elfsym.st_name:=fstrsec.writestr(objsym.name)        else          elfsym.st_name:=nameidx;        elfsym.st_size:=objsym.size;        elfsym.st_value:=objsym.address;{$ifdef ARM}        if objsym.ThumbFunc then          inc(elfsym.st_value);{$endif ARM}        { hidden symbols should have been converted to local symbols in          the linking pass in case we're writing an exe/library; don't          convert them to local here as well, as that would potentially          hide a bug there. }        case objsym.bind of          AB_LOCAL :            begin              elfsym.st_info:=STB_LOCAL shl 4;              inc(shinfo);            end;          AB_COMMON :            begin              elfsym.st_value:=size_2_align(objsym.size);              elfsym.st_info:=STB_GLOBAL shl 4;              elfsym.st_shndx:=SHN_COMMON;            end;          AB_EXTERNAL :            elfsym.st_info:=STB_GLOBAL shl 4;          AB_WEAK_EXTERNAL :            elfsym.st_info:=STB_WEAK shl 4;          AB_GLOBAL :            elfsym.st_info:=STB_GLOBAL shl 4;          AB_PRIVATE_EXTERN :            begin              elfsym.st_info:=STB_GLOBAL shl 4;              SetElfSymbolVisibility(elfsym.st_other,STV_HIDDEN);            end        else          InternalError(2012111801);        end;        { External symbols must be NOTYPE in relocatable files except if they are TLS symbols }        if (objsym.bind<>AB_EXTERNAL) or (kind<>esk_obj) or (objsym.typ=AT_TLS) then          begin            case objsym.typ of              AT_FUNCTION :                elfsym.st_info:=elfsym.st_info or STT_FUNC;              AT_DATA,              AT_METADATA:                elfsym.st_info:=elfsym.st_info or STT_OBJECT;              AT_TLS:                elfsym.st_info:=elfsym.st_info or STT_TLS;              AT_GNU_IFUNC:                elfsym.st_info:=elfsym.st_info or STT_GNU_IFUNC;              { other types are implicitly mapped to STT_NOTYPE }              else                ;            end;          end;        if objsym.bind<>AB_COMMON then          begin            if kind<>esk_obj then              begin                if assigned(objsym.objsection) and assigned(objsym.objsection.ExeSection) then                  begin                    if (objsym.typ=AT_TLS) then                      elfsym.st_value:=elfsym.st_value-tlsbase                    else if (oso_plt in objsym.objsection.SecOptions) then                      elfsym.st_value:=0                    else                      elfsym.st_shndx:=TElfExeSection(objsym.objsection.ExeSection).secshidx;                  end;              end            else              begin                if assigned(objsym.objsection) then                  elfsym.st_shndx:=objsym.objsection.index                else                  elfsym.st_shndx:=SHN_UNDEF;                objsym.symidx:=symidx;              end;          end;        inc(symidx);        MaybeSwapElfSymbol(elfsym);        write(elfsym,sizeof(TElfSymbol));      end;{****************************************************************************                            TElfObjectOutput****************************************************************************}    constructor TElfObjectOutput.create(AWriter:TObjectWriter);      begin        inherited Create(AWriter);        CObjData:=TElfObjData;      end;    procedure TElfObjectOutput.createrelocsection(s:TElfObjSection;data:TObjData);      var        i    : longint;        rel  : telfreloc;        objreloc : TObjRelocation;        relsym   : longint;        relocsect : TElfObjSection;      begin        { create the reloc section }        relocsect:=TElfObjSection.create_reloc(data,s.name,false);        relocsect.shlink:=symtabsect.index;        relocsect.shinfo:=s.index;        { add the relocations }        for i:=0 to s.Objrelocations.count-1 do          begin            objreloc:=TObjRelocation(s.Objrelocations[i]);            { Symbol }            if assigned(objreloc.symbol) then              begin                if objreloc.symbol.symidx=-1 then                  begin                    writeln(objreloc.symbol.Name);                    internalerror(200603012);                  end;                relsym:=objreloc.symbol.symidx;              end            else              begin                if objreloc.objsection<>nil then                  relsym:=objreloc.objsection.secsymidx                else                  relsym:=SHN_UNDEF;              end;            rel.address:=objreloc.dataoffset;            rel.info:=ELF_R_INFO(relsym,ElfTarget.encodereloc(objreloc));{$push}{$r-}            rel.addend:=objreloc.orgsize;{$pop}            { write reloc }            { ElfXX_Rel is essentially ElfXX_Rela without the addend field. }            MaybeSwapElfReloc(rel);            relocsect.write(rel,relocsect.shentsize);          end;      end;    procedure TElfObjectOutput.section_write_symbol(p:TObject;arg:pointer);      begin        { Must not write symbols for internal sections like .symtab }        { TODO: maybe use inclusive list of section types instead }        if (TElfObjSection(p).shtype in [SHT_SYMTAB,SHT_STRTAB,SHT_REL,SHT_RELA]) then          exit;        TObjSection(p).secsymidx:=symtabsect.symidx;        symtabsect.writeInternalSymbol(0,0,STT_SECTION,TObjSection(p).index);      end;    procedure TElfObjectOutput.createsymtab(data: TObjData);      var        i      : longint;        objsym : TObjSymbol;      begin        with data do         begin           { section symbols }           ObjSectionList.ForEachCall(@section_write_symbol,nil);           { First the Local Symbols, this is required by ELF. The localsyms             count stored in shinfo is used to skip the local symbols             when traversing the symtab }           for i:=0 to ObjSymbolList.Count-1 do             begin               objsym:=TObjSymbol(ObjSymbolList[i]);               if (objsym.bind=AB_LOCAL) and (objsym.typ<>AT_LABEL) then                 symtabsect.WriteSymbol(objsym);             end;           { Global Symbols }           for i:=0 to ObjSymbolList.Count-1 do             begin               objsym:=TObjSymbol(ObjSymbolList[i]);               if (objsym.bind<>AB_LOCAL) then                 symtabsect.WriteSymbol(objsym);             end;           { update the .symtab section header }           symtabsect.shlink:=symtabsect.fstrsec.index;         end;      end;    procedure TElfObjectOutput.createshstrtab(data: TObjData);      var        i,prefixlen:longint;        objsec,target:TElfObjSection;      begin        shstrtabsect.writezeros(1);        prefixlen:=length('.rel')+ord(ElfTarget.relocs_use_addend);        for i:=0 to data.ObjSectionList.Count-1 do          begin            objsec:=TElfObjSection(data.ObjSectionList[i]);            { Alias section names into names of corresponding reloc sections,              this is allowed by ELF specs and saves good half of .shstrtab space. }            if objsec.shtype=relsec_shtype[ElfTarget.relocs_use_addend] then              begin                target:=TElfObjSection(data.ObjSectionList[objsec.shinfo-1]);                if (target.ObjRelocations.Count=0) or                   (target.shstridx<prefixlen) then                  InternalError(2012101204);                objsec.shstridx:=target.shstridx-prefixlen;              end            else              begin                if objsec.ObjRelocations.Count<>0 then                  shstrtabsect.write(relsec_prefix[true][1],prefixlen);                objsec.shstridx:=shstrtabsect.writestr(objsec.name);              end;          end;      end;    procedure TElfObjectOutput.writesectionheader(s:TElfObjSection);      var        sechdr : telfsechdr;      begin        fillchar(sechdr,sizeof(sechdr),0);        sechdr.sh_name:=s.shstridx;        sechdr.sh_type:=s.shtype;        sechdr.sh_flags:=s.shflags;        sechdr.sh_offset:=s.datapos;        sechdr.sh_size:=s.Size;        sechdr.sh_link:=s.shlink;        sechdr.sh_info:=s.shinfo;        sechdr.sh_addralign:=s.secalign;        sechdr.sh_entsize:=s.shentsize;        MaybeSwapSecHeader(sechdr);        writer.write(sechdr,sizeof(sechdr));      end;    procedure TElfObjectOutput.section_count_sections(p:TObject;arg:pointer);      begin        TElfObjSection(p).index:=pword(arg)^;        inc(pword(arg)^);      end;    procedure TElfObjectOutput.section_create_relocsec(p:TObject;arg:pointer);      begin        if (TElfObjSection(p).ObjRelocations.count>0) then          createrelocsection(TElfObjSection(p),TObjData(arg));      end;    procedure TElfObjectOutput.section_write_sechdr(p:TObject;arg:pointer);      begin        writesectionheader(TElfObjSection(p));      end;    function TElfObjectOutput.writedata(data:TObjData):boolean;      var        header : telfheader;        shoffset,        datapos   : aword;        nsections : word;      begin        result:=false;        with data do         begin           { default sections }           symtabsect:=TElfSymtab.create(data,esk_obj);           shstrtabsect:=TElfObjSection.create_ext(data,'.shstrtab',SHT_STRTAB,0,1,0);           { "no executable stack" marker }           { TODO: used by OpenBSD/NetBSD as well? }           if (target_info.system in (systems_linux + systems_android + systems_freebsd + systems_dragonfly)) and              not(cs_executable_stack in current_settings.moduleswitches) then             TElfObjSection.create_ext(data,'.note.GNU-stack',SHT_PROGBITS,0,1,0);           { symbol for filename }           symtabsect.fstrsec.writestr(ExtractFileName(current_module.mainsource));           symtabsect.writeInternalSymbol(0,1,STT_FILE,SHN_ABS);           { calc amount of sections we have }           nsections:=1;           { also create the index in the section header table }           ObjSectionList.ForEachCall(@section_count_sections,@nsections);           { create .symtab and .strtab }           createsymtab(data);           { Create the relocation sections, this needs valid secidx and symidx }           ObjSectionList.ForEachCall(@section_create_relocsec,data);           { recalc nsections to incude the reloc sections }           nsections:=1;           ObjSectionList.ForEachCall(@section_count_sections,@nsections);           { create .shstrtab }           createshstrtab(data);           { Calculate the filepositions }           datapos:=$40; { elfheader + alignment }           { section data }           layoutsections(datapos);           { section headers }           shoffset:=align(datapos,dword(Sizeof(AInt)));           inc(datapos,(nsections+1)*sizeof(telfsechdr));           { Write ELF Header }           fillchar(header,sizeof(header),0);           header.e_ident[EI_MAG0]:=ELFMAG0; { = #127'ELF' }           header.e_ident[EI_MAG1]:=ELFMAG1;           header.e_ident[EI_MAG2]:=ELFMAG2;           header.e_ident[EI_MAG3]:=ELFMAG3;           header.e_ident[EI_CLASS]:=ELFCLASS;           if target_info.endian=endian_big then             header.e_ident[EI_DATA]:=ELFDATA2MSB           else             header.e_ident[EI_DATA]:=ELFDATA2LSB;           header.e_ident[EI_VERSION]:=1;           if target_info.system in systems_openbsd then             header.e_ident[EI_OSABI]:=ELFOSABI_OPENBSD           else if target_info.system in systems_freebsd then             header.e_ident[EI_OSABI]:=ELFOSABI_FREEBSD           else if target_info.system in systems_dragonfly then             header.e_ident[EI_OSABI]:=ELFOSABI_NONE;           header.e_type:=ET_REL;           header.e_machine:=ElfTarget.machine_code;           header.e_version:=1;           header.e_shoff:=shoffset;           header.e_shstrndx:=shstrtabsect.index;           header.e_shnum:=nsections;           header.e_ehsize:=sizeof(telfheader);           header.e_shentsize:=sizeof(telfsechdr);           if assigned(ElfTarget.encodeflags) then             header.e_flags:=ElfTarget.encodeflags();           MaybeSwapHeader(header);           writer.write(header,sizeof(header));           writer.writezeros($40-sizeof(header)); { align }           { Sections }           WriteSectionContent(data);           { Align header }           Writer.Writezeros(Align(Writer.Size,Sizeof(AInt))-Writer.Size);           { section headers, start with an empty header for sh_undef }           writer.writezeros(sizeof(telfsechdr));           ObjSectionList.ForEachCall(@section_write_sechdr,nil);         end;        result:=true;      end;{****************************************************************************                               TELFAssembler****************************************************************************}    constructor TElfAssembler.Create(info: pasminfo; smart:boolean);      begin        inherited;        CObjOutput:=TElfObjectOutput;        CInternalAr:=tarobjectwriter;      end;{****************************************************************************                               TELFObjectInput****************************************************************************}    constructor TElfObjInput.Create;      begin        inherited Create;        CObjData:=TElfObjData;        CObjSymbol:=TObjSymbol;      end;    destructor TElfObjInput.Destroy;      begin        if Assigned(FSymTbl) then          FreeMem(FSymTbl);        if Assigned(FSecTbl) then          FreeMem(FSecTbl);        strtab:=nil;        shstrtab:=nil;        symversions:=nil;        inherited Destroy;      end;    procedure TElfObjInput.LoadRelocations(const secrec:TSectionRec);      var        i: longint;        rel: TElfReloc;        reltyp: byte;        relsym: longint;        objrel: TObjRelocation;        p: TObjSymbol;      begin        FReader.Seek(secrec.relocpos);        if secrec.sec=nil then          InternalError(2012060203);        if (secrec.relentsize=3*sizeof(pint)) then          with secrec.sec do SecOptions:=SecOptions+[oso_rela_relocs];        for i:=0 to secrec.relocs-1 do          begin            FReader.Read(rel,secrec.relentsize);            MaybeSwapElfReloc(rel);            reltyp:=rel.info and $FF;{$ifdef cpu64bitaddr}            relsym:=rel.info shr 32;{$else cpu64bitaddr}            relsym:=(rel.info shr 8) and $FFFFFF;{$endif cpu64bitaddr}            if relsym>=syms then              InternalError(2012060204);            p:=TObjSymbol(FSymTbl[relsym]);            { Some relocations (e.g. R_ARM_V4BX) don't use a symbol at all }            if assigned(p) or (relsym=0) then              begin                objrel:=TObjRelocation.CreateRaw(rel.address-secrec.sec.mempos,p,reltyp);                if (secrec.relentsize=3*sizeof(pint)) then                  objrel.orgsize:=rel.addend;                { perform target-specific actions }                if Assigned(ElfTarget.loadreloc) then                  ElfTarget.loadreloc(objrel);                secrec.sec.ObjRelocations.add(objrel);              end            else              begin                InputError('Unable to resolve symbol of relocation');                exit;              end;          end;      end;    procedure TElfObjInput.LoadSymbols(objdata:TObjData;count,locals:longword);      var        i: longint;        sym: TElfSymbol;        bind: TAsmSymBind;        typ: TAsmSymType;        objsym: TObjSymbol;        ver: word;      begin        FSymTbl:=AllocMem(count*sizeof(Pointer));        for i:=1 to count-1 do          begin            FReader.Read(sym,sizeof(TElfSymbol));            MaybeSwapElfSymbol(sym);            if sym.st_name>=strtablen then              InternalError(2012060205);            if sym.st_shndx=SHN_ABS then    { ignore absolute symbols (should we really do it???) }              Continue            else if sym.st_shndx=SHN_COMMON then              bind:=AB_COMMON            else if (sym.st_shndx>=nsects) then              InternalError(2012060206)            else              case (sym.st_info shr 4) of                STB_LOCAL:                  bind:=AB_LOCAL;                STB_GLOBAL:                  if sym.st_shndx=SHN_UNDEF then                    bind:=AB_EXTERNAL                  else if GetElfSymbolVisibility(sym.st_other)=STV_HIDDEN then                    bind:=AB_PRIVATE_EXTERN                  else                    bind:=AB_GLOBAL;                STB_WEAK:                  bind:=AB_WEAK_EXTERNAL;              else                InternalError(2012060207);              end;            { Ignore section symbol if we didn't create the corresponding objsection              (examples are SHT_GROUP or .note.GNU-stack sections). }            if (sym.st_shndx>0) and (sym.st_shndx<SHN_LORESERVE) and              (FSecTbl[sym.st_shndx].sec=nil) and              (not dynobj) then              if ((sym.st_info and $0F)=STT_SECTION) then                Continue              else                begin                  writeln(objdata.name,' ',i);                  InternalError(2012110701)                end;            case (sym.st_info and $0F) of              STT_NOTYPE:                typ:=AT_NONE;              STT_OBJECT:                typ:=AT_DATA;              STT_FUNC:                typ:=AT_FUNCTION;              STT_SECTION:                typ:=AT_SECTION;              STT_FILE:                continue;              STT_TLS:                typ:=AT_TLS;              STT_GNU_IFUNC:                typ:=AT_GNU_IFUNC;            else              writeln(objdata.name,' ',sym.st_info and $0F);              InternalError(2012060208);            end;            { If reading DSO, we're interested only in global symbols defined there.              Symbols with non-current version should also be ignored. }            ver:=0;            if dynobj then              begin                if assigned(symversions) then                  begin                    ver:=symversions[i];                    if (ver=VER_NDX_LOCAL) or (ver>VERSYM_VERSION) then                      continue;                  end;                if (bind=AB_LOCAL) or (sym.st_shndx=SHN_UNDEF) then                  continue;                if ver>=verdefs.count then                  InternalError(2012120505);              end;            { validity of name and objsection has been checked above }            { !! all AT_SECTION symbols have duplicate (null) name,              therefore TObjSection.CreateSymbol cannot be used here }            objsym:=CObjSymbol.Create(objdata.ObjSymbolList,string(PChar(@strtab[sym.st_name])));            objsym.bind:=bind;            objsym.typ:=typ;            if bind<>AB_COMMON then              objsym.objsection:=FSecTbl[sym.st_shndx].sec;            objsym.offset:=sym.st_value;            objsym.size:=sym.st_size;            FSymTbl[i]:=objsym;            if (ver>VER_NDX_GLOBAL) then              TVersionedObjSymbol(objsym).version:=TElfVersionDef(verdefs[ver]);          end;      end;    function TElfObjInput.CreateSection(const shdr:TElfsechdr;index:longint;objdata:tobjdata;        out secname:string):TElfObjSection;      begin        secname:=string(PChar(@shstrtab[shdr.sh_name]));        result:=TElfObjSection.create_ext(objdata,secname,          shdr.sh_type,shdr.sh_flags,shdr.sh_addralign,shdr.sh_entsize);        result.index:=index;        result.DataPos:=shdr.sh_offset;        result.MemPos:=shdr.sh_addr;        result.Size:=shdr.sh_size;        FSecTbl[index].sec:=result;      end;    function TElfObjInput.ReadBytes(offs:longint;out buf;len:longint):boolean;      begin        FReader.Seek(offs);        result:=FReader.Read(buf,len);      end;    procedure TElfObjInput.LoadSection(const shdr:TElfsechdr;index:longint;objdata:tobjdata);      var        sec: TElfObjSection;        sym: TElfSymbol;        secname: string;      begin        if shdr.sh_name>=shstrtablen then          InternalError(2012060210);        case shdr.sh_type of          SHT_NULL:            {ignore};          { SHT_STRTAB may appear for .stabstr and other debug sections.            .shstrtab and .strtab are processed separately and don't appear here. }          SHT_PROGBITS,SHT_NOBITS,SHT_NOTE,SHT_STRTAB,          SHT_INIT_ARRAY,SHT_FINI_ARRAY,SHT_PREINIT_ARRAY:            begin              sec:=CreateSection(shdr,index,objdata,secname);              if (Length(secname)>3) and (secname[2] in ['d','f','n','s']) then                begin                  if (Pos('.stub',secname)=1) or                    (Pos('.fpc',secname)=1) then                    sec.SecOptions:=[oso_keep]                  { ELF does not have any flags specific to debug sections,                    but reserves names starting with '.debug' for this purpose }                  else if (Pos('.debug',secname)=1) or                    (secname='.stab') or                    (secname='.stabstr') then                    sec.SecOptions:=[oso_debug]                  else if (secname='.note.GNU-stack') and (shdr.sh_type=SHT_PROGBITS) then                    begin                      if (shdr.sh_flags and SHF_EXECINSTR)=0 then                        objdata.ExecStack:=False;                    end;                end;              if (shdr.sh_type=SHT_NOTE) and (shdr.sh_size<>0) then                sec.SecOptions:=[oso_keep];            end;          SHT_REL,SHT_RELA:            begin              if shdr.sh_info>=nsects then                InternalError(2012060211);              if shdr.sh_entsize<>longword((2+ord(shdr.sh_type=SHT_RELA))*sizeof(pint)) then                InternalError(2012060212);              with FSecTbl[shdr.sh_info] do                begin                  relocpos:=shdr.sh_offset;                  relocs:=shdr.sh_size div shdr.sh_entsize;                  relentsize:=shdr.sh_entsize;                end;            end;          SHT_GROUP:            if (shdr.sh_size>=2*sizeof(longword)) and              (shdr.sh_entsize=sizeof(longword)) and              ((shdr.sh_size mod shdr.sh_entsize)=0) then              begin                { Groups are identified by name of symbol pointed to by                  sh_link and sh_info, not by sh_name. This symbol                  may as well be STT_SECTION symbol of this section,                  in which case we end up using sh_name. }                if dynobj then                  InternalError(2012110801);                if (shdr.sh_link<>symtabndx) then                  InternalError(2012110703);                if (shdr.sh_info>=syms) then                  InternalError(2012110704);                FReader.Seek(symtaboffset+shdr.sh_info*sizeof(TElfSymbol));                FReader.Read(sym,sizeof(TElfSymbol));                MaybeSwapElfSymbol(sym);                if sym.st_name>=strtablen then                  InternalError(2012110705);                if (sym.st_shndx=index) and (sym.st_info=((STB_LOCAL shl 4) or STT_SECTION)) then                  secname:=string(PChar(@shstrtab[shdr.sh_name]))                else                  secname:=string(PChar(@strtab[sym.st_name]));                { Postpone further processing until all sections are loaded,                  we'll need to access correct section header.                  Since ABI requires SHT_GROUP sections to come first in the file,                  we assume that group number x has header index x+1.                  If we ever encounter files where this is not true, we'll have                  to maintain a separate index. }                objdata.CreateSectionGroup(secname);                if (index<>objdata.GroupsList.Count) then                  InternalError(2012110802);              end            else              InternalError(2012110706);          SHT_GNU_ATTRIBUTES:            { TODO: must not be ignored };        else          if not (assigned(ElfTarget.loadsection) and            ElfTarget.loadsection(self,objdata,shdr,index)) then            InternalError(2012072603);        end;        FLoaded[index]:=True;      end;    function TElfObjInput.LoadHeader(out objdata:TObjData):boolean;      var        header:TElfHeader;      begin        result:=false;        if not FReader.read(header,sizeof(header)) then          begin            InputError('Can''t read ELF header');            exit;          end;        if (header.e_ident[EI_MAG0]<>ELFMAG0) or (header.e_ident[EI_MAG1]<>ELFMAG1) or           (header.e_ident[EI_MAG2]<>ELFMAG2) or (header.e_ident[EI_MAG3]<>ELFMAG3) then          begin            InputError('Illegal ELF magic');            exit;          end;        if (header.e_ident[EI_VERSION]<>1) then          begin            InputError('Unknown ELF file version');            exit;          end;        if (header.e_ident[EI_CLASS]<>ELFCLASS) then          begin            InputError('Wrong ELF file class (32/64 bit mismatch)');            exit;          end;        if (header.e_ident[EI_DATA]<>1+ord(target_info.endian=endian_big)) then          begin            InputError('ELF endianness does not match target');            exit;          end;        MaybeSwapHeader(header);        if (header.e_version<>1) then          begin            InputError('Unknown ELF data version');            exit;          end;        if (header.e_machine<>ElfTarget.machine_code) then          begin            InputError('ELF file is for different CPU');            exit;          end;        if (header.e_type<>ET_REL) and (header.e_type<>ET_DYN) then          begin            InputError('Not a relocatable or dynamic ELF file');            exit;          end;        if header.e_shentsize<>sizeof(TElfsechdr) then          InternalError(2012062701);        nsects:=header.e_shnum;        dynobj:=(header.e_type=ET_DYN);        shoffset:=header.e_shoff;        shstrndx:=header.e_shstrndx;        if dynobj then          begin            objdata:=TElfDynamicObjData.Create(InputFilename);            verdefs:=TElfDynamicObjData(objdata).versiondefs;            CObjSymbol:=TVersionedObjSymbol;          end        else          objdata:=CObjData.Create(InputFilename);        TElfObjData(objdata).ident:=header.e_ident;        TElfObjData(objdata).flags:=header.e_flags;        result:=true;      end;    procedure TElfObjInput.LoadDynamic(const shdr:TElfsechdr;objdata:TObjData);      var        dt: TElfDyn;        i: longint;      begin        if (shdr.sh_entsize<>sizeof(TElfDyn)) then          InternalError(2012071403);        FReader.Seek(shdr.sh_offset);        for i:=0 to (shdr.sh_size div shdr.sh_entsize)-1 do          begin            FReader.Read(dt,sizeof(TElfDyn));            MaybeSwapElfDyn(dt);            case dt.d_tag of              DT_NULL:                break;              DT_SONAME:                TElfObjData(objdata).FName:=string(PChar(@strtab[dt.d_ptr]));              DT_NEEDED:                ;            end;          end;      end;    function TElfObjInput.ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;      var        i,j,strndx,dynndx,        versymndx,verdefndx,verneedndx: longint;        objsec: TObjSection;        grp: TObjSectionGroup;        tmp: longword;        count: longint;        vd: TElfverdef;        vda: TElfverdaux;        vdoffset: aword;      begin        FReader:=AReader;        InputFileName:=AReader.FileName;        result:=false;        strndx:=0;        if not LoadHeader(objData) then          exit;        FSecTbl:=AllocMem(nsects*sizeof(TSectionRec));        FLoaded:=AllocMem(nsects*sizeof(boolean));        SetLength(shdrs,nsects);        FReader.Seek(shoffset);        if not FReader.Read(shdrs[0],nsects*sizeof(TElfsechdr)) then          begin            InputError('Can''t read ELF section headers');            exit;          end;        if source_info.endian<>target_info.endian then          for i:=0 to nsects-1 do            MaybeSwapSecHeader(shdrs[i]);        { First, load the .shstrtab section }        if shstrndx>=nsects then          InternalError(2012060201);        if shdrs[shstrndx].sh_type<>SHT_STRTAB then          InternalError(2012060202);        shstrtablen:=shdrs[shstrndx].sh_size;        SetLength(shstrtab,shstrtablen);        FReader.seek(shdrs[shstrndx].sh_offset);        FReader.read(shstrtab[0],shstrtablen);        FLoaded[shstrndx]:=True;        { Locate the symtable, it is typically at the end so loop backwards.          Load the strings, postpone symtable itself until done with sections.          Note that is is legal to have no symtable.          For DSO, locate .dynsym instead, this one is near the beginning, but          overall number of sections won't be big. }        symtabndx:=0;        for i:=nsects-1 downto 1 do          begin            if (shdrs[i].sh_type<>symsectypes[dynobj]) then              continue;            if (shdrs[i].sh_entsize<>sizeof(TElfSymbol)) then              InternalError(2012060213);            if shdrs[i].sh_link>=nsects then              InternalError(2012062702);            strndx:=shdrs[i].sh_link;            if shdrs[strndx].sh_type<>SHT_STRTAB then              InternalError(2012062703);            strtablen:=shdrs[strndx].sh_size;            setLength(strtab,strtablen);            FReader.seek(shdrs[strndx].sh_offset);            FReader.read(strtab[0],strtablen);            symtaboffset:=shdrs[i].sh_offset;            syms:=shdrs[i].sh_size div sizeof(TElfSymbol);            localsyms:=shdrs[i].sh_info;            FLoaded[i]:=True;            FLoaded[strndx]:=True;            symtabndx:=i;            break;          end;        if dynobj then          begin            if symtabndx=0 then              InternalError(2012110707);            { Locate .dynamic and version sections. Expect a single one of a kind. }            dynndx:=0;            versymndx:=0;            verdefndx:=0;            verneedndx:=0;            for i:=nsects-1 downto 0 do              begin                case shdrs[i].sh_type of                  SHT_DYNAMIC:                    begin                      if dynndx<>0 then                        InternalError(2012102001);                      dynndx:=i;                      if (shdrs[dynndx].sh_link<>strndx) then                        InternalError(2012071402);                      LoadDynamic(shdrs[dynndx],objdata);                    end;                  SHT_GNU_versym:                    begin                      if versymndx<>0 then                        InternalError(2012102002);                      versymndx:=i;                      if shdrs[i].sh_entsize<>sizeof(word) then                        InternalError(2012102003);                      if shdrs[i].sh_link<>symtabndx then                        InternalError(2012102004);                      if shdrs[i].sh_size<>syms*sizeof(word) then                        InternalError(2012102005);                      SetLength(symversions,shdrs[i].sh_size);                      FReader.seek(shdrs[i].sh_offset);                      FReader.read(symversions[0],shdrs[i].sh_size);                      if source_info.endian<>target_info.endian then                        for j:=0 to syms-1 do                          symversions[j]:=SwapEndian(symversions[j]);                    end;                  SHT_GNU_verdef:                    begin                      if verdefndx<>0 then                        InternalError(2012102006);                      verdefndx:=i;                      if shdrs[i].sh_link<>strndx then                        InternalError(2012120501);                      vdoffset:=shdrs[i].sh_offset;                      { TODO: can we rely on sh_info, or must read until vd_next=0? }                      for j:=1 to shdrs[i].sh_info do                        begin                          FReader.seek(vdoffset);                          FReader.Read(vd,sizeof(TElfverdef));                          MaybeSwapElfverdef(vd);                          if vd.vd_version<>VER_DEF_CURRENT then                            InternalError(2012120502);                          FReader.seek(vdoffset+vd.vd_aux);                          vdoffset:=vdoffset+vd.vd_next;                          { First verdaux entry holds name of version (unless VER_FLG_BASE flag is set),                            subsequent one(s) point to parent(s). For our purposes, version hierarchy                            looks irrelevant. }                          FReader.Read(vda,sizeof(TElfverdaux));                          MaybeSwapElfverdaux(vda);                          if vda.vda_name>=strtablen then                            InternalError(2012120503);                          if (vd.vd_flags and VER_FLG_BASE)<>0 then                            continue;                          { Assuming verdef indices assigned continuously starting from 2,                            at least BFD produces files that way. }                          if verdefs.count<>vd.vd_ndx then                            InternalError(2012120504);                          TElfVersionDef.Create(verdefs,string(PChar(@strtab[vda.vda_name])));                        end;                    end;                  SHT_GNU_verneed:                    begin                      if verneedndx<>0 then                        InternalError(2012102007);                      verneedndx:=i;                      //sh_link->.dynstr                      //sh_info->number of entries                    end;                end;             end;            if dynndx=0 then              InternalError(2012071401);            { load the symtable }            FReader.Seek(symtaboffset+sizeof(TElfSymbol));            LoadSymbols(objdata,syms,localsyms);            result:=True;            exit;          end;        { assume stack is executable until proven otherwise }        objdata.ExecStack:=True;        { Process section headers }        for i:=1 to nsects-1 do          if not FLoaded[i] then            LoadSection(shdrs[i],i,objdata);        { load the content }        ReadSectionContent(objdata);        { load the symtable }        FReader.Seek(symtaboffset+sizeof(TElfSymbol));        LoadSymbols(objdata,syms,localsyms);        { finish relocations }        for i:=0 to objdata.ObjSectionList.Count-1 do          begin            objsec:=TObjSection(objdata.ObjsectionList[i]);            { skip debug sections }            if (oso_debug in objsec.SecOptions) and               (cs_link_strip in current_settings.globalswitches) and               not(cs_link_separate_dbg_file in current_settings.globalswitches) then              continue;            if FSecTbl[objsec.index].relocpos>0 then              LoadRelocations(FSecTbl[objsec.index]);          end;        { finish processing section groups, if any }        if Assigned(objdata.GroupsList) then          begin            for i:=0 to objdata.GroupsList.Count-1 do              begin                grp:=TObjSectionGroup(objData.GroupsList[i]);                FReader.Seek(shdrs[i+1].sh_offset);                { first dword is flags }                FReader.Read(tmp,sizeof(longword));                if source_info.endian<>target_info.endian then                  tmp:=SwapEndian(tmp);                if (tmp and GRP_COMDAT)<>0 then                  grp.IsComdat:=true;                count:=(shdrs[i+1].sh_size div sizeof(longword))-1;                SetLength(grp.members,count);                for j:=0 to count-1 do                  begin                    FReader.Read(tmp,sizeof(longword));                    if source_info.endian<>target_info.endian then                      tmp:=SwapEndian(tmp);                    if (tmp>=nsects) then                      InternalError(2012110805);                    objsec:=FSecTbl[tmp].sec;                    if (objsec=nil) then                      InternalError(2012110806);                    if (TElfObjSection(objsec).shflags and SHF_GROUP)=0 then                      InternalError(2012110807);                    grp.members[j]:=objsec;                    objsec.Group:=grp;                  end;              end;          end;        result:=True;      end;    class function TElfObjInput.CanReadObjData(AReader:TObjectreader):boolean;      var        header: TElfHeader;      begin        result:=false;        if AReader.Read(header,sizeof(header)) then          begin;            if (header.e_ident[EI_MAG0]=ELFMAG0) and (header.e_ident[EI_MAG1]=ELFMAG1) and               (header.e_ident[EI_MAG2]=ELFMAG2) and (header.e_ident[EI_MAG3]=ELFMAG3) then            { TODO: check additional fields }              result:=true;          end;        AReader.Seek(0);      end;{*****************************************************************************                                  TElfExeOutput*****************************************************************************}    constructor TElfExeOutput.Create;      begin        inherited Create;        CObjData:=TElfObjData;        CExeSection:=TElfExeSection;{$ifdef cpu64}        MaxMemPos:=Qword($FFFFFFFFFFFFFFFF);        //MaxMemPos:=$7EFFFFFF;   { As specified by SysV AMD64 ABI for small memory model }{$else cpu64}        MaxMemPos:=$7FFFFFFF;{$endif cpu64}        SectionMemAlign:=$20;        SectionDataAlign:=$20;        segmentlist:=TFPObjectList.Create(True);        neededlist:=TFPHashList.Create;      end;    destructor TElfExeOutput.Destroy;      begin        dyncopysyms.Free;        neededlist.Free;        segmentlist.Free;        dynsymlist.Free;        dynreloclist.Free;        if assigned(dynsymnames) then          FreeMem(dynsymnames);        stringdispose(FInterpreter);        inherited Destroy;      end;    function TElfExeOutput.AttachSection(objsec:TObjSection):TElfExeSection;      begin        objsec.SecOptions:=[oso_keep];        result:=TElfExeSection(FindExeSection(objsec.name));        if result=nil then          result:=TElfExeSection.Create(ExeSectionList,objsec.name);        result.AddObjSection(objsec);      end;    function TElfExeOutput.CreateSegment(atype,aflags,aalign:longword):TElfSegment;      begin        result:=TElfSegment.Create(atype,aflags,aalign);        segmentlist.add(result);      end;    procedure TElfExeOutput.WriteHeader;      var        header: TElfHeader;      begin        FillChar(header,sizeof(header),0);        header.e_ident[EI_MAG0]:=ELFMAG0; { = #127'ELF' }        header.e_ident[EI_MAG1]:=ELFMAG1;        header.e_ident[EI_MAG2]:=ELFMAG2;        header.e_ident[EI_MAG3]:=ELFMAG3;        header.e_ident[EI_CLASS]:=ELFCLASS;        if target_info.endian=endian_big then          header.e_ident[EI_DATA]:=ELFDATA2MSB        else          header.e_ident[EI_DATA]:=ELFDATA2LSB;        header.e_ident[EI_VERSION]:=1;        if target_info.system in systems_openbsd then          header.e_ident[EI_OSABI]:=ELFOSABI_OPENBSD        else if target_info.system in systems_freebsd then          header.e_ident[EI_OSABI]:=ELFOSABI_FREEBSD        else if target_info.system in systems_dragonfly then          header.e_ident[EI_OSABI]:=ELFOSABI_NONE;        if IsSharedLibrary then          header.e_type:=ET_DYN        else          header.e_type:=ET_EXEC;        header.e_machine:=ElfTarget.machine_code;        header.e_version:=1;        header.e_phoff:=sizeof(TElfHeader);        header.e_shoff:=shoffset;        header.e_shstrndx:=ExeSectionList.IndexOf(shstrtabsect.ExeSection)+1;        header.e_shnum:=ExeSectionList.Count+1;        header.e_phnum:=segmentlist.count;        header.e_ehsize:=sizeof(telfheader);        if assigned(ElfTarget.encodeflags) then          header.e_flags:=ElfTarget.encodeflags();        if assigned(EntrySym) then          header.e_entry:=EntrySym.Address;        header.e_shentsize:=sizeof(telfsechdr);        header.e_phentsize:=sizeof(telfproghdr);        MaybeSwapHeader(header);        FWriter.Write(header,sizeof(header));      end;    procedure TElfExeOutput.exesection_write_header(p:TObject;arg:Pointer);      var        shdr: TElfsechdr;        exesec: TElfExeSection absolute p;      begin        FillChar(shdr,sizeof(shdr),0);        shdr.sh_name:=exesec.shstridx;        if (ExeWriteMode=ewm_dbgonly) and           (exesec.SecOptions*[oso_debug,oso_debug_copy]=[]) then          shdr.sh_type:=SHT_NOBITS        else          shdr.sh_type:=exesec.shtype;        shdr.sh_flags:=exesec.shflags;        if (oso_load in exesec.SecOptions) then          shdr.sh_addr:=exesec.MemPos;        shdr.sh_offset:=exesec.DataPos;        shdr.sh_size:=exesec.Size;        shdr.sh_link:=exesec.shlink;        shdr.sh_info:=exesec.shinfo;        shdr.sh_addralign:=exesec.SecAlign;        shdr.sh_entsize:=exesec.shentsize;        MaybeSwapSecHeader(shdr);        FWriter.Write(shdr,sizeof(shdr));      end;    procedure TElfExeOutput.segment_write_header(p:TObject;arg:Pointer);      var        phdr: TElfproghdr;        seg: TElfSegment absolute p;      begin        FillChar(phdr,sizeof(phdr),0);        phdr.p_type:=seg.ptype;        phdr.p_flags:=seg.pflags;        phdr.p_align:=seg.align;        phdr.p_offset:=seg.DataPos;        phdr.p_filesz:=seg.DataSize;        phdr.p_memsz:=seg.MemSize;        phdr.p_vaddr:=seg.MemPos;        phdr.p_paddr:=seg.MemPos;        MaybeSwapHeader(phdr);        FWriter.Write(phdr,sizeof(phdr));      end;    procedure TElfExeOutput.WriteStaticSymtable;      var        i: longint;        sec: TElfExeSection;        exesym: TExeSymbol;      begin        if assigned(tlsseg) then          symtab.tlsbase:=tlsseg.MemPos;        for i:=0 to ExeSectionList.Count-1 do          begin            sec:=TElfExeSection(ExeSectionList[i]);            { Must not write symbols for internal sections like .symtab }            if (sec.shtype in [SHT_SYMTAB,SHT_STRTAB,SHT_REL,SHT_RELA]) then              continue;            sec.secsymidx:=symtab.symidx;            symtab.writeInternalSymbol(sec.mempos,0,STT_SECTION,sec.secshidx);          end;        { local symbols first }        for i:=0 to ExeSymbolList.Count-1 do          begin            exesym:=TExeSymbol(ExeSymbolList[i]);            if (exesym.objsymbol.bind=AB_LOCAL) and (exesym.objsymbol.typ<>AT_LABEL) then              symtab.WriteSymbol(exesym.objsymbol);          end;        { Global Symbols }        for i:=0 to ExeSymbolList.Count-1 do          begin            exesym:=TExeSymbol(ExeSymbolList[i]);            if (exesym.objsymbol.bind<>AB_LOCAL) then              symtab.WriteSymbol(exesym.objsymbol);          end;        { update exe section properties }        symtab.ExeSection.size:=symtab.size;        TElfExeSection(symtab.ExeSection).shinfo:=symtab.shinfo;        TElfExeSection(symtab.ExeSection).shlink:=ExeSectionList.IndexOf(symtab.fstrsec.ExeSection)+1;        symtab.fstrsec.ExeSection.Size:=symtab.fstrsec.size;      end;    procedure TElfExeOutput.MapSectionsToSegments;      var        seg: TElfSegment;        exesec: TExeSection;        i: longint;      begin        if (not IsSharedLibrary) and assigned(interpobjsec) then          begin            phdrseg:=CreateSegment(PT_PHDR,PF_R or PF_X,sizeof(pint));            seg:=CreateSegment(PT_INTERP,PF_R,1);            seg.Add(interpobjsec.ExeSection);          end;        textseg:=CreateSegment(PT_LOAD,PF_X or PF_R,ElfTarget.max_page_size);        dataseg:=CreateSegment(PT_LOAD,PF_R or PF_W,ElfTarget.max_page_size);        for i:=0 to ExeSectionList.Count-1 do          begin            exesec:=TExeSection(ExeSectionList[i]);            if (oso_load in exesec.SecOptions) then              begin                if (TElfExeSection(exesec).shflags and SHF_TLS)<>0 then                  begin                    if tlsseg=nil then                      tlsseg:=CreateSegment(PT_TLS,PF_R,sizeof(pint));                    tlsseg.add(exesec);                  end;                { TODO: at least on Linux, ld seems to drop .note.ABI-tag for static executables.                  (Logic is as follows: there is no .note.ABI-tag section in ld script, so it                  is processed as orphan section. As such, it is placed after .interp.                  For static executables .interp is dropped, and it looks like there's nowhere to                  place .note.ABI-tag in this case)                  Always including it doesn't harm though (except increasing file size). }                if TElfExeSection(exesec).shtype=SHT_NOTE then                  begin                    if noteseg=nil then                      noteseg:=CreateSegment(PT_NOTE,PF_R,4);                    noteseg.Add(exesec);                    Include(exesec.SecOptions,oso_debug_copy);                  end;                if (oso_executable in exesec.SecOptions) or                  not (oso_write in exesec.SecOptions) then                  textseg.add(exesec)                else                  dataseg.add(exesec);              end;          end;        if dynamiclink then          begin            seg:=CreateSegment(PT_DYNAMIC,PF_R or PF_W,sizeof(pint));            seg.add(dynamicsec.ExeSection);          end;        { stack flags }        CreateSegment(PT_GNU_STACK,PF_R or PF_W or (PF_X*ord(ExecStack)),sizeof(pint));      end;    procedure TElfExeOutput.make_dynamic_if_undefweak(exesym:TExeSymbol);      begin        if (exesym.dynindex=0) and (exesym.state=symstate_undefweak) and          not (cs_link_staticflag in current_settings.globalswitches) then          exesym.dynindex:=dynsymlist.add(exesym)+1;      end;    function TElfExeOutput.AllocGOTSlot(objsym:TObjSymbol):boolean;      var        exesym: TExeSymbol;      begin        result:=false;        exesym:=objsym.exesymbol;        { Although local symbols should not be accessed through GOT,          this isn't strictly forbidden. In this case we need to fake up          the exesym to store the GOT offset in it.          TODO: name collision; maybe use a different symbol list object? }        if exesym=nil then          begin            exesym:=TExeSymbol.Create(ExeSymbolList,objsym.name+'*local*');            exesym.objsymbol:=objsym;            objsym.exesymbol:=exesym;          end;        if exesym.GotOffset>0 then          exit;        gotobjsec.alloc(sizeof(pint));        exesym.GotOffset:=gotobjsec.size;        make_dynamic_if_undefweak(exesym);        { In shared library, every GOT entry needs a RELATIVE dynamic reloc,          imported/exported symbols need GLOB_DAT instead. For executables,          only the latter applies. }        if IsSharedLibrary or (exesym.dynindex>0) then          dynrelocsec.alloc(dynrelocsec.shentsize);        result:=true;      end;    procedure TElfExeOutput.PrepareGOT;      var        i,j,k: longint;        objsec: TElfObjSection;        exesec: TExeSection;      begin        for i:=0 to ExeSectionList.Count-1 do          begin            exesec:=TExeSection(ExeSectionList[i]);            for j:=0 to exesec.ObjSectionlist.count-1 do              begin                objsec:=TElfObjSection(exesec.ObjSectionlist[j]);                { ignore linker-generated and debug sections }                if (objsec.objdata=internalobjdata) or (oso_debug in objsec.SecOptions) then                  continue;                if not objsec.Used then                  internalerror(2012060901);                k:=0;                while k<objsec.ObjRelocations.Count do                  begin                    GOTRelocPass1(objsec,k);                    inc(k);                  end;              end;          end;        { remember sizes for sanity checking }        gotsize:=gotobjsec.size;        if assigned(dynrelocsec) then          dynrelsize:=dynrelocsec.size        else          dynrelsize:=0;      end;    procedure TElfExeOutput.CreateGOTSection;      begin        gotpltobjsec:=TElfObjSection.create_ext(internalObjData,'.got.plt',          SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(pint));        gotobjsec:=TElfObjSection.create_ext(internalObjData,'.got',            SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(pint));        gotobjsec.SecOptions:=[oso_keep];        { GOT symbol and reserved .got.plt entries }        internalObjData.SetSection(gotpltobjsec);        gotsymbol:=internalObjData.SymbolDefine('_GLOBAL_OFFSET_TABLE_',AB_GLOBAL,AT_DATA);        gotpltobjsec.writeZeros(3*sizeof(pint));      end;    procedure TElfExeOutput.Load_Start;      begin        inherited Load_Start;        dynsymlist:=TFPObjectList.Create(False);        CreateGOTSection;      end;    procedure TElfExeOutput.Load_DynamicObject(objdata:TObjData;asneeded:boolean);      var        i: longint;        exesym: TExeSymbol;        objsym: TObjSymbol;        needed: boolean;      begin        Comment(v_debug,'Dynamic object: '+objdata.name);        needed:=false;        for i:=0 to UnresolvedExeSymbols.Count-1 do          begin            exesym:=TExeSymbol(UnresolvedExeSymbols[i]);            if not (exesym.State in [symstate_undefined,symstate_undefweak]) then              continue;            objsym:=TObjSymbol(objdata.ObjSymbolList.Find(exesym.name));            if assigned(objsym) then              begin                exesym.State:=symstate_defined;                exesym.dynindex:=dynsymlist.Add(exesym)+1;                { The original binding, value and section of external symbol                  must be preserved, therefore resolving directly to .so symbol                  hurts more than it helps. Copy type and size, and store .so                  symbol in objsym.indsymbol for later use. }                exesym.ObjSymbol.typ:=objsym.typ;                if objsym.typ<>AT_FUNCTION then                  exesym.ObjSymbol.size:=objsym.size;                exesym.ObjSymbol.indsymbol:=objsym;                objsym.ExeSymbol:=exesym;                needed:=true;              end;          end;        if (needed or (not asneeded)) and          (neededlist.Find(objdata.name)=nil) then          neededlist.Add(objdata.name,objdata);      end;    procedure TElfExeOutput.Order_Start;      begin        inherited Order_Start;        dynamiclink:=IsSharedLibrary or (dynsymlist.count>0) or          (            (UnresolvedExeSymbols.Count>0) and            not (cs_link_staticflag in current_settings.globalswitches)          );        if dynamiclink then          InitDynlink;        if dynamiclink or (IndirectObjSymbols.Count>0) then          CreatePLT;      end;    procedure TElfExeOutput.Order_end;      procedure set_oso_keep(const s:string;out firstsec:TObjSection);        var          exesec:TExeSection;          objsec:TObjSection;          i:longint;          sz: aword;        begin          firstsec:=nil;          sz:=0;          exesec:=TExeSection(ExeSectionList.Find(s));          if assigned(exesec) then            begin              for i:=0 to exesec.ObjSectionList.Count-1 do                begin                  objsec:=TObjSection(exesec.ObjSectionList[i]);                  { ignore sections used for symbol definition }                  if oso_data in objsec.SecOptions then                    begin                      if firstsec=nil then                        firstsec:=objsec;                      objsec.SecOptions:=[oso_keep];                      inc(sz,objsec.size);                    end;                end;              exesec.size:=sz;            end;        end;      var        dummy: TObjSection;      begin        OrderOrphanSections;        inherited Order_end;        set_oso_keep('.init',dummy);        set_oso_keep('.fini',dummy);        set_oso_keep('.jcr',dummy);        set_oso_keep('.ctors',dummy);        set_oso_keep('.dtors',dummy);        set_oso_keep('.preinit_array',preinitarraysec);        if assigned(preinitarraysec) and IsSharedLibrary then          Comment(v_error,'.preinit_array section is not allowed in shared libraries');        set_oso_keep('.init_array',initarraysec);        set_oso_keep('.fini_array',finiarraysec);        set_oso_keep('.eh_frame',dummy);        { let .dynamic reference other dynamic sections so they aren't marked          for removal as unused }        if dynamiclink then          WriteDynamicTags;      end;    procedure TElfExeOutput.OrderOrphanSections;      var        i,j:longint;        objdata:TObjData;        objsec:TObjSection;        exesec:TExeSection;        opts:TObjSectionOptions;        s:string;        newsections:TFPHashObjectList;        allsections:TFPList;        inserts:array[0..6] of TExeSection;        idx,inspos:longint;      begin        newsections:=TFPHashObjectList.Create(false);        allsections:=TFPList.Create;        { copy existing sections }        allsections.Capacity:=ExeSectionList.Count;        for i:=0 to ExeSectionList.Count-1 do          allsections.add(ExeSectionList[i]);        inserts[0]:=FindExeSection('.comment');        inserts[1]:=nil;        inserts[2]:=FindExeSection('.interp');        inserts[3]:=FindExeSection('.bss');        inserts[4]:=FindExeSection('.data');        inserts[5]:=FindExeSection('.rodata');        inserts[6]:=FindExeSection('.text');        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 objsec.Used then                  continue;                s:=objsec.name;                exesec:=TExeSection(newsections.Find(s));                if assigned(exesec) then                  begin                    exesec.AddObjSection(objsec);                    continue;                  end;                opts:=objsec.SecOptions*[oso_data,oso_load,oso_write,oso_executable];                if (objsec.SecOptions*[oso_load,oso_debug]=[]) then                  { non-alloc, after .comment                    GNU ld places .comment between stabs and dwarf debug info }                  inspos:=0                else if not (oso_load in objsec.SecOptions) then                  inspos:=1   { debugging, skip }                else if (oso_load in objsec.SecOptions) and                  (TElfObjSection(objsec).shtype=SHT_NOTE) then                  inspos:=2   { after .interp }                else if (opts=[oso_load,oso_write]) then                  inspos:=3   { after .bss }                else if (opts=[oso_data,oso_load,oso_write]) then                  inspos:=4   { after .data }                else if (opts=[oso_data,oso_load]) then                  inspos:=5   { rodata, relocs=??? }                else if (opts=[oso_data,oso_load,oso_executable]) then                  inspos:=6   { text }                else                  begin                    Comment(v_debug,'Orphan section '+objsec.fullname+' has attributes that are not handled!');                    continue;                  end;                if (inserts[inspos]=nil) then                  begin                    Comment(v_debug,'Orphan section '+objsec.fullname+': nowhere to insert, ignored');                    continue;                  end;                idx:=allsections.IndexOf(inserts[inspos]);                exesec:=CExeSection.Create(newsections,s);                allsections.Insert(idx+1,exesec);                inserts[inspos]:=exesec;                exesec.AddObjSection(objsec);              end;          end;        { Now replace the ExeSectionList with content of allsections }        if (newsections.count<>0) then          ReplaceExeSectionList(allsections);        newsections.Free;        allsections.Free;      end;    procedure TElfExeOutput.AfterUnusedSectionRemoval;      var        i:longint;        exesym:TExeSymbol;        objsym:TObjSymbol;        objsec: TObjSection;      begin        { Unused section removal sets Used property of referenced exesymbols.          Remaining ones can be removed. }        for i:=0 to dynsymlist.count-1 do          begin            exesym:=TExeSymbol(dynsymlist[i]);            if assigned(exesym.ObjSymbol.ObjSection) then  // an exported symbol              continue;            if not exesym.used then              begin                dynsymlist[i]:=nil;                exesym.dynindex:=0;              end;          end;        dynsymlist.Pack;        { reindex }        for i:=0 to dynsymlist.count-1 do          TExeSymbol(dynsymlist[i]).dynindex:=i+1;        { Drop unresolved symbols that aren't referenced, assign dynamic          indices to remaining ones, but not if linking with -Xt.          TODO: behavior of .so with -Xt ? }        if (cs_link_staticflag in current_settings.globalswitches) then          UnresolvedExeSymbols.Clear        else        for i:=0 to UnresolvedExeSymbols.Count-1 do          begin            exesym:=TExeSymbol(UnresolvedExeSymbols[i]);            if exesym.used then              begin                if exesym.dynindex<>0 then                  InternalError(2012062301);                { Weak-referenced symbols are changed into dynamic ones                  only if referenced through GOT or PLT (this is BFD-compatible) }                if exesym.state<>symstate_undefweak then                  exesym.dynindex:=dynsymlist.add(exesym)+1;              end            else              UnresolvedExeSymbols[i]:=nil;          end;        UnresolvedExeSymbols.Pack;        { Scan relocations to determine size of GOT, dynamic reloc section, etc. }        PrepareGOT;        { Write required PLT entries }        for i:=0 to dynsymlist.Count-1 do          begin            exesym:=TExeSymbol(dynsymlist[i]);            if assigned(exesym.ObjSymbol.objsection) then  // an exported symbol              continue;            if ((exesym.ObjSymbol.refs and symref_plt)<>0) or              ((exesym.ObjSymbol.typ in [AT_FUNCTION,AT_GNU_IFUNC]) and (not IsSharedLibrary)) then              begin                make_dynamic_if_undefweak(exesym);                { This symbol has a valid address to which relocations are resolved,                  but it remains (weak)external when written to dynamic symtable. }                objsym:=internalobjdata.CreateSymbol(exesym.name);                objsym.typ:=AT_FUNCTION;                objsym.bind:=exesym.ObjSymbol.bind;  { AB_EXTERNAL or AB_WEAK_EXTERNAL }                objsym.indsymbol:=exesym.ObjSymbol.indsymbol;                objsym.offset:=pltobjsec.size;                objsym.objsection:=pltobjsec;                objsym.exesymbol:=exesym;                exesym.ObjSymbol:=objsym;                WritePLTEntry(exesym);              end            else if ((exesym.ObjSymbol.refs and symref_from_text)<>0) and              (exesym.ObjSymbol.typ<>AT_FUNCTION) and (not IsSharedLibrary) and              (exesym.state<>symstate_undefweak) then              begin                if exesym.ObjSymbol.size=0 then                  Comment(v_error,'Dynamic variable '+exesym.name+' has zero size');                internalobjdata.setSection(dynbssobjsec);                internalobjdata.allocalign(size_2_align(exesym.ObjSymbol.size));                objsym:=internalobjdata.SymbolDefine(exesym.name,AB_GLOBAL,AT_DATA);                objsym.size:=exesym.ObjSymbol.size;                objsym.indsymbol:=exesym.ObjSymbol.indsymbol;                exesym.ObjSymbol:=objsym;                objsym.exesymbol:=exesym;                dynbssobjsec.alloc(objsym.size);                { allocate space for R_xx_COPY relocation for this symbol;                  we'll create it later, to be consistent with "-z combreloc" semantics }                dyncopysyms.add(objsym);                dynrelocsec.alloc(dynrelocsec.shentsize);                inc(dynrelsize,dynrelocsec.shentsize);              end;          end;        { Handle indirect symbols }        for i:=0 to IndirectObjSymbols.Count-1 do          begin            objsym:=TObjSymbol(IndirectObjSymbols[i]);            objsec:=objsym.ExeSymbol.ObjSymbol.objsection;            objsym.bind:=AB_EXTERNAL;  { cheat FixupSymbols }            if (oso_plt in objsec.SecOptions) then              continue;            WriteIndirectPLTEntry(objsym.ExeSymbol);          end;        FixupSymbols;        if dynamiclink then          begin            WriteVersionSections;            WriteDynamicSymbolsHash;          end;        { Create .shstrtab section, which is needed in both exe and .dbg files }        shstrtabsect:=TElfObjSection.Create_ext(internalObjData,'.shstrtab',SHT_STRTAB,0,1,0);        shstrtabsect.SecOptions:=[oso_debug_copy];        AttachSection(shstrtabsect);        { Create the static symtable (.symtab and .strtab) }        if (cs_link_separate_dbg_file in current_settings.globalswitches) or          not(cs_link_strip in current_settings.globalswitches) then          begin            symtab:=TElfSymtab.Create(internalObjData,esk_exe);            symtab.SecOptions:=[oso_debug];            symtab.fstrsec.SecOptions:=[oso_debug];            AttachSection(symtab);            AttachSection(symtab.fstrsec);          end;        { Re-enable sections which end up to contain some data          (.got, .rel[a].dyn, .rel[a].plt (includes .rel[a].iplt) and .hash }        if gotobjsec.size<>0 then          gotobjsec.ExeSection.Disabled:=false;        if assigned(dynrelocsec) and          ((dynrelocsec.size<>0) or (dyncopysyms.count<>0)) then          dynrelocsec.ExeSection.Disabled:=false;        if assigned(pltrelocsec) and (pltrelocsec.size>0) then          pltrelocsec.ExeSection.Disabled:=false;        if assigned(ipltrelocsec) and (ipltrelocsec.size>0) then          ipltrelocsec.ExeSection.Disabled:=false;        if assigned(hashobjsec) then          hashobjsec.ExeSection.Disabled:=false;        if assigned(symversec) and (symversec.size<>0) then          symversec.ExeSection.Disabled:=false;        if assigned(verneedsec) and (verneedsec.size<>0) then          verneedsec.ExeSection.Disabled:=false;        if assigned(verdefsec) and (verdefsec.size<>0) then          verdefsec.ExeSection.Disabled:=false;        RemoveDisabledSections;        MapSectionsToSegments;        if dynamiclink then          FinishDynamicTags;      end;    procedure TElfExeOutput.WriteShStrtab;      var        i: longint;        exesec: TElfExeSection;      begin        { Remove any existing .shstrtab contents }        if (shstrtabsect.size>0) then          begin            shstrtabsect.ReleaseData;            shstrtabsect.Size:=0;            shstrtabsect.SecOptions:=[oso_data];          end;        shstrtabsect.writezeros(1);        for i:=0 to ExeSectionList.Count-1 do          begin            exesec:=TElfExeSection(ExeSectionList[i]);            exesec.shstridx:=shstrtabsect.writestr(exesec.Name);            exesec.secshidx:=i+1;          end;      end;    procedure TElfExeOutput.FixupSectionLinks;      var        dynstrndx,dynsymndx: longword;      begin        if dynamiclink then          begin            dynstrndx:=TElfExeSection(dynsymtable.fstrsec.ExeSection).secshidx;            dynsymndx:=TElfExeSection(dynsymtable.ExeSection).secshidx;            TElfExeSection(hashobjsec.ExeSection).shlink:=dynsymndx;            TElfExeSection(dynamicsec.ExeSection).shlink:=dynstrndx;            TElfExeSection(dynsymtable.ExeSection).shlink:=dynstrndx;            if assigned(pltrelocsec) then              begin                TElfExeSection(pltrelocsec.ExeSection).shlink:=dynsymndx;                TElfExeSection(pltrelocsec.ExeSection).shinfo:=TElfExeSection(pltobjsec.ExeSection).secshidx;              end;            if assigned(dynrelocsec) and assigned(dynrelocsec.ExeSection) then              TElfExeSection(dynrelocsec.ExeSection).shlink:=dynsymndx;            if symversec.size>0 then              TElfExeSection(symversec.ExeSection).shlink:=dynsymndx;            if verdefsec.size>0 then              TElfExeSection(verdefsec.ExeSection).shlink:=dynstrndx;            if verneedsec.size>0 then              TElfExeSection(verneedsec.ExeSection).shlink:=dynstrndx;          end        else if assigned(ipltrelocsec) then          TElfExeSection(ipltrelocsec.ExeSection).shinfo:=TElfExeSection(pltobjsec.ExeSection).secshidx;      end;    procedure TElfExeOutput.Do_Mempos;      var        i,j: longint;        seg: TElfSegment;        exesec: TElfExeSection;        objsec: TObjSection;        tempmempos: qword;      begin        if IsSharedLibrary then          CurrMemPos:=0        else          CurrMemPos:=ElfTarget.exe_image_base;        textseg.MemPos:=CurrMemPos;        if assigned(phdrseg) then          begin            phdrseg.Mempos:=CurrMemPos+sizeof(TElfHeader);            phdrseg.Memsize:=sizeof(TElfproghdr)*segmentlist.count;          end;        CurrMemPos:=CurrMemPos+sizeof(TElfHeader)+segmentlist.count*sizeof(TElfproghdr);        MemPos_Segment(textseg);        CurrMemPos:=Align(CurrMemPos,SectionDataAlign); {! Data,not MemAlign}        CurrMemPos:=CurrMemPos+ElfTarget.max_page_size;        dataseg.MemPos:=CurrMemPos;        MemPos_Segment(dataseg);        { Mempos of unmapped sections is forced to zero, but we have to set positions          of its objsections and update sizes }        for i:=0 to ExeSectionList.Count-1 do          begin            exesec:=TElfExeSection(ExeSectionList[i]);            if not (oso_load in exesec.SecOptions) then              begin                tempmempos:=0;                exesec.MemPos:=tempmempos;                for j:=0 to exesec.ObjSectionList.Count-1 do                  begin                    objsec:=TObjSection(exesec.ObjSectionList[j]);                    tempmempos:=objsec.setmempos(tempmempos);                  end;                exesec.Size:=tempmempos;              end;          end;        { Update MemPos and MemSize of non-load segments,          in particular, TLS sizes are needed to resolve relocations }        for i:=0 to segmentlist.count-1 do          begin            seg:=TElfSegment(segmentlist[i]);            if (seg.ptype=PT_LOAD) or (seg.FSectionList.Count=0) then              continue;            seg.MemPos:=TExeSection(seg.FSectionList.First).MemPos;            for j:=0 to seg.FSectionList.Count-1 do              begin                exesec:=TElfExeSection(seg.FSectionList[j]);                seg.MemSize:=exesec.MemPos+exesec.Size-seg.MemPos;              end;          end;      end;    procedure TElfExeOutput.MemPos_Start;      var        i: longint;      begin        { Assign section indices and fill .shstrtab          List of sections cannot be modified after this point. }        WriteShStrtab;        { fixup sh_link/sh_info members of various dynamic sections }        FixupSectionLinks;        { The actual layout }        Do_Mempos;        if (not gotwritten) then          begin            { Reset size of .got and .rel[a].dyn, they will be refilled while fixing up relocations.              For .got, consider already written reserved entries. }            if assigned(gotobjsec) then              gotobjsec.size:=gotobjsec.data.size;            if assigned(dynrelocsec) then              begin                dynrelocsec.size:=0;                { write actual .dynsym content (needs valid symbol addresses) }                if assigned(tlsseg) then                  dynsymtable.tlsbase:=tlsseg.MemPos;                dynsymtable.size:=sizeof(TElfsymbol);                for i:=0 to dynsymlist.count-1 do                  dynsymtable.writeSymbol(TExeSymbol(dynsymlist[i]).objsymbol,dynsymnames[i]);              end;          end;      end;    procedure TElfExeOutput.MemPos_Segment(seg:TElfSegment);      var        i: longint;        exesec: TElfExeSection;      begin        for i:=0 to seg.FSectionList.Count-1 do          begin            exesec:=TElfExeSection(seg.FSectionList[i]);            inherited MemPos_ExeSection(exesec);            { .tbss should not contribute to address space }            if (exesec.shtype=SHT_NOBITS) and ((exesec.shflags and SHF_TLS)<>0) then              CurrMemPos:=exesec.MemPos;          end;        { calculate size of the segment }        seg.MemSize:=CurrMemPos-seg.MemPos;      end;    procedure TElfExeOutput.MemPos_ExeSection(const aname:string);      begin        // Ignore. All layout is done in mempos_start      end;    procedure TElfExeOutput.DataPos_Start;      var        i,j: longint;        exesec: TExeSection;        seg: TElfSegment;        objreloc: TObjRelocation;        objsym: TObjSymbol;      begin        gotwritten:=true;        { If target does not support sorted relocations, it is expected to write the          entire .rel[a].dyn section during FixupRelocations, and leave dynreloclist empty.          Otherwise, only RELATIVE ones should be written, space for non-relative relocations          should remain. }        if assigned(dynrelocsec) then          begin            { Append R_xx_COPY relocations }            dynreloclist.capacity:=dynreloclist.count+dyncopysyms.count;            for i:=0 to dyncopysyms.count-1 do              begin                objsym:=TObjSymbol(dyncopysyms[i]);                dynreloclist.Add(TObjRelocation.CreateRaw(objsym.address,objsym,ElfTarget.dyn_reloc_codes[dr_copy]));              end;            dyncopysyms.Clear;            if (dynrelocsec.size+(dynreloclist.count*dynrelocsec.shentsize)<>dynrelsize) then              InternalError(2012110601);            { Write out non-RELATIVE dynamic relocations              TODO: additional sorting? }            for i:=0 to dynreloclist.count-1 do              begin                objreloc:=TObjRelocation(dynreloclist[i]);                WriteDynRelocEntry(objreloc.dataoffset,objreloc.ftype,objreloc.symbol.exesymbol.dynindex,0);              end;          end;        { sanity checks }        if assigned(gotobjsec) and (gotsize<>gotobjsec.size) then          InternalError(2012092501);        if assigned(dynrelocsec) and (dynrelsize<>dynrelocsec.size) then          InternalError(2012092502);        if (ExeWriteMode=ewm_dbgonly) or          (            (ExeWriteMode=ewm_exefull) and             not(cs_link_strip in current_settings.globalswitches)          ) then          WriteStaticSymtable;        { first handle primary segments }        textseg.DataPos:=0;        CurrDataPos:=sizeof(TElfHeader)+sizeof(TElfproghdr)*segmentlist.count;        if assigned(phdrseg) then          begin            phdrseg.DataPos:=sizeof(TElfHeader);            phdrseg.DataSize:=sizeof(TElfproghdr)*segmentlist.count;          end;        DataPos_Segment(textseg);        CurrDataPos:=align(CurrDataPos,SectionDataAlign);        dataseg.DataPos:=CurrDataPos;        DataPos_Segment(dataseg);        { then unmapped sections }        for i:=0 to ExeSectionList.Count-1 do          begin            exesec:=TExeSection(ExeSectionList[i]);            if not (oso_load in exesec.SecOptions) then              inherited DataPos_ExeSection(exesec);          end;        { finally, update size/position of non-load segments }        for i:=0 to segmentlist.count-1 do          begin            seg:=TElfSegment(segmentlist[i]);            if (seg.ptype=PT_LOAD) or (seg.FSectionList.Count=0) then              continue;            seg.DataPos:=TExeSection(seg.FSectionList.First).DataPos;            for j:=0 to seg.FSectionList.Count-1 do              begin                exesec:=TExeSection(seg.FSectionList[j]);                if oso_data in exesec.SecOptions then                  seg.DataSize:=exesec.DataPos+exesec.Size-seg.DataPos;              end;          end;        { place section headers after the data }        shoffset:=CurrDataPos;        CurrDataPos:=CurrDataPos+ExeSectionList.Count*sizeof(TElfsechdr);      end;    procedure TElfExeOutput.DataPos_Segment(seg:TElfSegment);      var        i: longint;        exesec: TElfExeSection;      begin        for i:=0 to seg.FSectionList.Count-1 do          begin            exesec:=TElfExeSection(seg.FSectionList[i]);            { ELF needs DataPos set to 'would-be' value for sections that              don't have data, and for non-debug sections in .dbg file, too.              This slightly differs from generic approach. }            if not (oso_data in exesec.SecOptions) or              (                (ExeWriteMode=ewm_dbgonly) and                (exesec.SecOptions*[oso_debug,oso_debug_copy]=[])              ) then              begin                CurrDataPos:=align(CurrDataPos,SectionDataAlign);                exesec.DataPos:=CurrDataPos;              end            else              inherited DataPos_ExeSection(exesec);          end;        { calculate size of the segment }        seg.DataSize:=CurrDataPos-seg.DataPos;      end;    procedure TElfExeOutput.DataPos_ExeSection(const aname:string);      begin        // Ignore. Work is done entirely in datapos_start.      end;    procedure TElfExeOutput.InitDynlink;      begin        if not IsSharedLibrary then          begin            interpobjsec:=internalObjData.createsection('.interp',1,[oso_data,oso_load,oso_keep]);            interpobjsec.writestr(interpreter^);          end;        hashobjsec:=TElfObjSection.create_ext(internalObjData,'.hash',          SHT_HASH,SHF_ALLOC,sizeof(pint),4);        hashobjsec.secoptions:=[oso_keep];        dynsymtable:=TElfSymtab.create(internalObjData,esk_dyn);        dynamicsec:=TElfObjSection.create_ext(internalObjData,'.dynamic',          SHT_DYNAMIC,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(TElfDyn));        dynamicsec.SecOptions:=[oso_keep];        dynrelocsec:=TElfObjSection.create_reloc(internalObjData,'.dyn',true);        dynrelocsec.SecOptions:=[oso_keep];        dynbssobjsec:=TElfObjSection.create_ext(internalObjData,'.dynbss',          SHT_NOBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint){16??},0);        dynbssobjsec.SecOptions:=[oso_keep];        dynreloclist:=TFPObjectList.Create(true);        symversec:=TElfObjSection.create_ext(internalObjData,'.gnu.version',          SHT_GNU_VERSYM,SHF_ALLOC,sizeof(word),sizeof(word));        symversec.SecOptions:=[oso_keep];        verdefsec:=TElfObjSection.create_ext(internalObjData,'.gnu.version_d',          SHT_GNU_VERDEF,SHF_ALLOC,sizeof(pint),0);        verdefsec.SecOptions:=[oso_keep];        verneedsec:=TElfObjSection.create_ext(internalObjData,'.gnu.version_r',          SHT_GNU_VERNEED,SHF_ALLOC,sizeof(pint),0);        verneedsec.SecOptions:=[oso_keep];        dyncopysyms:=TFPObjectList.Create(False);      end;    const      hashbuckets: array[0..15] of longint=(        1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,        16411, 32771);{$push}{$r-,q-}    function elfhash(const name:string):longword;      var        g: longword;        i: longint;      begin        result:=0;        for i:=1 to length(name) do        begin          result:=(result shl 4)+ord(name[i]);          g:=result and $F0000000;          if g>0 then            result:=result xor (g shr 24);          result:=result and (not g);        end;      end;{$pop}    procedure TElfExeOutput.WriteDynamicSymbolsHash;      var        nchains,nbuckets: longint;        i,j: longint;        hashdata: plongint;        sym: TExeSymbol;      begin        dynsymnames:=AllocMem(dynsymlist.count*sizeof(longword));        nchains:=dynsymlist.Count+1;        { determine suitable bucket count }        i:=high(hashbuckets);        while (i>=0) and (nchains<hashbuckets[i]) do          dec(i);        nbuckets:=hashbuckets[i];        hashdata:=AllocMem((2+nchains+nbuckets)*sizeof(longint));        hashdata[0]:=nbuckets;        hashdata[1]:=nchains;        { The contents of .dynsym can be written only after mempos pass          because it needs valid symbol virtual addresses and section indices.          Here we preset .dynsym size and write names, in order to get          correct size of .dynstr section. }        dynsymtable.size:=(dynsymlist.count+1)*sizeof(TElfsymbol);        for i:=0 to dynsymlist.Count-1 do          begin            sym:=TExeSymbol(dynsymlist[i]);            dynsymnames[i]:=dynsymtable.fstrsec.writestr(sym.objsymbol.name);            j:=(elfhash(sym.objsymbol.name) mod nbuckets)+2;            while hashdata[j]<>0 do              j:=2+nbuckets+hashdata[j];            hashdata[j]:=i+1;          end;        if source_info.endian<>target_info.endian then          for i:=0 to nchains+nbuckets+1 do            hashdata[i]:=swapendian(hashdata[i]);        hashobjsec.write(hashdata^,(2+nchains+nbuckets)*sizeof(longint));        freemem(hashdata);      end;    procedure TElfExeOutput.WriteVersionSections;      var        i,j: longint;        idx,auxidx: longword;        exesym: TExeSymbol;        dynobj: TElfDynamicObjData;        ver: TElfVersionDef;        vn: TElfverneed;        vna: TElfvernaux;        symversions: TWordDynArray;      begin        SetLength(symversions,(dynsymlist.count+1));        { Assign version indices }        idx:=VER_NDX_GLOBAL+1;        for i:=0 to dynsymlist.count-1 do          begin            exesym:=TExeSymbol(dynsymlist[i]);            if (exesym.objsymbol.indsymbol is TVersionedObjSymbol) then              ver:=TVersionedObjSymbol(exesym.objsymbol.indsymbol).version            else              ver:=nil;            if assigned(ver) then              begin                if ver.index=0 then                  begin                    ver.index:=idx;                    inc(idx);                  end;                symversions[i+1]:=ver.index;              end            else if exesym.state in [symstate_undefined,symstate_undefweak] then              symversions[i+1]:=VER_NDX_LOCAL            else              symversions[i+1]:=VER_NDX_GLOBAL;          end;        { Count entries to be written }        verneedcount:=0;        for i:=0 to neededlist.count-1 do          begin            dynobj:=TElfDynamicObjData(neededlist[i]);            dynobj.vernaux_count:=0;            for j:=2 to dynobj.versiondefs.count-1 do              begin                ver:=TElfVersionDef(dynobj.versiondefs[j]);                if ver.index>VER_NDX_GLOBAL then                  inc(dynobj.vernaux_count);              end;            if (dynobj.vernaux_count>0) then              inc(verneedcount);          end;        { Now write }        idx:=0;        for i:=0 to neededlist.count-1 do          begin            dynobj:=TElfDynamicObjData(neededlist[i]);            if dynobj.vernaux_count=0 then              continue;            inc(idx);            vn.vn_version:=VER_NEED_CURRENT;            vn.vn_cnt:=dynobj.vernaux_count;            vn.vn_file:=dynobj.soname_strofs;            vn.vn_aux:=sizeof(TElfverneed);            vn.vn_next:=ord(idx<verneedcount)*(sizeof(TElfverneed)+vn.vn_cnt*sizeof(TElfvernaux));            MaybeSwapElfverneed(vn);            verneedsec.write(vn,sizeof(TElfverneed));            auxidx:=0;            for j:=2 to dynobj.versiondefs.count-1 do              begin                ver:=TElfVersionDef(dynobj.versiondefs[j]);                if ver.index<=VER_NDX_GLOBAL then                  continue;                inc(auxidx);                vna.vna_hash:=elfhash(ver.name);                vna.vna_flags:=0;   { BFD copies this from verdef.vd_flags?? }                vna.vna_other:=ver.index;                vna.vna_name:=dynsymtable.fstrsec.writestr(ver.name);                vna.vna_next:=ord(auxidx<dynobj.vernaux_count)*sizeof(TElfvernaux);                MaybeSwapElfvernaux(vna);                verneedsec.write(vna,sizeof(TElfvernaux));              end;          end;        TElfExeSection(verneedsec.ExeSection).shinfo:=verneedcount;        { If there are no needed versions, .gnu.version section is not needed }        if verneedcount>0 then          begin            if source_info.endian<>target_info.endian then              for i:=0 to dynsymlist.count+1 do                symversions[i]:=swapendian(symversions[i]);            symversec.write(symversions[0],(dynsymlist.count+1)*sizeof(word));          end;        symversions:=nil;      end;    procedure TElfExeOutput.WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword);      var        rel:telfreloc;      begin        rel.address:=dataofs;        rel.info:=ELF_R_INFO(symidx,typ);{$push}{$r-}        rel.addend:=addend;{$pop}        MaybeSwapElfReloc(rel);        dynrelocsec.write(rel,dynrelocsec.shentsize);      end;    procedure TElfExeOutput.WriteDynTag(aTag:longword;aValue:longword);      var        d: TElfDyn;      begin        d.d_tag:=aTag;        d.d_val:=aValue;        MaybeSwapElfDyn(d);        dynamicsec.write(d,sizeof(TElfDyn));      end;    procedure TElfExeOutput.WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword);      var        d: TElfDyn;      begin        d.d_tag:=aTag;        if source_info.endian<>target_info.endian then          d.d_tag:=swapendian(d.d_tag);        dynamicsec.write(d.d_tag,sizeof(d.d_tag));        { TODO: ignores endianness! }        dynamicsec.writeReloc_internal(aSection,aOffs,sizeof(d.d_ptr),RELOC_ABSOLUTE);      end;    procedure TElfExeOutput.WriteTargetDynamicTags;      begin        { to be overridden by CPU-specific descendants }      end;    procedure TElfExeOutput.WriteDynamicTags;      var        s: aword;        i: longint;        sym: TExeSymbol;        hs:string;        dynobj: TElfDynamicObjData;      begin        for i:=0 to neededlist.Count-1 do          begin            dynobj:=TElfDynamicObjData(neededlist[i]);            s:=dynsymtable.fstrsec.writestr(dynobj.name);            dynobj.soname_strofs:=s;            WriteDynTag(DT_NEEDED,s);          end;        if IsSharedLibrary then          begin            s:=dynsymtable.fstrsec.writestr(ExtractFileName(current_module.sharedlibfilename));            WriteDynTag(DT_SONAME,s);            { TODO: names hardcoded here }            sym:=TExeSymbol(ExeSymbolList.Find('FPC_SHARED_LIB_START'));            if assigned(sym) then              WriteDynTag(DT_INIT,sym.objsymbol.objsection,sym.objsymbol.offset);            sym:=TExeSymbol(ExeSymbolList.Find('FPC_LIB_EXIT'));            if assigned(sym) then              WriteDynTag(DT_FINI,sym.objsymbol.objsection,sym.objsymbol.offset);          end;        { TODO: we need a dedicated parameter to pass runpath, instead of this hack          (-Xr is a different thing, it passes "-rpath-link"). }        if (ParaLinkOptions<>'') then          begin            hs:=ParaLinkOptions;            while (hs<>'') do              begin                if (GetToken(hs,' ')='-rpath') then                  begin                    s:=dynsymtable.fstrsec.writestr(GetToken(hs,' '));                    WriteDynTag(DT_RPATH,s);                  end;              end;          end;        if assigned(preinitarraysec) then          begin            WriteDynTag(DT_PREINIT_ARRAY,preinitarraysec,0);            WriteDynTag(DT_PREINIT_ARRAYSZ,preinitarraysec.exesection.size);          end;        if assigned(initarraysec) then          begin            WriteDynTag(DT_INIT_ARRAY,initarraysec,0);            WriteDynTag(DT_INIT_ARRAYSZ,initarraysec.exesection.size);          end;        if assigned(finiarraysec) then          begin            WriteDynTag(DT_FINI_ARRAY,finiarraysec,0);            WriteDynTag(DT_FINI_ARRAYSZ,finiarraysec.exesection.size);          end;        writeDynTag(DT_HASH,hashobjsec);        writeDynTag(DT_STRTAB,dynsymtable.fstrsec);        writeDynTag(DT_SYMTAB,dynsymtable);        writeDynTag(DT_SYMENT,sizeof(TElfSymbol));        if Assigned(gotpltobjsec) then          writeDynTag(DT_PLTGOT,gotpltobjsec);      end;    const      pltreltags: array[boolean] of longword=(DT_REL,DT_RELA);      relsztags:  array[boolean] of longword=(DT_RELSZ,DT_RELASZ);      relenttags: array[boolean] of longword=(DT_RELENT,DT_RELAENT);      {$ifndef MIPS}      relcnttags: array[boolean] of longword=(DT_RELCOUNT,DT_RELACOUNT);      {$endif MIPS}    procedure TElfExeOutput.FinishDynamicTags;      var        rela: boolean;      begin        if assigned(dynsymtable) then          writeDynTag(DT_STRSZ,dynsymtable.fstrsec.size);        if hastextrelocs then          writeDynTag(DT_TEXTREL,0);        if Assigned(pltrelocsec) and (pltrelocsec.size>0) then          begin            writeDynTag(DT_PLTRELSZ,pltrelocsec.Size);            writeDynTag(DT_PLTREL,pltreltags[pltrelocsec.shtype=SHT_RELA]);            writeDynTag(DT_JMPREL,pltrelocsec);          end;        if Assigned(dynrelocsec) and (dynrelocsec.size>0) then          begin            rela:=(dynrelocsec.shtype=SHT_RELA);            writeDynTag(pltreltags[rela],dynrelocsec);            writeDynTag(relsztags[rela],dynrelocsec.Size);            writeDynTag(relenttags[rela],dynrelocsec.shentsize);{$ifndef MIPS}            if (relative_reloc_count>0) then              writeDynTag(relcnttags[rela],relative_reloc_count);{$endif MIPS}          end;        WriteTargetDynamicTags;        if (verdefcount>0) or (verneedcount>0) then          begin            if (verdefcount>0) then              begin                writeDynTag(DT_VERDEF,verdefsec);                writeDynTag(DT_VERDEFNUM,verdefcount);              end;            if (verneedcount>0) then              begin                writeDynTag(DT_VERNEED,verneedsec);                writeDynTag(DT_VERNEEDNUM,verneedcount);              end;            writeDynTag(DT_VERSYM,symversec);          end;        writeDynTag(DT_NULL,0);      end;    procedure TElfExeOutput.CreatePLT;      var        reloc: TObjRelocation;      begin        pltobjsec:=TElfObjSection.create_ext(internalObjData,'.plt',          SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,4,16);        pltobjsec.SecOptions:=[oso_keep,oso_plt];        pltrelocsec:=TElfObjSection.create_reloc(internalObjData,'.plt',true);        pltrelocsec.SecOptions:=[oso_keep];        ipltrelocsec:=TElfObjSection.create_reloc(internalObjData,'.iplt',true);        ipltrelocsec.SecOptions:=[oso_keep];        { reference .dynamic from .got.plt, this isn't necessary if linking statically }        { TODO: maybe move writing initial .got.plt entries here completely          (needs testing --- GOT symbol may get lost if .got.plt is empty)}        if dynamiclink then          begin            reloc:=TObjRelocation.CreateSection(0,dynamicsec,RELOC_ABSOLUTE);            reloc.size:=sizeof(pint);            gotpltobjsec.ObjRelocations.Add(reloc);          end;        { Initial PLT entry, CPU-specific }        WriteFirstPLTEntry;      end;    procedure TElfExeOutput.WritePLTEntry(exesym:TExeSymbol);      begin        // must be implemented by CPU-specific descendant        InternalError(2012092102);      end;    procedure TElfExeOutput.WriteIndirectPLTEntry(exesym:TExeSymbol);      begin        // must be implemented by CPU-specific descendant        InternalError(2012092101);      end;    function TElfExeOutput.WriteData:boolean;      begin        WriteHeader;        segmentlist.ForEachCall(@segment_write_header,nil);        WriteExeSectionContent;        FWriter.WriteZeros(sizeof(TElfsechdr));        ExeSectionList.ForEachCall(@exesection_write_header,nil);        result:=true;      end;    procedure TElfExeOutput.GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);      var        exportlist: TCmdStrList;        sym: TExeSymbol;      begin        AllowUndefinedSymbols:=IsSharedLibrary;        { add exported symbols to dynamic list }        exportlist:=texportlibunix(exportlib).exportedsymnames;        if not exportlist.empty then          repeat            sym:=TExeSymbol(ExeSymbolList.Find(exportlist.getfirst));            if assigned(sym) then              begin                if assigned(sym.objsymbol.objsection) then                  sym.objsymbol.objsection.SecOptions:=[oso_keep];                sym.dynindex:=dynsymlist.add(sym)+1              end            else              InternalError(2012071801);          until exportlist.empty;      end;    procedure TElfExeOutput.ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);      begin        { TODO: include objsec properties into message }        Comment(v_error,'Relocation '+ElfTarget.RelocName(reltyp)+' against '''+objreloc.TargetName+''' cannot be used when linking a shared object; recompile with -Cg');      end;    procedure TElfExeOutput.ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);      begin        { TODO: include objsec properties into message }        Comment(v_error,'Relocation truncated to fit: '+ElfTarget.RelocName(reltyp)+' against '''+objreloc.TargetName+'''');      end;{****************************************************************************                               TElfExeSection****************************************************************************}    procedure TElfExeSection.AddObjSection(objsec:TObjSection;ignoreprops:boolean);      begin        inherited AddObjSection(objsec,ignoreprops);        if ignoreprops then          exit;        if (shtype=SHT_NULL) then        begin          shtype:=TElfObjSection(objsec).shtype;          shflags:=TElfObjSection(objsec).shflags;          shentsize:=TElfObjSection(objsec).shentsize;        end;      end;{****************************************************************************                                TElfSegment****************************************************************************}    constructor TElfSegment.Create(atype,aflags,aalign:longword);      begin        ptype:=atype;        pflags:=aflags;        align:=aalign;        FSectionList:=TFPObjectList.Create(false);      end;    destructor TElfSegment.Destroy;      begin        FSectionList.Free;        inherited Destroy;      end;    procedure TElfSegment.Add(exesec:TExeSection);      begin        FSectionList.Add(exesec);      end;end.
 |