machosubwriter.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Resource writer for Mach-O 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. _TMachOSymbolTable_ = class(TMachOSymbolTable)
  13. protected
  14. function AddSymbol(aName : string; sect : byte; addr : longword;
  15. glob : boolean) : integer; override;
  16. protected
  17. public
  18. procedure WriteToStream(aStream : TStream); override;
  19. end;
  20. _TMachOSubWriter_ = class(TAbstractMachOSubWriter)
  21. private
  22. procedure SwapSection(var aSection: _TSection_);
  23. protected
  24. procedure PrescanResourceTree; override;
  25. procedure WriteResHeader(aStream : TStream; aResources : TResources); override;
  26. procedure WriteNodeInfos(aStream : TStream); override;
  27. procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
  28. procedure AllocateSpaceForLoadCommands(aStream : TStream); override;
  29. procedure FixLoadCommands(aStream : TStream; aResources : TResources); override;
  30. procedure FixResHeader(aStream : TStream); override;
  31. public
  32. constructor Create(aParent : TMachOResourceWriter; const aMachineType
  33. : TMachOMachineType; const aOppositeEndianess : boolean); override;
  34. end;
  35. { _TMachOSymbolTable_ }
  36. function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword;
  37. glob: boolean): integer;
  38. var p : _PNlist_;
  39. begin
  40. p:=GetMem(sizeof(_TNlist_));
  41. p^.strx:=fStringTable.Add(aName);
  42. p^._type:=N_SECT;
  43. if glob then p^._type:=p^._type or N_EXT;
  44. p^.desc:=0;
  45. p^.sect:=sect;
  46. p^.value:=addr;
  47. Result:=fList.Count;
  48. fList.Add(p);
  49. end;
  50. procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream);
  51. var nlist : _TNlist_;
  52. i : integer;
  53. begin
  54. for i:=0 to fList.Count-1 do
  55. begin
  56. nlist:=_PNlist_(fList[i])^;
  57. if fOppositeEndianess then
  58. begin
  59. nlist.strx:=SwapEndian(nlist.strx);
  60. nlist.desc:=SwapEndian(nlist.desc);
  61. nlist.value:=SwapEndian(nlist.value);
  62. end;
  63. aStream.WriteBuffer(nlist,sizeof(nlist));
  64. end;
  65. end;
  66. { _TMachOSubWriter_ }
  67. procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_);
  68. begin
  69. aSection.addr:=SwapEndian(aSection.addr);
  70. aSection.size:=SwapEndian(aSection.size);
  71. aSection.offset:=SwapEndian(aSection.offset);
  72. aSection.align:=SwapEndian(aSection.align);
  73. aSection.reloff:=SwapEndian(aSection.reloff);
  74. aSection.nreloc:=SwapEndian(aSection.nreloc);
  75. aSection.flags:=SwapEndian(aSection.flags);
  76. aSection.reserved1:=SwapEndian(aSection.reserved1);
  77. aSection.reserved2:=SwapEndian(aSection.reserved2);
  78. end;
  79. procedure _TMachOSubWriter_.PrescanResourceTree;
  80. begin
  81. fResStrTable.Clear;
  82. fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_);
  83. fResStrTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_));
  84. if fResStrTable.Used then
  85. fDataCurOfs:=NextAligned(fDataAlignment,fResStrTable.StartOfs+fResStrTable.Size)
  86. else
  87. fDataCurOfs:=fResStrTable.StartOfs;
  88. end;
  89. procedure _TMachOSubWriter_.WriteResHeader(aStream: TStream;
  90. aResources: TResources);
  91. var hdr : _TResHdr_;
  92. begin
  93. hdr.rootptr:=sizeof(hdr);
  94. hdr.count:=aResources.Count;
  95. hdr.usedhandles:=0;
  96. hdr.handles:=0;
  97. fRelocations.Add(0,1);
  98. fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),2);
  99. if fOppositeEndianess then
  100. begin
  101. hdr.rootptr:=SwapEndian(hdr.rootptr);
  102. hdr.count:=SwapEndian(hdr.count);
  103. //handles must be fixed later
  104. // hdr.usedhandles:=SwapEndian(hdr.usedhandles);
  105. // hdr.handles:=SwapEndian(hdr.handles);
  106. end;
  107. aStream.WriteBuffer(hdr,sizeof(hdr));
  108. end;
  109. procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream);
  110. begin
  111. fCurOfs:=sizeof(_TResHdr_);
  112. WriteNodeInfo(aStream,fRoot);
  113. WriteSubNodes(aStream,fRoot);
  114. end;
  115. procedure _TMachOSubWriter_.WriteNodeInfo(aStream: TStream;
  116. aNode: TResourceTreeNode);
  117. var infonode : _TResInfoNode_;
  118. begin
  119. if aNode.Desc.DescType=dtID then
  120. infonode.nameid:=aNode.Desc.ID
  121. else
  122. begin
  123. infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA;
  124. fRelocations.Add(fCurOfs,1);
  125. end;
  126. infonode.ncount:=aNode.NamedCount;
  127. if aNode.IsLeaf then
  128. begin
  129. infonode.idcountsize:=aNode.Data.RawData.Size;
  130. infonode.subptr:=fDataCurOfs;
  131. fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize);
  132. end
  133. else
  134. begin
  135. infonode.idcountsize:=aNode.IDCount;
  136. infonode.subptr:=aNode.SubDirRVA;
  137. end;
  138. fRelocations.Add(
  139. fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
  140. sizeof(infonode.idcountsize),1);
  141. if fOppositeEndianess then
  142. begin
  143. infonode.nameid:=SwapEndian(infonode.nameid);
  144. infonode.ncount:=SwapEndian(infonode.ncount);
  145. infonode.idcountsize:=SwapEndian(infonode.idcountsize);
  146. infonode.subptr:=SwapEndian(infonode.subptr);
  147. end;
  148. aStream.WriteBuffer(infonode,sizeof(infonode));
  149. inc(fCurOfs,sizeof(infonode));
  150. end;
  151. procedure _TMachOSubWriter_.AllocateSpaceForLoadCommands(aStream: TStream);
  152. var buf : pbyte;
  153. begin
  154. fHeader.sizeofcmds:=
  155. //segment+res section+bss section
  156. sizeof(_TSegmentCommand_)+sizeof(_TSection_)*2+
  157. //symbol table and dynamic symbol table commands
  158. sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+
  159. //common header of the three commands
  160. sizeof(TLoadCommand)*3;
  161. buf:=GetMem(fHeader.sizeofcmds);
  162. FillByte(buf^,fHeader.sizeofcmds,0);
  163. try
  164. aStream.WriteBuffer(buf^,fHeader.sizeofcmds);
  165. finally
  166. FreeMem(buf);
  167. end;
  168. end;
  169. procedure _TMachOSubWriter_.FixLoadCommands(aStream: TStream; aResources : TResources);
  170. var ldcommand : TLoadCommand;
  171. segcommand : _TSegmentCommand_;
  172. symcommand : TSymtabCommand;
  173. dysymcommand : TDySymtabCommand;
  174. ressection,bsssection : _TSection_;
  175. begin
  176. ldcommand.cmd:=fSegType;
  177. ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*2;
  178. FillByte(segcommand.name[0],16,0);
  179. segcommand.vmaddr:=0;
  180. segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count;
  181. segcommand.fileoff:=fSectionStart;
  182. segcommand.filesize:=fDataCurOfs;
  183. segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE;
  184. segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE;
  185. segcommand.nsects:=2;
  186. segcommand.flags:=0;
  187. ressection.sectname:=RsrcSectName;
  188. ressection.segname:=DataSegName;
  189. ressection.addr:=0;
  190. ressection.size:=segcommand.filesize;
  191. ressection.offset:=segcommand.fileoff;
  192. ressection.align:=fSectAlignment;
  193. ressection.reloff:=fRelocations.StartOfs;
  194. ressection.nreloc:=fRelocations.Count;
  195. ressection.flags:=S_ATTR_LOC_RELOC;
  196. ressection.reserved1:=0;
  197. ressection.reserved2:=0;
  198. bsssection.sectname:=HandlesSectName;
  199. bsssection.segname:=DataSegName;
  200. bsssection.addr:=fDataCurOfs;
  201. bsssection.size:=sizeof(_ptrtype_)*aResources.Count;
  202. bsssection.offset:=0;
  203. bsssection.align:=fSectAlignment;
  204. bsssection.reloff:=0;
  205. bsssection.nreloc:=0;
  206. bsssection.flags:=S_ZEROFILL;
  207. bsssection.reserved1:=0;
  208. bsssection.reserved2:=0;
  209. if fOppositeEndianess then
  210. begin
  211. ldcommand.cmd:=SwapEndian(ldcommand.cmd);
  212. ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
  213. segcommand.vmaddr:=SwapEndian(segcommand.vmaddr);
  214. segcommand.vmsize:=SwapEndian(segcommand.vmsize);
  215. segcommand.fileoff:=SwapEndian(segcommand.fileoff);
  216. segcommand.filesize:=SwapEndian(segcommand.filesize);
  217. segcommand.maxprot:=SwapEndian(segcommand.maxprot);
  218. segcommand.initprot:=SwapEndian(segcommand.initprot);
  219. segcommand.nsects:=SwapEndian(segcommand.nsects);
  220. segcommand.flags:=SwapEndian(segcommand.flags);
  221. SwapSection(ressection);
  222. SwapSection(bsssection);
  223. end;
  224. aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
  225. aStream.WriteBuffer(segcommand,sizeof(segcommand));
  226. aStream.WriteBuffer(ressection,sizeof(ressection));
  227. aStream.WriteBuffer(bsssection,sizeof(bsssection));
  228. ldcommand.cmd:=LC_SYMTAB;
  229. ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(symcommand);
  230. symcommand.symoff:=fSymbolTable.StartOfs;
  231. symcommand.nsyms:=fSymbolTable.Count;
  232. symcommand.stroff:=fMachOStringTable.StartOfs;
  233. symcommand.strsize:=NextAligned(fDataAlignment,fMachOStringTable.Size);
  234. if fOppositeEndianess then
  235. begin
  236. ldcommand.cmd:=SwapEndian(ldcommand.cmd);
  237. ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
  238. symcommand.symoff:=SwapEndian(symcommand.symoff);
  239. symcommand.nsyms:=SwapEndian(symcommand.nsyms);
  240. symcommand.stroff:=SwapEndian(symcommand.stroff);
  241. symcommand.strsize:=SwapEndian(symcommand.strsize);
  242. end;
  243. aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
  244. aStream.WriteBuffer(symcommand,sizeof(symcommand));
  245. ldcommand.cmd:=LC_DYSYMTAB;
  246. ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(dysymcommand);
  247. dysymcommand.ilocalsym:=0;
  248. dysymcommand.nlocalsym:=fSymbolTable.LocalCount;
  249. dysymcommand.iextdefsym:=dysymcommand.ilocalsym+dysymcommand.nlocalsym;
  250. dysymcommand.nextdefsym:=fSymbolTable.GlobalCount;
  251. dysymcommand.iundefsym:=dysymcommand.iextdefsym+dysymcommand.nextdefsym;
  252. dysymcommand.nundefsym:=0;
  253. dysymcommand.tocoff:=0;
  254. dysymcommand.ntoc:=0;
  255. dysymcommand.modtaboff:=0;
  256. dysymcommand.nmodtab:=0;
  257. dysymcommand.extrefsymoff:=0;
  258. dysymcommand.nextrefsyms:=0;
  259. dysymcommand.indirectsymoff:=0;
  260. dysymcommand.nindirectsyms:=0;
  261. dysymcommand.extreloff:=0;
  262. dysymcommand.nextrel:=0;
  263. dysymcommand.locreloff:=0;
  264. dysymcommand.nlocrel:=0;
  265. if fOppositeEndianess then
  266. begin
  267. ldcommand.cmd:=SwapEndian(ldcommand.cmd);
  268. ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
  269. dysymcommand.ilocalsym:=SwapEndian(dysymcommand.ilocalsym);
  270. dysymcommand.nlocalsym:=SwapEndian(dysymcommand.nlocalsym);
  271. dysymcommand.iextdefsym:=SwapEndian(dysymcommand.iextdefsym);
  272. dysymcommand.nextdefsym:=SwapEndian(dysymcommand.nextdefsym);
  273. dysymcommand.iundefsym:=SwapEndian(dysymcommand.iundefsym);
  274. dysymcommand.nundefsym:=SwapEndian(dysymcommand.nundefsym);
  275. dysymcommand.tocoff:=SwapEndian(dysymcommand.tocoff);
  276. dysymcommand.ntoc:=SwapEndian(dysymcommand.ntoc);
  277. dysymcommand.modtaboff:=SwapEndian(dysymcommand.modtaboff);
  278. dysymcommand.nmodtab:=SwapEndian(dysymcommand.nmodtab);
  279. dysymcommand.extrefsymoff:=SwapEndian(dysymcommand.extrefsymoff);
  280. dysymcommand.nextrefsyms:=SwapEndian(dysymcommand.nextrefsyms);
  281. dysymcommand.indirectsymoff:=SwapEndian(dysymcommand.indirectsymoff);
  282. dysymcommand.nindirectsyms:=SwapEndian(dysymcommand.nindirectsyms);
  283. dysymcommand.extreloff:=SwapEndian(dysymcommand.extreloff);
  284. dysymcommand.nextrel:=SwapEndian(dysymcommand.nextrel);
  285. dysymcommand.locreloff:=SwapEndian(dysymcommand.locreloff);
  286. dysymcommand.nlocrel:=SwapEndian(dysymcommand.nlocrel);
  287. end;
  288. aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
  289. aStream.WriteBuffer(dysymcommand,sizeof(dysymcommand));
  290. end;
  291. procedure _TMachOSubWriter_.FixResHeader(aStream : TStream);
  292. var hdr : _TResHdr_;
  293. begin
  294. hdr.handles:=fDataCurOfs;
  295. if fOppositeEndianess then
  296. hdr.handles:=SwapEndian(hdr.handles);
  297. aStream.Seek(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),
  298. soFromCurrent);
  299. aStream.WriteBuffer(hdr.handles,sizeof(hdr.handles));
  300. end;
  301. constructor _TMachOSubWriter_.Create(aParent : TMachOResourceWriter;
  302. const aMachineType : TMachOMachineType; const aOppositeEndianess : boolean);
  303. begin
  304. inherited Create(aParent, aMachineType,aOppositeEndianess);
  305. fSymbolTable:=_TMachOSymbolTable_.Create(fMachOStringTable);
  306. fSymbolTable.OppositeEndianess:=fOppositeEndianess;
  307. {$IF _TMachOSubWriter_=TMachO32SubWriter}
  308. fDataAlignment:=4;
  309. fSectAlignment:=2; //2^2
  310. fSegType:=LC_SEGMENT;
  311. {$ELSE}
  312. fDataAlignment:=8;
  313. fSectAlignment:=3; //2^3
  314. fSegType:=LC_SEGMENT_64;
  315. {$ENDIF}
  316. end;