elfres.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. { *********************************************************************** }
  2. { }
  3. { fpcres2elf - Free Pascal Resource to ELF object compiler }
  4. { Part of the Free Pascal and CrossFPC distributions }
  5. { }
  6. { Copyright (C) 2005 Simon Kissel }
  7. { }
  8. { See the file COPYING.FPC, included in the FPC distribution, }
  9. { for details about the copyright. }
  10. { }
  11. { This program is distributed in the hope that it will be useful, }
  12. { but WITHOUT ANY WARRANTY; without even the implied warranty of }
  13. { MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
  14. { }
  15. { *********************************************************************** }
  16. {
  17. This unit will compile an ELF object file out of a supplied .res resource
  18. file. Optionally, Delphi/Kylix dfm/xfm form files are also accepted as
  19. input. These will automatically be converted into resources internally.
  20. fpcres2elf builds with Delphi, Kylix and FPC.
  21. Currently this only works on 32Bit targets, but support for 64Bit targets
  22. is in the works. Support for big endian systems is completely missing,
  23. though.
  24. Format used for the various resource sections:
  25. .fpc.resptrs: This section is contained in resptrs.o and always linked to the executable by
  26. FPC. It containes an exported label fpcrespointers, which is used at runtime
  27. to find the resptrs section in memory. The resptrs contains pointers to all the
  28. sections and their sizes. These are updated in a post-precessing step by the
  29. compiler and by the external resource embedder when applied to an ELF file.
  30. This section always is 128 Bytes long and initially filled with zeros.
  31. The first integer (32/64 Bit) value in this section contains the version
  32. number of the resource system. Currently this value is 1.
  33. The second integer (32/64 Bit) value in this section contains the number of
  34. resources.
  35. After this follows a version-defined number of TFPCResourceSectionInfo entries.
  36. .fpc.ressym: Contains the resource names. This simply is a stream of zero-terminated strings.
  37. Only textual names are supported, numeric IDs get autoconverted to #ID's.
  38. The reshash table has got a byte index into ressym to quickly get that data if needed
  39. .fpc.reshash: n TFPCResourceInfo records. (number of entries is defined in fpc.resptrs)
  40. .fpc.resdata: Contains the plain resource data stream. A byte index into the data stream
  41. is given for each resource entry in TResourceInfo
  42. .fpc.resspare: An empty section which is resized to make room if the size of any of the previous
  43. sections gets changed. NOT USED IN VERSION 1 (SIZE WILL BE 0)
  44. .fpc.resstr: This section is completely seperated from the rest and contains a block of
  45. resourcestrings in internal FPC format.
  46. resptr TFPCResourceSectionInfo list for FPC resources version 1:
  47. Index Pointer to
  48. 0 ressym
  49. 1 reshash
  50. 2 resdata
  51. 3 resspare
  52. 4 resstr
  53. 5 reserved for future extension (stabs)
  54. 6 reserved for future extension
  55. }
  56. {$ifdef fpc}
  57. {$mode objfpc}
  58. {$endif}
  59. {$h+}
  60. unit elfres;
  61. interface
  62. uses
  63. elfbfd,
  64. SysUtils,
  65. Classes;
  66. const fpcres2elf_version=1;
  67. type
  68. TSectionKind = (skSymtab, skStrtab, skShstrtab, skText, skData, skBss, skFpcRessym, skFpcResstr,
  69. skFpcReshash, skFpcResdata, skFpcResspare);
  70. // Do not change the following consts, they are dummy tables to generate an .o that makes ld happy
  71. const symtab = #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00+
  72. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$01#$00+
  73. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$02#$00+
  74. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$03#$00+
  75. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$04#$00+
  76. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$05#$00+
  77. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$06#$00+
  78. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$07#$00+
  79. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$08#$00;
  80. strtab = #$00#$00; // this actually is just one byte long
  81. zeros = #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00;
  82. // header of a windows 32 bit .res file (16 bytes)
  83. reshdr = #$00#$00#$00#$00#$20#$00#$00#$00#$FF#$FF#$00#$00#$FF#$FF#$00#$00+
  84. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00;
  85. FilerSignature: array[1..4] of Char = 'TPF0';
  86. SDefaultExtension = '.or';
  87. Type
  88. { TElfResCreator }
  89. TElfResCreator = Class(TObject)
  90. private
  91. FDestFileName: String;
  92. FExtension: string;
  93. FSourceFileName: String;
  94. FOverwrite: Boolean;
  95. FVerbose: Boolean;
  96. FVersion: Integer;
  97. FShStrTab: string;
  98. FShStrOffsets: array[TSectionKind] of Longint;
  99. Protected
  100. FSectionStream: TMemoryStream;
  101. FDataStream: TMemoryStream;
  102. FSymStream: TMemoryStream;
  103. FHashStream: TMemoryStream;
  104. sectionheader_ofs: integer;
  105. shstrtab_ofs: integer;
  106. CurrentResource:integer;
  107. resheader: string;
  108. Signature: byte;
  109. Procedure AllocateData; virtual;
  110. Procedure FreeData; virtual;
  111. Procedure DoAlign(const a: integer);
  112. Public
  113. Constructor Create;
  114. Procedure Convert(Const Source,Destination : String);
  115. Procedure ConvertStreams(Source,Dest : TStream);
  116. Procedure DoConvertStreams(Source,Dest : TStream); virtual;Abstract;
  117. Property Verbose : Boolean Read FVerbose Write FVerbose;
  118. Property SourceFileName : String Read FSourceFileName;
  119. Property DestFileName : String Read FDestFileName;
  120. Property Overwrite : Boolean Read FOverwrite Write FOverWrite;
  121. Property Version : Integer Read FVersion Write FVersion;
  122. Property Extension : string Read FExtension Write FExtension;
  123. end;
  124. { TElf32ResCreator }
  125. TElf32ResCreator = Class(TElfResCreator)
  126. Private
  127. ResourceEntries: array of TELF32ResourceInfo;
  128. Protected
  129. Procedure AllocateData; override;
  130. Procedure FreeData; override;
  131. procedure AddSection(aKind: TSectionKind; atype, aflags, aaddr, aoffset, asize, alink, ainfo, aaddralign, aentsize: longint);
  132. public
  133. procedure LoadBinaryDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  134. procedure LoadTextDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  135. procedure LoadRESEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  136. Procedure DoConvertStreams(Source,Dest : TStream); override;
  137. end;
  138. { TElf64Creator }
  139. TElf64ResCreator = Class(TElfResCreator)
  140. Procedure DoConvertStreams(Source,Dest : TStream); override;
  141. end;
  142. EElfResError = Class(Exception);
  143. implementation
  144. resourcestring
  145. SErrUnrecognizedFormat = 'Unrecognized file format for input file "%s"';
  146. Procedure DoError (Msg : String);
  147. begin
  148. Raise EElfResError.Create(Msg);
  149. end;
  150. Procedure DoErrorFmt (Msg : String; Args : Array of const);
  151. begin
  152. Raise EElfResError.CreateFmt(Msg,Args);
  153. end;
  154. function HashELF(const S : string) : longint;
  155. {Note: this hash function is described in "Practical Algorithms For
  156. Programmers" by Andrew Binstock and John Rex, Addison Wesley,
  157. with modifications in Dr Dobbs Journal, April 1996}
  158. var
  159. G : longint;
  160. i : integer;
  161. begin
  162. Result := 0;
  163. for i := 1 to length(S) do begin
  164. Result := (Result shl 4) + ord(S[i]);
  165. G := Result and $F0000000;
  166. if (G <> 0) then
  167. Result := Result xor (G shr 24);
  168. Result := Result and (not G);
  169. end;
  170. end;
  171. { TElfResCreator }
  172. const
  173. sectionNames: array[TSectionKind] of PChar = (
  174. '.symtab',
  175. '.strtab',
  176. '.shstrtab',
  177. '.text',
  178. '.data',
  179. '.bss',
  180. '.fpc.ressym',
  181. '.fpc.resstr',
  182. '.fpc.reshash',
  183. '.fpc.resdata',
  184. '.fpc.resspare'
  185. );
  186. procedure TElfResCreator.AllocateData;
  187. var
  188. i: TSectionKind;
  189. begin
  190. FSectionStream:=TMemoryStream.Create;
  191. FDataStream:=TMemoryStream.Create;
  192. FSymStream:=TMemoryStream.Create;
  193. FHashStream:=TMemoryStream.Create;
  194. for i := Low(TSectionKind) to High(TSectionKind) do
  195. begin
  196. FShStrOffsets[i] := Length(FShStrTab) + 1;
  197. FShStrTab := FShStrTab + #0 + string(sectionNames[i]);
  198. end;
  199. FShStrTab := FShStrTab + #0#0;
  200. end;
  201. procedure TElfResCreator.FreeData;
  202. begin
  203. FreeAndNil(FSectionStream);
  204. FreeAndNil(FDataStream);
  205. FreeAndNil(FSymStream);
  206. FreeAndNil(FHashStream);
  207. end;
  208. constructor TElfResCreator.Create;
  209. begin
  210. FVersion:=fpcres2elf_version;
  211. FOverwrite:=True;
  212. FVerbose:=False;
  213. FExtension:=SDefaultExtension;
  214. end;
  215. // fill the memorystream so it is aligned, max supported align is 16
  216. procedure TElfResCreator.DoAlign(const a: integer);
  217. var i: integer;
  218. begin
  219. i:=(4 - (FSectionStream.position MOD a)) MOD a;
  220. if (i>0) then FSectionStream.Write(zeros[1],i);
  221. end;
  222. procedure TElfResCreator.Convert(const Source, Destination: String);
  223. Var
  224. Src,Dest : TFileStream;
  225. begin
  226. FSourceFileName:=Source;
  227. FDestFileName:=Destination;
  228. if FDestFileName='' then
  229. FDestFileName:=ChangeFileExt(Source,FExtension);
  230. Src:=TFileStream.Create(FSourceFileName,fmOpenRead or fmShareDenyWrite);
  231. try
  232. Dest:=TFileStream.Create(FDestFileName,fmCreate or fmShareDenyWrite);
  233. Try
  234. ConvertStreams(Src,Dest);
  235. Finally
  236. Dest.Free;
  237. end;
  238. Finally
  239. Src.Free;
  240. end;
  241. end;
  242. procedure TElfResCreator.ConvertStreams(Source, Dest: TStream);
  243. begin
  244. AllocateData;
  245. Try
  246. DoConvertStreams(Source,Dest);
  247. Finally
  248. FreeData;
  249. end;
  250. end;
  251. { ---------------------------------------------------------------------
  252. TElf32ResCreator
  253. ---------------------------------------------------------------------}
  254. procedure TElf32ResCreator.AllocateData;
  255. begin
  256. inherited AllocateData;
  257. // reserve space for 1024 resource entries for now
  258. SetLength(ResourceEntries,1024);
  259. CurrentResource:=0;
  260. end;
  261. procedure TElf32ResCreator.FreeData;
  262. begin
  263. inherited FreeData;
  264. SetLength(ResourceEntries,0);
  265. end;
  266. procedure TElf32ResCreator.LoadRESEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  267. var l:longint;
  268. w:word;
  269. ws:WideString;
  270. wc:WideChar;
  271. name:string;
  272. i,nl: integer;
  273. headersize:integer;
  274. headerstart:integer;
  275. begin
  276. headerstart:=rs.Position;
  277. resinfo.ptr:=DataStream.Position;
  278. rs.Read(resinfo.size,4);
  279. rs.Read(headersize,4);
  280. rs.Read(l,4); // Type
  281. if (l AND $0000FFFF)=$0000FFFF then
  282. begin // Type is stored as ID
  283. resinfo.restype:=(l AND $FFFF0000) shr 16; // kill the marker, we always use IDs
  284. end
  285. else
  286. begin
  287. // we don't support text IDs for now, skip until we have reached the end
  288. // of the widestring, and set rcdata (10) in this case.
  289. repeat
  290. rs.Read(w,2);
  291. until w=0;
  292. resinfo.restype:=10;
  293. end;
  294. rs.Read(l,4); // Name
  295. if (l AND $0000FFFF)=$0000FFFF then
  296. begin // Name is stored as ID.
  297. l:=(l AND $FFFF0000) shr 16; // kill the marker
  298. // We don't want to support integer names, we'll instead convert them to a #id string
  299. // which is more common.
  300. name:='#'+inttostr(l);
  301. end
  302. else
  303. begin
  304. // Ok, it's a widestring ID
  305. ws:=widechar(l AND $0000FFFF);
  306. ws:=ws+widechar((l AND $FFFF0000) shr 16);
  307. // get the rest of it
  308. repeat
  309. rs.Read(wc,2);
  310. if wc<>#0 then ws:=ws+wc;
  311. until wc=#0;
  312. // convert to ANSI
  313. name:=ws;
  314. end;
  315. // create a hash of the name
  316. resinfo.reshash:=HashELF(name);
  317. // save the name plus a trailing #0 to the SymStream, also save
  318. // the position of this name in the SymStream
  319. resinfo.name:=SymStream.Position;
  320. name:=name+#0;
  321. nl:=length(name);
  322. SymStream.Write(name[1],length(name));
  323. // We don't care about the rest of the header
  324. rs.Seek(headersize-(rs.position-headerstart),soFromCurrent);
  325. // Now copy over the resource data into our internal memory stream
  326. DataStream.CopyFrom(rs,resinfo.size);
  327. // Align the resource stream on a dword boundary
  328. i:=(4 - (rs.Position MOD 4)) MOD 4;
  329. if (i>0) then rs.Seek(i,soFromCurrent);
  330. // Align the data stream on a dword boundary
  331. i:=(4 - (DataStream.Position MOD 4)) MOD 4;
  332. if (i>0) then DataStream.Write(zeros[1],i);
  333. end;
  334. procedure TElf32ResCreator.LoadBinaryDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  335. var name: string;
  336. i: integer;
  337. begin
  338. resinfo.ptr:=0;
  339. resinfo.restype:=10; // RCDATA
  340. // Skip the header
  341. rs.Position:=3;
  342. // Read the name
  343. setlength(name,64); // Component names can be 64 chars at max
  344. rs.Read(name[1],64);
  345. // Find end of name
  346. i:=pos(#0,name);
  347. name:=copy(name,1,i-1);
  348. // Seek to after the name and skip other crap
  349. rs.Position:=i+9;
  350. resinfo.size:=rs.Size-rs.Position;
  351. // ...this is followed by the data.
  352. // create a hash of the name
  353. resinfo.reshash:=HashELF(name);
  354. // save the name plus a trailing #0 to the SymStream, also save
  355. // the position of this name in the SymStream
  356. resinfo.name:=SymStream.Position;
  357. name:=name+#0;
  358. SymStream.Write(name[1],length(name));
  359. // Now copy over the resource data into our internal memory stream
  360. DataStream.CopyFrom(rs,resinfo.size);
  361. // Align the data stream on a dword boundary
  362. i:=(4 - (DataStream.Position MOD 4)) MOD 4;
  363. if (i>0) then DataStream.Write(zeros,i);
  364. end;
  365. procedure TElf32ResCreator.LoadTextDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  366. var ms:TMemoryStream;
  367. begin
  368. ms:=nil;
  369. try
  370. ms:=TMemoryStream.Create;
  371. ObjectTextToResource(rs,ms);
  372. LoadBinaryDFMEntry(ms, DataStream, SymStream, resinfo);
  373. finally
  374. ms.free;
  375. end;
  376. end;
  377. procedure TElf32ResCreator.AddSection(aKind: TSectionKind; atype, aflags, aaddr, aoffset, asize, alink, ainfo, aaddralign, aentsize: longint);
  378. var
  379. sechdr: TElf32sechdr;
  380. begin
  381. sechdr.sh_name := FShStrOffsets[aKind];
  382. sechdr.sh_type := atype;
  383. sechdr.sh_flags := aflags;
  384. sechdr.sh_addr := aaddr;
  385. sechdr.sh_offset := aoffset;
  386. sechdr.sh_size := asize;
  387. sechdr.sh_link := alink;
  388. sechdr.sh_info := ainfo;
  389. sechdr.sh_addralign := aaddralign;
  390. sechdr.sh_entsize := aentsize;
  391. FSectionStream.Write(sechdr, sizeOf(sechdr));
  392. end;
  393. procedure TElf32ResCreator.DoConvertStreams(Source, Dest: TStream);
  394. Var
  395. I : Integer;
  396. ElfHeader: TElf32Header;
  397. SectionHeader: TElf32sechdr;
  398. ressym: TELF32ResourceSectionInfo;
  399. resstr: TELF32ResourceSectionInfo;
  400. reshash: TELF32ResourceSectionInfo;
  401. resdata: TELF32ResourceSectionInfo;
  402. resspare: TELF32ResourceSectionInfo;
  403. begin
  404. // Read and check the header of the input file. First check if it's a 32bit resource
  405. // file...
  406. SetLength(resheader,32);
  407. Source.Read(resheader[1],32);
  408. if (resheader<>reshdr) then
  409. begin
  410. // ...not a 32Bit resource file. Now let's see if it's a text or binary dfm/xfm/lfm file.
  411. Source.Position:=0;
  412. Source.Read(Signature,1);
  413. if (Signature=$FF) then
  414. begin
  415. Source.Position:=0;
  416. LoadBinaryDFMEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
  417. end
  418. else if char(Signature) in ['o','O','i','I',' ',#13,#11,#9] then
  419. begin
  420. Source.Position:=0;
  421. LoadTextDFMEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
  422. end
  423. else
  424. DoErrorFmt(SErrUnrecognizedFormat,[SourceFileName]);
  425. inc(CurrentResource,1);
  426. end
  427. else // ...yes, it's a resource file.
  428. while Source.Position<Source.Size do
  429. begin
  430. // Load Resource info, and copy the resource data into the DataStream
  431. LoadRESEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
  432. inc(CurrentResource,1);
  433. // if we hit the current limit of allocated ResourceEntries in the
  434. // array, allocate some more space
  435. if (CurrentResource>=length(ResourceEntries)) then
  436. setlength(ResourceEntries,length(ResourceEntries)+1024);
  437. end;
  438. // downsize the ResourceEntries to the really needed size
  439. SetLength(ResourceEntries,CurrentResource);
  440. // Write the symbol table - ressym
  441. ressym.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  442. FSymStream.Position:=0;
  443. FSectionStream.CopyFrom(FSymStream,FSymStream.Size);
  444. // resstr
  445. resstr.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  446. resstr.size:=0;
  447. // TODO: Load string data here
  448. doalign(4);
  449. // Now write the ResourceInfos.
  450. reshash.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  451. for i:=0 to high(ResourceEntries) do
  452. begin
  453. FSectionStream.Write(ResourceEntries[i],sizeof(TELF32ResourceInfo));
  454. end;
  455. doalign(4);
  456. // Next write the resource data stream
  457. resdata.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  458. FDataStream.Position:=0;
  459. FSectionStream.CopyFrom(FDataStream,FDataStream.Size);
  460. doalign(4);
  461. // resspare
  462. resspare.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  463. // don't write anything, this is an empty section
  464. // shstrtab - this is not aligned
  465. shstrtab_ofs:=FSectionStream.Position+sizeof(TElf32Header);
  466. FSectionStream.Write(FShStrtab[1], length(FShStrtab));
  467. // Write 12 section headers. The headers itself don't need to be aligned,
  468. // as their size can be divided by 4. As shstrtab is uneven and not aligned,
  469. // we however need to align the start of the section header table
  470. doalign(4);
  471. sectionheader_ofs:=FSectionStream.Position+sizeof(TElf32Header);;
  472. // empty one
  473. fillchar(SectionHeader,sizeof(SectionHeader),0);
  474. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  475. AddSection(skText, SHT_PROGBITS, 6 {AX}, 0, sizeof(TElf32Header), 0, 0, 0, 4, 0);
  476. AddSection(skData, SHT_PROGBITS, 3 {WA}, 0, sizeof(TElf32Header), 0, 0, 0, 4, 0);
  477. AddSection(skBss, SHT_NOBITS, 3 {WA}, 0, sizeof(TElf32Header), 0, 0, 0, 4, 0);
  478. AddSection(skFpcRessym, SHT_PROGBITS, 2 {A}, 0, ressym.ptr, FSymStream.Size, 0, 0, 1, 0);
  479. AddSection(skFpcResstr, SHT_PROGBITS, 2 {A}, 0, resstr.ptr, 0, 0, 0, 4, 0);
  480. AddSection(skFpcReshash, SHT_PROGBITS, 2 {A}, 0, reshash.ptr, length(ResourceEntries)*sizeof(TELF32ResourceInfo), 0, 0, 4, 0);
  481. AddSection(skFpcResdata, SHT_PROGBITS, 2 {A}, 0, resdata.ptr, FDataStream.Size, 0, 0, 4, 0);
  482. AddSection(skFpcResspare, SHT_NOBITS, 2 {A}, 0, resspare.ptr, 0, 0, 0, 4, 0);
  483. AddSection(skShstrtab, SHT_STRTAB, 0, 0, shstrtab_ofs, length(FShStrtab), 0, 0, 1, 0);
  484. AddSection(skSymtab, SHT_SYMTAB, 0, 0, FSectionStream.Position+sizeof(TElf32Header) + 2 * sizeof(SectionHeader), length(symtab), $0B, $09, 4, $10);
  485. AddSection(skStrtab, SHT_STRTAB, 0, 0, FSectionStream.Position+sizeof(TElf32Header) + sizeof(SectionHeader) + length(symtab), 1, 0, 0, 1, 0);
  486. // now write the symbol table
  487. FSectionStream.Write(symtab[1],length(symtab));
  488. // We don't need to align it, as it's $90 in size
  489. // now write the string table, it's just a single byte
  490. FSectionStream.Write(strtab[1],1);
  491. // Ok, we are done, now let's really write something to disk...
  492. // First write the ELF header
  493. fillchar(ElfHeader,sizeof(ElfHeader),0);
  494. ElfHeader.magic0123:=$464c457f; { = #127'ELF' }
  495. ElfHeader.file_class:=1;
  496. ElfHeader.data_encoding:=1;
  497. ElfHeader.file_version:=1;
  498. ElfHeader.e_type:=1;
  499. ElfHeader.e_machine:=3;
  500. ElfHeader.e_version:=1;
  501. ElfHeader.e_shoff:=sectionheader_ofs;
  502. ElfHeader.e_shstrndx:=9;
  503. ElfHeader.e_shnum:=12;
  504. ElfHeader.e_ehsize:=sizeof(TElf32header);
  505. ElfHeader.e_shentsize:=sizeof(TElf32sechdr);
  506. Dest.Write(ElfHeader,sizeof(TElf32header));
  507. // And now let's dump our whole memorystream into it.
  508. FSectionStream.Position:=0;
  509. Dest.CopyFrom(FSectionStream,FsectionStream.Size);
  510. end;
  511. { TElf64Creator }
  512. procedure TElf64ResCreator.DoConvertStreams(Source, Dest: TStream);
  513. begin
  514. DoError('64 bits resources not yet supported')
  515. end;
  516. end.