elfsubwriter.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Resource writer for ELF files
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. type
  12. (*
  13. generic TElfRelocTable<_TPElfRela_,_TElfRela_,_TPElfRel_,_TElfRel_,_Tword_> = class
  14. ...
  15. TElf32RelocTable = specialize TElfRelocTable<PElf32Rela,TElf32Rela,
  16. PElf32Rel,TElf32Rel,longword>;
  17. TElf64RelocTable = specialize TElfRelocTable<PElf64Rela,TElf64Rela,
  18. PElf64Rel,TElf64Rel,qword>;
  19. *)
  20. _TElfRelocTable_= class
  21. private
  22. fList : TFPList;
  23. fRelocType : byte;
  24. fEntrySize : integer;
  25. fSectionType : integer;
  26. fSectionName : string;
  27. function GetCount : integer;
  28. function GetItem(index : integer) : _TPElfRela_;
  29. protected
  30. public
  31. constructor Create(const fRelocInfo : TElfRelocInfo);
  32. destructor Destroy; override;
  33. procedure Add(const aOffset,aValue : _Tword_; aSymIdx : longword);
  34. procedure Clear;
  35. property Count : integer read GetCount;
  36. property Items[index : integer] : _TPElfRela_ read GetItem; default;
  37. property EntrySize : integer read fEntrySize;
  38. property SectionType : integer read fSectionType;
  39. property SectionName : string read fSectionName;
  40. end;
  41. { TElfSubWriter }
  42. (*
  43. generic TElfSubWriter<_TElfRelocTable_,_TElfHdr_,_TElfSectHdr_,_TElfSymbol_,
  44. _TPElfRela_,_TElfRela_,_TResHdr_,_TResInfoNode_> = class
  45. ...
  46. TElf32SubWriter = specialize TElfSubWriter<TElf32RelocTable,_TElf32Hdr_,
  47. TElf32SectHdr,TElf32Symbol,PElf32Rela,TElf32Rela,TResHdr32,TResInfoNode32>;
  48. TElf64SubWriter = specialize TElfSubWriter<TElf64RelocTable,_TElf64Hdr_,
  49. TElf64SectHdr,TElf64Symbol,PElf64Rela,TElf64Rela,TResHdr64,TResInfoNode64>;
  50. *)
  51. _TElfSubWriter_ = class(TAbstractElfSubWriter)
  52. private
  53. fRelocInfo : TElfRelocInfo;
  54. fRelocTable : _TElfRelocTable_;
  55. procedure PrescanResourceTree; override;
  56. procedure WriteEmptyElfHeader(aStream : TStream);
  57. procedure WriteResHeader(aStream : TStream; aResources : TResources);
  58. procedure WriteNodeInfos(aStream : TStream);
  59. procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
  60. procedure WriteSectHeaders(aStream : TStream);
  61. procedure FixElfHeader(aStream : TStream);
  62. procedure WriteSymbols(aStream : TStream);
  63. procedure WriteRelocations(aStream : TStream);
  64. protected
  65. procedure Write(aResources : TResources; aStream : TStream); override;
  66. public
  67. constructor Create(aParent : TElfResourceWriter; const aMachineType
  68. : integer; const aOppositeEndianess : boolean); override;
  69. destructor Destroy; override;
  70. end;
  71. { TElfRelocTable }
  72. function _TElfRelocTable_.GetCount: integer;
  73. begin
  74. Result:=fList.Count;
  75. end;
  76. function _TElfRelocTable_.GetItem(index: integer): _TPElfRela_;
  77. begin
  78. Result:=_TPElfRela_(fList[index]);
  79. end;
  80. constructor _TElfRelocTable_.Create(const fRelocInfo : TElfRelocInfo);
  81. begin
  82. fList:=TFPList.Create;
  83. fRelocType:=fRelocInfo.RelocType;
  84. fSectionType:=fRelocInfo.SectionType;
  85. case fSectionType of
  86. SHT_REL : begin
  87. fEntrySize:= sizeof(_TElfRel_);
  88. fSectionName:='.rel'+RsrcSectName;
  89. end;
  90. SHT_RELA : begin
  91. fEntrySize:= sizeof(_TElfRela_);
  92. fSectionName:='.rela'+RsrcSectName;
  93. end;
  94. end;
  95. end;
  96. destructor _TElfRelocTable_.Destroy;
  97. begin
  98. Clear;
  99. fList.Free;
  100. end;
  101. procedure _TElfRelocTable_.Add(const aOffset,aValue : _Tword_; aSymIdx : longword);
  102. var p : _TPElfRela_;
  103. begin
  104. p:=GetMem(sizeof(_TElfRela_));
  105. p^.Offset:=aOffset;
  106. P^.Info:=aSymIdx;
  107. {$IF _TElfRelocTable_=TElf64RelocTable}
  108. P^.Info:=P^.Info shl 32;
  109. P^.Info:=P^.Info or fRelocType;
  110. {$ELSE}
  111. P^.Info:=P^.Info shl 8;
  112. P^.Info:=P^.Info or (fRelocType and $FF);
  113. {$ENDIF}
  114. p^.addend:=aValue;
  115. fList.Add(p);
  116. end;
  117. procedure _TElfRelocTable_.Clear;
  118. var i : integer;
  119. p : _TPElfRela_;
  120. begin
  121. for i:=0 to fList.Count-1 do
  122. begin
  123. p:=_TPElfRela_(fList[i]);
  124. FreeMem(p);
  125. end;
  126. fList.Clear;
  127. end;
  128. { TElfSubWriter }
  129. procedure _TElfSubWriter_.PrescanResourceTree;
  130. begin
  131. fResStringTable.Clear;
  132. fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_);
  133. fResStringTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_));
  134. if fResStringTable.Used then
  135. fDataCurOfs:=NextAligned(fDataAlignment,fResStringTable.StartOfs+fResStringTable.Size)
  136. else
  137. fDataCurOfs:=fResStringTable.StartOfs;
  138. end;
  139. procedure _TElfSubWriter_.WriteEmptyElfHeader(aStream: TStream);
  140. var hdr : _TElfHdr_;
  141. begin
  142. FillByte(hdr,sizeof(hdr),0);
  143. aStream.WriteBuffer(hdr,sizeof(hdr));
  144. end;
  145. procedure _TElfSubWriter_.WriteResHeader(aStream: TStream;
  146. aResources: TResources);
  147. var hdr : _TResHdr_;
  148. begin
  149. hdr.count:=aResources.Count;
  150. hdr.usedhandles:=0;
  151. hdr.handles:=0;
  152. fSymbolTable.AddSection(RSRCSECT_IDX);
  153. fSymbolTable.AddSection(HANDLESECT_IDX);
  154. case fRelocInfo.SectionType of
  155. SHT_REL : hdr.rootptr:=sizeof(hdr);
  156. SHT_RELA : hdr.rootptr:=0;
  157. end;
  158. fRelocTable.Add(0,sizeof(hdr),RSRCSECT_IDX);
  159. fRelocTable.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),0,HANDLESECT_IDX);
  160. if fOppositeEndianess then
  161. begin
  162. hdr.rootptr:=SwapEndian(hdr.rootptr);
  163. hdr.count:=SwapEndian(hdr.count);
  164. //handles must be fixed later
  165. // hdr.usedhandles:=SwapEndian(hdr.usedhandles);
  166. // hdr.handles:=SwapEndian(hdr.handles);
  167. end;
  168. aStream.WriteBuffer(hdr,sizeof(hdr));
  169. end;
  170. procedure _TElfSubWriter_.WriteNodeInfos(aStream: TStream);
  171. begin
  172. fCurOfs:=sizeof(_TResHdr_);
  173. WriteNodeInfo(aStream,fRoot);
  174. WriteSubNodes(aStream,fRoot);
  175. end;
  176. procedure _TElfSubWriter_.WriteNodeInfo(aStream: TStream;
  177. aNode: TResourceTreeNode);
  178. var infonode : _TResInfoNode_;
  179. begin
  180. if aNode.Desc.DescType=dtID then
  181. infonode.nameid:=aNode.Desc.ID
  182. else
  183. begin
  184. infonode.nameid:=fResStringTable.StartOfs+aNode.NameRVA;
  185. fRelocTable.Add(fCurOfs,infonode.nameid,RSRCSECT_IDX);
  186. if fRelocInfo.SectionType=SHT_RELA then infonode.nameid:=0;
  187. end;
  188. infonode.ncount:=aNode.NamedCount;
  189. if aNode.IsLeaf then
  190. begin
  191. infonode.idcountsize:=aNode.Data.RawData.Size;
  192. infonode.subptr:=fDataCurOfs;
  193. fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize);
  194. end
  195. else
  196. begin
  197. infonode.idcountsize:=aNode.IDCount;
  198. infonode.subptr:=aNode.SubDirRVA;
  199. end;
  200. fRelocTable.Add(
  201. fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
  202. sizeof(infonode.idcountsize),infonode.subptr,RSRCSECT_IDX);
  203. if fRelocInfo.SectionType=SHT_RELA then infonode.subptr:=0;
  204. if fOppositeEndianess then
  205. begin
  206. infonode.nameid:=SwapEndian(infonode.nameid);
  207. infonode.ncount:=SwapEndian(infonode.ncount);
  208. infonode.idcountsize:=SwapEndian(infonode.idcountsize);
  209. infonode.subptr:=SwapEndian(infonode.subptr);
  210. end;
  211. aStream.WriteBuffer(infonode,sizeof(infonode));
  212. inc(fCurOfs,sizeof(infonode));
  213. end;
  214. procedure _TElfSubWriter_.WriteSectHeaders(aStream: TStream);
  215. var i : integer;
  216. orig : PElf64SectHdr;
  217. hdr : _TElfSectHdr_;
  218. begin
  219. Align(fDataAlignment,aStream);
  220. fSectHdrOffset:=aStream.Position;
  221. for i:=0 to fSections.Count-1 do
  222. begin
  223. orig:=fSections[i];
  224. {$IF _TElfSubWriter_=TElf64SubWriter}
  225. hdr:=orig^;
  226. {$ELSE}
  227. hdr.NameIdx:=orig^.NameIdx;
  228. hdr._Type:=orig^._Type;
  229. hdr.Flags:=orig^.Flags;
  230. hdr.Address:=orig^.Address;
  231. hdr.Offset:=orig^.Offset;
  232. hdr.Size:=orig^.Size;
  233. hdr.Link:=orig^.Link;
  234. hdr.Info:=orig^.Info;
  235. hdr.AddrAlign:=orig^.AddrAlign;
  236. hdr.EntSize:=orig^.EntSize;
  237. {$ENDIF}
  238. if fOppositeEndianess then
  239. begin
  240. hdr.NameIdx:=SwapEndian(hdr.NameIdx);
  241. hdr._Type:=SwapEndian(hdr._Type);
  242. hdr.Flags:=SwapEndian(hdr.Flags);
  243. hdr.Address:=SwapEndian(hdr.Address);
  244. hdr.Offset:=SwapEndian(hdr.Offset);
  245. hdr.Size:=SwapEndian(hdr.Size);
  246. hdr.Link:=SwapEndian(hdr.Link);
  247. hdr.Info:=SwapEndian(hdr.Info);
  248. hdr.AddrAlign:=SwapEndian(hdr.AddrAlign);
  249. hdr.EntSize:=SwapEndian(hdr.EntSize);
  250. end;
  251. aStream.WriteBuffer(hdr,sizeof(hdr));
  252. end;
  253. end;
  254. procedure _TElfSubWriter_.FixElfHeader(aStream: TStream);
  255. var hdr : _TElfHdr_;
  256. begin
  257. hdr._Type:=ET_REL;
  258. hdr.Machine:=fMachineType;
  259. hdr.Version:=EV_CURRENT;
  260. hdr.Entry:=0;
  261. hdr.ProgHdrOffset:=0;
  262. hdr.SectHdrOffset:=fSectHdrOffset;
  263. hdr.Flags:=fMachineFlags;
  264. hdr.HdrSize:=sizeof(_TElfHdr_)+sizeof(TElfIdent);
  265. hdr.ProgHdrEntrySize:=0;
  266. hdr.ProgHdrNum:=0;
  267. hdr.SectHdrEntrySize:=sizeof(_TElfSectHdr_);
  268. hdr.SectHdrNum:=fSections.Count;
  269. hdr.NameTableIndex:=fShStrTabIdx;
  270. if fOppositeEndianess then
  271. begin
  272. hdr._Type:=SwapEndian(hdr._Type);
  273. hdr.Machine:=SwapEndian(hdr.Machine);
  274. hdr.Version:=SwapEndian(hdr.Version);
  275. hdr.Entry:=SwapEndian(hdr.Entry);
  276. hdr.ProgHdrOffset:=SwapEndian(hdr.ProgHdrOffset);
  277. hdr.SectHdrOffset:=SwapEndian(hdr.SectHdrOffset);
  278. hdr.Flags:=SwapEndian(hdr.Flags);
  279. hdr.HdrSize:=SwapEndian(hdr.HdrSize);
  280. hdr.ProgHdrEntrySize:=SwapEndian(hdr.ProgHdrEntrySize);
  281. hdr.ProgHdrNum:=SwapEndian(hdr.ProgHdrNum);
  282. hdr.SectHdrEntrySize:=SwapEndian(hdr.SectHdrEntrySize);
  283. hdr.SectHdrNum:=SwapEndian(hdr.SectHdrNum);
  284. hdr.NameTableIndex:=SwapEndian(hdr.NameTableIndex);
  285. end;
  286. aStream.Position:=sizeof(TElfIdent);
  287. aStream.WriteBuffer(hdr,sizeof(hdr));
  288. end;
  289. procedure _TElfSubWriter_.WriteSymbols(aStream: TStream);
  290. var i : integer;
  291. orig : PElf64Symbol;
  292. sym : _TElfSymbol_;
  293. startpos : int64;
  294. begin
  295. Align(fDataAlignment,aStream);
  296. startpos:=aStream.Position;
  297. for i:=0 to fSymbolTable.Count-1 do
  298. begin
  299. orig:=fSymbolTable[i];
  300. {$IF _TElfSubWriter_=TElf64SubWriter}
  301. sym:=orig^;
  302. {$ELSE}
  303. sym.Name:=orig^.Name;
  304. sym.Value:=orig^.Value;
  305. sym.Size:=orig^.Size;
  306. sym.Info:=orig^.Info;
  307. sym.Other:=orig^.Other;
  308. sym.SectIdx:=orig^.SectIdx;
  309. {$ENDIF}
  310. if fOppositeEndianess then
  311. begin
  312. sym.Name:=SwapEndian(sym.Name);
  313. sym.Value:=SwapEndian(sym.Value);
  314. sym.Size:=SwapEndian(sym.Size);
  315. sym.SectIdx:=SwapEndian(sym.SectIdx);
  316. end;
  317. aStream.WriteBuffer(sym,sizeof(sym));
  318. end;
  319. fSymTabIdx:=fSections.Add('.symtab',SHT_SYMTAB,0,startpos,
  320. fSymbolTable.Count*sizeof(_TElfSymbol_),sizeof(_TElfSymbol_),fSymStrTabIdx,
  321. fSymbolTable.FirstGlobal,fDataAlignment);
  322. end;
  323. procedure _TElfSubWriter_.WriteRelocations(aStream: TStream);
  324. var orig : _TPElfRela_;
  325. rel : _TElfRela_;
  326. startpos : int64;
  327. i : integer;
  328. begin
  329. Align(fDataAlignment,aStream);
  330. startpos:=aStream.Position;
  331. for i:=0 to fRelocTable.Count-1 do
  332. begin
  333. orig:=fRelocTable[i];
  334. rel:=orig^;
  335. if fOppositeEndianess then
  336. begin
  337. rel.Offset:=SwapEndian(rel.Offset);
  338. rel.Info:=SwapEndian(rel.Info);
  339. rel.Addend:=SwapEndian(rel.Addend);
  340. end;
  341. aStream.WriteBuffer(rel,fRelocTable.EntrySize);
  342. end;
  343. fSections.Add(fRelocTable.SectionName,fRelocTable.SectionType,0,startpos,
  344. fRelocTable.Count*fRelocTable.EntrySize,fRelocTable.EntrySize,
  345. fSymTabIdx,1,fDataAlignment);
  346. end;
  347. procedure _TElfSubWriter_.Write(aResources: TResources; aStream: TStream);
  348. begin
  349. fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
  350. WriteEmptyElfHeader(aStream);
  351. fSectionStart:=aStream.Position;
  352. PrescanResourceTree;
  353. WriteResHeader(aStream,aResources);
  354. WriteNodeInfos(aStream);
  355. WriteResStringTable(aStream);
  356. WriteRawData(aStream);
  357. fSections.Add(RsrcSectName, SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,fSectionStart,
  358. fDataCurOfs,fDataAlignment);
  359. AddEmptySections(aResources,aStream);
  360. fSymbolTable.AddGlobal('FPC_RESSYMBOL',0,0,STT_OBJECT,RSRCSECT_IDX);
  361. WriteStrTab(aStream);
  362. WriteSymbols(aStream);
  363. WriteRelocations(aStream);
  364. WriteShStrTab(aStream);
  365. WriteSectHeaders(aStream);
  366. FixElfHeader(aStream);
  367. end;
  368. constructor _TElfSubWriter_.Create(aParent : TElfResourceWriter; const
  369. aMachineType: integer; const aOppositeEndianess: boolean);
  370. begin
  371. inherited Create(aParent, aMachineType, aOppositeEndianess);
  372. with fRelocInfo do
  373. case aMachineType of
  374. EM_386 : begin RelocType:=R_386_32; SectionType:=SHT_REL; end;
  375. EM_PPC : begin RelocType:=R_PPC_ADDR32; SectionType:=SHT_RELA; end;
  376. EM_ARM : begin RelocType:=R_ARM_ABS32; SectionType:=SHT_REL; end;
  377. EM_68K : begin RelocType:=R_68K_32; SectionType:=SHT_RELA; end;
  378. EM_SPARC : begin RelocType:=R_SPARC_32; SectionType:=SHT_RELA; end;
  379. EM_X86_64 : begin RelocType:=R_x86_64_64; SectionType:=SHT_RELA; end;
  380. EM_PPC64 : begin RelocType:=R_PPC64_ADDR64; SectionType:=SHT_RELA; end;
  381. EM_ALPHA : begin RelocType:=R_ALPHA_REFQUAD; SectionType:=SHT_RELA; end;
  382. EM_IA_64 : begin RelocType:=R_IA64_DIR64LSB; SectionType:=SHT_RELA; end;
  383. else
  384. raise EElfResourceWriterUnknownMachineException.Create('');
  385. end;
  386. fRelocTable:=_TElfRelocTable_.Create(fRelocInfo);
  387. {$IF _TElfSubWriter_=TElf64SubWriter}
  388. fDataAlignment:=8;
  389. {$ELSE}
  390. fDataAlignment:=4;
  391. {$ENDIF}
  392. if aMachineType=EM_IA_64 then fMachineFlags:=EF_IA_64_ABI64
  393. else fMachineFlags:=0;
  394. end;
  395. destructor _TElfSubWriter_.Destroy;
  396. begin
  397. fRelocTable.Free;
  398. inherited Destroy;
  399. end;