ogelf.pas 107 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105
  1. {
  2. Copyright (c) 1998-2006 by Peter Vreman
  3. Contains the binary elf writer
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ogelf;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. { common }
  22. cclasses,globtype,
  23. { target }
  24. systems,
  25. { assembler }
  26. cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,assemble,
  27. { ELF definitions }
  28. elfbase,
  29. { output }
  30. ogbase,
  31. owbase;
  32. type
  33. {$ifdef cpu64bitaddr}
  34. TElfsechdr = TElf64sechdr;
  35. {$else cpu64bitaddr}
  36. TElfsechdr = TElf32sechdr;
  37. {$endif cpu64bitaddr}
  38. TElfObjSection = class(TObjSection)
  39. public
  40. shstridx,
  41. shtype,
  42. shflags,
  43. shlink,
  44. shinfo,
  45. shentsize : longint;
  46. constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);override;
  47. constructor create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:shortint;Aentsize:longint);
  48. constructor create_reloc(aobjdata:TObjData;const Aname:string;allocflag:boolean);
  49. procedure writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);override;
  50. end;
  51. TElfSymtabKind = (esk_obj,esk_exe,esk_dyn);
  52. TElfSymtab = class(TElfObjSection)
  53. public
  54. kind: TElfSymtabKind;
  55. fstrsec: TObjSection;
  56. symidx: longint;
  57. tlsbase: aword;
  58. constructor create(aObjData:TObjData;aKind:TElfSymtabKind);reintroduce;
  59. procedure writeSymbol(objsym:TObjSymbol;nameidx:longword=0);
  60. procedure writeInternalSymbol(avalue:aword;astridx:longword;ainfo:byte;ashndx:word);
  61. end;
  62. TElfObjData = class(TObjData)
  63. public
  64. constructor create(const n:string);override;
  65. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  66. procedure CreateDebugSections;override;
  67. procedure writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);override;
  68. end;
  69. TElfObjectOutput = class(tObjOutput)
  70. private
  71. symtabsect: TElfSymtab;
  72. shstrtabsect: TElfObjSection;
  73. procedure createrelocsection(s:TElfObjSection;data:TObjData);
  74. procedure createshstrtab(data:TObjData);
  75. procedure createsymtab(data: TObjData);
  76. procedure writesectionheader(s:TElfObjSection);
  77. procedure section_write_symbol(p:TObject;arg:pointer);
  78. procedure section_count_sections(p:TObject;arg:pointer);
  79. procedure section_create_relocsec(p:TObject;arg:pointer);
  80. procedure section_write_sechdr(p:TObject;arg:pointer);
  81. protected
  82. function writedata(data:TObjData):boolean;override;
  83. public
  84. constructor Create(AWriter:TObjectWriter);override;
  85. end;
  86. TElfAssembler = class(tinternalassembler)
  87. constructor create(smart:boolean);override;
  88. end;
  89. PSectionRec=^TSectionRec;
  90. TSectionRec=record
  91. sec: TObjSection;
  92. relocpos: aword;
  93. relocs: longint;
  94. relentsize: longint;
  95. end;
  96. TElfsecheaderarray=array of TElfsechdr;
  97. TElfObjInput=class(TObjInput)
  98. private
  99. FSecTbl: PSectionRec;
  100. FSymTbl: PPointer;
  101. FLoaded: PBoolean;
  102. shdrs: TElfsecheaderarray;
  103. nsects: longword;
  104. shentsize: longword;
  105. shoffset: aword;
  106. shstrndx: longword;
  107. symtabndx: longword;
  108. shstrtab: PChar;
  109. strtab: PChar;
  110. shstrtablen: longword;
  111. strtablen: longword;
  112. symtaboffset: aword;
  113. syms: longword;
  114. localsyms: longword;
  115. symversions: PWord;
  116. dynobj: boolean;
  117. verdefs: TFPHashObjectList;
  118. function LoadHeader:word;
  119. procedure LoadSection(const shdr:TElfsechdr;index:longint;objdata:TObjData);
  120. procedure LoadRelocations(const secrec:TSectionRec);
  121. procedure LoadSymbols(objdata:TObjData;count,locals:longword);
  122. procedure LoadDynamic(const shdr:TElfsechdr;objdata:TObjData);
  123. public
  124. constructor Create;override;
  125. destructor Destroy;override;
  126. function ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;override;
  127. class function CanReadObjData(AReader:TObjectreader):boolean;override;
  128. function CreateSection(const shdr:TElfsechdr;index:longint;objdata:TObjData;
  129. out secname:string):TElfObjSection;
  130. end;
  131. TElfVersionDef = class(TFPHashObject)
  132. public
  133. index: longword;
  134. end;
  135. TElfDynamicObjData = class(TElfObjData)
  136. private
  137. FVersionDefs: TFPHashObjectList;
  138. public
  139. soname_strofs: longword;
  140. vernaux_count: longword;
  141. constructor create(const n:string);override;
  142. destructor destroy;override;
  143. property versiondefs:TFPHashObjectList read FVersionDefs;
  144. end;
  145. TRelocNameProc=function(reltyp:byte):string;
  146. TEncodeRelocProc=function(objrel:TObjRelocation):byte;
  147. TLoadRelocProc=procedure(objrel:TObjRelocation);
  148. TLoadSectionProc=function(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean;
  149. TDynamicReloc=(
  150. dr_relative,
  151. dr_glob_dat,
  152. dr_jump_slot,
  153. dr_copy,
  154. dr_irelative
  155. );
  156. TElfTarget=record
  157. max_page_size: longword;
  158. exe_image_base: longword;
  159. machine_code: word;
  160. relocs_use_addend: boolean;
  161. dyn_reloc_codes: array[TDynamicReloc] of byte;
  162. relocname: TRelocNameProc;
  163. encodereloc: TEncodeRelocProc;
  164. loadreloc: TLoadRelocProc;
  165. loadsection: TLoadSectionProc;
  166. end;
  167. TElfExeSection=class(TExeSection)
  168. public
  169. secshidx : longword; { index of the section header }
  170. shstridx,
  171. shtype,
  172. shflags,
  173. shlink,
  174. shinfo,
  175. shentsize : longword;
  176. procedure AddObjSection(objsec:TObjSection;ignoreprops:boolean=false);override;
  177. end;
  178. TElfSegment=class
  179. public
  180. ptype: longword;
  181. pflags: longword;
  182. DataPos: aword;
  183. DataSize: aword;
  184. MemPos: aword;
  185. MemSize: aword;
  186. align: longword;
  187. //physaddr: aword;
  188. FSectionList: TFPObjectList;
  189. constructor Create(atype,aflags,aalign:longword);
  190. destructor Destroy; override;
  191. procedure Add(exesec:TExeSection);
  192. end;
  193. TElfExeOutput=class(TExeOutput)
  194. private
  195. segmentlist: TFPObjectList;
  196. textseg,
  197. dataseg,
  198. noteseg,
  199. phdrseg: TElfSegment;
  200. shstrtabsect: TElfObjSection;
  201. symtab: TElfSymtab;
  202. shoffset: aword;
  203. gotwritten: boolean;
  204. { dynamic linking }
  205. dynamiclink: boolean;
  206. dynsymnames: Plongword;
  207. dynsymtable: TElfSymtab;
  208. interpobjsec: TObjSection;
  209. FInterpreter: pshortstring;
  210. verneedcount,
  211. verdefcount: longword;
  212. symversec,
  213. verdefsec,
  214. verneedsec,
  215. dynamicsec,
  216. hashobjsec: TElfObjSection;
  217. neededlist: TFPHashList;
  218. gotsize: aword;
  219. dynrelsize: aword;
  220. function AttachSection(objsec:TObjSection):TElfExeSection;
  221. function CreateSegment(atype,aflags,aalign:longword):TElfSegment;
  222. procedure WriteHeader;
  223. procedure WriteDynamicSymbolsHash;
  224. procedure WriteDynamicTags;
  225. procedure FinishDynamicTags;
  226. procedure exesection_write_header(p:TObject;arg:Pointer);
  227. procedure segment_write_header(p:TObject;arg:Pointer);
  228. procedure mempos_segment(seg:TElfSegment);
  229. procedure datapos_segment(seg:TElfSegment);
  230. procedure MapSectionsToSegments;
  231. procedure WriteStaticSymtable;
  232. procedure InitDynlink;
  233. procedure PrepareGOT;
  234. protected
  235. hastextrelocs: boolean;
  236. gotsymbol: TObjSymbol;
  237. dynsymlist: TFPObjectList;
  238. gotobjsec: TObjSection;
  239. pltobjsec,
  240. gotpltobjsec,
  241. pltrelocsec,
  242. ipltrelocsec,
  243. dynrelocsec: TElfObjSection;
  244. dynreloclist: TFPObjectList;
  245. tlsseg: TElfSegment;
  246. relative_reloc_count: longint;
  247. function AllocGOTSlot(objsym: TObjSymbol):boolean;
  248. procedure CreateGOTSection;virtual;
  249. procedure make_dynamic_if_undefweak(exesym:TExeSymbol);
  250. procedure WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword);
  251. procedure CreatePLT;virtual;
  252. procedure WriteFirstPLTEntry;virtual;abstract;
  253. procedure WritePLTEntry(exesym:TExeSymbol);virtual;
  254. procedure WriteIndirectPLTEntry(exesym:TExeSymbol);virtual;
  255. procedure WriteTargetDynamicTags;virtual;
  256. procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);virtual;abstract;
  257. procedure ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
  258. procedure ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
  259. procedure WriteDynTag(aTag:longword;aValue:longword);
  260. procedure WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword=0);
  261. public
  262. constructor Create;override;
  263. destructor Destroy;override;
  264. procedure Load_Start;override;
  265. procedure Load_DynamicObject(ObjData:TObjData;asneeded:boolean);override;
  266. procedure Order_Start;override;
  267. procedure Order_end;override;
  268. procedure AfterUnusedSectionRemoval;override;
  269. procedure MemPos_Start;override;
  270. procedure MemPos_ExeSection(const aname:string);override;
  271. procedure DataPos_Start;override;
  272. procedure DataPos_ExeSection(const aname:string);override;
  273. function writeData:boolean;override;
  274. procedure GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);override;
  275. property interpreter:pshortstring read FInterpreter write FInterpreter;
  276. end;
  277. var
  278. ElfExeOutputClass: TExeOutputClass;
  279. ElfTarget: TElfTarget;
  280. const
  281. { Bits of TObjSymbol.refs field }
  282. symref_plt = 1;
  283. symref_from_text = 2;
  284. implementation
  285. uses
  286. SysUtils,
  287. verbose,
  288. export,expunix,
  289. cutils,globals,fmodule;
  290. const
  291. symbolresize = 200*18;
  292. {$ifdef cpu64bitaddr}
  293. const
  294. ELFCLASS = ELFCLASS64;
  295. type
  296. telfheader = telf64header;
  297. telfreloc = telf64reloc;
  298. telfsymbol = telf64symbol;
  299. telfproghdr = telf64proghdr;
  300. telfdyn = telf64dyn;
  301. function ELF_R_INFO(sym:longword;typ:byte):qword;inline;
  302. begin
  303. result:=(qword(sym) shl 32) or typ;
  304. end;
  305. {$else cpu64bitaddr}
  306. const
  307. ELFCLASS = ELFCLASS32;
  308. type
  309. telfheader = telf32header;
  310. telfreloc = telf32reloc;
  311. telfsymbol = telf32symbol;
  312. telfproghdr = telf32proghdr;
  313. telfdyn = telf32dyn;
  314. function ELF_R_INFO(sym:longword;typ:byte):longword;inline;
  315. begin
  316. result:=(sym shl 8) or typ;
  317. end;
  318. {$endif cpu64bitaddr}
  319. procedure MayBeSwapHeader(var h : telf32header);
  320. begin
  321. if source_info.endian<>target_info.endian then
  322. with h do
  323. begin
  324. e_type:=swapendian(e_type);
  325. e_machine:=swapendian(e_machine);
  326. e_version:=swapendian(e_version);
  327. e_entry:=swapendian(e_entry);
  328. e_phoff:=swapendian(e_phoff);
  329. e_shoff:=swapendian(e_shoff);
  330. e_flags:=swapendian(e_flags);
  331. e_ehsize:=swapendian(e_ehsize);
  332. e_phentsize:=swapendian(e_phentsize);
  333. e_phnum:=swapendian(e_phnum);
  334. e_shentsize:=swapendian(e_shentsize);
  335. e_shnum:=swapendian(e_shnum);
  336. e_shstrndx:=swapendian(e_shstrndx);
  337. end;
  338. end;
  339. procedure MayBeSwapHeader(var h : telf64header);
  340. begin
  341. if source_info.endian<>target_info.endian then
  342. with h do
  343. begin
  344. e_type:=swapendian(e_type);
  345. e_machine:=swapendian(e_machine);
  346. e_version:=swapendian(e_version);
  347. e_entry:=swapendian(e_entry);
  348. e_phoff:=swapendian(e_phoff);
  349. e_shoff:=swapendian(e_shoff);
  350. e_flags:=swapendian(e_flags);
  351. e_ehsize:=swapendian(e_ehsize);
  352. e_phentsize:=swapendian(e_phentsize);
  353. e_phnum:=swapendian(e_phnum);
  354. e_shentsize:=swapendian(e_shentsize);
  355. e_shnum:=swapendian(e_shnum);
  356. e_shstrndx:=swapendian(e_shstrndx);
  357. end;
  358. end;
  359. procedure MayBeSwapHeader(var h : telf32proghdr);
  360. begin
  361. if source_info.endian<>target_info.endian then
  362. with h do
  363. begin
  364. p_align:=swapendian(p_align);
  365. p_filesz:=swapendian(p_filesz);
  366. p_flags:=swapendian(p_flags);
  367. p_memsz:=swapendian(p_memsz);
  368. p_offset:=swapendian(p_offset);
  369. p_paddr:=swapendian(p_paddr);
  370. p_type:=swapendian(p_type);
  371. p_vaddr:=swapendian(p_vaddr);
  372. end;
  373. end;
  374. procedure MayBeSwapHeader(var h : telf64proghdr);
  375. begin
  376. if source_info.endian<>target_info.endian then
  377. with h do
  378. begin
  379. p_align:=swapendian(p_align);
  380. p_filesz:=swapendian(p_filesz);
  381. p_flags:=swapendian(p_flags);
  382. p_memsz:=swapendian(p_memsz);
  383. p_offset:=swapendian(p_offset);
  384. p_paddr:=swapendian(p_paddr);
  385. p_type:=swapendian(p_type);
  386. p_vaddr:=swapendian(p_vaddr);
  387. end;
  388. end;
  389. procedure MaybeSwapSecHeader(var h : telf32sechdr);
  390. begin
  391. if source_info.endian<>target_info.endian then
  392. with h do
  393. begin
  394. sh_name:=swapendian(sh_name);
  395. sh_type:=swapendian(sh_type);
  396. sh_flags:=swapendian(sh_flags);
  397. sh_addr:=swapendian(sh_addr);
  398. sh_offset:=swapendian(sh_offset);
  399. sh_size:=swapendian(sh_size);
  400. sh_link:=swapendian(sh_link);
  401. sh_info:=swapendian(sh_info);
  402. sh_addralign:=swapendian(sh_addralign);
  403. sh_entsize:=swapendian(sh_entsize);
  404. end;
  405. end;
  406. procedure MaybeSwapSecHeader(var h : telf64sechdr);
  407. begin
  408. if source_info.endian<>target_info.endian then
  409. with h do
  410. begin
  411. sh_name:=swapendian(sh_name);
  412. sh_type:=swapendian(sh_type);
  413. sh_flags:=swapendian(sh_flags);
  414. sh_addr:=swapendian(sh_addr);
  415. sh_offset:=swapendian(sh_offset);
  416. sh_size:=swapendian(sh_size);
  417. sh_link:=swapendian(sh_link);
  418. sh_info:=swapendian(sh_info);
  419. sh_addralign:=swapendian(sh_addralign);
  420. sh_entsize:=swapendian(sh_entsize);
  421. end;
  422. end;
  423. procedure MaybeSwapElfSymbol(var h : telf32symbol);
  424. begin
  425. if source_info.endian<>target_info.endian then
  426. with h do
  427. begin
  428. st_name:=swapendian(st_name);
  429. st_value:=swapendian(st_value);
  430. st_size:=swapendian(st_size);
  431. st_shndx:=swapendian(st_shndx);
  432. end;
  433. end;
  434. procedure MaybeSwapElfSymbol(var h : telf64symbol);
  435. begin
  436. if source_info.endian<>target_info.endian then
  437. with h do
  438. begin
  439. st_name:=swapendian(st_name);
  440. st_value:=swapendian(st_value);
  441. st_size:=swapendian(st_size);
  442. st_shndx:=swapendian(st_shndx);
  443. end;
  444. end;
  445. procedure MaybeSwapElfReloc(var h : telf32reloc);
  446. begin
  447. if source_info.endian<>target_info.endian then
  448. with h do
  449. begin
  450. address:=swapendian(address);
  451. info:=swapendian(info);
  452. addend:=swapendian(addend);
  453. end;
  454. end;
  455. procedure MaybeSwapElfReloc(var h : telf64reloc);
  456. begin
  457. if source_info.endian<>target_info.endian then
  458. with h do
  459. begin
  460. address:=swapendian(address);
  461. info:=swapendian(info);
  462. addend:=swapendian(addend);
  463. end;
  464. end;
  465. procedure MaybeSwapElfDyn(var h : telf32dyn);
  466. begin
  467. if source_info.endian<>target_info.endian then
  468. with h do
  469. begin
  470. d_tag:=swapendian(d_tag);
  471. d_val:=swapendian(d_val);
  472. end;
  473. end;
  474. procedure MaybeSwapElfDyn(var h : telf64dyn);
  475. begin
  476. if source_info.endian<>target_info.endian then
  477. with h do
  478. begin
  479. d_tag:=swapendian(d_tag);
  480. d_val:=swapendian(d_val);
  481. end;
  482. end;
  483. procedure MaybeSwapElfverdef(var h: TElfverdef);
  484. begin
  485. if source_info.endian<>target_info.endian then
  486. with h do
  487. begin
  488. vd_version:=swapendian(vd_version);
  489. vd_flags:=swapendian(vd_flags);
  490. vd_ndx:=swapendian(vd_ndx);
  491. vd_cnt:=swapendian(vd_cnt);
  492. vd_hash:=swapendian(vd_hash);
  493. vd_aux:=swapendian(vd_aux);
  494. vd_next:=swapendian(vd_next);
  495. end;
  496. end;
  497. procedure MaybeSwapElfverdaux(var h: TElfverdaux);
  498. begin
  499. if source_info.endian<>target_info.endian then
  500. with h do
  501. begin
  502. vda_name:=swapendian(vda_name);
  503. vda_next:=swapendian(vda_next);
  504. end;
  505. end;
  506. procedure MaybeSwapElfverneed(var h: TElfverneed);
  507. begin
  508. if source_info.endian<>target_info.endian then
  509. with h do
  510. begin
  511. vn_version:=swapendian(vn_version);
  512. vn_cnt:=swapendian(vn_cnt);
  513. vn_file:=swapendian(vn_file);
  514. vn_aux:=swapendian(vn_aux);
  515. vn_next:=swapendian(vn_next);
  516. end;
  517. end;
  518. procedure MaybeSwapElfvernaux(var h: TElfvernaux);
  519. begin
  520. if source_info.endian<>target_info.endian then
  521. with h do
  522. begin
  523. vna_hash:=swapendian(vna_hash);
  524. vna_flags:=swapendian(vna_flags);
  525. vna_other:=swapendian(vna_other);
  526. vna_name:=swapendian(vna_name);
  527. vna_next:=swapendian(vna_next);
  528. end;
  529. end;
  530. {****************************************************************************
  531. Helpers
  532. ****************************************************************************}
  533. procedure encodesechdrflags(aoptions:TObjSectionOptions;out AshType:longint;out Ashflags:longint);
  534. begin
  535. { Section Type }
  536. AshType:=SHT_PROGBITS;
  537. if oso_strings in aoptions then
  538. AshType:=SHT_STRTAB
  539. else if not(oso_data in aoptions) then
  540. AshType:=SHT_NOBITS;
  541. { Section Flags }
  542. Ashflags:=0;
  543. if oso_load in aoptions then
  544. Ashflags:=Ashflags or SHF_ALLOC;
  545. if oso_executable in aoptions then
  546. Ashflags:=Ashflags or SHF_EXECINSTR;
  547. if oso_write in aoptions then
  548. Ashflags:=Ashflags or SHF_WRITE;
  549. end;
  550. procedure decodesechdrflags(AshType:longint;Ashflags:longint;out aoptions:TObjSectionOptions);
  551. begin
  552. aoptions:=[];
  553. { Section Type }
  554. if AshType<>SHT_NOBITS then
  555. include(aoptions,oso_data);
  556. if AshType=SHT_STRTAB then
  557. include(aoptions,oso_strings);
  558. { Section Flags }
  559. if Ashflags and SHF_ALLOC<>0 then
  560. include(aoptions,oso_load);
  561. if Ashflags and SHF_WRITE<>0 then
  562. include(aoptions,oso_write);
  563. if Ashflags and SHF_EXECINSTR<>0 then
  564. include(aoptions,oso_executable);
  565. end;
  566. {****************************************************************************
  567. TElfObjSection
  568. ****************************************************************************}
  569. constructor TElfObjSection.create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);
  570. begin
  571. inherited create(AList,Aname,Aalign,aoptions);
  572. index:=0;
  573. shstridx:=0;
  574. encodesechdrflags(aoptions,shtype,shflags);
  575. shlink:=0;
  576. shinfo:=0;
  577. if name='.stab' then
  578. shentsize:=sizeof(TObjStabEntry);
  579. end;
  580. constructor TElfObjSection.create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:shortint;Aentsize:longint);
  581. var
  582. aoptions : TObjSectionOptions;
  583. begin
  584. decodesechdrflags(Ashtype,Ashflags,aoptions);
  585. inherited create(aobjdata.ObjSectionList,Aname,Aalign,aoptions);
  586. objdata:=aobjdata;
  587. index:=0;
  588. shstridx:=0;
  589. shtype:=AshType;
  590. shflags:=AshFlags;
  591. shentsize:=Aentsize;
  592. end;
  593. const
  594. relsec_prefix:array[boolean] of string[5] = ('.rel','.rela');
  595. relsec_shtype:array[boolean] of longword = (SHT_REL,SHT_RELA);
  596. constructor TElfObjSection.create_reloc(aobjdata:TObjData;const Aname:string;allocflag:boolean);
  597. begin
  598. create_ext(aobjdata,
  599. relsec_prefix[ElfTarget.relocs_use_addend]+aname,
  600. relsec_shtype[ElfTarget.relocs_use_addend],
  601. SHF_ALLOC*ord(allocflag),
  602. sizeof(pint),
  603. (2+ord(ElfTarget.relocs_use_addend))*sizeof(pint));
  604. end;
  605. procedure TElfObjSection.writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);
  606. var
  607. reloc: TObjRelocation;
  608. begin
  609. reloc:=TObjRelocation.CreateSection(Size,aTarget,reltype);
  610. reloc.size:=len;
  611. ObjRelocations.Add(reloc);
  612. if reltype=RELOC_RELATIVE then
  613. { ARM does not require this adjustment, other CPUs must be checked }
  614. {$if defined(i386) or defined(x86_64)}
  615. dec(offset,len)
  616. {$endif i386 or x86_64}
  617. else if reltype<>RELOC_ABSOLUTE then
  618. InternalError(2012062401);
  619. if ElfTarget.relocs_use_addend then
  620. begin
  621. reloc.orgsize:=offset;
  622. offset:=0;
  623. end;
  624. write(offset,len);
  625. end;
  626. {****************************************************************************
  627. TElfObjData
  628. ****************************************************************************}
  629. constructor TElfObjData.create(const n:string);
  630. begin
  631. inherited create(n);
  632. CObjSection:=TElfObjSection;
  633. end;
  634. function TElfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  635. const
  636. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  637. { TODO: sec_rodata is still writable }
  638. '.text','.data','.data','.rodata','.bss','.threadvar',
  639. '.pdata',
  640. '.text', { darwin stubs }
  641. '__DATA,__nl_symbol_ptr',
  642. '__DATA,__la_symbol_ptr',
  643. '__DATA,__mod_init_func',
  644. '__DATA,__mod_term_func',
  645. '.stab','.stabstr',
  646. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  647. '.eh_frame',
  648. '.debug_frame','.debug_info','.debug_line','.debug_abbrev',
  649. '.fpc',
  650. '.toc',
  651. '.init',
  652. '.fini',
  653. '.objc_class',
  654. '.objc_meta_class',
  655. '.objc_cat_cls_meth',
  656. '.objc_cat_inst_meth',
  657. '.objc_protocol',
  658. '.objc_string_object',
  659. '.objc_cls_meth',
  660. '.objc_inst_meth',
  661. '.objc_cls_refs',
  662. '.objc_message_refs',
  663. '.objc_symbols',
  664. '.objc_category',
  665. '.objc_class_vars',
  666. '.objc_instance_vars',
  667. '.objc_module_info',
  668. '.objc_class_names',
  669. '.objc_meth_var_types',
  670. '.objc_meth_var_names',
  671. '.objc_selector_strs',
  672. '.objc_protocol_ext',
  673. '.objc_class_ext',
  674. '.objc_property',
  675. '.objc_image_info',
  676. '.objc_cstring_object',
  677. '.objc_sel_fixup',
  678. '__DATA,__objc_data',
  679. '__DATA,__objc_const',
  680. '.objc_superrefs',
  681. '__DATA, __datacoal_nt,coalesced',
  682. '.objc_classlist',
  683. '.objc_nlclasslist',
  684. '.objc_catlist',
  685. '.obcj_nlcatlist',
  686. '.objc_protolist'
  687. );
  688. var
  689. sep : string[3];
  690. secname : string;
  691. begin
  692. { section type user gives the user full controll on the section name }
  693. if atype=sec_user then
  694. result:=aname
  695. else
  696. begin
  697. secname:=secnames[atype];
  698. if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
  699. begin
  700. result:=secname+'.'+aname;
  701. exit;
  702. end;
  703. if create_smartlink_sections and (aname<>'') then
  704. begin
  705. case aorder of
  706. secorder_begin :
  707. sep:='.b_';
  708. secorder_end :
  709. sep:='.z_';
  710. else
  711. sep:='.n_';
  712. end;
  713. result:=secname+sep+aname
  714. end
  715. else
  716. result:=secname;
  717. end;
  718. end;
  719. procedure TElfObjData.CreateDebugSections;
  720. begin
  721. if target_dbg.id=dbg_stabs then
  722. begin
  723. stabssec:=createsection(sec_stab);
  724. stabstrsec:=createsection(sec_stabstr);
  725. end;
  726. end;
  727. procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);
  728. var
  729. symaddr : aint;
  730. objreloc: TObjRelocation;
  731. begin
  732. if CurrObjSec=nil then
  733. internalerror(200403292);
  734. objreloc:=nil;
  735. if assigned(p) then
  736. begin
  737. { real address of the symbol }
  738. symaddr:=p.address;
  739. { Local ObjSymbols can be resolved already or need a section reloc }
  740. if (p.bind=AB_LOCAL) and
  741. (reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}]) then
  742. begin
  743. { For a reltype relocation in the same section the
  744. value can be calculated }
  745. if (p.objsection=CurrObjSec) and
  746. (reltype=RELOC_RELATIVE) then
  747. inc(data,symaddr-len-CurrObjSec.Size)
  748. else
  749. begin
  750. objreloc:=TObjRelocation.CreateSection(CurrObjSec.Size,p.objsection,reltype);
  751. CurrObjSec.ObjRelocations.Add(objreloc);
  752. inc(data,symaddr);
  753. end;
  754. end
  755. else
  756. begin
  757. objreloc:=TObjRelocation.CreateSymbol(CurrObjSec.Size,p,reltype);
  758. CurrObjSec.ObjRelocations.Add(objreloc);
  759. { If target is a local label and it isn't handled above,
  760. patch its type in order to get it written to symtable.
  761. This may happen e.g. when taking address of Pascal label in PIC mode. }
  762. if (p.bind=AB_LOCAL) and (p.typ=AT_LABEL) then
  763. p.typ:=AT_ADDR;
  764. end;
  765. end;
  766. if assigned(objreloc) then
  767. begin
  768. objreloc.size:=len;
  769. if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_GOTPCREL{$endif}] then
  770. dec(data,len);
  771. if ElfTarget.relocs_use_addend then
  772. begin
  773. objreloc.orgsize:=data;
  774. data:=0;
  775. end;
  776. end;
  777. CurrObjSec.write(data,len);
  778. end;
  779. {****************************************************************************
  780. TElfDynamicObjData
  781. ****************************************************************************}
  782. constructor TElfDynamicObjData.create(const n:string);
  783. begin
  784. inherited Create(n);
  785. FVersionDefs:=TFPHashObjectList.create(true);
  786. { Default symversions with indices 0 and 1 }
  787. TElfVersionDef.create(FVersionDefs,'*local*');
  788. TElfVersionDef.create(FVersionDefs,'*global*');
  789. end;
  790. destructor TElfDynamicObjData.destroy;
  791. begin
  792. FVersionDefs.free;
  793. inherited Destroy;
  794. end;
  795. {****************************************************************************
  796. TElfSymtab
  797. ****************************************************************************}
  798. const
  799. symsecnames: array[boolean] of string[8] = ('.symtab','.dynsym');
  800. strsecnames: array[boolean] of string[8] = ('.strtab','.dynstr');
  801. symsectypes: array[boolean] of longword = (SHT_SYMTAB,SHT_DYNSYM);
  802. symsecattrs: array[boolean] of longword = (0,SHF_ALLOC);
  803. constructor TElfSymtab.create(aObjData:TObjData;aKind:TElfSymtabKind);
  804. var
  805. dyn:boolean;
  806. begin
  807. dyn:=(aKind=esk_dyn);
  808. create_ext(aObjData,symsecnames[dyn],symsectypes[dyn],symsecattrs[dyn],sizeof(pint),sizeof(TElfSymbol));
  809. fstrsec:=TElfObjSection.create_ext(aObjData,strsecnames[dyn],SHT_STRTAB,symsecattrs[dyn],1,0);
  810. fstrsec.writezeros(1);
  811. writezeros(sizeof(TElfSymbol));
  812. symidx:=1;
  813. shinfo:=1;
  814. kind:=aKind;
  815. end;
  816. procedure TElfSymtab.writeInternalSymbol(avalue:aword;astridx:longword;ainfo:byte;ashndx:word);
  817. var
  818. elfsym:TElfSymbol;
  819. begin
  820. fillchar(elfsym,sizeof(elfsym),0);
  821. elfsym.st_value:=avalue;
  822. elfsym.st_name:=astridx;
  823. elfsym.st_info:=ainfo;
  824. elfsym.st_shndx:=ashndx;
  825. inc(symidx);
  826. inc(shinfo);
  827. MaybeSwapElfSymbol(elfsym);
  828. write(elfsym,sizeof(elfsym));
  829. end;
  830. procedure TElfSymtab.writeSymbol(objsym:TObjSymbol;nameidx:longword);
  831. var
  832. elfsym:TElfSymbol;
  833. begin
  834. fillchar(elfsym,sizeof(elfsym),0);
  835. if nameidx=0 then
  836. elfsym.st_name:=fstrsec.writestr(objsym.name)
  837. else
  838. elfsym.st_name:=nameidx;
  839. elfsym.st_size:=objsym.size;
  840. elfsym.st_value:=objsym.address;
  841. case objsym.bind of
  842. AB_LOCAL :
  843. begin
  844. elfsym.st_info:=STB_LOCAL shl 4;
  845. inc(shinfo);
  846. end;
  847. AB_COMMON :
  848. begin
  849. elfsym.st_value:=var_align(objsym.size);
  850. elfsym.st_info:=STB_GLOBAL shl 4;
  851. elfsym.st_shndx:=SHN_COMMON;
  852. end;
  853. AB_EXTERNAL :
  854. elfsym.st_info:=STB_GLOBAL shl 4;
  855. AB_WEAK_EXTERNAL :
  856. elfsym.st_info:=STB_WEAK shl 4;
  857. AB_GLOBAL :
  858. elfsym.st_info:=STB_GLOBAL shl 4;
  859. else
  860. InternalError(2012111801);
  861. end;
  862. { External symbols must be NOTYPE in relocatable files }
  863. if (objsym.bind<>AB_EXTERNAL) or (kind<>esk_obj) then
  864. begin
  865. case objsym.typ of
  866. AT_FUNCTION :
  867. elfsym.st_info:=elfsym.st_info or STT_FUNC;
  868. AT_DATA :
  869. elfsym.st_info:=elfsym.st_info or STT_OBJECT;
  870. AT_TLS:
  871. elfsym.st_info:=elfsym.st_info or STT_TLS;
  872. AT_GNU_IFUNC:
  873. elfsym.st_info:=elfsym.st_info or STT_GNU_IFUNC;
  874. { other types are implicitly mapped to STT_NOTYPE }
  875. end;
  876. end;
  877. if objsym.bind<>AB_COMMON then
  878. begin
  879. if kind<>esk_obj then
  880. begin
  881. if assigned(objsym.objsection) and assigned(objsym.objsection.ExeSection) then
  882. begin
  883. if (objsym.typ=AT_TLS) then
  884. elfsym.st_value:=elfsym.st_value-tlsbase
  885. else if (oso_plt in objsym.objsection.SecOptions) then
  886. elfsym.st_value:=0
  887. else
  888. elfsym.st_shndx:=TElfExeSection(objsym.objsection.ExeSection).secshidx;
  889. end;
  890. end
  891. else
  892. begin
  893. if assigned(objsym.objsection) then
  894. elfsym.st_shndx:=objsym.objsection.index
  895. else
  896. elfsym.st_shndx:=SHN_UNDEF;
  897. objsym.symidx:=symidx;
  898. end;
  899. end;
  900. inc(symidx);
  901. MaybeSwapElfSymbol(elfsym);
  902. write(elfsym,sizeof(TElfSymbol));
  903. end;
  904. {****************************************************************************
  905. TElfObjectOutput
  906. ****************************************************************************}
  907. constructor TElfObjectOutput.create(AWriter:TObjectWriter);
  908. begin
  909. inherited Create(AWriter);
  910. CObjData:=TElfObjData;
  911. end;
  912. procedure TElfObjectOutput.createrelocsection(s:TElfObjSection;data:TObjData);
  913. var
  914. i : longint;
  915. rel : telfreloc;
  916. objreloc : TObjRelocation;
  917. relsym : longint;
  918. relocsect : TElfObjSection;
  919. begin
  920. { create the reloc section }
  921. relocsect:=TElfObjSection.create_reloc(data,s.name,false);
  922. relocsect.shlink:=symtabsect.index;
  923. relocsect.shinfo:=s.index;
  924. { add the relocations }
  925. for i:=0 to s.Objrelocations.count-1 do
  926. begin
  927. objreloc:=TObjRelocation(s.Objrelocations[i]);
  928. { Symbol }
  929. if assigned(objreloc.symbol) then
  930. begin
  931. if objreloc.symbol.symidx=-1 then
  932. begin
  933. writeln(objreloc.symbol.Name);
  934. internalerror(200603012);
  935. end;
  936. relsym:=objreloc.symbol.symidx;
  937. end
  938. else
  939. begin
  940. if objreloc.objsection<>nil then
  941. relsym:=objreloc.objsection.secsymidx
  942. else
  943. relsym:=SHN_UNDEF;
  944. end;
  945. rel.address:=objreloc.dataoffset;
  946. rel.info:=ELF_R_INFO(relsym,ElfTarget.encodereloc(objreloc));
  947. rel.addend:=objreloc.orgsize;
  948. { write reloc }
  949. { ElfXX_Rel is essentially ElfXX_Rela without the addend field. }
  950. MaybeSwapElfReloc(rel);
  951. relocsect.write(rel,relocsect.shentsize);
  952. end;
  953. end;
  954. procedure TElfObjectOutput.section_write_symbol(p:TObject;arg:pointer);
  955. begin
  956. { Must not write symbols for internal sections like .symtab }
  957. { TODO: maybe use inclusive list of section types instead }
  958. if (TElfObjSection(p).shtype in [SHT_SYMTAB,SHT_STRTAB,SHT_REL,SHT_RELA]) then
  959. exit;
  960. TObjSection(p).secsymidx:=symtabsect.symidx;
  961. symtabsect.writeInternalSymbol(0,0,STT_SECTION,TObjSection(p).index);
  962. end;
  963. procedure TElfObjectOutput.createsymtab(data: TObjData);
  964. var
  965. i : longint;
  966. objsym : TObjSymbol;
  967. begin
  968. with data do
  969. begin
  970. { section symbols }
  971. ObjSectionList.ForEachCall(@section_write_symbol,nil);
  972. { First the Local Symbols, this is required by ELF. The localsyms
  973. count stored in shinfo is used to skip the local symbols
  974. when traversing the symtab }
  975. for i:=0 to ObjSymbolList.Count-1 do
  976. begin
  977. objsym:=TObjSymbol(ObjSymbolList[i]);
  978. if (objsym.bind=AB_LOCAL) and (objsym.typ<>AT_LABEL) then
  979. symtabsect.WriteSymbol(objsym);
  980. end;
  981. { Global Symbols }
  982. for i:=0 to ObjSymbolList.Count-1 do
  983. begin
  984. objsym:=TObjSymbol(ObjSymbolList[i]);
  985. if (objsym.bind<>AB_LOCAL) then
  986. symtabsect.WriteSymbol(objsym);
  987. end;
  988. { update the .symtab section header }
  989. symtabsect.shlink:=symtabsect.fstrsec.index;
  990. end;
  991. end;
  992. procedure TElfObjectOutput.createshstrtab(data: TObjData);
  993. var
  994. i,prefixlen:longint;
  995. objsec,target:TElfObjSection;
  996. begin
  997. shstrtabsect.writezeros(1);
  998. prefixlen:=length('.rel')+ord(ElfTarget.relocs_use_addend);
  999. for i:=0 to data.ObjSectionList.Count-1 do
  1000. begin
  1001. objsec:=TElfObjSection(data.ObjSectionList[i]);
  1002. { Alias section names into names of corresponding reloc sections,
  1003. this is allowed by ELF specs and saves good half of .shstrtab space. }
  1004. if objsec.shtype=relsec_shtype[ElfTarget.relocs_use_addend] then
  1005. begin
  1006. target:=TElfObjSection(data.ObjSectionList[objsec.shinfo-1]);
  1007. if (target.ObjRelocations.Count=0) or
  1008. (target.shstridx<prefixlen) then
  1009. InternalError(2012101204);
  1010. objsec.shstridx:=target.shstridx-prefixlen;
  1011. end
  1012. else
  1013. begin
  1014. if objsec.ObjRelocations.Count<>0 then
  1015. shstrtabsect.write(relsec_prefix[true][1],prefixlen);
  1016. objsec.shstridx:=shstrtabsect.writestr(objsec.name);
  1017. end;
  1018. end;
  1019. end;
  1020. procedure TElfObjectOutput.writesectionheader(s:TElfObjSection);
  1021. var
  1022. sechdr : telfsechdr;
  1023. begin
  1024. fillchar(sechdr,sizeof(sechdr),0);
  1025. sechdr.sh_name:=s.shstridx;
  1026. sechdr.sh_type:=s.shtype;
  1027. sechdr.sh_flags:=s.shflags;
  1028. sechdr.sh_offset:=s.datapos;
  1029. sechdr.sh_size:=s.Size;
  1030. sechdr.sh_link:=s.shlink;
  1031. sechdr.sh_info:=s.shinfo;
  1032. sechdr.sh_addralign:=s.secalign;
  1033. sechdr.sh_entsize:=s.shentsize;
  1034. MaybeSwapSecHeader(sechdr);
  1035. writer.write(sechdr,sizeof(sechdr));
  1036. end;
  1037. procedure TElfObjectOutput.section_count_sections(p:TObject;arg:pointer);
  1038. begin
  1039. TElfObjSection(p).index:=pword(arg)^;
  1040. inc(pword(arg)^);
  1041. end;
  1042. procedure TElfObjectOutput.section_create_relocsec(p:TObject;arg:pointer);
  1043. begin
  1044. if (TElfObjSection(p).ObjRelocations.count>0) then
  1045. createrelocsection(TElfObjSection(p),TObjData(arg));
  1046. end;
  1047. procedure TElfObjectOutput.section_write_sechdr(p:TObject;arg:pointer);
  1048. begin
  1049. writesectionheader(TElfObjSection(p));
  1050. end;
  1051. function TElfObjectOutput.writedata(data:TObjData):boolean;
  1052. var
  1053. header : telfheader;
  1054. shoffset,
  1055. datapos : aword;
  1056. nsections : word;
  1057. begin
  1058. result:=false;
  1059. with data do
  1060. begin
  1061. { default sections }
  1062. symtabsect:=TElfSymtab.create(data,esk_obj);
  1063. shstrtabsect:=TElfObjSection.create_ext(data,'.shstrtab',SHT_STRTAB,0,1,0);
  1064. { "no executable stack" marker for Linux }
  1065. if (target_info.system in systems_linux) and
  1066. not(cs_executable_stack in current_settings.moduleswitches) then
  1067. TElfObjSection.create_ext(data,'.note.GNU-stack',SHT_PROGBITS,0,1,0);
  1068. { symbol for filename }
  1069. symtabsect.fstrsec.writestr(ExtractFileName(current_module.mainsource));
  1070. symtabsect.writeInternalSymbol(0,1,STT_FILE,SHN_ABS);
  1071. { calc amount of sections we have }
  1072. nsections:=1;
  1073. { also create the index in the section header table }
  1074. ObjSectionList.ForEachCall(@section_count_sections,@nsections);
  1075. { create .symtab and .strtab }
  1076. createsymtab(data);
  1077. { Create the relocation sections, this needs valid secidx and symidx }
  1078. ObjSectionList.ForEachCall(@section_create_relocsec,data);
  1079. { recalc nsections to incude the reloc sections }
  1080. nsections:=1;
  1081. ObjSectionList.ForEachCall(@section_count_sections,@nsections);
  1082. { create .shstrtab }
  1083. createshstrtab(data);
  1084. { Calculate the filepositions }
  1085. datapos:=$40; { elfheader + alignment }
  1086. { section data }
  1087. layoutsections(datapos);
  1088. { section headers }
  1089. shoffset:=datapos;
  1090. inc(datapos,(nsections+1)*sizeof(telfsechdr));
  1091. { Write ELF Header }
  1092. fillchar(header,sizeof(header),0);
  1093. header.e_ident[EI_MAG0]:=ELFMAG0; { = #127'ELF' }
  1094. header.e_ident[EI_MAG1]:=ELFMAG1;
  1095. header.e_ident[EI_MAG2]:=ELFMAG2;
  1096. header.e_ident[EI_MAG3]:=ELFMAG3;
  1097. header.e_ident[EI_CLASS]:=ELFCLASS;
  1098. if target_info.endian=endian_big then
  1099. header.e_ident[EI_DATA]:=ELFDATA2MSB
  1100. else
  1101. header.e_ident[EI_DATA]:=ELFDATA2LSB;
  1102. header.e_ident[EI_VERSION]:=1;
  1103. if target_info.system in systems_openbsd then
  1104. header.e_ident[EI_OSABI]:=ELFOSABI_OPENBSD;
  1105. header.e_type:=ET_REL;
  1106. header.e_machine:=ElfTarget.machine_code;
  1107. header.e_version:=1;
  1108. header.e_shoff:=shoffset;
  1109. header.e_shstrndx:=shstrtabsect.index;
  1110. header.e_shnum:=nsections;
  1111. header.e_ehsize:=sizeof(telfheader);
  1112. header.e_shentsize:=sizeof(telfsechdr);
  1113. MaybeSwapHeader(header);
  1114. writer.write(header,sizeof(header));
  1115. writer.writezeros($40-sizeof(header)); { align }
  1116. { Sections }
  1117. WriteSectionContent(data);
  1118. { section headers, start with an empty header for sh_undef }
  1119. writer.writezeros(sizeof(telfsechdr));
  1120. ObjSectionList.ForEachCall(@section_write_sechdr,nil);
  1121. end;
  1122. result:=true;
  1123. end;
  1124. {****************************************************************************
  1125. TELFAssembler
  1126. ****************************************************************************}
  1127. constructor TElfAssembler.Create(smart:boolean);
  1128. begin
  1129. inherited Create(smart);
  1130. CObjOutput:=TElfObjectOutput;
  1131. end;
  1132. {****************************************************************************
  1133. TELFObjectInput
  1134. ****************************************************************************}
  1135. constructor TElfObjInput.Create;
  1136. begin
  1137. inherited Create;
  1138. CObjData:=TElfObjData;
  1139. end;
  1140. destructor TElfObjInput.Destroy;
  1141. begin
  1142. if Assigned(FSymTbl) then
  1143. FreeMem(FSymTbl);
  1144. if Assigned(FSecTbl) then
  1145. FreeMem(FSecTbl);
  1146. if Assigned(strtab) then
  1147. FreeMem(strtab);
  1148. if Assigned(shstrtab) then
  1149. FreeMem(shstrtab);
  1150. if Assigned(symversions) then
  1151. FreeMem(symversions);
  1152. inherited Destroy;
  1153. end;
  1154. procedure TElfObjInput.LoadRelocations(const secrec:TSectionRec);
  1155. var
  1156. i: longint;
  1157. rel: TElfReloc;
  1158. reltyp: byte;
  1159. relsym: longint;
  1160. objrel: TObjRelocation;
  1161. p: TObjSymbol;
  1162. begin
  1163. FReader.Seek(secrec.relocpos);
  1164. if secrec.sec=nil then
  1165. InternalError(2012060203);
  1166. for i:=0 to secrec.relocs-1 do
  1167. begin
  1168. FReader.Read(rel,secrec.relentsize);
  1169. MaybeSwapElfReloc(rel);
  1170. reltyp:=rel.info and $FF;
  1171. {$ifdef cpu64bitaddr}
  1172. relsym:=rel.info shr 32;
  1173. {$else cpu64bitaddr}
  1174. relsym:=(rel.info shr 8) and $FFFFFF;
  1175. {$endif cpu64bitaddr}
  1176. if relsym>=syms then
  1177. InternalError(2012060204);
  1178. p:=TObjSymbol(FSymTbl[relsym]);
  1179. { Some relocations (e.g. R_ARM_V4BX) don't use a symbol at all }
  1180. if assigned(p) or (relsym=0) then
  1181. begin
  1182. objrel:=TObjRelocation.CreateRaw(rel.address-secrec.sec.mempos,p,reltyp);
  1183. if (secrec.relentsize=3*sizeof(pint)) then
  1184. objrel.orgsize:=rel.addend;
  1185. { perform target-specific actions }
  1186. if Assigned(ElfTarget.loadreloc) then
  1187. ElfTarget.loadreloc(objrel);
  1188. secrec.sec.ObjRelocations.add(objrel);
  1189. end
  1190. else
  1191. begin
  1192. InputError('Unable to resolve symbol of relocation');
  1193. exit;
  1194. end;
  1195. end;
  1196. end;
  1197. procedure TElfObjInput.LoadSymbols(objdata:TObjData;count,locals:longword);
  1198. var
  1199. i: longint;
  1200. sym: TElfSymbol;
  1201. bind: TAsmSymBind;
  1202. typ: TAsmSymType;
  1203. objsym: TObjSymbol;
  1204. ver: word;
  1205. begin
  1206. FSymTbl:=AllocMem(count*sizeof(Pointer));
  1207. for i:=1 to count-1 do
  1208. begin
  1209. FReader.Read(sym,sizeof(TElfSymbol));
  1210. MaybeSwapElfSymbol(sym);
  1211. if sym.st_name>=strtablen then
  1212. InternalError(2012060205);
  1213. if sym.st_shndx=SHN_ABS then { ignore absolute symbols (should we really do it???) }
  1214. Continue
  1215. else if sym.st_shndx=SHN_COMMON then
  1216. bind:=AB_COMMON
  1217. else if (sym.st_shndx>=nsects) then
  1218. InternalError(2012060206)
  1219. else
  1220. case (sym.st_info shr 4) of
  1221. STB_LOCAL:
  1222. bind:=AB_LOCAL;
  1223. STB_GLOBAL:
  1224. if sym.st_shndx=SHN_UNDEF then
  1225. bind:=AB_EXTERNAL
  1226. else
  1227. bind:=AB_GLOBAL;
  1228. STB_WEAK:
  1229. bind:=AB_WEAK_EXTERNAL;
  1230. else
  1231. InternalError(2012060207);
  1232. end;
  1233. { Ignore section symbol if we didn't create the corresponding objsection
  1234. (examples are SHT_GROUP or .note.GNU-stack sections). }
  1235. if (sym.st_shndx>0) and (sym.st_shndx<SHN_LORESERVE) and
  1236. (FSecTbl[sym.st_shndx].sec=nil) and
  1237. (not dynobj) then
  1238. if ((sym.st_info and $0F)=STT_SECTION) then
  1239. Continue
  1240. else
  1241. begin
  1242. writeln(objdata.name,' ',i);
  1243. InternalError(2012110701)
  1244. end;
  1245. case (sym.st_info and $0F) of
  1246. STT_NOTYPE:
  1247. typ:=AT_NONE;
  1248. STT_OBJECT:
  1249. typ:=AT_DATA;
  1250. STT_FUNC:
  1251. typ:=AT_FUNCTION;
  1252. STT_SECTION:
  1253. typ:=AT_SECTION;
  1254. STT_FILE:
  1255. continue;
  1256. STT_TLS:
  1257. typ:=AT_TLS;
  1258. STT_GNU_IFUNC:
  1259. typ:=AT_GNU_IFUNC;
  1260. else
  1261. writeln(objdata.name,' ',sym.st_info and $0F);
  1262. InternalError(2012060208);
  1263. end;
  1264. { If reading DSO, we're interested only in global symbols defined there.
  1265. Symbols with non-current version should also be ignored. }
  1266. ver:=0;
  1267. if dynobj then
  1268. begin
  1269. if assigned(symversions) then
  1270. begin
  1271. ver:=symversions[i];
  1272. if (ver=VER_NDX_LOCAL) or (ver>VERSYM_VERSION) then
  1273. continue;
  1274. end;
  1275. if (bind=AB_LOCAL) or (sym.st_shndx=SHN_UNDEF) then
  1276. continue;
  1277. if ver>=verdefs.count then
  1278. InternalError(2012120505);
  1279. end;
  1280. { validity of name and objsection has been checked above }
  1281. { !! all AT_SECTION symbols have duplicate (null) name,
  1282. therefore TObjSection.CreateSymbol cannot be used here }
  1283. objsym:=TObjSymbol.Create(objdata.ObjSymbolList,string(PChar(@strtab[sym.st_name])));
  1284. objsym.bind:=bind;
  1285. objsym.typ:=typ;
  1286. if bind<>AB_COMMON then
  1287. objsym.objsection:=FSecTbl[sym.st_shndx].sec;
  1288. objsym.offset:=sym.st_value;
  1289. objsym.size:=sym.st_size;
  1290. FSymTbl[i]:=objsym;
  1291. end;
  1292. end;
  1293. function TElfObjInput.CreateSection(const shdr:TElfsechdr;index:longint;objdata:tobjdata;
  1294. out secname:string):TElfObjSection;
  1295. begin
  1296. secname:=string(PChar(@shstrtab[shdr.sh_name]));
  1297. result:=TElfObjSection.create_ext(objdata,secname,
  1298. shdr.sh_type,shdr.sh_flags,shdr.sh_addralign,shdr.sh_entsize);
  1299. result.index:=index;
  1300. result.DataPos:=shdr.sh_offset;
  1301. result.MemPos:=shdr.sh_addr;
  1302. result.Size:=shdr.sh_size;
  1303. FSecTbl[index].sec:=result;
  1304. end;
  1305. procedure TElfObjInput.LoadSection(const shdr:TElfsechdr;index:longint;objdata:tobjdata);
  1306. var
  1307. sec: TElfObjSection;
  1308. sym: TElfSymbol;
  1309. secname: string;
  1310. begin
  1311. if shdr.sh_name>=shstrtablen then
  1312. InternalError(2012060210);
  1313. case shdr.sh_type of
  1314. SHT_NULL:
  1315. {ignore};
  1316. { SHT_STRTAB may appear for .stabstr and other debug sections.
  1317. .shstrtab and .strtab are processed separately and don't appear here. }
  1318. SHT_PROGBITS,SHT_NOBITS,SHT_NOTE,SHT_STRTAB,
  1319. SHT_INIT_ARRAY,SHT_FINI_ARRAY,SHT_PREINIT_ARRAY:
  1320. begin
  1321. sec:=CreateSection(shdr,index,objdata,secname);
  1322. if (Length(secname)>3) and (secname[2] in ['d','f','n','s']) then
  1323. begin
  1324. if (Pos('.stub',secname)=1) or
  1325. (Pos('.fpc',secname)=1) then
  1326. sec.SecOptions:=[oso_keep]
  1327. { ELF does not have any flags specific to debug sections,
  1328. but reserves names starting with '.debug' for this purpose }
  1329. else if (Pos('.debug',secname)=1) or
  1330. (secname='.stab') or
  1331. (secname='.stabstr') then
  1332. sec.SecOptions:=[oso_debug]
  1333. else if (secname='.note.GNU-stack') and (shdr.sh_type=SHT_PROGBITS) then
  1334. begin
  1335. if (shdr.sh_flags and SHF_EXECINSTR)=0 then
  1336. objdata.ExecStack:=False;
  1337. end;
  1338. end;
  1339. if (shdr.sh_type=SHT_NOTE) and (shdr.sh_size<>0) then
  1340. sec.SecOptions:=[oso_keep];
  1341. end;
  1342. SHT_REL,SHT_RELA:
  1343. begin
  1344. if shdr.sh_info>=nsects then
  1345. InternalError(2012060211);
  1346. if shdr.sh_entsize<>longword((2+ord(shdr.sh_type=SHT_RELA))*sizeof(pint)) then
  1347. InternalError(2012060212);
  1348. with FSecTbl[shdr.sh_info] do
  1349. begin
  1350. relocpos:=shdr.sh_offset;
  1351. relocs:=shdr.sh_size div shdr.sh_entsize;
  1352. relentsize:=shdr.sh_entsize;
  1353. end;
  1354. end;
  1355. SHT_GROUP:
  1356. if (shdr.sh_size>=2*sizeof(longword)) and
  1357. (shdr.sh_entsize=sizeof(longword)) and
  1358. ((shdr.sh_size mod shdr.sh_entsize)=0) then
  1359. begin
  1360. { Groups are identified by name of symbol pointed to by
  1361. sh_link and sh_info, not by sh_name. This symbol
  1362. may as well be STT_SECTION symbol of this section,
  1363. in which case we end up using sh_name. }
  1364. if dynobj then
  1365. InternalError(2012110801);
  1366. if (shdr.sh_link<>symtabndx) then
  1367. InternalError(2012110703);
  1368. if (shdr.sh_info>=syms) then
  1369. InternalError(2012110704);
  1370. FReader.Seek(symtaboffset+shdr.sh_info*sizeof(TElfSymbol));
  1371. FReader.Read(sym,sizeof(TElfSymbol));
  1372. MaybeSwapElfSymbol(sym);
  1373. if sym.st_name>=strtablen then
  1374. InternalError(2012110705);
  1375. if (sym.st_shndx=index) and (sym.st_info=((STB_LOCAL shl 4) or STT_SECTION)) then
  1376. secname:=string(PChar(@shstrtab[shdr.sh_name]))
  1377. else
  1378. secname:=string(PChar(@strtab[sym.st_name]));
  1379. { Postpone further processing until all sections are loaded,
  1380. we'll need to access correct section header.
  1381. Since ABI requires SHT_GROUP sections to come first in the file,
  1382. we assume that group number x has header index x+1.
  1383. If we ever encounter files where this is not true, we'll have
  1384. to maintain a separate index. }
  1385. objdata.CreateSectionGroup(secname);
  1386. if (index<>objdata.GroupsList.Count) then
  1387. InternalError(2012110802);
  1388. end
  1389. else
  1390. InternalError(2012110706);
  1391. SHT_GNU_ATTRIBUTES:
  1392. { TODO: must not be ignored };
  1393. else
  1394. if not (assigned(ElfTarget.loadsection) and
  1395. ElfTarget.loadsection(self,objdata,shdr,index)) then
  1396. InternalError(2012072603);
  1397. end;
  1398. FLoaded[index]:=True;
  1399. end;
  1400. function TElfObjInput.LoadHeader:word;
  1401. var
  1402. header:TElfHeader;
  1403. begin
  1404. result:=ET_NONE;
  1405. if not FReader.read(header,sizeof(header)) then
  1406. begin
  1407. InputError('Can''t read ELF header');
  1408. exit;
  1409. end;
  1410. if (header.e_ident[EI_MAG0]<>ELFMAG0) or (header.e_ident[EI_MAG1]<>ELFMAG1) or
  1411. (header.e_ident[EI_MAG2]<>ELFMAG2) or (header.e_ident[EI_MAG3]<>ELFMAG3) then
  1412. begin
  1413. InputError('Illegal ELF magic');
  1414. exit;
  1415. end;
  1416. if (header.e_ident[EI_VERSION]<>1) then
  1417. begin
  1418. InputError('Unknown ELF file version');
  1419. exit;
  1420. end;
  1421. if (header.e_ident[EI_CLASS]<>ELFCLASS) then
  1422. begin
  1423. InputError('Wrong ELF file class (32/64 bit mismatch)');
  1424. exit;
  1425. end;
  1426. if (header.e_ident[EI_DATA]<>1+ord(target_info.endian=endian_big)) then
  1427. begin
  1428. InputError('ELF endianness does not match target');
  1429. exit;
  1430. end;
  1431. MaybeSwapHeader(header);
  1432. if (header.e_version<>1) then
  1433. begin
  1434. InputError('Unknown ELF data version');
  1435. exit;
  1436. end;
  1437. if (header.e_machine<>ElfTarget.machine_code) then
  1438. begin
  1439. InputError('ELF file is for different CPU');
  1440. exit;
  1441. end;
  1442. nsects:=header.e_shnum;
  1443. shentsize:=header.e_shentsize;
  1444. shoffset:=header.e_shoff;
  1445. shstrndx:=header.e_shstrndx;
  1446. result:=header.e_type;
  1447. end;
  1448. procedure TElfObjInput.LoadDynamic(const shdr:TElfsechdr;objdata:TObjData);
  1449. var
  1450. dt: TElfDyn;
  1451. i: longint;
  1452. begin
  1453. if (shdr.sh_entsize<>sizeof(TElfDyn)) then
  1454. InternalError(2012071403);
  1455. FReader.Seek(shdr.sh_offset);
  1456. for i:=0 to (shdr.sh_size div shdr.sh_entsize)-1 do
  1457. begin
  1458. FReader.Read(dt,sizeof(TElfDyn));
  1459. MaybeSwapElfDyn(dt);
  1460. case dt.d_tag of
  1461. DT_NULL:
  1462. break;
  1463. DT_SONAME:
  1464. TElfObjData(objdata).FName:=string(PChar(@strtab[dt.d_ptr]));
  1465. DT_NEEDED:
  1466. ;
  1467. end;
  1468. end;
  1469. end;
  1470. function TElfObjInput.ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;
  1471. var
  1472. i,j,strndx,dynndx,
  1473. versymndx,verdefndx,verneedndx: longint;
  1474. objsec: TObjSection;
  1475. grp: TObjSectionGroup;
  1476. tmp: longword;
  1477. count: longint;
  1478. vd: TElfverdef;
  1479. vda: TElfverdaux;
  1480. vdoffset: aword;
  1481. begin
  1482. FReader:=AReader;
  1483. InputFileName:=AReader.FileName;
  1484. result:=false;
  1485. i:=LoadHeader;
  1486. if (i=ET_NONE) then { error message already given in this case }
  1487. exit;
  1488. if (i<>ET_REL) and (i<>ET_DYN) then
  1489. begin
  1490. InputError('Not a relocatable or dynamic ELF file');
  1491. exit;
  1492. end;
  1493. dynobj:=(i=ET_DYN);
  1494. if shentsize<>sizeof(TElfsechdr) then
  1495. InternalError(2012062701);
  1496. if dynobj then
  1497. begin
  1498. objdata:=TElfDynamicObjData.Create(InputFilename);
  1499. verdefs:=TElfDynamicObjData(objdata).versiondefs;
  1500. end
  1501. else
  1502. objdata:=CObjData.Create(InputFilename);
  1503. FSecTbl:=AllocMem(nsects*sizeof(TSectionRec));
  1504. FLoaded:=AllocMem(nsects*sizeof(boolean));
  1505. SetLength(shdrs,nsects);
  1506. FReader.Seek(shoffset);
  1507. if not FReader.Read(shdrs[0],nsects*sizeof(TElfsechdr)) then
  1508. begin
  1509. InputError('Can''t read ELF section headers');
  1510. exit;
  1511. end;
  1512. if source_info.endian<>target_info.endian then
  1513. for i:=0 to nsects-1 do
  1514. MaybeSwapSecHeader(shdrs[i]);
  1515. { First, load the .shstrtab section }
  1516. if shstrndx>=nsects then
  1517. InternalError(2012060201);
  1518. if shdrs[shstrndx].sh_type<>SHT_STRTAB then
  1519. InternalError(2012060202);
  1520. shstrtablen:=shdrs[shstrndx].sh_size;
  1521. GetMem(shstrtab,shstrtablen);
  1522. FReader.seek(shdrs[shstrndx].sh_offset);
  1523. FReader.read(shstrtab^,shstrtablen);
  1524. FLoaded[shstrndx]:=True;
  1525. { Locate the symtable, it is typically at the end so loop backwards.
  1526. Load the strings, postpone symtable itself until done with sections.
  1527. Note that is is legal to have no symtable.
  1528. For DSO, locate .dynsym instead, this one is near the beginning, but
  1529. overall number of sections won't be big. }
  1530. symtabndx:=0;
  1531. for i:=nsects-1 downto 1 do
  1532. begin
  1533. if (shdrs[i].sh_type<>symsectypes[dynobj]) then
  1534. continue;
  1535. if (shdrs[i].sh_entsize<>sizeof(TElfSymbol)) then
  1536. InternalError(2012060213);
  1537. if shdrs[i].sh_link>=nsects then
  1538. InternalError(2012062702);
  1539. strndx:=shdrs[i].sh_link;
  1540. if shdrs[strndx].sh_type<>SHT_STRTAB then
  1541. InternalError(2012062703);
  1542. strtablen:=shdrs[strndx].sh_size;
  1543. GetMem(strtab,strtablen);
  1544. FReader.seek(shdrs[strndx].sh_offset);
  1545. FReader.read(strtab^,strtablen);
  1546. symtaboffset:=shdrs[i].sh_offset;
  1547. syms:=shdrs[i].sh_size div sizeof(TElfSymbol);
  1548. localsyms:=shdrs[i].sh_info;
  1549. FLoaded[i]:=True;
  1550. FLoaded[strndx]:=True;
  1551. symtabndx:=i;
  1552. break;
  1553. end;
  1554. if dynobj then
  1555. begin
  1556. if symtabndx=0 then
  1557. InternalError(2012110707);
  1558. { Locate .dynamic and version sections. Expect a single one of a kind. }
  1559. dynndx:=0;
  1560. versymndx:=0;
  1561. verdefndx:=0;
  1562. verneedndx:=0;
  1563. for i:=nsects-1 downto 0 do
  1564. begin
  1565. case shdrs[i].sh_type of
  1566. SHT_DYNAMIC:
  1567. begin
  1568. if dynndx<>0 then
  1569. InternalError(2012102001);
  1570. dynndx:=i;
  1571. if (shdrs[dynndx].sh_link<>strndx) then
  1572. InternalError(2012071402);
  1573. LoadDynamic(shdrs[dynndx],objdata);
  1574. end;
  1575. SHT_GNU_versym:
  1576. begin
  1577. if versymndx<>0 then
  1578. InternalError(2012102002);
  1579. versymndx:=i;
  1580. if shdrs[i].sh_entsize<>sizeof(word) then
  1581. InternalError(2012102003);
  1582. if shdrs[i].sh_link<>symtabndx then
  1583. InternalError(2012102004);
  1584. if shdrs[i].sh_size<>syms*sizeof(word) then
  1585. InternalError(2012102005);
  1586. GetMem(symversions,shdrs[i].sh_size);
  1587. FReader.seek(shdrs[i].sh_offset);
  1588. FReader.read(symversions^,shdrs[i].sh_size);
  1589. if source_info.endian<>target_info.endian then
  1590. for j:=0 to syms-1 do
  1591. SwapEndian(symversions[j]);
  1592. end;
  1593. SHT_GNU_verdef:
  1594. begin
  1595. if verdefndx<>0 then
  1596. InternalError(2012102006);
  1597. verdefndx:=i;
  1598. if shdrs[i].sh_link<>strndx then
  1599. InternalError(2012120501);
  1600. vdoffset:=shdrs[i].sh_offset;
  1601. { TODO: can we rely on sh_info, or must read until vd_next=0? }
  1602. for j:=1 to shdrs[i].sh_info do
  1603. begin
  1604. FReader.seek(vdoffset);
  1605. FReader.Read(vd,sizeof(TElfverdef));
  1606. MaybeSwapElfverdef(vd);
  1607. if vd.vd_version<>VER_DEF_CURRENT then
  1608. InternalError(2012120502);
  1609. FReader.seek(vdoffset+vd.vd_aux);
  1610. vdoffset:=vdoffset+vd.vd_next;
  1611. { First verdaux entry holds name of version (unless VER_FLG_BASE flag is set),
  1612. subsequent one(s) point to parent(s). For our purposes, version hierarchy
  1613. looks irrelevant. }
  1614. FReader.Read(vda,sizeof(TElfverdaux));
  1615. MaybeSwapElfverdaux(vda);
  1616. if vda.vda_name>=strtablen then
  1617. InternalError(2012120503);
  1618. if (vd.vd_flags and VER_FLG_BASE)<>0 then
  1619. continue;
  1620. { Assuming verdef indices assigned continuously starting from 2,
  1621. at least BFD produces files that way. }
  1622. if verdefs.count<>vd.vd_ndx then
  1623. InternalError(2012120504);
  1624. TElfVersionDef.Create(verdefs,string(PChar(@strtab[vda.vda_name])));
  1625. end;
  1626. end;
  1627. SHT_GNU_verneed:
  1628. begin
  1629. if verneedndx<>0 then
  1630. InternalError(2012102007);
  1631. verneedndx:=i;
  1632. //sh_link->.dynstr
  1633. //sh_info->number of entries
  1634. end;
  1635. end;
  1636. end;
  1637. if dynndx=0 then
  1638. InternalError(2012071401);
  1639. { for DSO, we aren't interested in actual sections, but need to a dummy one
  1640. to maintain integrity. }
  1641. objsec:=TElfObjSection.create_ext(objdata,'*DSO*',SHT_PROGBITS,0,0,0);
  1642. for i:=1 to nsects-1 do
  1643. FSecTbl[i].sec:=objsec;
  1644. { load the symtable }
  1645. FReader.Seek(symtaboffset+sizeof(TElfSymbol));
  1646. LoadSymbols(objdata,syms,localsyms);
  1647. result:=True;
  1648. exit;
  1649. end;
  1650. { assume stack is executable until proven otherwise }
  1651. objdata.ExecStack:=True;
  1652. { Process section headers }
  1653. for i:=1 to nsects-1 do
  1654. if not FLoaded[i] then
  1655. LoadSection(shdrs[i],i,objdata);
  1656. { load the content }
  1657. ReadSectionContent(objdata);
  1658. { load the symtable }
  1659. FReader.Seek(symtaboffset+sizeof(TElfSymbol));
  1660. LoadSymbols(objdata,syms,localsyms);
  1661. { finish relocations }
  1662. for i:=0 to objdata.ObjSectionList.Count-1 do
  1663. begin
  1664. objsec:=TObjSection(objdata.ObjsectionList[i]);
  1665. { skip debug sections }
  1666. if (oso_debug in objsec.SecOptions) and
  1667. (cs_link_strip in current_settings.globalswitches) and
  1668. not(cs_link_separate_dbg_file in current_settings.globalswitches) then
  1669. continue;
  1670. if FSecTbl[objsec.index].relocpos>0 then
  1671. LoadRelocations(FSecTbl[objsec.index]);
  1672. end;
  1673. { finish processing section groups, if any }
  1674. if Assigned(objdata.GroupsList) then
  1675. begin
  1676. for i:=0 to objdata.GroupsList.Count-1 do
  1677. begin
  1678. grp:=TObjSectionGroup(objData.GroupsList[i]);
  1679. FReader.Seek(shdrs[i+1].sh_offset);
  1680. { first dword is flags }
  1681. FReader.Read(tmp,sizeof(longword));
  1682. if source_info.endian<>target_info.endian then
  1683. tmp:=SwapEndian(tmp);
  1684. if (tmp and GRP_COMDAT)<>0 then
  1685. grp.IsComdat:=true;
  1686. count:=(shdrs[i+1].sh_size div sizeof(longword))-1;
  1687. SetLength(grp.members,count);
  1688. for j:=0 to count-1 do
  1689. begin
  1690. FReader.Read(tmp,sizeof(longword));
  1691. if source_info.endian<>target_info.endian then
  1692. tmp:=SwapEndian(tmp);
  1693. if (tmp>=nsects) then
  1694. InternalError(2012110805);
  1695. objsec:=FSecTbl[tmp].sec;
  1696. if (objsec=nil) then
  1697. InternalError(2012110806);
  1698. if (TElfObjSection(objsec).shflags and SHF_GROUP)=0 then
  1699. InternalError(2012110807);
  1700. grp.members[j]:=objsec;
  1701. objsec.Group:=grp;
  1702. end;
  1703. end;
  1704. end;
  1705. result:=True;
  1706. end;
  1707. class function TElfObjInput.CanReadObjData(AReader:TObjectreader):boolean;
  1708. var
  1709. header: TElfHeader;
  1710. begin
  1711. result:=false;
  1712. if AReader.Read(header,sizeof(header)) then
  1713. begin;
  1714. if (header.e_ident[EI_MAG0]=ELFMAG0) and (header.e_ident[EI_MAG1]=ELFMAG1) and
  1715. (header.e_ident[EI_MAG2]=ELFMAG2) and (header.e_ident[EI_MAG3]=ELFMAG3) then
  1716. { TODO: check additional fields }
  1717. result:=true;
  1718. end;
  1719. AReader.Seek(0);
  1720. end;
  1721. {*****************************************************************************
  1722. TElfExeOutput
  1723. *****************************************************************************}
  1724. constructor TElfExeOutput.Create;
  1725. begin
  1726. inherited Create;
  1727. CObjData:=TElfObjData;
  1728. CExeSection:=TElfExeSection;
  1729. {$ifdef cpu64}
  1730. MaxMemPos:=Qword($FFFFFFFFFFFFFFFF);
  1731. //MaxMemPos:=$7EFFFFFF; { As specified by SysV AMD64 ABI for small memory model }
  1732. {$else cpu64}
  1733. MaxMemPos:=$7FFFFFFF;
  1734. {$endif cpu64}
  1735. SectionMemAlign:=$20;
  1736. SectionDataAlign:=$20;
  1737. segmentlist:=TFPObjectList.Create(True);
  1738. neededlist:=TFPHashList.Create;
  1739. end;
  1740. destructor TElfExeOutput.Destroy;
  1741. begin
  1742. neededlist.Free;
  1743. segmentlist.Free;
  1744. dynsymlist.Free;
  1745. dynreloclist.Free;
  1746. if assigned(dynsymnames) then
  1747. FreeMem(dynsymnames);
  1748. stringdispose(FInterpreter);
  1749. inherited Destroy;
  1750. end;
  1751. function TElfExeOutput.AttachSection(objsec:TObjSection):TElfExeSection;
  1752. begin
  1753. objsec.SecOptions:=[oso_keep];
  1754. result:=TElfExeSection(FindExeSection(objsec.name));
  1755. if result=nil then
  1756. result:=TElfExeSection.Create(ExeSectionList,objsec.name);
  1757. result.AddObjSection(objsec);
  1758. end;
  1759. function TElfExeOutput.CreateSegment(atype,aflags,aalign:longword):TElfSegment;
  1760. begin
  1761. result:=TElfSegment.Create(atype,aflags,aalign);
  1762. segmentlist.add(result);
  1763. end;
  1764. procedure TElfExeOutput.WriteHeader;
  1765. var
  1766. header: TElfHeader;
  1767. begin
  1768. FillChar(header,sizeof(header),0);
  1769. header.e_ident[EI_MAG0]:=ELFMAG0; { = #127'ELF' }
  1770. header.e_ident[EI_MAG1]:=ELFMAG1;
  1771. header.e_ident[EI_MAG2]:=ELFMAG2;
  1772. header.e_ident[EI_MAG3]:=ELFMAG3;
  1773. header.e_ident[EI_CLASS]:=ELFCLASS;
  1774. if target_info.endian=endian_big then
  1775. header.e_ident[EI_DATA]:=ELFDATA2MSB
  1776. else
  1777. header.e_ident[EI_DATA]:=ELFDATA2LSB;
  1778. header.e_ident[EI_VERSION]:=1;
  1779. if IsSharedLibrary then
  1780. header.e_type:=ET_DYN
  1781. else
  1782. header.e_type:=ET_EXEC;
  1783. header.e_machine:=ElfTarget.machine_code;
  1784. header.e_version:=1;
  1785. header.e_phoff:=sizeof(TElfHeader);
  1786. header.e_shoff:=shoffset;
  1787. header.e_shstrndx:=ExeSectionList.IndexOf(shstrtabsect.ExeSection)+1;
  1788. header.e_shnum:=ExeSectionList.Count+1;
  1789. header.e_phnum:=segmentlist.count;
  1790. header.e_ehsize:=sizeof(telfheader);
  1791. if assigned(EntrySym) then
  1792. header.e_entry:=EntrySym.Address;
  1793. header.e_shentsize:=sizeof(telfsechdr);
  1794. header.e_phentsize:=sizeof(telfproghdr);
  1795. MaybeSwapHeader(header);
  1796. FWriter.Write(header,sizeof(header));
  1797. end;
  1798. procedure TElfExeOutput.exesection_write_header(p:TObject;arg:Pointer);
  1799. var
  1800. shdr: TElfsechdr;
  1801. exesec: TElfExeSection absolute p;
  1802. begin
  1803. FillChar(shdr,sizeof(shdr),0);
  1804. shdr.sh_name:=exesec.shstridx;
  1805. if (ExeWriteMode=ewm_dbgonly) and
  1806. (exesec.SecOptions*[oso_debug,oso_debug_copy]=[]) then
  1807. shdr.sh_type:=SHT_NOBITS
  1808. else
  1809. shdr.sh_type:=exesec.shtype;
  1810. shdr.sh_flags:=exesec.shflags;
  1811. if (oso_load in exesec.SecOptions) then
  1812. shdr.sh_addr:=exesec.MemPos;
  1813. shdr.sh_offset:=exesec.DataPos;
  1814. shdr.sh_size:=exesec.Size;
  1815. shdr.sh_link:=exesec.shlink;
  1816. shdr.sh_info:=exesec.shinfo;
  1817. shdr.sh_addralign:=exesec.SecAlign;
  1818. shdr.sh_entsize:=exesec.shentsize;
  1819. MaybeSwapSecHeader(shdr);
  1820. FWriter.Write(shdr,sizeof(shdr));
  1821. end;
  1822. procedure TElfExeOutput.segment_write_header(p:TObject;arg:Pointer);
  1823. var
  1824. phdr: TElfproghdr;
  1825. seg: TElfSegment absolute p;
  1826. begin
  1827. FillChar(phdr,sizeof(phdr),0);
  1828. phdr.p_type:=seg.ptype;
  1829. phdr.p_flags:=seg.pflags;
  1830. phdr.p_align:=seg.align;
  1831. phdr.p_offset:=seg.DataPos;
  1832. phdr.p_filesz:=seg.DataSize;
  1833. phdr.p_memsz:=seg.MemSize;
  1834. phdr.p_vaddr:=seg.MemPos;
  1835. phdr.p_paddr:=seg.MemPos;
  1836. MaybeSwapHeader(phdr);
  1837. FWriter.Write(phdr,sizeof(phdr));
  1838. end;
  1839. procedure TElfExeOutput.WriteStaticSymtable;
  1840. var
  1841. i: longint;
  1842. sec: TElfExeSection;
  1843. exesym: TExeSymbol;
  1844. begin
  1845. if assigned(tlsseg) then
  1846. symtab.tlsbase:=tlsseg.MemPos;
  1847. for i:=0 to ExeSectionList.Count-1 do
  1848. begin
  1849. sec:=TElfExeSection(ExeSectionList[i]);
  1850. { Must not write symbols for internal sections like .symtab }
  1851. if (sec.shtype in [SHT_SYMTAB,SHT_STRTAB,SHT_REL,SHT_RELA]) then
  1852. continue;
  1853. sec.secsymidx:=symtab.symidx;
  1854. symtab.writeInternalSymbol(sec.mempos,0,STT_SECTION,sec.secshidx);
  1855. end;
  1856. { local symbols first }
  1857. for i:=0 to ExeSymbolList.Count-1 do
  1858. begin
  1859. exesym:=TExeSymbol(ExeSymbolList[i]);
  1860. if (exesym.objsymbol.bind=AB_LOCAL) and (exesym.objsymbol.typ<>AT_LABEL) then
  1861. symtab.WriteSymbol(exesym.objsymbol);
  1862. end;
  1863. { Global Symbols }
  1864. for i:=0 to ExeSymbolList.Count-1 do
  1865. begin
  1866. exesym:=TExeSymbol(ExeSymbolList[i]);
  1867. if (exesym.objsymbol.bind<>AB_LOCAL) then
  1868. symtab.WriteSymbol(exesym.objsymbol);
  1869. end;
  1870. { update exe section properties }
  1871. symtab.ExeSection.size:=symtab.size;
  1872. TElfExeSection(symtab.ExeSection).shinfo:=symtab.shinfo;
  1873. TElfExeSection(symtab.ExeSection).shlink:=ExeSectionList.IndexOf(symtab.fstrsec.ExeSection)+1;
  1874. symtab.fstrsec.ExeSection.Size:=symtab.fstrsec.size;
  1875. end;
  1876. procedure TElfExeOutput.MapSectionsToSegments;
  1877. var
  1878. seg: TElfSegment;
  1879. exesec: TExeSection;
  1880. i: longint;
  1881. begin
  1882. if (not IsSharedLibrary) and assigned(interpobjsec) then
  1883. begin
  1884. phdrseg:=CreateSegment(PT_PHDR,PF_R or PF_X,sizeof(pint));
  1885. seg:=CreateSegment(PT_INTERP,PF_R,1);
  1886. seg.Add(interpobjsec.ExeSection);
  1887. end;
  1888. textseg:=CreateSegment(PT_LOAD,PF_X or PF_R,ElfTarget.max_page_size);
  1889. dataseg:=CreateSegment(PT_LOAD,PF_R or PF_W,ElfTarget.max_page_size);
  1890. for i:=0 to ExeSectionList.Count-1 do
  1891. begin
  1892. exesec:=TExeSection(ExeSectionList[i]);
  1893. if (oso_load in exesec.SecOptions) then
  1894. begin
  1895. if (TElfExeSection(exesec).shflags and SHF_TLS)<>0 then
  1896. begin
  1897. if tlsseg=nil then
  1898. tlsseg:=CreateSegment(PT_TLS,PF_R,sizeof(pint));
  1899. tlsseg.add(exesec);
  1900. end;
  1901. { TODO: at least on Linux, ld seems to drop .note.ABI-tag for static executables.
  1902. (Logic is as follows: there is no .note.ABI-tag section in ld script, so it
  1903. is processed as orphan section. As such, it is placed after .interp.
  1904. For static executables .interp is dropped, and it looks like there's nowhere to
  1905. place .note.ABI-tag in this case)
  1906. Always including it doesn't harm though (except increasing file size). }
  1907. if TElfExeSection(exesec).shtype=SHT_NOTE then
  1908. begin
  1909. if noteseg=nil then
  1910. noteseg:=CreateSegment(PT_NOTE,PF_R,4);
  1911. noteseg.Add(exesec);
  1912. Include(exesec.SecOptions,oso_debug_copy);
  1913. end;
  1914. if (oso_executable in exesec.SecOptions) or
  1915. not (oso_write in exesec.SecOptions) then
  1916. textseg.add(exesec)
  1917. else
  1918. dataseg.add(exesec);
  1919. end;
  1920. end;
  1921. if dynamiclink then
  1922. begin
  1923. seg:=CreateSegment(PT_DYNAMIC,PF_R or PF_W,sizeof(pint));
  1924. seg.add(dynamicsec.ExeSection);
  1925. end;
  1926. { stack flags }
  1927. CreateSegment(PT_GNU_STACK,PF_R or PF_W or (PF_X*ord(ExecStack)),sizeof(pint));
  1928. end;
  1929. procedure TElfExeOutput.make_dynamic_if_undefweak(exesym:TExeSymbol);
  1930. begin
  1931. if (exesym.dynindex=0) and (exesym.state=symstate_undefweak) and
  1932. not (cs_link_staticflag in current_settings.globalswitches) then
  1933. exesym.dynindex:=dynsymlist.add(exesym)+1;
  1934. end;
  1935. function TElfExeOutput.AllocGOTSlot(objsym:TObjSymbol):boolean;
  1936. var
  1937. exesym: TExeSymbol;
  1938. begin
  1939. result:=false;
  1940. exesym:=objsym.exesymbol;
  1941. { Although local symbols should not be accessed through GOT,
  1942. this isn't strictly forbidden. In this case we need to fake up
  1943. the exesym to store the GOT offset in it.
  1944. TODO: name collision; maybe use a different symbol list object? }
  1945. if exesym=nil then
  1946. begin
  1947. exesym:=TExeSymbol.Create(ExeSymbolList,objsym.name+'*local*');
  1948. exesym.objsymbol:=objsym;
  1949. objsym.exesymbol:=exesym;
  1950. end;
  1951. if exesym.GotOffset>0 then
  1952. exit;
  1953. gotobjsec.alloc(sizeof(pint));
  1954. exesym.GotOffset:=gotobjsec.size;
  1955. { In shared library, every GOT entry needs a RELATIVE dynamic reloc,
  1956. imported/exported symbols need GLOB_DAT instead. For executables,
  1957. only the latter applies. }
  1958. if IsSharedLibrary or (exesym.dynindex>0) then
  1959. dynrelocsec.alloc(dynrelocsec.shentsize);
  1960. result:=true;
  1961. end;
  1962. procedure TElfExeOutput.PrepareGOT;
  1963. var
  1964. i,j,k: longint;
  1965. objsec: TElfObjSection;
  1966. exesec: TExeSection;
  1967. begin
  1968. for i:=0 to ExeSectionList.Count-1 do
  1969. begin
  1970. exesec:=TExeSection(ExeSectionList[i]);
  1971. for j:=0 to exesec.ObjSectionlist.count-1 do
  1972. begin
  1973. objsec:=TElfObjSection(exesec.ObjSectionlist[j]);
  1974. { ignore linker-generated and debug sections }
  1975. if (objsec.objdata=internalobjdata) or (oso_debug in objsec.SecOptions) then
  1976. continue;
  1977. if not objsec.Used then
  1978. internalerror(2012060901);
  1979. k:=0;
  1980. while k<objsec.ObjRelocations.Count do
  1981. begin
  1982. GOTRelocPass1(objsec,k);
  1983. inc(k);
  1984. end;
  1985. end;
  1986. end;
  1987. { remember sizes for sanity checking }
  1988. gotsize:=gotobjsec.size;
  1989. if assigned(dynrelocsec) then
  1990. dynrelsize:=dynrelocsec.size
  1991. else
  1992. dynrelsize:=0;
  1993. end;
  1994. procedure TElfExeOutput.CreateGOTSection;
  1995. begin
  1996. gotpltobjsec:=TElfObjSection.create_ext(internalObjData,'.got.plt',
  1997. SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(pint));
  1998. gotobjsec:=TElfObjSection.create_ext(internalObjData,'.got',
  1999. SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(pint));
  2000. gotobjsec.SecOptions:=[oso_keep];
  2001. { GOT symbol and reserved .got.plt entries }
  2002. internalObjData.SetSection(gotpltobjsec);
  2003. gotsymbol:=internalObjData.SymbolDefine('_GLOBAL_OFFSET_TABLE_',AB_GLOBAL,AT_DATA);
  2004. gotpltobjsec.writeZeros(3*sizeof(pint));
  2005. end;
  2006. procedure TElfExeOutput.Load_Start;
  2007. begin
  2008. inherited Load_Start;
  2009. dynsymlist:=TFPObjectList.Create(False);
  2010. CreateGOTSection;
  2011. end;
  2012. procedure TElfExeOutput.Load_DynamicObject(objdata:TObjData;asneeded:boolean);
  2013. var
  2014. i: longint;
  2015. exesym: TExeSymbol;
  2016. objsym: TObjSymbol;
  2017. needed: boolean;
  2018. begin
  2019. Comment(v_debug,'Dynamic object: '+objdata.name);
  2020. needed:=false;
  2021. for i:=0 to UnresolvedExeSymbols.Count-1 do
  2022. begin
  2023. exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
  2024. if not (exesym.State in [symstate_undefined,symstate_undefweak]) then
  2025. continue;
  2026. objsym:=TObjSymbol(objdata.ObjSymbolList.Find(exesym.name));
  2027. if assigned(objsym) then
  2028. begin
  2029. exesym.State:=symstate_defined;
  2030. exesym.dynindex:=dynsymlist.Add(exesym)+1;
  2031. needed:=true;
  2032. end;
  2033. end;
  2034. if (needed or (not asneeded)) and
  2035. (neededlist.Find(objdata.name)=nil) then
  2036. neededlist.Add(objdata.name,objdata);
  2037. end;
  2038. procedure TElfExeOutput.Order_Start;
  2039. begin
  2040. inherited Order_Start;
  2041. dynamiclink:=IsSharedLibrary or (dynsymlist.count>0) or
  2042. (
  2043. (UnresolvedExeSymbols.Count>0) and
  2044. not (cs_link_staticflag in current_settings.globalswitches)
  2045. );
  2046. if dynamiclink then
  2047. InitDynlink;
  2048. if dynamiclink or (IndirectObjSymbols.Count>0) then
  2049. CreatePLT;
  2050. end;
  2051. procedure TElfExeOutput.Order_end;
  2052. procedure set_oso_keep(const s:string);
  2053. var
  2054. exesec:TExeSection;
  2055. objsec:TObjSection;
  2056. i:longint;
  2057. begin
  2058. exesec:=TExeSection(ExeSectionList.Find(s));
  2059. if assigned(exesec) then
  2060. begin
  2061. for i:=0 to exesec.ObjSectionList.Count-1 do
  2062. begin
  2063. objsec:=TObjSection(exesec.ObjSectionList[i]);
  2064. { ignore sections used for symbol definition }
  2065. if oso_data in objsec.SecOptions then
  2066. objsec.SecOptions:=[oso_keep];
  2067. end;
  2068. end;
  2069. end;
  2070. begin
  2071. inherited Order_end;
  2072. set_oso_keep('.init');
  2073. set_oso_keep('.fini');
  2074. set_oso_keep('.jcr');
  2075. set_oso_keep('.ctors');
  2076. set_oso_keep('.dtors');
  2077. set_oso_keep('.preinit_array');
  2078. set_oso_keep('.init_array');
  2079. set_oso_keep('.fini_array');
  2080. set_oso_keep('.eh_frame');
  2081. { let .dynamic reference other dynamic sections so they aren't marked
  2082. for removal as unused }
  2083. if dynamiclink then
  2084. WriteDynamicTags;
  2085. end;
  2086. procedure TElfExeOutput.AfterUnusedSectionRemoval;
  2087. var
  2088. i:longint;
  2089. exesym:TExeSymbol;
  2090. objsym:TObjSymbol;
  2091. objsec: TObjSection;
  2092. begin
  2093. { Unused section removal sets Used property of referenced exesymbols.
  2094. Remaining ones can be removed. }
  2095. for i:=0 to dynsymlist.count-1 do
  2096. begin
  2097. exesym:=TExeSymbol(dynsymlist[i]);
  2098. if assigned(exesym.ObjSymbol.ObjSection) then // an exported symbol
  2099. continue;
  2100. if not exesym.used then
  2101. begin
  2102. dynsymlist[i]:=nil;
  2103. exesym.dynindex:=0;
  2104. end;
  2105. end;
  2106. dynsymlist.Pack;
  2107. { reindex }
  2108. for i:=0 to dynsymlist.count-1 do
  2109. TExeSymbol(dynsymlist[i]).dynindex:=i+1;
  2110. { Drop unresolved symbols that aren't referenced, assign dynamic
  2111. indices to remaining ones, but not if linking with -Xt.
  2112. TODO: behavior of .so with -Xt ? }
  2113. if (cs_link_staticflag in current_settings.globalswitches) then
  2114. UnresolvedExeSymbols.Clear
  2115. else
  2116. for i:=0 to UnresolvedExeSymbols.Count-1 do
  2117. begin
  2118. exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
  2119. if exesym.used then
  2120. begin
  2121. if exesym.dynindex<>0 then
  2122. InternalError(2012062301);
  2123. exesym.dynindex:=dynsymlist.add(exesym)+1;
  2124. exesym.state:=symstate_defined;
  2125. end
  2126. else
  2127. UnresolvedExeSymbols[i]:=nil;
  2128. end;
  2129. UnresolvedExeSymbols.Pack;
  2130. { Scan relocations to determine size of GOT, dynamic reloc section, etc. }
  2131. PrepareGOT;
  2132. { Write required PLT entries }
  2133. for i:=0 to dynsymlist.Count-1 do
  2134. begin
  2135. exesym:=TExeSymbol(dynsymlist[i]);
  2136. if assigned(exesym.ObjSymbol.objsection) then // an exported symbol
  2137. continue;
  2138. { if there's no PLT references to symbol, then PLT entry isn't needed }
  2139. { !! Does not work correctly yet !! }
  2140. // if (exesym.objsymbol.refs and symref_plt)=0 then
  2141. // continue;
  2142. { This symbol has a valid address to which relocations are resolved,
  2143. but it remains (weak)external when written to dynamic symtable. }
  2144. objsym:=internalobjdata.CreateSymbol(exesym.name);
  2145. objsym.typ:=AT_FUNCTION;
  2146. objsym.bind:=exesym.ObjSymbol.bind; { AB_EXTERNAL or AB_WEAK_EXTERNAL }
  2147. objsym.offset:=pltobjsec.size;
  2148. objsym.objsection:=pltobjsec;
  2149. exesym.ObjSymbol:=objsym;
  2150. WritePLTEntry(exesym);
  2151. end;
  2152. { Handle indirect symbols }
  2153. for i:=0 to IndirectObjSymbols.Count-1 do
  2154. begin
  2155. objsym:=TObjSymbol(IndirectObjSymbols[i]);
  2156. objsec:=objsym.ExeSymbol.ObjSymbol.objsection;
  2157. objsym.bind:=AB_EXTERNAL; { cheat FixupSymbols }
  2158. if (oso_plt in objsec.SecOptions) then
  2159. continue;
  2160. WriteIndirectPLTEntry(objsym.ExeSymbol);
  2161. end;
  2162. FixupSymbols;
  2163. if dynamiclink then
  2164. WriteDynamicSymbolsHash;
  2165. { Create .shstrtab section, which is needed in both exe and .dbg files }
  2166. shstrtabsect:=TElfObjSection.Create_ext(internalObjData,'.shstrtab',SHT_STRTAB,0,1,0);
  2167. shstrtabsect.SecOptions:=[oso_debug_copy];
  2168. AttachSection(shstrtabsect);
  2169. { Create the static symtable (.symtab and .strtab) }
  2170. if (cs_link_separate_dbg_file in current_settings.globalswitches) or
  2171. not(cs_link_strip in current_settings.globalswitches) then
  2172. begin
  2173. symtab:=TElfSymtab.Create(internalObjData,esk_exe);
  2174. symtab.SecOptions:=[oso_debug];
  2175. symtab.fstrsec.SecOptions:=[oso_debug];
  2176. AttachSection(symtab);
  2177. AttachSection(symtab.fstrsec);
  2178. end;
  2179. { Re-enable sections which end up to contain some data
  2180. (.got, .rel[a].dyn, .rel[a].plt (includes .rel[a].iplt) and .hash }
  2181. if gotobjsec.size<>0 then
  2182. Exclude(gotobjsec.ExeSection.SecOptions,oso_disabled);
  2183. if assigned(dynrelocsec) and (dynrelocsec.size<>0) then
  2184. Exclude(dynrelocsec.ExeSection.SecOptions,oso_disabled);
  2185. if assigned(pltrelocsec) and (pltrelocsec.size>0) then
  2186. Exclude(pltrelocsec.ExeSection.SecOptions,oso_disabled);
  2187. if assigned(ipltrelocsec) and (ipltrelocsec.size>0) then
  2188. Exclude(ipltrelocsec.ExeSection.SecOptions,oso_disabled);
  2189. if assigned(hashobjsec) then
  2190. Exclude(hashobjsec.ExeSection.SecOptions,oso_disabled);
  2191. if assigned(symversec) and (symversec.size<>0) then
  2192. Exclude(symversec.ExeSection.SecOptions,oso_disabled);
  2193. if assigned(verneedsec) and (verneedsec.size<>0) then
  2194. Exclude(verneedsec.ExeSection.SecOptions,oso_disabled);
  2195. if assigned(verdefsec) and (verdefsec.size<>0) then
  2196. Exclude(verneedsec.ExeSection.SecOptions,oso_disabled);
  2197. RemoveDisabledSections;
  2198. MapSectionsToSegments;
  2199. if dynamiclink then
  2200. FinishDynamicTags;
  2201. end;
  2202. procedure TElfExeOutput.MemPos_Start;
  2203. var
  2204. i,j: longint;
  2205. dynstrndx,dynsymndx: longword;
  2206. seg: TElfSegment;
  2207. exesec: TElfExeSection;
  2208. objsec: TObjSection;
  2209. tempmempos: qword;
  2210. begin
  2211. { Remove any existing .shstrtab contents }
  2212. if (shstrtabsect.size>0) then
  2213. begin
  2214. shstrtabsect.ReleaseData;
  2215. shstrtabsect.Size:=0;
  2216. shstrtabsect.SecOptions:=[oso_data];
  2217. end;
  2218. { Assign section indices and fill .shstrtab
  2219. List of sections cannot be modified after this point. }
  2220. shstrtabsect.writezeros(1);
  2221. for i:=0 to ExeSectionList.Count-1 do
  2222. begin
  2223. exesec:=TElfExeSection(ExeSectionList[i]);
  2224. exesec.shstridx:=shstrtabsect.writestr(exesec.Name);
  2225. exesec.secshidx:=i+1;
  2226. end;
  2227. if dynamiclink then
  2228. begin
  2229. { fixup sh_link/sh_info members of various dynamic sections }
  2230. dynstrndx:=TElfExeSection(dynsymtable.fstrsec.ExeSection).secshidx;
  2231. dynsymndx:=TElfExeSection(dynsymtable.ExeSection).secshidx;
  2232. TElfExeSection(hashobjsec.ExeSection).shlink:=dynsymndx;
  2233. TElfExeSection(dynamicsec.ExeSection).shlink:=dynstrndx;
  2234. TElfExeSection(dynsymtable.ExeSection).shlink:=dynstrndx;
  2235. if assigned(pltrelocsec) then
  2236. begin
  2237. TElfExeSection(pltrelocsec.ExeSection).shlink:=dynsymndx;
  2238. TElfExeSection(pltrelocsec.ExeSection).shinfo:=TElfExeSection(pltobjsec.ExeSection).secshidx;
  2239. end;
  2240. if assigned(dynrelocsec) and assigned(dynrelocsec.ExeSection) then
  2241. TElfExeSection(dynrelocsec.ExeSection).shlink:=dynsymndx;
  2242. if symversec.size>0 then
  2243. TElfExeSection(symversec.ExeSection).shlink:=dynsymndx;
  2244. if verdefsec.size>0 then
  2245. TElfExeSection(verdefsec.ExeSection).shlink:=dynstrndx;
  2246. if verneedsec.size>0 then
  2247. TElfExeSection(verneedsec.ExeSection).shlink:=dynstrndx;
  2248. end
  2249. else if assigned(ipltrelocsec) then
  2250. TElfExeSection(ipltrelocsec.ExeSection).shinfo:=TElfExeSection(pltobjsec.ExeSection).secshidx;
  2251. { The actual layout }
  2252. if IsSharedLibrary then
  2253. CurrMemPos:=0
  2254. else
  2255. CurrMemPos:=ElfTarget.exe_image_base;
  2256. textseg.MemPos:=CurrMemPos;
  2257. if assigned(phdrseg) then
  2258. begin
  2259. phdrseg.Mempos:=CurrMemPos+sizeof(TElfHeader);
  2260. phdrseg.Memsize:=sizeof(TElfproghdr)*segmentlist.count;
  2261. end;
  2262. CurrMemPos:=CurrMemPos+sizeof(TElfHeader)+segmentlist.count*sizeof(TElfproghdr);
  2263. MemPos_Segment(textseg);
  2264. CurrMemPos:=Align(CurrMemPos,SectionDataAlign); {! Data,not MemAlign}
  2265. CurrMemPos:=CurrMemPos+ElfTarget.max_page_size;
  2266. dataseg.MemPos:=CurrMemPos;
  2267. MemPos_Segment(dataseg);
  2268. { Mempos of unmapped sections is forced to zero, but we have to set positions
  2269. of its objsections and update sizes }
  2270. for i:=0 to ExeSectionList.Count-1 do
  2271. begin
  2272. exesec:=TElfExeSection(ExeSectionList[i]);
  2273. if not (oso_load in exesec.SecOptions) then
  2274. begin
  2275. tempmempos:=0;
  2276. exesec.MemPos:=tempmempos;
  2277. for j:=0 to exesec.ObjSectionList.Count-1 do
  2278. begin
  2279. objsec:=TObjSection(exesec.ObjSectionList[j]);
  2280. tempmempos:=objsec.setmempos(tempmempos);
  2281. end;
  2282. exesec.Size:=tempmempos;
  2283. end;
  2284. end;
  2285. { Update MemPos and MemSize of non-load segments,
  2286. in particular, TLS sizes are needed to resolve relocations }
  2287. for i:=0 to segmentlist.count-1 do
  2288. begin
  2289. seg:=TElfSegment(segmentlist[i]);
  2290. if (seg.ptype=PT_LOAD) or (seg.FSectionList.Count=0) then
  2291. continue;
  2292. seg.MemPos:=TExeSection(seg.FSectionList.First).MemPos;
  2293. for j:=0 to seg.FSectionList.Count-1 do
  2294. begin
  2295. exesec:=TElfExeSection(seg.FSectionList[j]);
  2296. seg.MemSize:=exesec.MemPos+exesec.Size-seg.MemPos;
  2297. end;
  2298. end;
  2299. if (not gotwritten) then
  2300. begin
  2301. { reset size of .got and .rel[a].dyn, they will be refilled while fixing up relocations }
  2302. if assigned(gotobjsec) then
  2303. gotobjsec.size:=0;
  2304. if assigned(dynrelocsec) then
  2305. begin
  2306. dynrelocsec.size:=0;
  2307. { write actual .dynsym content (needs valid symbol addresses) }
  2308. if assigned(tlsseg) then
  2309. dynsymtable.tlsbase:=tlsseg.MemPos;
  2310. dynsymtable.size:=sizeof(TElfsymbol);
  2311. for i:=0 to dynsymlist.count-1 do
  2312. dynsymtable.writeSymbol(TExeSymbol(dynsymlist[i]).objsymbol,dynsymnames[i]);
  2313. end;
  2314. end;
  2315. end;
  2316. procedure TElfExeOutput.MemPos_Segment(seg:TElfSegment);
  2317. var
  2318. i: longint;
  2319. exesec: TElfExeSection;
  2320. begin
  2321. for i:=0 to seg.FSectionList.Count-1 do
  2322. begin
  2323. exesec:=TElfExeSection(seg.FSectionList[i]);
  2324. inherited MemPos_ExeSection(exesec);
  2325. { .tbss should not contribute to address space }
  2326. if (exesec.shtype=SHT_NOBITS) and ((exesec.shflags and SHF_TLS)<>0) then
  2327. CurrMemPos:=exesec.MemPos;
  2328. end;
  2329. { calculate size of the segment }
  2330. seg.MemSize:=CurrMemPos-seg.MemPos;
  2331. end;
  2332. procedure TElfExeOutput.MemPos_ExeSection(const aname:string);
  2333. begin
  2334. // Ignore. All layout is done in mempos_start
  2335. end;
  2336. procedure TElfExeOutput.DataPos_Start;
  2337. var
  2338. i,j: longint;
  2339. exesec: TExeSection;
  2340. seg: TElfSegment;
  2341. objreloc: TObjRelocation;
  2342. begin
  2343. gotwritten:=true;
  2344. { If target does not support sorted relocations, it is expected to write the
  2345. entire .rel[a].dyn section during FixupRelocations, and leave dynreloclist empty.
  2346. Otherwise, only RELATIVE ones should be written, space for non-relative relocations
  2347. should remain. }
  2348. if assigned(dynrelocsec) then
  2349. begin
  2350. if (dynrelocsec.size+(dynreloclist.count*dynrelocsec.shentsize)<>dynrelsize) then
  2351. InternalError(2012110601);
  2352. { Write out non-RELATIVE dynamic relocations
  2353. TODO: additional sorting? }
  2354. for i:=0 to dynreloclist.count-1 do
  2355. begin
  2356. objreloc:=TObjRelocation(dynreloclist[i]);
  2357. WriteDynRelocEntry(objreloc.dataoffset,objreloc.ftype,objreloc.symbol.exesymbol.dynindex,0);
  2358. end;
  2359. end;
  2360. { sanity checks }
  2361. if assigned(gotobjsec) and (gotsize<>gotobjsec.size) then
  2362. InternalError(2012092501);
  2363. if assigned(dynrelocsec) and (dynrelsize<>dynrelocsec.size) then
  2364. InternalError(2012092502);
  2365. if (ExeWriteMode=ewm_dbgonly) or
  2366. (
  2367. (ExeWriteMode=ewm_exefull) and
  2368. not(cs_link_strip in current_settings.globalswitches)
  2369. ) then
  2370. WriteStaticSymtable;
  2371. { first handle primary segments }
  2372. textseg.DataPos:=0;
  2373. CurrDataPos:=sizeof(TElfHeader)+sizeof(TElfproghdr)*segmentlist.count;
  2374. if assigned(phdrseg) then
  2375. begin
  2376. phdrseg.DataPos:=sizeof(TElfHeader);
  2377. phdrseg.DataSize:=sizeof(TElfproghdr)*segmentlist.count;
  2378. end;
  2379. DataPos_Segment(textseg);
  2380. CurrDataPos:=align(CurrDataPos,SectionDataAlign);
  2381. dataseg.DataPos:=CurrDataPos;
  2382. DataPos_Segment(dataseg);
  2383. { then unmapped sections }
  2384. for i:=0 to ExeSectionList.Count-1 do
  2385. begin
  2386. exesec:=TExeSection(ExeSectionList[i]);
  2387. if not (oso_load in exesec.SecOptions) then
  2388. inherited DataPos_ExeSection(exesec);
  2389. end;
  2390. { finally, update size/position of non-load segments }
  2391. for i:=0 to segmentlist.count-1 do
  2392. begin
  2393. seg:=TElfSegment(segmentlist[i]);
  2394. if (seg.ptype=PT_LOAD) or (seg.FSectionList.Count=0) then
  2395. continue;
  2396. seg.DataPos:=TExeSection(seg.FSectionList.First).DataPos;
  2397. for j:=0 to seg.FSectionList.Count-1 do
  2398. begin
  2399. exesec:=TExeSection(seg.FSectionList[j]);
  2400. if oso_data in exesec.SecOptions then
  2401. seg.DataSize:=exesec.DataPos+exesec.Size-seg.DataPos;
  2402. end;
  2403. end;
  2404. { place section headers after the data }
  2405. shoffset:=CurrDataPos;
  2406. CurrDataPos:=CurrDataPos+ExeSectionList.Count*sizeof(TElfsechdr);
  2407. end;
  2408. procedure TElfExeOutput.DataPos_Segment(seg:TElfSegment);
  2409. var
  2410. i: longint;
  2411. exesec: TElfExeSection;
  2412. begin
  2413. for i:=0 to seg.FSectionList.Count-1 do
  2414. begin
  2415. exesec:=TElfExeSection(seg.FSectionList[i]);
  2416. { ELF needs DataPos set to 'would-be' value for sections that
  2417. don't have data, and for non-debug sections in .dbg file, too.
  2418. This slightly differs from generic approach. }
  2419. if not (oso_data in exesec.SecOptions) or
  2420. (
  2421. (ExeWriteMode=ewm_dbgonly) and
  2422. (exesec.SecOptions*[oso_debug,oso_debug_copy]=[])
  2423. ) then
  2424. begin
  2425. CurrDataPos:=align(CurrDataPos,SectionDataAlign);
  2426. exesec.DataPos:=CurrDataPos;
  2427. end
  2428. else
  2429. inherited DataPos_ExeSection(exesec);
  2430. end;
  2431. { calculate size of the segment }
  2432. seg.DataSize:=CurrDataPos-seg.DataPos;
  2433. end;
  2434. procedure TElfExeOutput.DataPos_ExeSection(const aname:string);
  2435. begin
  2436. // Ignore. Work is done entirely in datapos_start.
  2437. end;
  2438. procedure TElfExeOutput.InitDynlink;
  2439. begin
  2440. if not IsSharedLibrary then
  2441. begin
  2442. interpobjsec:=internalObjData.createsection('.interp',1,[oso_data,oso_load,oso_keep]);
  2443. interpobjsec.writestr(interpreter^);
  2444. end;
  2445. hashobjsec:=TElfObjSection.create_ext(internalObjData,'.hash',
  2446. SHT_HASH,SHF_ALLOC,sizeof(pint),4);
  2447. hashobjsec.secoptions:=[oso_keep];
  2448. dynsymtable:=TElfSymtab.create(internalObjData,esk_dyn);
  2449. dynamicsec:=TElfObjSection.create_ext(internalObjData,'.dynamic',
  2450. SHT_DYNAMIC,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(TElfDyn));
  2451. dynamicsec.SecOptions:=[oso_keep];
  2452. dynrelocsec:=TElfObjSection.create_reloc(internalObjData,'.dyn',true);
  2453. dynrelocsec.SecOptions:=[oso_keep];
  2454. dynreloclist:=TFPObjectList.Create(true);
  2455. symversec:=TElfObjSection.create_ext(internalObjData,'.gnu.version',
  2456. SHT_GNU_VERSYM,SHF_ALLOC,sizeof(word),sizeof(word));
  2457. symversec.SecOptions:=[oso_keep];
  2458. verdefsec:=TElfObjSection.create_ext(internalObjData,'.gnu.version_d',
  2459. SHT_GNU_VERDEF,SHF_ALLOC,sizeof(pint),0);
  2460. verdefsec.SecOptions:=[oso_keep];
  2461. verneedsec:=TElfObjSection.create_ext(internalObjData,'.gnu.version_r',
  2462. SHT_GNU_VERNEED,SHF_ALLOC,sizeof(pint),0);
  2463. verneedsec.SecOptions:=[oso_keep];
  2464. end;
  2465. const
  2466. hashbuckets: array[0..15] of longint=(
  2467. 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
  2468. 16411, 32771);
  2469. {$push}{$r-,q-}
  2470. function elfhash(const name:string):longword;
  2471. var
  2472. g: longword;
  2473. i: longint;
  2474. begin
  2475. result:=0;
  2476. for i:=1 to length(name) do
  2477. begin
  2478. result:=(result shl 4)+ord(name[i]);
  2479. g:=result and $F0000000;
  2480. if g>0 then
  2481. result:=result xor (g shr 24);
  2482. result:=result and (not g);
  2483. end;
  2484. end;
  2485. {$pop}
  2486. procedure TElfExeOutput.WriteDynamicSymbolsHash;
  2487. var
  2488. nchains,nbuckets: longint;
  2489. i,j: longint;
  2490. hashdata: plongint;
  2491. sym: TExeSymbol;
  2492. begin
  2493. dynsymnames:=AllocMem(dynsymlist.count*sizeof(longword));
  2494. nchains:=dynsymlist.Count+1;
  2495. { determine suitable bucket count }
  2496. i:=high(hashbuckets);
  2497. while (i>=0) and (nchains<hashbuckets[i]) do
  2498. dec(i);
  2499. nbuckets:=hashbuckets[i];
  2500. hashdata:=AllocMem((2+nchains+nbuckets)*sizeof(longint));
  2501. hashdata[0]:=nbuckets;
  2502. hashdata[1]:=nchains;
  2503. { The contents of .dynsym can be written only after mempos pass
  2504. because it needs valid symbol virtual addresses and section indices.
  2505. Here we preset .dynsym size and write names, in order to get
  2506. correct size of .dynstr section. }
  2507. dynsymtable.size:=(dynsymlist.count+1)*sizeof(TElfsymbol);
  2508. for i:=0 to dynsymlist.Count-1 do
  2509. begin
  2510. sym:=TExeSymbol(dynsymlist[i]);
  2511. dynsymnames[i]:=dynsymtable.fstrsec.writestr(sym.objsymbol.name);
  2512. j:=(elfhash(sym.objsymbol.name) mod nbuckets)+2;
  2513. while hashdata[j]<>0 do
  2514. j:=2+nbuckets+hashdata[j];
  2515. hashdata[j]:=i+1;
  2516. end;
  2517. if source_info.endian<>target_info.endian then
  2518. for i:=0 to nchains+nbuckets+1 do
  2519. hashdata[i]:=swapendian(hashdata[i]);
  2520. hashobjsec.write(hashdata^,(2+nchains+nbuckets)*sizeof(longint));
  2521. freemem(hashdata);
  2522. end;
  2523. procedure TElfExeOutput.WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword);
  2524. var
  2525. rel:telfreloc;
  2526. begin
  2527. rel.address:=dataofs;
  2528. rel.info:=ELF_R_INFO(symidx,typ);
  2529. rel.addend:=addend;
  2530. MaybeSwapElfReloc(rel);
  2531. dynrelocsec.write(rel,dynrelocsec.shentsize);
  2532. end;
  2533. procedure TElfExeOutput.WriteDynTag(aTag:longword;aValue:longword);
  2534. var
  2535. d: TElfDyn;
  2536. begin
  2537. d.d_tag:=aTag;
  2538. d.d_val:=aValue;
  2539. MaybeSwapElfDyn(d);
  2540. dynamicsec.write(d,sizeof(TElfDyn));
  2541. end;
  2542. procedure TElfExeOutput.WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword);
  2543. var
  2544. d: TElfDyn;
  2545. begin
  2546. d.d_tag:=aTag;
  2547. if source_info.endian<>target_info.endian then
  2548. d.d_tag:=swapendian(d.d_tag);
  2549. dynamicsec.write(d.d_tag,sizeof(d.d_tag));
  2550. { TODO: ignores endianness! }
  2551. dynamicsec.writeReloc_internal(aSection,aOffs,sizeof(d.d_ptr),RELOC_ABSOLUTE);
  2552. end;
  2553. procedure TElfExeOutput.WriteTargetDynamicTags;
  2554. begin
  2555. { to be overridden by CPU-specific descendants }
  2556. end;
  2557. procedure TElfExeOutput.WriteDynamicTags;
  2558. var
  2559. s: aword;
  2560. i: longint;
  2561. sym: TExeSymbol;
  2562. hs:string;
  2563. dynobj: TElfDynamicObjData;
  2564. begin
  2565. for i:=0 to neededlist.Count-1 do
  2566. begin
  2567. dynobj:=TElfDynamicObjData(neededlist[i]);
  2568. s:=dynsymtable.fstrsec.writestr(dynobj.name);
  2569. dynobj.soname_strofs:=s;
  2570. WriteDynTag(DT_NEEDED,s);
  2571. end;
  2572. if IsSharedLibrary then
  2573. begin
  2574. s:=dynsymtable.fstrsec.writestr(ExtractFileName(current_module.sharedlibfilename));
  2575. WriteDynTag(DT_SONAME,s);
  2576. { TODO: names hardcoded here }
  2577. sym:=TExeSymbol(ExeSymbolList.Find('FPC_SHARED_LIB_START'));
  2578. if assigned(sym) then
  2579. WriteDynTag(DT_INIT,sym.objsymbol.objsection,sym.objsymbol.offset);
  2580. sym:=TExeSymbol(ExeSymbolList.Find('FPC_LIB_EXIT'));
  2581. if assigned(sym) then
  2582. WriteDynTag(DT_FINI,sym.objsymbol.objsection,sym.objsymbol.offset);
  2583. end;
  2584. { TODO: we need a dedicated parameter to pass runpath, instead of this hack
  2585. (-Xr is a different thing, it passes "-rpath-link"). }
  2586. if (ParaLinkOptions<>'') then
  2587. begin
  2588. hs:=ParaLinkOptions;
  2589. while (hs<>'') do
  2590. begin
  2591. if (GetToken(hs,' ')='-rpath') then
  2592. begin
  2593. s:=dynsymtable.fstrsec.writestr(GetToken(hs,' '));
  2594. WriteDynTag(DT_RPATH,s);
  2595. end;
  2596. end;
  2597. end;
  2598. writeDynTag(DT_HASH,hashobjsec);
  2599. writeDynTag(DT_STRTAB,dynsymtable.fstrsec);
  2600. writeDynTag(DT_SYMTAB,dynsymtable);
  2601. writeDynTag(DT_SYMENT,sizeof(TElfSymbol));
  2602. if Assigned(gotpltobjsec) then
  2603. writeDynTag(DT_PLTGOT,gotpltobjsec);
  2604. end;
  2605. const
  2606. pltreltags: array[boolean] of longword=(DT_REL,DT_RELA);
  2607. relsztags: array[boolean] of longword=(DT_RELSZ,DT_RELASZ);
  2608. relenttags: array[boolean] of longword=(DT_RELENT,DT_RELAENT);
  2609. relcnttags: array[boolean] of longword=(DT_RELCOUNT,DT_RELACOUNT);
  2610. procedure TElfExeOutput.FinishDynamicTags;
  2611. var
  2612. rela: boolean;
  2613. begin
  2614. if assigned(dynsymtable) then
  2615. writeDynTag(DT_STRSZ,dynsymtable.fstrsec.size);
  2616. if hastextrelocs then
  2617. writeDynTag(DT_TEXTREL,0);
  2618. if Assigned(pltrelocsec) and (pltrelocsec.size>0) then
  2619. begin
  2620. writeDynTag(DT_PLTRELSZ,pltrelocsec.Size);
  2621. writeDynTag(DT_PLTREL,pltreltags[pltrelocsec.shtype=SHT_RELA]);
  2622. writeDynTag(DT_JMPREL,pltrelocsec);
  2623. end;
  2624. if Assigned(dynrelocsec) and (dynrelocsec.size>0) then
  2625. begin
  2626. rela:=(dynrelocsec.shtype=SHT_RELA);
  2627. writeDynTag(pltreltags[rela],dynrelocsec);
  2628. writeDynTag(relsztags[rela],dynrelocsec.Size);
  2629. writeDynTag(relenttags[rela],dynrelocsec.shentsize);
  2630. if (relative_reloc_count>0) then
  2631. writeDynTag(relcnttags[rela],relative_reloc_count);
  2632. end;
  2633. WriteTargetDynamicTags;
  2634. if (verdefcount>0) or (verneedcount>0) then
  2635. begin
  2636. if (verdefcount>0) then
  2637. begin
  2638. writeDynTag(DT_VERDEF,verdefsec);
  2639. writeDynTag(DT_VERDEFNUM,verdefcount);
  2640. end;
  2641. if (verneedcount>0) then
  2642. begin
  2643. writeDynTag(DT_VERNEED,verneedsec);
  2644. writeDynTag(DT_VERNEEDNUM,verneedcount);
  2645. end;
  2646. writeDynTag(DT_VERSYM,symversec);
  2647. end;
  2648. writeDynTag(DT_NULL,0);
  2649. end;
  2650. procedure TElfExeOutput.CreatePLT;
  2651. var
  2652. reloc: TObjRelocation;
  2653. begin
  2654. pltobjsec:=TElfObjSection.create_ext(internalObjData,'.plt',
  2655. SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,4,16);
  2656. pltobjsec.SecOptions:=[oso_keep,oso_plt];
  2657. pltrelocsec:=TElfObjSection.create_reloc(internalObjData,'.plt',true);
  2658. pltrelocsec.SecOptions:=[oso_keep];
  2659. ipltrelocsec:=TElfObjSection.create_reloc(internalObjData,'.iplt',true);
  2660. ipltrelocsec.SecOptions:=[oso_keep];
  2661. { reference .dynamic from .got.plt, this isn't necessary if linking statically }
  2662. { TODO: maybe move writing initial .got.plt entries here completely
  2663. (needs testing --- GOT symbol may get lost if .got.plt is empty)}
  2664. if dynamiclink then
  2665. begin
  2666. reloc:=TObjRelocation.CreateSection(0,dynamicsec,RELOC_ABSOLUTE);
  2667. reloc.size:=sizeof(pint);
  2668. gotpltobjsec.ObjRelocations.Add(reloc);
  2669. end;
  2670. { Initial PLT entry, CPU-specific }
  2671. WriteFirstPLTEntry;
  2672. end;
  2673. procedure TElfExeOutput.WritePLTEntry(exesym:TExeSymbol);
  2674. begin
  2675. // must be implemented by CPU-specific descendant
  2676. InternalError(2012092102);
  2677. end;
  2678. procedure TElfExeOutput.WriteIndirectPLTEntry(exesym:TExeSymbol);
  2679. begin
  2680. // must be implemented by CPU-specific descendant
  2681. InternalError(2012092101);
  2682. end;
  2683. function TElfExeOutput.WriteData:boolean;
  2684. begin
  2685. WriteHeader;
  2686. segmentlist.ForEachCall(@segment_write_header,nil);
  2687. WriteExeSectionContent;
  2688. FWriter.WriteZeros(sizeof(TElfsechdr));
  2689. ExeSectionList.ForEachCall(@exesection_write_header,nil);
  2690. result:=true;
  2691. end;
  2692. procedure TElfExeOutput.GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);
  2693. var
  2694. exportlist: TCmdStrList;
  2695. sym: TExeSymbol;
  2696. begin
  2697. AllowUndefinedSymbols:=IsSharedLibrary;
  2698. { add exported symbols to dynamic list }
  2699. exportlist:=texportlibunix(exportlib).exportedsymnames;
  2700. if not exportlist.empty then
  2701. repeat
  2702. sym:=TExeSymbol(ExeSymbolList.Find(exportlist.getfirst));
  2703. if assigned(sym) then
  2704. begin
  2705. if assigned(sym.objsymbol.objsection) then
  2706. sym.objsymbol.objsection.SecOptions:=[oso_keep];
  2707. sym.dynindex:=dynsymlist.add(sym)+1
  2708. end
  2709. else
  2710. InternalError(2012071801);
  2711. until exportlist.empty;
  2712. end;
  2713. procedure TElfExeOutput.ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
  2714. begin
  2715. { TODO: include objsec properties into message }
  2716. Comment(v_error,'Relocation '+ElfTarget.RelocName(reltyp)+' against '''+objreloc.TargetName+''' cannot be used when linking a shared object; recompile with -Cg');
  2717. end;
  2718. procedure TElfExeOutput.ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
  2719. begin
  2720. { TODO: include objsec properties into message }
  2721. Comment(v_error,'Relocation truncated to fit: '+ElfTarget.RelocName(reltyp)+' against '''+objreloc.TargetName+'''');
  2722. end;
  2723. {****************************************************************************
  2724. TElfExeSection
  2725. ****************************************************************************}
  2726. procedure TElfExeSection.AddObjSection(objsec:TObjSection;ignoreprops:boolean);
  2727. begin
  2728. inherited AddObjSection(objsec,ignoreprops);
  2729. if ignoreprops then
  2730. exit;
  2731. if (shtype=SHT_NULL) then
  2732. begin
  2733. shtype:=TElfObjSection(objsec).shtype;
  2734. shflags:=TElfObjSection(objsec).shflags;
  2735. shentsize:=TElfObjSection(objsec).shentsize;
  2736. end;
  2737. end;
  2738. {****************************************************************************
  2739. TElfSegment
  2740. ****************************************************************************}
  2741. constructor TElfSegment.Create(atype,aflags,aalign:longword);
  2742. begin
  2743. ptype:=atype;
  2744. pflags:=aflags;
  2745. align:=aalign;
  2746. FSectionList:=TFPObjectList.Create(false);
  2747. end;
  2748. destructor TElfSegment.Destroy;
  2749. begin
  2750. FSectionList.Free;
  2751. inherited Destroy;
  2752. end;
  2753. procedure TElfSegment.Add(exesec:TExeSection);
  2754. begin
  2755. FSectionList.Add(exesec);
  2756. end;
  2757. end.