ogelf.pas 110 KB

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