machosubwriter.inc 12 KB

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