ogelf.pas 107 KB

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