machosubwriter.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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, undef : boolean) : integer; override;
  16. protected
  17. public
  18. procedure WriteToStream(aStream : TStream); override;
  19. procedure SetSymbolOffset(symbolnum : integer; offset: longword); override;
  20. end;
  21. _TMachOSubWriter_ = class(TAbstractMachOSubWriter)
  22. private
  23. procedure SwapSection(var aSection: _TSection_);
  24. protected
  25. procedure PrescanResourceTree; override;
  26. procedure WriteResHeader(aStream : TStream; aResources : TResources); override;
  27. procedure WriteNodeInfos(aStream : TStream); override;
  28. procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
  29. procedure AllocateSpaceForLoadCommands(aStream : TStream); override;
  30. procedure FixLoadCommands(aStream : TStream; aResources : TResources); 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, undef: boolean): integer;
  39. var p : _PNlist_;
  40. begin
  41. p:=GetMem(sizeof(_TNlist_));
  42. p^.strx:=fStringTable.Add(aName);
  43. if not undef then
  44. p^._type:=N_SECT
  45. else
  46. p^._type:=N_UNDF;
  47. if glob then
  48. p^._type:=p^._type or N_EXT;
  49. p^.desc:=0;
  50. p^.sect:=sect;
  51. p^.value:=addr;
  52. Result:=fList.Count;
  53. fList.Add(p);
  54. end;
  55. procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream);
  56. var nlist : _TNlist_;
  57. i : integer;
  58. sawglobal: boolean;
  59. begin
  60. { first write local symbols, then global ones, as ilocalsym is hardcoded to
  61. be index 0. Can't reorder here because we may already have used symbol
  62. numbers to generate relocations -> give an error if a global symbol
  63. comes before any local symbols }
  64. sawglobal:=false;
  65. for i:=0 to fList.Count-1 do
  66. begin
  67. nlist:=_PNlist_(fList[i])^;
  68. if (nlist._type and N_EXT)<>0 then
  69. sawglobal:=true
  70. else if sawglobal then
  71. raise EMachOResourceWriterSymbolTableWrongOrderException.Create('');
  72. if fOppositeEndianess then
  73. begin
  74. nlist.strx:=SwapEndian(nlist.strx);
  75. nlist.desc:=SwapEndian(nlist.desc);
  76. nlist.value:=SwapEndian(nlist.value);
  77. end;
  78. aStream.WriteBuffer(nlist,sizeof(nlist));
  79. end;
  80. end;
  81. procedure _TMachOSymbolTable_.SetSymbolOffset(symbolnum: integer; offset: longword);
  82. var
  83. p : _PNlist_;
  84. begin
  85. p:=_PNlist_(flist[symbolnum]);
  86. p^.value:=offset;
  87. end;
  88. { _TMachOSubWriter_ }
  89. procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_);
  90. begin
  91. aSection.addr:=SwapEndian(aSection.addr);
  92. aSection.size:=SwapEndian(aSection.size);
  93. aSection.offset:=SwapEndian(aSection.offset);
  94. aSection.align:=SwapEndian(aSection.align);
  95. aSection.reloff:=SwapEndian(aSection.reloff);
  96. aSection.nreloc:=SwapEndian(aSection.nreloc);
  97. aSection.flags:=SwapEndian(aSection.flags);
  98. aSection.reserved1:=SwapEndian(aSection.reserved1);
  99. aSection.reserved2:=SwapEndian(aSection.reserved2);
  100. end;
  101. procedure _TMachOSubWriter_.PrescanResourceTree;
  102. begin
  103. fResStrTable.Clear;
  104. fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_);
  105. fResStrTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_));
  106. if fResStrTable.Used then
  107. fDataCurOfs:=NextAligned(fDataAlignment,fResStrTable.StartOfs+fResStrTable.Size)
  108. else
  109. fDataCurOfs:=fResStrTable.StartOfs;
  110. end;
  111. procedure _TMachOSubWriter_.WriteResHeader(aStream: TStream;
  112. aResources: TResources);
  113. var hdr : _TResHdr_;
  114. begin
  115. hdr.rootptr:=sizeof(hdr);
  116. hdr.count:=aResources.Count;
  117. hdr.usedhandles:=0;
  118. hdr.handles:=0;
  119. { the first pointer (rootptr at offset 0) goes to the root node, which comes
  120. right after the header (the addend has been set to sizeof(hdr) -> add the
  121. address of the fpc.resources section to it via a relocations}
  122. fRelocations.Add(0,ffpcresourcessym);
  123. { the last pointer (handles at offset sizeof(fields before it)) goes to the
  124. fpc.reshandles section }
  125. fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),ffpcreshandlessym);
  126. if fOppositeEndianess then
  127. begin
  128. hdr.rootptr:=SwapEndian(hdr.rootptr);
  129. hdr.count:=SwapEndian(hdr.count);
  130. //handles must be fixed later
  131. // hdr.usedhandles:=SwapEndian(hdr.usedhandles);
  132. // hdr.handles:=SwapEndian(hdr.handles);
  133. end;
  134. aStream.WriteBuffer(hdr,sizeof(hdr));
  135. end;
  136. procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream);
  137. begin
  138. { offset inside the object }
  139. fCurOfs:=sizeof(_TResHdr_);
  140. WriteNodeInfo(aStream,fRoot);
  141. WriteSubNodes(aStream,fRoot);
  142. end;
  143. procedure _TMachOSubWriter_.WriteNodeInfo(aStream: TStream;
  144. aNode: TResourceTreeNode);
  145. var infonode : _TResInfoNode_;
  146. begin
  147. if aNode.Desc.DescType=dtID then
  148. infonode.nameid:=aNode.Desc.ID
  149. else
  150. begin
  151. infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA;
  152. fRelocations.Add(fCurOfs,ffpcresourcessym);
  153. end;
  154. infonode.ncount:=aNode.NamedCount;
  155. if aNode.IsLeaf then
  156. begin
  157. infonode.idcountsize:=aNode.Data.RawData.Size;
  158. infonode.subptr:=fDataCurOfs;
  159. fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize);
  160. end
  161. else
  162. begin
  163. infonode.idcountsize:=aNode.IDCount;
  164. infonode.subptr:=aNode.SubDirRVA;
  165. end;
  166. fRelocations.Add(
  167. fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
  168. sizeof(infonode.idcountsize),ffpcresourcessym);
  169. if fOppositeEndianess then
  170. begin
  171. infonode.nameid:=SwapEndian(infonode.nameid);
  172. infonode.ncount:=SwapEndian(infonode.ncount);
  173. infonode.idcountsize:=SwapEndian(infonode.idcountsize);
  174. infonode.subptr:=SwapEndian(infonode.subptr);
  175. end;
  176. aStream.WriteBuffer(infonode,sizeof(infonode));
  177. inc(fCurOfs,sizeof(infonode));
  178. end;
  179. procedure _TMachOSubWriter_.AllocateSpaceForLoadCommands(aStream: TStream);
  180. var buf : pbyte;
  181. begin
  182. fHeader.sizeofcmds:=
  183. //segment+res section+bss section
  184. sizeof(_TSegmentCommand_)+sizeof(_TSection_)*3+
  185. //symbol table and dynamic symbol table commands
  186. sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+
  187. //common header of the three commands
  188. sizeof(TLoadCommand)*3;
  189. buf:=GetMem(fHeader.sizeofcmds);
  190. FillByte(buf^,fHeader.sizeofcmds,0);
  191. try
  192. aStream.WriteBuffer(buf^,fHeader.sizeofcmds);
  193. finally
  194. FreeMem(buf);
  195. end;
  196. end;
  197. procedure _TMachOSubWriter_.FixLoadCommands(aStream: TStream; aResources : TResources);
  198. var ldcommand : TLoadCommand;
  199. segcommand : _TSegmentCommand_;
  200. symcommand : TSymtabCommand;
  201. dysymcommand : TDySymtabCommand;
  202. ressection,bsssection,textsection : _TSection_;
  203. begin
  204. ldcommand.cmd:=fSegType;
  205. ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*3;
  206. FillByte(segcommand.name[0],16,0);
  207. segcommand.vmaddr:=0;
  208. segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count;
  209. segcommand.fileoff:=fSectionStart;
  210. segcommand.filesize:=fDataCurOfs;
  211. segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
  212. segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
  213. segcommand.nsects:=3;
  214. segcommand.flags:=0;
  215. fillbyte(textsection,sizeof(textsection),0);
  216. textsection.sectname:='__text';
  217. textsection.segname:='__TEXT';
  218. textsection.addr:=0;
  219. textsection.size:=0;
  220. textsection.offset:=segcommand.fileoff;
  221. textsection.align:=0;
  222. textsection.reloff:=0;
  223. textsection.nreloc:=0;
  224. textsection.flags:=S_ATTR_PURE_INSTRUCTIONS;
  225. textsection.reserved1:=0;
  226. textsection.reserved2:=0;
  227. fillbyte(ressection,sizeof(ressection),0);
  228. ressection.sectname:=RsrcSectName;
  229. ressection.segname:=DataSegName;
  230. ressection.addr:=0;
  231. ressection.size:=segcommand.filesize;
  232. ressection.offset:=segcommand.fileoff;
  233. ressection.align:=fSectAlignment;
  234. ressection.reloff:=fRelocations.StartOfs;
  235. ressection.nreloc:=fRelocations.Count;
  236. ressection.flags:=S_ATTR_LOC_RELOC;
  237. ressection.reserved1:=0;
  238. ressection.reserved2:=0;
  239. fillbyte(bsssection,sizeof(bsssection),0);
  240. bsssection.sectname:=HandlesSectName;
  241. bsssection.segname:=DataSegName;
  242. bsssection.addr:=fDataCurOfs;
  243. bsssection.size:=sizeof(_ptrtype_)*aResources.Count;
  244. bsssection.offset:=0;
  245. bsssection.align:=fSectAlignment;
  246. bsssection.reloff:=0;
  247. bsssection.nreloc:=0;
  248. bsssection.flags:=S_ZEROFILL;
  249. bsssection.reserved1:=0;
  250. bsssection.reserved2:=0;
  251. if fOppositeEndianess then
  252. begin
  253. ldcommand.cmd:=SwapEndian(ldcommand.cmd);
  254. ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
  255. segcommand.vmaddr:=SwapEndian(segcommand.vmaddr);
  256. segcommand.vmsize:=SwapEndian(segcommand.vmsize);
  257. segcommand.fileoff:=SwapEndian(segcommand.fileoff);
  258. segcommand.filesize:=SwapEndian(segcommand.filesize);
  259. segcommand.maxprot:=SwapEndian(segcommand.maxprot);
  260. segcommand.initprot:=SwapEndian(segcommand.initprot);
  261. segcommand.nsects:=SwapEndian(segcommand.nsects);
  262. segcommand.flags:=SwapEndian(segcommand.flags);
  263. SwapSection(textsection);
  264. SwapSection(ressection);
  265. SwapSection(bsssection);
  266. end;
  267. aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
  268. aStream.WriteBuffer(segcommand,sizeof(segcommand));
  269. aStream.WriteBuffer(textsection,sizeof(textsection));
  270. aStream.WriteBuffer(ressection,sizeof(ressection));
  271. aStream.WriteBuffer(bsssection,sizeof(bsssection));
  272. ldcommand.cmd:=LC_SYMTAB;
  273. ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(symcommand);
  274. symcommand.symoff:=fSymbolTable.StartOfs;
  275. symcommand.nsyms:=fSymbolTable.Count;
  276. symcommand.stroff:=fMachOStringTable.StartOfs;
  277. symcommand.strsize:=NextAligned(4,fMachOStringTable.Size);
  278. if fOppositeEndianess then
  279. begin
  280. ldcommand.cmd:=SwapEndian(ldcommand.cmd);
  281. ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
  282. symcommand.symoff:=SwapEndian(symcommand.symoff);
  283. symcommand.nsyms:=SwapEndian(symcommand.nsyms);
  284. symcommand.stroff:=SwapEndian(symcommand.stroff);
  285. symcommand.strsize:=SwapEndian(symcommand.strsize);
  286. end;
  287. aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
  288. aStream.WriteBuffer(symcommand,sizeof(symcommand));
  289. ldcommand.cmd:=LC_DYSYMTAB;
  290. ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(dysymcommand);
  291. dysymcommand.ilocalsym:=0;
  292. dysymcommand.nlocalsym:=fSymbolTable.LocalCount;
  293. dysymcommand.iextdefsym:=dysymcommand.ilocalsym+dysymcommand.nlocalsym;
  294. dysymcommand.nextdefsym:=fSymbolTable.GlobalCount;
  295. dysymcommand.iundefsym:=dysymcommand.iextdefsym+dysymcommand.nextdefsym;
  296. dysymcommand.nundefsym:=0;
  297. dysymcommand.tocoff:=0;
  298. dysymcommand.ntoc:=0;
  299. dysymcommand.modtaboff:=0;
  300. dysymcommand.nmodtab:=0;
  301. dysymcommand.extrefsymoff:=0;
  302. dysymcommand.nextrefsyms:=0;
  303. dysymcommand.indirectsymoff:=0;
  304. dysymcommand.nindirectsyms:=0;
  305. dysymcommand.extreloff:=0;
  306. dysymcommand.nextrel:=0;
  307. dysymcommand.locreloff:=0;
  308. dysymcommand.nlocrel:=0;
  309. if fOppositeEndianess then
  310. begin
  311. ldcommand.cmd:=SwapEndian(ldcommand.cmd);
  312. ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
  313. dysymcommand.ilocalsym:=SwapEndian(dysymcommand.ilocalsym);
  314. dysymcommand.nlocalsym:=SwapEndian(dysymcommand.nlocalsym);
  315. dysymcommand.iextdefsym:=SwapEndian(dysymcommand.iextdefsym);
  316. dysymcommand.nextdefsym:=SwapEndian(dysymcommand.nextdefsym);
  317. dysymcommand.iundefsym:=SwapEndian(dysymcommand.iundefsym);
  318. dysymcommand.nundefsym:=SwapEndian(dysymcommand.nundefsym);
  319. dysymcommand.tocoff:=SwapEndian(dysymcommand.tocoff);
  320. dysymcommand.ntoc:=SwapEndian(dysymcommand.ntoc);
  321. dysymcommand.modtaboff:=SwapEndian(dysymcommand.modtaboff);
  322. dysymcommand.nmodtab:=SwapEndian(dysymcommand.nmodtab);
  323. dysymcommand.extrefsymoff:=SwapEndian(dysymcommand.extrefsymoff);
  324. dysymcommand.nextrefsyms:=SwapEndian(dysymcommand.nextrefsyms);
  325. dysymcommand.indirectsymoff:=SwapEndian(dysymcommand.indirectsymoff);
  326. dysymcommand.nindirectsyms:=SwapEndian(dysymcommand.nindirectsyms);
  327. dysymcommand.extreloff:=SwapEndian(dysymcommand.extreloff);
  328. dysymcommand.nextrel:=SwapEndian(dysymcommand.nextrel);
  329. dysymcommand.locreloff:=SwapEndian(dysymcommand.locreloff);
  330. dysymcommand.nlocrel:=SwapEndian(dysymcommand.nlocrel);
  331. end;
  332. aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
  333. aStream.WriteBuffer(dysymcommand,sizeof(dysymcommand));
  334. end;
  335. constructor _TMachOSubWriter_.Create(aParent : TMachOResourceWriter;
  336. const aMachineType : TMachOMachineType; const aSubMachineType: TMachoSubMachineType; const aOppositeEndianess : boolean);
  337. begin
  338. inherited Create(aParent,aMachineType,aSubMachineType,aOppositeEndianess);
  339. fSymbolTable:=_TMachOSymbolTable_.Create(fMachOStringTable);
  340. fSymbolTable.OppositeEndianess:=fOppositeEndianess;
  341. {$IF _TMachOSubWriter_=TMachO32SubWriter}
  342. fDataAlignment:=4;
  343. fSectAlignment:=2; //2^2
  344. fSegType:=LC_SEGMENT;
  345. {$ELSE}
  346. fDataAlignment:=8;
  347. fSectAlignment:=3; //2^3
  348. fSegType:=LC_SEGMENT_64;
  349. {$ENDIF}
  350. end;