ogelf.pas 104 KB

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