1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460 |
- {
- 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 }
- cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,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:shortint;Aoptions:TObjSectionOptions);override;
- constructor create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:shortint;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(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: PChar;
- strtab: PChar;
- shstrtablen: longword;
- strtablen: longword;
- symtaboffset: aword;
- syms: longword;
- localsyms: longword;
- symversions: PWord;
- 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;
- 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}
- procedure MayBeSwapHeader(var h : telf32header);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- e_type:=swapendian(e_type);
- e_machine:=swapendian(e_machine);
- e_version:=swapendian(e_version);
- e_entry:=swapendian(e_entry);
- e_phoff:=swapendian(e_phoff);
- e_shoff:=swapendian(e_shoff);
- e_flags:=swapendian(e_flags);
- e_ehsize:=swapendian(e_ehsize);
- e_phentsize:=swapendian(e_phentsize);
- e_phnum:=swapendian(e_phnum);
- e_shentsize:=swapendian(e_shentsize);
- e_shnum:=swapendian(e_shnum);
- e_shstrndx:=swapendian(e_shstrndx);
- end;
- end;
- procedure MayBeSwapHeader(var h : telf64header);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- e_type:=swapendian(e_type);
- e_machine:=swapendian(e_machine);
- e_version:=swapendian(e_version);
- e_entry:=swapendian(e_entry);
- e_phoff:=swapendian(e_phoff);
- e_shoff:=swapendian(e_shoff);
- e_flags:=swapendian(e_flags);
- e_ehsize:=swapendian(e_ehsize);
- e_phentsize:=swapendian(e_phentsize);
- e_phnum:=swapendian(e_phnum);
- e_shentsize:=swapendian(e_shentsize);
- e_shnum:=swapendian(e_shnum);
- e_shstrndx:=swapendian(e_shstrndx);
- end;
- end;
- procedure MayBeSwapHeader(var h : telf32proghdr);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- p_align:=swapendian(p_align);
- p_filesz:=swapendian(p_filesz);
- p_flags:=swapendian(p_flags);
- p_memsz:=swapendian(p_memsz);
- p_offset:=swapendian(p_offset);
- p_paddr:=swapendian(p_paddr);
- p_type:=swapendian(p_type);
- p_vaddr:=swapendian(p_vaddr);
- end;
- end;
- procedure MayBeSwapHeader(var h : telf64proghdr);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- p_align:=swapendian(p_align);
- p_filesz:=swapendian(p_filesz);
- p_flags:=swapendian(p_flags);
- p_memsz:=swapendian(p_memsz);
- p_offset:=swapendian(p_offset);
- p_paddr:=swapendian(p_paddr);
- p_type:=swapendian(p_type);
- p_vaddr:=swapendian(p_vaddr);
- end;
- end;
- procedure MaybeSwapSecHeader(var h : telf32sechdr);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- sh_name:=swapendian(sh_name);
- sh_type:=swapendian(sh_type);
- sh_flags:=swapendian(sh_flags);
- sh_addr:=swapendian(sh_addr);
- sh_offset:=swapendian(sh_offset);
- sh_size:=swapendian(sh_size);
- sh_link:=swapendian(sh_link);
- sh_info:=swapendian(sh_info);
- sh_addralign:=swapendian(sh_addralign);
- sh_entsize:=swapendian(sh_entsize);
- end;
- end;
- procedure MaybeSwapSecHeader(var h : telf64sechdr);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- sh_name:=swapendian(sh_name);
- sh_type:=swapendian(sh_type);
- sh_flags:=swapendian(sh_flags);
- sh_addr:=swapendian(sh_addr);
- sh_offset:=swapendian(sh_offset);
- sh_size:=swapendian(sh_size);
- sh_link:=swapendian(sh_link);
- sh_info:=swapendian(sh_info);
- sh_addralign:=swapendian(sh_addralign);
- sh_entsize:=swapendian(sh_entsize);
- end;
- end;
- procedure MaybeSwapElfSymbol(var h : telf32symbol);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- st_name:=swapendian(st_name);
- st_value:=swapendian(st_value);
- st_size:=swapendian(st_size);
- st_shndx:=swapendian(st_shndx);
- end;
- end;
- procedure MaybeSwapElfSymbol(var h : telf64symbol);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- st_name:=swapendian(st_name);
- st_value:=swapendian(st_value);
- st_size:=swapendian(st_size);
- st_shndx:=swapendian(st_shndx);
- end;
- end;
- procedure MaybeSwapElfReloc(var h : telf32reloc);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- address:=swapendian(address);
- info:=swapendian(info);
- addend:=swapendian(addend);
- end;
- end;
- procedure MaybeSwapElfReloc(var h : telf64reloc);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- address:=swapendian(address);
- info:=swapendian(info);
- addend:=swapendian(addend);
- end;
- end;
- procedure MaybeSwapElfDyn(var h : telf32dyn);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- d_tag:=swapendian(d_tag);
- d_val:=swapendian(d_val);
- end;
- end;
- procedure MaybeSwapElfDyn(var h : telf64dyn);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- d_tag:=swapendian(d_tag);
- d_val:=swapendian(d_val);
- end;
- end;
- procedure MaybeSwapElfverdef(var h: TElfverdef);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- vd_version:=swapendian(vd_version);
- vd_flags:=swapendian(vd_flags);
- vd_ndx:=swapendian(vd_ndx);
- vd_cnt:=swapendian(vd_cnt);
- vd_hash:=swapendian(vd_hash);
- vd_aux:=swapendian(vd_aux);
- vd_next:=swapendian(vd_next);
- end;
- end;
- procedure MaybeSwapElfverdaux(var h: TElfverdaux);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- vda_name:=swapendian(vda_name);
- vda_next:=swapendian(vda_next);
- end;
- end;
- procedure MaybeSwapElfverneed(var h: TElfverneed);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- vn_version:=swapendian(vn_version);
- vn_cnt:=swapendian(vn_cnt);
- vn_file:=swapendian(vn_file);
- vn_aux:=swapendian(vn_aux);
- vn_next:=swapendian(vn_next);
- end;
- end;
- procedure MaybeSwapElfvernaux(var h: TElfvernaux);
- begin
- if source_info.endian<>target_info.endian then
- with h do
- begin
- vna_hash:=swapendian(vna_hash);
- vna_flags:=swapendian(vna_flags);
- vna_other:=swapendian(vna_other);
- vna_name:=swapendian(vna_name);
- vna_next:=swapendian(vna_next);
- end;
- end;
- {****************************************************************************
- Helpers
- ****************************************************************************}
- procedure encodesechdrflags(aoptions:TObjSectionOptions;out AshType:longint;out Ashflags:longint);
- begin
- { Section Type }
- AshType:=SHT_PROGBITS;
- if oso_strings in aoptions then
- AshType:=SHT_STRTAB
- else if not(oso_data in aoptions) then
- AshType:=SHT_NOBITS;
- { 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;
- 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);
- end;
- {****************************************************************************
- TElfObjSection
- ****************************************************************************}
- constructor TElfObjSection.create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;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:shortint;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',
- '.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'
- );
- 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 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);
- var
- symaddr : aint;
- 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}]) then
- begin
- { 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;
- if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_GOTPCREL{$endif}] then
- dec(data,len);
- if ElfTarget.relocs_use_addend then
- begin
- objreloc.orgsize:=aword(data);
- data:=0;
- end;
- end;
- 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}
- 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;
- else
- InternalError(2012111801);
- end;
- { External symbols must be NOTYPE in relocatable files }
- if (objsym.bind<>AB_EXTERNAL) or (kind<>esk_obj) then
- begin
- case objsym.typ of
- AT_FUNCTION :
- elfsym.st_info:=elfsym.st_info or STT_FUNC;
- AT_DATA :
- 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 }
- 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:=datapos;
- 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);
- { 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(smart:boolean);
- begin
- inherited Create(smart);
- CObjOutput:=TElfObjectOutput;
- 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);
- if Assigned(strtab) then
- FreeMem(strtab);
- if Assigned(shstrtab) then
- FreeMem(shstrtab);
- if Assigned(symversions) then
- FreeMem(symversions);
- 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
- 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;
- GetMem(shstrtab,shstrtablen);
- FReader.seek(shdrs[shstrndx].sh_offset);
- FReader.read(shstrtab^,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;
- GetMem(strtab,strtablen);
- FReader.seek(shdrs[strndx].sh_offset);
- FReader.read(strtab^,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);
- GetMem(symversions,shdrs[i].sh_size);
- FReader.seek(shdrs[i].sh_offset);
- FReader.read(symversions^,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 }
- 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 }
- 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: pword;
- begin
- symversions:=AllocMem((dynsymlist.count+1)*sizeof(word));
- { 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^,(dynsymlist.count+1)*sizeof(word));
- end;
- FreeMem(symversions);
- 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);
- relcnttags: array[boolean] of longword=(DT_RELCOUNT,DT_RELACOUNT);
- 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.
|