elfresfix.pas 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. { *********************************************************************** }
  2. { }
  3. { elfresfix - Free Pascal Resource to ELF object compiler - fixup tool }
  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 tool will update the fpc.resptrs section of an ELF executable to point
  18. to the various resource sections in the file. This is done so that the FPC
  19. RTL at runtime is able to get pointers to these sections.
  20. This tool is automatically run on any fpc compiled ELF executable that
  21. contains ELF resources.
  22. fpcresfix builds with Delphi, Kylix and FPC.
  23. Currently this only works on 32Bit targets, but support for 64Bit targets
  24. is in the works. Support for big endian systems is completely missing,
  25. though.
  26. }
  27. {$ifdef fpc}
  28. {$mode objfpc}
  29. {$endif}
  30. {$h+}
  31. unit elfresfix;
  32. interface
  33. uses
  34. SysUtils, Classes, elfbfd;
  35. Type
  36. TLogEvent = Procedure(Const Msg : String) of object;
  37. { TElfResourceFixer }
  38. TElfResourceFixer = Class(TObject)
  39. private
  40. FFileName: String;
  41. FOnVerbose: TLogEvent;
  42. FVerbose: Boolean;
  43. Procedure DoVerbose(Msg : String);
  44. public
  45. Procedure FixFile(AFileName : String);
  46. Procedure DoFixStream(Stream : TStream); virtual; abstract;
  47. Property Verbose : Boolean read FVerbose write FVerbose;
  48. Property FileName : String Read FFileName;
  49. Property Onverbose : TLogEvent Read FOnVerbose Write FOnVerbose;
  50. end;
  51. { TElf32ResourceFixer }
  52. TElf32ResourceFixer = Class(TElfResourceFixer)
  53. Procedure DoFixStream(Stream : TStream); override;
  54. end;
  55. { TElf64ResourceFixer }
  56. TElf64ResourceFixer = Class(TElfResourceFixer)
  57. Procedure DoFixStream(Stream : TStream); override;
  58. end;
  59. EElfResFixError = Class(Exception);
  60. Implementation
  61. ResourceString
  62. SCheckingHeader = 'Checking ELF Header... ';
  63. SReadingSectionHeaders = 'Reading Section Headers...';
  64. SHeaderOK = 'ELF Header is OK';
  65. SCheckingHeaderTable = 'Checking Section Header table...';
  66. SStrTabFound = 'Found strtab...';
  67. SProcessingSection = 'Processing section: ';
  68. SUpdatingResptrs = 'Updating resptrs section...';
  69. SFileFixed = 'File fixed successfully!';
  70. SNothingToFix = 'There was nothing to fix in this file.';
  71. SErrUnsupportedHeaderSize = 'Unsupported Section Header size.';
  72. SErrInvalidELFHeader = 'Not a valid linux ELF binary.';
  73. SErrResPtrsNotFound = 'Unable to find resptrs section.';
  74. Procedure DoError (Msg : String);
  75. begin
  76. Raise EElfResFixError.Create(Msg);
  77. end;
  78. Procedure DoErrorFmt (Msg : String; Args : Array of const);
  79. begin
  80. Raise EElfResFixError.CreateFmt(Msg,Args);
  81. end;
  82. { TElfResourceFixer }
  83. procedure TElfResourceFixer.DoVerbose(Msg: String);
  84. begin
  85. If FVerbose and Assigned(FOnVerbose) then
  86. FOnVerbose(Msg);
  87. end;
  88. procedure TElfResourceFixer.FixFile(AFileName: String);
  89. Var
  90. F : TStream;
  91. begin
  92. FFileName:=AFileName;
  93. F:=TFileStream.Create(AFilename,fmOpenReadWrite or fmShareDenyWrite);
  94. Try
  95. DoFixStream(F);
  96. Finally
  97. F.Free;
  98. end;
  99. end;
  100. { TElf32ResourceFixer }
  101. procedure TElf32ResourceFixer.DoFixStream(Stream: TStream);
  102. var
  103. ElfHeader:TElf32header;
  104. ResourceSectionTable: TElf32ResourceSectionTable;
  105. SectionHeaders: array of TElf32sechdr;
  106. i:integer;
  107. sn:string;
  108. SectionHeaderOffset:integer;
  109. fixed: boolean;
  110. strtab:string;
  111. SectionName: string;
  112. ResPtrsSection: integer;
  113. begin
  114. Fixed:=False;
  115. Stream.Read(ElfHeader,sizeof(TElf32header));
  116. DoVerbose(SCheckingHeader);
  117. if (ElfHeader.magic0123<>$464C457F) then
  118. DoError(SErrInvalidELFheader);
  119. if ElfHeader.e_shentsize=sizeof(TElf32sechdr) then
  120. DoVerbose(SHeaderOK)
  121. else
  122. DoError(SErrUnSupportedHeaderSize);
  123. DoVerbose(SReadingSectionHeaders);
  124. setlength(SectionHeaders,ElfHeader.e_shnum);
  125. SectionHeaderOffset:=ElfHeader.e_shoff;
  126. Stream.Position:=SectionHeaderOffset;
  127. for i:=0 to ElfHeader.e_shnum-1 do
  128. begin
  129. Stream.Read(SectionHeaders[i],sizeof(TElf32sechdr));
  130. end;
  131. DoVerbose(SCheckingHeaderTable);
  132. // Get the section header strtab
  133. i:=ElfHeader.e_shstrndx;
  134. if SectionHeaders[i].sh_type=SHT_STRTAB then
  135. begin
  136. DoVerbose(SStrTabFound);
  137. // read the strtab
  138. Stream.Position:=SectionHeaders[i].sh_offset;
  139. setlength(strtab,SectionHeaders[i].sh_size);
  140. Stream.Read(strtab[1],SectionHeaders[i].sh_size);
  141. end
  142. else
  143. begin
  144. writeln('Error: Unable to find strtab.');
  145. halt(5);
  146. end;
  147. ResPtrsSection:=-1;
  148. ResourceSectionTable.version:=66;
  149. // Next cycle through all sections to gather pointers to all the resource
  150. // sections, and note the index of the resptrs section
  151. for i:=0 to ElfHeader.e_shnum-1 do
  152. begin
  153. SectionName:=copy(strtab,SectionHeaders[i].sh_name+1,32);
  154. SectionName:=copy(SectionName,1,pos(#0,SectionName)-1);
  155. DoVerbose(SProcessingSection+SectionName);
  156. sn:=Copy(SectionName,1,4);
  157. // FPC section ?
  158. if (sn='fpc.') then
  159. begin
  160. sn:=SectionName;
  161. Delete(SN,1,4);
  162. if SN='resptrs' then
  163. begin
  164. ResPtrsSection:=i;
  165. end
  166. else if sn='ressym' then
  167. begin
  168. ResourceSectionTable.ressym.ptr:=SectionHeaders[i].sh_addr;
  169. ResourceSectionTable.ressym.size:=SectionHeaders[i].sh_size;
  170. end
  171. else if sn='reshash' then
  172. begin
  173. ResourceSectionTable.reshash.ptr:=SectionHeaders[i].sh_addr;
  174. ResourceSectionTable.reshash.size:=SectionHeaders[i].sh_size;
  175. ResourceSectionTable.resentries:=SectionHeaders[i].sh_size DIV sizeof(TELF32ResourceInfo);
  176. end
  177. else if sn='resdata' then
  178. begin
  179. ResourceSectionTable.resdata.ptr:=SectionHeaders[i].sh_addr;
  180. ResourceSectionTable.resdata.size:=SectionHeaders[i].sh_size;
  181. end
  182. else if sn='resspare' then
  183. begin
  184. ResourceSectionTable.resspare.ptr:=SectionHeaders[i].sh_addr;
  185. ResourceSectionTable.resspare.size:=SectionHeaders[i].sh_size;
  186. end
  187. else if SectionName='resstr' then
  188. begin
  189. ResourceSectionTable.resstr.ptr:=SectionHeaders[i].sh_addr;
  190. ResourceSectionTable.resstr.size:=SectionHeaders[i].sh_size;
  191. end;
  192. end
  193. end;
  194. // Ok, we now have pointers to all resource sections and also
  195. // know the number of resources.
  196. // Now update the resptrs table
  197. if ResPtrsSection>-1 then
  198. begin
  199. Doverbose(SUpdatingResPtrs);
  200. Stream.Position:=SectionHeaders[ResPtrsSection].sh_offset;
  201. Stream.Write(ResourceSectionTable,sizeof(TELF32ResourceSectionTable));
  202. fixed:=true;
  203. end
  204. else
  205. DoError(SErrREsptrsNotFound);
  206. if fixed then
  207. DoVerbose(SFileFixed)
  208. else
  209. writeln(SNothingToFix);
  210. end;
  211. { TElf64ResourceFixer }
  212. procedure TElf64ResourceFixer.DoFixStream(Stream: TStream);
  213. begin
  214. DoError('64-bit resources not yet supported');
  215. end;
  216. end.