elfres.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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. // Do not change the following consts, they are dummy tables to generate an .o that makes ld happy
  68. const shstrtab = #0+'.symtab'+#0+'.strtab'+#0+'.shstrtab'+#0+'.text'+#0+'.data'+#0+
  69. '.bss'+#0+'fpc.ressym'+#0+'fpc.resstr'+#0+'fpc.reshash'+#0+
  70. 'fpc.resdata'+#0+'fpc.resspare'+#0+#0;
  71. 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. fake = 'fakefakefakefakefakefakefakefake';
  83. // header of a windows 32 bit .res file (16 bytes)
  84. reshdr = #$00#$00#$00#$00#$20#$00#$00#$00#$FF#$FF#$00#$00#$FF#$FF#$00#$00+
  85. #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00;
  86. FilerSignature: array[1..4] of Char = 'TPF0';
  87. SDefaultExtension = '.or';
  88. Type
  89. { TElfResCreator }
  90. TElfResCreator = Class(TObject)
  91. private
  92. FDestFileName: String;
  93. FExtension: string;
  94. FSourceFileName: String;
  95. FOverwrite: Boolean;
  96. FVerbose: Boolean;
  97. FVersion: Integer;
  98. Protected
  99. FSectionStream: TMemoryStream;
  100. FDataStream: TMemoryStream;
  101. FSymStream: TMemoryStream;
  102. FHashStream: TMemoryStream;
  103. sectionheader_ofs: integer;
  104. shstrtab_ofs: integer;
  105. CurrentResource:integer;
  106. resheader: string;
  107. Signature: byte;
  108. Procedure AllocateData; virtual;
  109. Procedure FreeData; virtual;
  110. Procedure DoAlign(const a: integer);
  111. Public
  112. Constructor Create;
  113. Procedure Convert(Const Source,Destination : String);
  114. Procedure ConvertStreams(Source,Dest : TStream);
  115. Procedure DoConvertStreams(Source,Dest : TStream); virtual;Abstract;
  116. Property Verbose : Boolean Read FVerbose Write FVerbose;
  117. Property SourceFileName : String Read FSourceFileName;
  118. Property DestFileName : String Read FDestFileName;
  119. Property Overwrite : Boolean Read FOverwrite Write FOverWrite;
  120. Property Version : Integer Read FVersion Write FVersion;
  121. Property Extension : string Read FExtension Write FExtension;
  122. end;
  123. { TElf32ResCreator }
  124. TElf32ResCreator = Class(TElfResCreator)
  125. Private
  126. ResourceEntries: array of TELF32ResourceInfo;
  127. Protected
  128. Procedure AllocateData; override;
  129. Procedure FreeData; override;
  130. public
  131. procedure LoadBinaryDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  132. procedure LoadTextDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  133. procedure LoadRESEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  134. Procedure DoConvertStreams(Source,Dest : TStream); override;
  135. end;
  136. { TElf64Creator }
  137. TElf64ResCreator = Class(TElfResCreator)
  138. Procedure DoConvertStreams(Source,Dest : TStream); override;
  139. end;
  140. EElfResError = Class(Exception);
  141. implementation
  142. resourcestring
  143. SErrUnrecognizedFormat = 'Unrecognized file format for input file "%s"';
  144. Procedure DoError (Msg : String);
  145. begin
  146. Raise EElfResError.Create(Msg);
  147. end;
  148. Procedure DoErrorFmt (Msg : String; Args : Array of const);
  149. begin
  150. Raise EElfResError.CreateFmt(Msg,Args);
  151. end;
  152. function HashELF(const S : string) : longint;
  153. {Note: this hash function is described in "Practical Algorithms For
  154. Programmers" by Andrew Binstock and John Rex, Addison Wesley,
  155. with modifications in Dr Dobbs Journal, April 1996}
  156. var
  157. G : longint;
  158. i : integer;
  159. begin
  160. Result := 0;
  161. for i := 1 to length(S) do begin
  162. Result := (Result shl 4) + ord(S[i]);
  163. G := Result and $F0000000;
  164. if (G <> 0) then
  165. Result := Result xor (G shr 24);
  166. Result := Result and (not G);
  167. end;
  168. end;
  169. { TElfResCreator }
  170. procedure TElfResCreator.AllocateData;
  171. begin
  172. FSectionStream:=TMemoryStream.Create;
  173. FDataStream:=TMemoryStream.Create;
  174. FSymStream:=TMemoryStream.Create;
  175. FHashStream:=TMemoryStream.Create;
  176. end;
  177. procedure TElfResCreator.FreeData;
  178. begin
  179. FreeAndNil(FSectionStream);
  180. FreeAndNil(FDataStream);
  181. FreeAndNil(FSymStream);
  182. FreeAndNil(FHashStream);
  183. end;
  184. constructor TElfResCreator.Create;
  185. begin
  186. FVersion:=fpcres2elf_version;
  187. FOverwrite:=True;
  188. FVerbose:=False;
  189. FExtension:=SDefaultExtension;
  190. end;
  191. // fill the memorystream so it is aligned, max supported align is 16
  192. procedure TElfResCreator.DoAlign(const a: integer);
  193. var i: integer;
  194. begin
  195. i:=(4 - (FSectionStream.position MOD a)) MOD a;
  196. if (i>0) then FSectionStream.Write(zeros[1],i);
  197. end;
  198. procedure TElfResCreator.Convert(const Source, Destination: String);
  199. Var
  200. Src,Dest : TFileStream;
  201. begin
  202. FSourceFileName:=Source;
  203. FDestFileName:=Destination;
  204. if FDestFileName='' then
  205. FDestFileName:=ChangeFileExt(Source,FExtension);
  206. Src:=TFileStream.Create(FSourceFileName,fmOpenRead or fmShareDenyWrite);
  207. try
  208. Dest:=TFileStream.Create(FDestFileName,fmCreate or fmShareDenyWrite);
  209. Try
  210. ConvertStreams(Src,Dest);
  211. Finally
  212. Dest.Free;
  213. end;
  214. Finally
  215. Src.Free;
  216. end;
  217. end;
  218. procedure TElfResCreator.ConvertStreams(Source, Dest: TStream);
  219. begin
  220. AllocateData;
  221. Try
  222. DoConvertStreams(Source,Dest);
  223. Finally
  224. FreeData;
  225. end;
  226. end;
  227. { ---------------------------------------------------------------------
  228. TElf32ResCreator
  229. ---------------------------------------------------------------------}
  230. procedure TElf32ResCreator.AllocateData;
  231. begin
  232. inherited AllocateData;
  233. // reserve space for 1024 resource entries for now
  234. SetLength(ResourceEntries,1024);
  235. CurrentResource:=0;
  236. end;
  237. procedure TElf32ResCreator.FreeData;
  238. begin
  239. inherited FreeData;
  240. SetLength(ResourceEntries,0);
  241. end;
  242. procedure TElf32ResCreator.LoadRESEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  243. var l:longint;
  244. w:word;
  245. ws:WideString;
  246. wc:WideChar;
  247. name:string;
  248. i,nl: integer;
  249. headersize:integer;
  250. headerstart:integer;
  251. begin
  252. headerstart:=rs.Position;
  253. resinfo.ptr:=DataStream.Position;
  254. rs.Read(resinfo.size,4);
  255. rs.Read(headersize,4);
  256. rs.Read(l,4); // Type
  257. if (l AND $0000FFFF)=$0000FFFF then
  258. begin // Type is stored as ID
  259. resinfo.restype:=(l AND $FFFF0000) shr 16; // kill the marker, we always use IDs
  260. end
  261. else
  262. begin
  263. // we don't support text IDs for now, skip until we have reached the end
  264. // of the widestring, and set rcdata (10) in this case.
  265. repeat
  266. rs.Read(w,2);
  267. until w=0;
  268. resinfo.restype:=10;
  269. end;
  270. rs.Read(l,4); // Name
  271. if (l AND $0000FFFF)=$0000FFFF then
  272. begin // Name is stored as ID.
  273. l:=(l AND $FFFF0000) shr 16; // kill the marker
  274. // We don't want to support integer names, we'll instead convert them to a #id string
  275. // which is more common.
  276. name:='#'+inttostr(l);
  277. end
  278. else
  279. begin
  280. // Ok, it's a widestring ID
  281. ws:=widechar(l AND $0000FFFF);
  282. ws:=ws+widechar((l AND $FFFF0000) shr 16);
  283. // get the rest of it
  284. repeat
  285. rs.Read(wc,2);
  286. if wc<>#0 then ws:=ws+wc;
  287. until wc=#0;
  288. // convert to ANSI
  289. name:=ws;
  290. end;
  291. // create a hash of the name
  292. resinfo.reshash:=HashELF(name);
  293. // save the name plus a trailing #0 to the SymStream, also save
  294. // the position of this name in the SymStream
  295. resinfo.name:=SymStream.Position;
  296. name:=name+#0;
  297. nl:=length(name);
  298. SymStream.Write(name[1],length(name));
  299. // We don't care about the rest of the header
  300. rs.Seek(headersize-(rs.position-headerstart),soFromCurrent);
  301. // Now copy over the resource data into our internal memory stream
  302. DataStream.CopyFrom(rs,resinfo.size);
  303. // Align the resource stream on a dword boundary
  304. i:=(4 - (rs.Position MOD 4)) MOD 4;
  305. if (i>0) then rs.Seek(i,soFromCurrent);
  306. // Align the data stream on a dword boundary
  307. i:=(4 - (DataStream.Position MOD 4)) MOD 4;
  308. if (i>0) then DataStream.Write(zeros[1],i);
  309. end;
  310. procedure TElf32ResCreator.LoadBinaryDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  311. var name: string;
  312. i: integer;
  313. begin
  314. resinfo.ptr:=0;
  315. resinfo.restype:=10; // RCDATA
  316. // Skip the header
  317. rs.Position:=3;
  318. // Read the name
  319. setlength(name,64); // Component names can be 64 chars at max
  320. rs.Read(name[1],64);
  321. // Find end of name
  322. i:=pos(#0,name);
  323. name:=copy(name,1,i-1);
  324. // Seek to after the name and skip other crap
  325. rs.Position:=i+9;
  326. resinfo.size:=rs.Size-rs.Position;
  327. // ...this is followed by the data.
  328. // create a hash of the name
  329. resinfo.reshash:=HashELF(name);
  330. // save the name plus a trailing #0 to the SymStream, also save
  331. // the position of this name in the SymStream
  332. resinfo.name:=SymStream.Position;
  333. name:=name+#0;
  334. SymStream.Write(name[1],length(name));
  335. // Now copy over the resource data into our internal memory stream
  336. DataStream.CopyFrom(rs,resinfo.size);
  337. // Align the data stream on a dword boundary
  338. i:=(4 - (DataStream.Position MOD 4)) MOD 4;
  339. if (i>0) then DataStream.Write(zeros,i);
  340. end;
  341. procedure TElf32ResCreator.LoadTextDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
  342. var ms:TMemoryStream;
  343. begin
  344. ms:=nil;
  345. try
  346. ms:=TMemoryStream.Create;
  347. ObjectTextToResource(rs,ms);
  348. LoadBinaryDFMEntry(ms, DataStream, SymStream, resinfo);
  349. finally
  350. ms.free;
  351. end;
  352. end;
  353. procedure TElf32ResCreator.DoConvertStreams(Source, Dest: TStream);
  354. Var
  355. I : Integer;
  356. ElfHeader: TElf32Header;
  357. SectionHeader: TElf32sechdr;
  358. ressym: TELF32ResourceSectionInfo;
  359. resstr: TELF32ResourceSectionInfo;
  360. reshash: TELF32ResourceSectionInfo;
  361. resdata: TELF32ResourceSectionInfo;
  362. resspare: TELF32ResourceSectionInfo;
  363. begin
  364. // Read and check the header of the input file. First check if it's a 32bit resource
  365. // file...
  366. SetLength(resheader,32);
  367. Source.Read(resheader[1],32);
  368. if (resheader<>reshdr) then
  369. begin
  370. // ...not a 32Bit resource file. Now let's see if it's a text or binary dfm/xfm/lfm file.
  371. Source.Position:=0;
  372. Source.Read(Signature,1);
  373. if (Signature=$FF) then
  374. begin
  375. Source.Position:=0;
  376. LoadBinaryDFMEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
  377. end
  378. else if char(Signature) in ['o','O','i','I',' ',#13,#11,#9] then
  379. begin
  380. Source.Position:=0;
  381. LoadTextDFMEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
  382. end
  383. else
  384. DoErrorFmt(SErrUnrecognizedFormat,[SourceFileName]);
  385. inc(CurrentResource,1);
  386. end
  387. else // ...yes, it's a resource file.
  388. while Source.Position<Source.Size do
  389. begin
  390. // Load Resource info, and copy the resource data into the DataStream
  391. LoadRESEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
  392. inc(CurrentResource,1);
  393. // if we hit the current limit of allocated ResourceEntries in the
  394. // array, allocate some more space
  395. if (CurrentResource>=length(ResourceEntries)) then
  396. setlength(ResourceEntries,length(ResourceEntries)+1024);
  397. end;
  398. // downsize the ResourceEntries to the really needed size
  399. SetLength(ResourceEntries,CurrentResource);
  400. // Write the symbol table - ressym
  401. ressym.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  402. FSymStream.Position:=0;
  403. FSectionStream.CopyFrom(FSymStream,FSymStream.Size);
  404. // resstr
  405. resstr.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  406. resstr.size:=0;
  407. // TODO: Load string data here
  408. doalign(4);
  409. // Now write the ResourceInfos.
  410. reshash.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  411. for i:=0 to high(ResourceEntries) do
  412. begin
  413. FSectionStream.Write(ResourceEntries[i],sizeof(TELF32ResourceInfo));
  414. end;
  415. doalign(4);
  416. // Next write the resource data stream
  417. resdata.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  418. FDataStream.Position:=0;
  419. FSectionStream.CopyFrom(FDataStream,FDataStream.Size);
  420. doalign(4);
  421. // resspare
  422. resspare.ptr:=FSectionStream.Position+sizeof(TElf32Header);
  423. // don't write anything, this is an empty section
  424. // shstrtab - this is not aligned
  425. shstrtab_ofs:=FSectionStream.Position+sizeof(TElf32Header);
  426. FSectionStream.Write(shstrtab[1],length(shstrtab));
  427. // Write 12 section headers. The headers itself don't need to be aligned,
  428. // as their size can be divided by 4. As shstrtab is uneven and not aligned,
  429. // we however need to align the start of the section header table
  430. doalign(4);
  431. sectionheader_ofs:=FSectionStream.Position+sizeof(TElf32Header);;
  432. // empty one
  433. fillchar(SectionHeader,sizeof(SectionHeader),0);
  434. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  435. // .text
  436. SectionHeader.sh_name:=$1B;
  437. SectionHeader.sh_type:=1; // PROGBITS
  438. SectionHeader.sh_flags:=6; // AX
  439. SectionHeader.sh_addr:=0;
  440. SectionHeader.sh_offset:=sizeof(TElf32Header); // after header, dummy as size is 0
  441. SectionHeader.sh_size:=0; // yep, pretty empty it is
  442. SectionHeader.sh_link:=0;
  443. SectionHeader.sh_info:=0;
  444. SectionHeader.sh_addralign:=4; // alignment
  445. SectionHeader.sh_entsize:=0;
  446. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  447. // .data
  448. SectionHeader.sh_name:=$21;
  449. SectionHeader.sh_type:=1; // PROGBITS
  450. SectionHeader.sh_flags:=3; // WA
  451. SectionHeader.sh_addr:=0;
  452. SectionHeader.sh_offset:=sizeof(TElf32Header); // after header, dummy as size is 0
  453. SectionHeader.sh_size:=0; // yep, pretty empty it is
  454. SectionHeader.sh_link:=0;
  455. SectionHeader.sh_info:=0;
  456. SectionHeader.sh_addralign:=4; // alignment
  457. SectionHeader.sh_entsize:=0;
  458. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  459. // .bss
  460. SectionHeader.sh_name:=$27;
  461. SectionHeader.sh_type:=8; // NOBITS
  462. SectionHeader.sh_flags:=3; // WA
  463. SectionHeader.sh_addr:=0;
  464. SectionHeader.sh_offset:=sizeof(TElf32Header); // after header, dummy as size is 0
  465. SectionHeader.sh_size:=0; // yep, pretty empty it is
  466. SectionHeader.sh_link:=0;
  467. SectionHeader.sh_info:=0;
  468. SectionHeader.sh_addralign:=4; // alignment
  469. SectionHeader.sh_entsize:=0;
  470. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  471. // fpc.ressym
  472. SectionHeader.sh_name:=$2C;
  473. SectionHeader.sh_type:=1; // PROGBITS
  474. SectionHeader.sh_flags:=2; // A
  475. SectionHeader.sh_addr:=0;
  476. SectionHeader.sh_offset:=ressym.ptr; // directly after header
  477. SectionHeader.sh_size:=FSymStream.Size;
  478. SectionHeader.sh_link:=0;
  479. SectionHeader.sh_info:=0;
  480. SectionHeader.sh_addralign:=1; // DON'T align this, as this section will be merged by ld
  481. SectionHeader.sh_entsize:=0;
  482. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  483. // fpc.resstr
  484. SectionHeader.sh_name:=$37;
  485. SectionHeader.sh_type:=1; // PROGBITS
  486. SectionHeader.sh_flags:=2; // A
  487. SectionHeader.sh_addr:=0;
  488. SectionHeader.sh_offset:=resstr.ptr;
  489. SectionHeader.sh_size:=0; // currently empty
  490. SectionHeader.sh_link:=0;
  491. SectionHeader.sh_info:=0;
  492. SectionHeader.sh_addralign:=4; // alignment
  493. SectionHeader.sh_entsize:=0;
  494. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  495. // fpc.reshash
  496. SectionHeader.sh_name:=$42;
  497. SectionHeader.sh_type:=1; // PROGBITS
  498. SectionHeader.sh_flags:=2; // A
  499. SectionHeader.sh_addr:=0;
  500. SectionHeader.sh_offset:=reshash.ptr;
  501. SectionHeader.sh_size:=length(ResourceEntries)*sizeof(TELF32ResourceInfo);
  502. SectionHeader.sh_link:=0;
  503. SectionHeader.sh_info:=0;
  504. SectionHeader.sh_addralign:=4; // alignment
  505. SectionHeader.sh_entsize:=0;
  506. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  507. // fpc.resdata
  508. SectionHeader.sh_name:=$4e;
  509. SectionHeader.sh_type:=1; // PROGBITS
  510. SectionHeader.sh_flags:=2; // A
  511. SectionHeader.sh_addr:=0;
  512. SectionHeader.sh_offset:=resdata.ptr;
  513. SectionHeader.sh_size:=FDataStream.Size;
  514. SectionHeader.sh_link:=0;
  515. SectionHeader.sh_info:=0;
  516. SectionHeader.sh_addralign:=4; // alignment
  517. SectionHeader.sh_entsize:=0;
  518. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  519. // fpc.resspare
  520. // Not used in V1
  521. SectionHeader.sh_name:=$5a;
  522. SectionHeader.sh_type:=8; // NOBITS
  523. SectionHeader.sh_flags:=2; // A
  524. SectionHeader.sh_addr:=0;
  525. SectionHeader.sh_offset:=resspare.ptr; // fake, as it's empty, should be equal to shstrtab's offset
  526. SectionHeader.sh_size:=0; //DataStream.Size; // Leave as much room as we currently have in resdata section
  527. SectionHeader.sh_link:=0;
  528. SectionHeader.sh_info:=0;
  529. SectionHeader.sh_addralign:=4; // alignment
  530. SectionHeader.sh_entsize:=0;
  531. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  532. // .shstrtab
  533. SectionHeader.sh_name:=$11;
  534. SectionHeader.sh_type:=3; // STRTAB
  535. SectionHeader.sh_flags:=0;
  536. SectionHeader.sh_addr:=0;
  537. SectionHeader.sh_offset:=shstrtab_ofs; // $3E
  538. SectionHeader.sh_size:=$67;
  539. SectionHeader.sh_link:=0;
  540. SectionHeader.sh_info:=0;
  541. SectionHeader.sh_addralign:=1; // alignment
  542. SectionHeader.sh_entsize:=0;
  543. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  544. // .symtab
  545. SectionHeader.sh_name:=$01;
  546. SectionHeader.sh_type:=2; // SYMTAB
  547. SectionHeader.sh_flags:=0;
  548. SectionHeader.sh_addr:=0;
  549. SectionHeader.sh_offset:=FSectionStream.Position+sizeof(TElf32Header)+sizeOf(SectionHeader)+sizeOf(SectionHeader); // will come directly after this and the next section. $0288;
  550. SectionHeader.sh_size:=$90;
  551. SectionHeader.sh_link:=$0B;
  552. SectionHeader.sh_info:=$09;
  553. SectionHeader.sh_addralign:=4; // alignment
  554. SectionHeader.sh_entsize:=$10;
  555. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  556. // .strtab
  557. SectionHeader.sh_name:=$09;
  558. SectionHeader.sh_type:=3; // STRTAB
  559. SectionHeader.sh_flags:=0;
  560. SectionHeader.sh_addr:=0;
  561. SectionHeader.sh_offset:=FSectionStream.Position+sizeof(TElf32Header)+sizeOf(SectionHeader)+$90; // will come after this sectionheader and the $90 bytes symtab - $0318; end of file
  562. SectionHeader.sh_size:=1;
  563. SectionHeader.sh_link:=0;
  564. SectionHeader.sh_info:=0;
  565. SectionHeader.sh_addralign:=1; // alignment
  566. SectionHeader.sh_entsize:=$0;
  567. FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
  568. // now write the symbol table
  569. FSectionStream.Write(symtab[1],length(symtab));
  570. // We don't need to align it, as it's $90 in size
  571. // now write the string table, it's just a single byte
  572. FSectionStream.Write(strtab[1],1);
  573. // Ok, we are done, now let's really write something to disk...
  574. // First write the ELF header
  575. fillchar(ElfHeader,sizeof(ElfHeader),0);
  576. ElfHeader.magic0123:=$464c457f; { = #127'ELF' }
  577. ElfHeader.file_class:=1;
  578. ElfHeader.data_encoding:=1;
  579. ElfHeader.file_version:=1;
  580. ElfHeader.e_type:=1;
  581. ElfHeader.e_machine:=3;
  582. ElfHeader.e_version:=1;
  583. ElfHeader.e_shoff:=sectionheader_ofs;
  584. ElfHeader.e_shstrndx:=9;
  585. ElfHeader.e_shnum:=12;
  586. ElfHeader.e_ehsize:=sizeof(TElf32header);
  587. ElfHeader.e_shentsize:=sizeof(TElf32sechdr);
  588. Dest.Write(ElfHeader,sizeof(TElf32header));
  589. // And now let's dump our whole memorystream into it.
  590. FSectionStream.Position:=0;
  591. Dest.CopyFrom(FSectionStream,FsectionStream.Size);
  592. end;
  593. { TElf64Creator }
  594. procedure TElf64ResCreator.DoConvertStreams(Source, Dest: TStream);
  595. begin
  596. DoError('64 bits resources not yet supported')
  597. end;
  598. end.