machoutils.pas 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468
  1. {
  2. Copyright (c) 2009-2010 by Dmitry Boyarintsev
  3. Contains utility routines and types for handling mach-o structure and types.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit machoutils;
  18. {$i fpcdefs.inc}
  19. {$h+}
  20. interface
  21. uses
  22. macho;
  23. type
  24. TRawWriter=class(TObject)
  25. public
  26. procedure WriteRaw(const data; datasize: Integer); virtual; abstract;
  27. end;
  28. TRawReader=class(TObject)
  29. public
  30. function ReadRaw(var data; datasize: Integer): Integer; virtual; abstract;
  31. function Seek(pos: qword): Boolean; virtual; abstract;
  32. function ReadPos: qword; virtual; abstract;
  33. end;
  34. TMachHeader=record
  35. cputype : cpu_type_t;
  36. cpusubtype : cpu_subtype_t;
  37. filetype : longword;
  38. ncmds : longword;
  39. sizeofcmds : longword;
  40. flags : longword;
  41. end;
  42. TSegmentName=string[16];
  43. TSectionName=TSegmentName;
  44. TMachoSegment=record
  45. segname : TSegmentName;
  46. vmaddr : qword;
  47. vmsize : qword;
  48. fileoff : qword;
  49. filesize : qword;
  50. maxprot : vm_prot_t;
  51. initprot : vm_prot_t;
  52. nsects : longword;
  53. flags : longword;
  54. end;
  55. TMachoSection=record
  56. sectname : TSectionName;
  57. segname : TSegmentName;
  58. addr : uint64_t;
  59. size : uint64_t;
  60. offset : uint32_t;
  61. align : uint32_t;
  62. reloff : uint32_t;
  63. nreloc : uint32_t;
  64. flags : uint32_t;
  65. indirectIndex : Integer; // reserved1 for LAZY and NON_LAZY pointers
  66. stubSize : Integer; // reserved2 for S_SYMBOL_STUBS
  67. end;
  68. TMachoRoutine=record
  69. init_address : uint64_t; { address of initialization routine }
  70. init_module : uint64_t; { index into the module table that }
  71. end;
  72. { TMachoWriter }
  73. TMachoWriter=class(TObject)
  74. private
  75. fwriter : TRawWriter;
  76. fown : Boolean;
  77. protected
  78. public
  79. constructor Create(ARawWriter: TRawWriter; AllowFreeWriter: Boolean);
  80. destructor Destroy; override;
  81. { non platform specific writer }
  82. procedure WriteData(const data; dataSize: Integer);
  83. procedure WriteUint8(i: uint8_t);
  84. { endian specific writer }
  85. procedure WriteUint16(i: uint16_t); virtual; abstract;
  86. procedure WriteUint32(i: uint32_t); virtual; abstract;
  87. procedure WriteUint64(i: uint64_t); virtual; abstract;
  88. { endian and ptr-size specific writer }
  89. procedure WritePtr(ofs: QWord); virtual; abstract; // ptr is 32 bit for 32-bit platforms
  90. { macro utility methods }
  91. procedure WriteHeader(const hdr: TMachHeader); virtual; abstract;
  92. procedure WriteSegmentCmd(const seg: TMachoSegment; cmdSize: LongWord); virtual; abstract;
  93. procedure WriteSection(const sec: TMachoSection); virtual; abstract;
  94. procedure WriteRoutineCmd(const rt: TMachoRoutine); virtual; abstract;
  95. procedure WriteLoadCommand(const cmd: load_command); virtual; abstract; overload;
  96. procedure WriteLoadCommand(cmd, cmdsize: Integer); overload;
  97. procedure WriteRelocation(const ri: relocation_info); virtual; abstract;
  98. procedure WriteScatterReloc(const ri: scattered_relocation_info); virtual; abstract;
  99. procedure WriteNList(const list: nlist_64); virtual; abstract;
  100. end;
  101. { TLE32MachoWriter }
  102. TLE32MachoWriter=class(TMachoWriter)
  103. public
  104. procedure WriteUint16(i: uint16_t); override;
  105. procedure WriteUint32(i: uint32_t); override;
  106. procedure WriteUint64(i: uint64_t); override;
  107. procedure WritePtr(ofs: QWord); override;
  108. procedure WriteHeader(const hdr: TMachHeader); override;
  109. procedure WriteSegmentCmd(const seg: TMachoSegment; ACmdSize: LongWord); override;
  110. procedure WriteSection(const sec: TMachoSection); override;
  111. procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
  112. procedure WriteLoadCommand(const cmd: load_command); override;
  113. procedure WriteRelocation(const ri: relocation_info); override;
  114. procedure WriteScatterReloc(const ri: scattered_relocation_info); override;
  115. procedure WriteNList(const list: nlist_64); override;
  116. end;
  117. { TLE64MachoWriter }
  118. TLE64MachoWriter=class(TLE32MachoWriter)
  119. public
  120. procedure WritePtr(ofs: QWord); override;
  121. procedure WriteHeader(const hdr: TMachHeader); override;
  122. procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
  123. procedure WriteSection(const sec: TMachoSection); override;
  124. procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
  125. procedure WriteNList(const list: nlist_64); override;
  126. end;
  127. { TBE32MachoWriter }
  128. TBE32MachoWriter=class(TMachoWriter)
  129. public
  130. procedure WriteUint16(i: uint16_t); override;
  131. procedure WriteUint32(i: uint32_t); override;
  132. procedure WriteUint64(i: uint64_t); override;
  133. procedure WritePtr(ofs: QWord); override;
  134. procedure WriteHeader(const hdr: TMachHeader); override;
  135. procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
  136. procedure WriteSection(const sec: TMachoSection); override;
  137. procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
  138. procedure WriteLoadCommand(const cmd: load_command); override;
  139. procedure WriteRelocation(const ri: relocation_info); override;
  140. procedure WriteScatterReloc(const ri: scattered_relocation_info); override;
  141. procedure WriteNList(const list: nlist_64); override;
  142. end;
  143. { TBE64MachoWriter }
  144. TBE64MachoWriter=class(TBE32MachoWriter)
  145. public
  146. procedure WritePtr(ofs: QWord); override;
  147. procedure WriteHeader(const hdr: TMachHeader); override;
  148. procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
  149. procedure WriteSection(const sec: TMachoSection); override;
  150. procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
  151. procedure WriteNList(const list: nlist_64); override;
  152. end;
  153. { TLEMachoStructConverter }
  154. { converter for Little-endian structures to Host }
  155. TLEMachoStructConverter = class(TObject)
  156. public
  157. procedure ConvertMachoHeader(const mh: mach_header; var hdr: TMachHeader); virtual;
  158. procedure ConvertMachoHeader64(const mh: mach_header_64; var hdr: TMachHeader); virtual;
  159. procedure ConvertLoadCommand(var cmd: load_command); virtual;
  160. procedure ConvertSegment(const segcmd: segment_command; var segment: TMachoSegment); virtual;
  161. procedure ConvertSegment64(const segcmd: segment_command_64; var segment: TMachoSegment); virtual;
  162. procedure ConvertSection(const sec: section; var section: TMachoSection); virtual;
  163. procedure ConvertSection64(const sec: section_64; var section: TMachoSection); virtual;
  164. procedure ConvertUInt16(var v: Word); virtual;
  165. procedure ConvertUInt32(var v: LongWord); virtual;
  166. procedure ConvertUInt64(var v: qWord); virtual;
  167. end;
  168. { converter for Big-endian structures to Host }
  169. TBEMachoStructConverter = class(TLEMachoStructConverter);
  170. {common}
  171. TMachoStructConverter = TLEMachoStructConverter;
  172. { TMachoReader }
  173. TMachoReader=class(TObject)
  174. private
  175. fReader : TRawReader;
  176. HdrOfs : qword;
  177. fCnv : TMachoStructConverter;
  178. fHdr : TMachHeader;
  179. is64 : Boolean;
  180. cmdofs : array of qword;
  181. cmds : array of load_command;
  182. protected
  183. function IntReadStruct: Boolean;
  184. public
  185. constructor Create(ARawReader: TRawReader; StartOfs: QWord=0);
  186. function ReadHeader(var hdr: TMachHeader): Boolean;
  187. function ReadCommandID(index: LongWord; var cmd: load_command): Boolean;
  188. function GetCmdOfs(index: LongWord): qword;
  189. function ReadSegmentCommand(cmdindex: LongWord; var segment: TMachoSegment): Boolean;
  190. function ReadSection(segindex, secindex: LongWord; var machsection: TMachoSection): Boolean;
  191. function ReadSymTabCmd(var symcmd: symtab_command): Boolean;
  192. function ReadUInt32(var v: LongWord): Boolean;
  193. function ReadData(var data; dataSize: Integer): Integer;
  194. {todo: ReadNList - using index of symbol, instead of file offset?}
  195. function GetNListSize: Integer;
  196. function ReadNList(fileofs: qword; var nsym: nlist_64): Boolean;
  197. procedure Seek(apos: qword);
  198. end;
  199. const
  200. seg_TEXT : TSegmentName = '__TEXT';
  201. seg_DATA : TSegmentName = '__DATA';
  202. seg_OBJC : TSegmentName = '__OBJC';
  203. seg_IMPORT : TSegmentName = '__IMPORT';
  204. seg_DWARF : TSegmentName = '__DWARF';
  205. function AllocMachoWriter(cputarget: cpu_type_t; ARawWriter: TRawWriter; AllowFreeWriter: Boolean): TMachoWriter;
  206. function sizeMachHeader(cputarget: cpu_type_t): integer; inline;
  207. function sizeSegment(cputarget: cpu_type_t): integer; inline;
  208. function sizeSection(cputarget: cpu_type_t): integer; inline;
  209. function sizeNList(cputarget: cpu_type_t): integer; inline;
  210. function AlignAddr(cputarget: cpu_type_t; addr: qword): qword;
  211. procedure InitSegment(var seg: TMachoSegment);
  212. function MakeSectionName(const segName, secName: shortstring): shortstring;
  213. function GetSegmentSectionName(const objSecName: shortstring; var segName, secName: shortstring): shortstring;
  214. function GetSectionFlags(const segName, secName: shortstring): LongWord;
  215. type
  216. TRelocInfoLength = (ril_byte = 0, ril_word = 1, ril_long = 2, ril_quad = 3);
  217. procedure RelocInfo(addr, symnum, reltype: integer; len: TRelocInfoLength; pcrel, extern: Boolean; var info: relocation_info);
  218. procedure ScatterRelocInfo(value, addr, reltype: integer; len: TRelocInfoLength; pcrel: Boolean; var info: scattered_relocation_info);
  219. function GetReserved1(const macho: TMachoSection): integer;
  220. function GetReserved2(const macho: TMachoSection): integer;
  221. function GetStubSize(cputarget: Integer; Pic: Boolean): Integer;
  222. function MachoAlign(al: integer): integer;
  223. implementation
  224. function MachoAlign(al: integer): integer;
  225. begin
  226. Result:=0;
  227. al:=al shr 1;
  228. while al>0 do
  229. begin
  230. inc(Result);
  231. al:=al shr 1;
  232. end;
  233. end;
  234. function AllocConverter(magic: LongWord): TMachoStructConverter;
  235. begin
  236. {$ifdef ENDIAN_BIG}
  237. if magic=MH_MAGIC then
  238. Result:=TBEMachoStructConverter.Create
  239. else
  240. Result:=TLEMachoStructConverter.Create;
  241. {$else}
  242. if magic=MH_MAGIC then
  243. Result:=TLEMachoStructConverter.Create
  244. else
  245. Result:=TBEMachoStructConverter.Create;
  246. {$endif}
  247. end;
  248. {result values are used from aggas.pas, see TGNUAssembler.WriteSection }
  249. function GetStubSize(cputarget: Integer; Pic: Boolean): Integer;
  250. begin
  251. case cputarget of
  252. CPU_TYPE_I386, CPU_TYPE_X86_64:
  253. Result:=5;
  254. CPU_TYPE_POWERPC, CPU_TYPE_POWERPC64:
  255. if Pic then
  256. Result:=32
  257. else
  258. Result:=16;
  259. CPU_TYPE_ARM:
  260. if Pic then
  261. Result:=16
  262. else
  263. Result:=12;
  264. else
  265. Result:=-1;
  266. end;
  267. end;
  268. function GetReserved1(const macho: TMachoSection): integer;
  269. begin
  270. case macho.flags and SECTION_TYPE of
  271. S_NON_LAZY_SYMBOL_POINTERS, S_LAZY_SYMBOL_POINTERS:
  272. Result:=macho.indirectIndex;
  273. else
  274. Result:=0;
  275. end;
  276. end;
  277. function GetReserved2(const macho: TMachoSection): integer;
  278. begin
  279. case macho.flags and SECTION_TYPE of
  280. S_SYMBOL_STUBS:
  281. Result:=macho.stubSize
  282. else
  283. Result:=0;
  284. end;
  285. end;
  286. procedure RelocInfo(addr, symnum, reltype: integer; len: TRelocInfoLength; pcrel, extern: Boolean; var info: relocation_info);
  287. {$ifdef ENDIAN_BIG}
  288. const
  289. relbit : array [Boolean] of Integer = (0, 1 shl 7);
  290. extbit : array [Boolean] of Integer = (0, 1 shl 4);
  291. ri_len_mask : array [TRelocInfoLength] of Integer = (0 shl 5, 1 shl 5, 2 shl 5, 3 shl 5);
  292. begin
  293. info.r_address:=addr;
  294. info.r_info:=((symnum and $FFFFFF) shl 8) or // r_symbolnum:24
  295. relbit[pcrel] or // r_pcrel:1;
  296. ri_len_mask[len] or // r_length:2;
  297. extbit[extern] or // r_extern:1;
  298. (reltype and $F); // r_type:4;
  299. end;
  300. {$else}
  301. const
  302. relbit : array [Boolean] of Integer = (0, 1 shl 24);
  303. extbit : array [Boolean] of Integer = (0, 1 shl 27);
  304. ri_len_mask : array [TRelocInfoLength] of Integer = (0 shl 25, 1 shl 25, 2 shl 25, 3 shl 25);
  305. begin
  306. info.r_address:=addr;
  307. info.r_info:=(symnum and $FFFFFF) or // r_symbolnum:24
  308. relbit[pcrel] or // r_pcrel:1;
  309. extbit[extern] or // r_length:2;
  310. ri_len_mask[len] or // r_extern:1;
  311. (reltype shl 28); // r_type:4;
  312. end;
  313. {$endif}
  314. const
  315. si_len_mask: array [TRelocInfoLength] of Integer = (0 shl 28, 1 shl 28, 2 shl 28, 3 shl 28);
  316. si_type_ofs = 24;
  317. si_pcrel_bit = 1 shl 30;
  318. si_scatter_bit = 1 shl 31;
  319. si_addr_ofs = 0;
  320. procedure ScatterRelocInfo(value, addr, reltype: integer; len: TRelocInfoLength; pcrel: Boolean; var info: scattered_relocation_info);
  321. const
  322. relbit : array [Boolean] of Integer = (0, si_pcrel_bit);
  323. begin
  324. // big endian
  325. info.r_info:=si_scatter_bit or // r_scattered:1, /* 1=scattered, 0=non-scattered (see above) */
  326. relbit[pcrel] or // r_pcrel:1, /* was relocated pc relative already */
  327. si_len_mask[len] or // r_length:2, /* 0=byte, 1=word, 2=long, 3=quad */
  328. ((reltype and $F) shl si_type_ofs) or // r_type:4, /* if not 0, machine specific relocation type */
  329. ((addr and $FFFFFF) shl si_addr_ofs); // r_address:24; /* offset in the section to what is being relocated */}
  330. info.r_value:=value;
  331. // little endian
  332. // r_address:24, /* offset in the section to what is being relocated */
  333. // r_type:4, /* if not 0, machine specific relocation type */
  334. // r_length:2, /* 0=byte, 1=word, 2=long, 3=quad */
  335. // r_pcrel:1, /* was relocated pc relative already */
  336. // r_scattered:1; /* 1=scattered, 0=non-scattered (see above) */ *}
  337. end;
  338. function GetSectionFlags(const segName, secName: shortstring): LongWord;
  339. begin
  340. Result:=0;
  341. if segName = seg_DATA then
  342. begin
  343. if secName = '__nl_symbol_ptr' then
  344. Result:=Result or S_NON_LAZY_SYMBOL_POINTERS
  345. else if secName = '__la_symbol_ptr' then
  346. Result:=Result or S_LAZY_SYMBOL_POINTERS
  347. else if secName = '__common' then
  348. Result:=Result or S_ZEROFILL
  349. end
  350. else if segName = seg_TEXT then
  351. begin
  352. if (secName = '__text') then
  353. Result:=Result or S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS
  354. else if secName = '__textcoal_nt' then
  355. Result:=Result or S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS or S_COALESCED
  356. else if secName = '.fpc' then
  357. Result:=Result or S_ATTR_NO_DEAD_STRIP
  358. else if secName = '__cstring' then
  359. Result:=Result or S_CSTRING_LITERALS;
  360. end
  361. else if (segName = seg_IMPORT) then
  362. begin
  363. if (secName = '__jump_table') then
  364. Result:=Result or S_SYMBOL_STUBS or S_ATTR_SELF_MODIFYING_CODE or S_ATTR_SOME_INSTRUCTIONS
  365. end
  366. else if (segName=seg_OBJC) then
  367. begin
  368. Result:=S_ATTR_NO_DEAD_STRIP;
  369. if secName='__message_refs' then
  370. Result:=Result or S_ATTR_NO_DEAD_STRIP or S_LITERAL_POINTERS
  371. else if secName='__cls_refs' then
  372. Result:=Result or S_ATTR_NO_DEAD_STRIP or S_LITERAL_POINTERS;
  373. end;
  374. end;
  375. function MakeSectionName(const segName, secName: shortstring): shortstring;
  376. begin
  377. if segName = '' then
  378. Result:=secName
  379. else
  380. Result:=segName+' '+secName;
  381. end;
  382. function GetSegmentSectionName(const objSecName: shortstring; var segName, secName: shortstring): shortstring;
  383. var
  384. i : integer;
  385. begin
  386. i:=Pos(' ', objSecName);
  387. if i>0 then
  388. begin
  389. segName:=copy(objsecName, 1, i-1);
  390. secName:=copy(objsecName, i+1, length(objsecName)-i);
  391. end
  392. else
  393. begin
  394. segName:='';
  395. secName:=objSecName;
  396. end;
  397. Result:=objSecName;
  398. end;
  399. procedure InitSegment(var seg: TMachoSegment);
  400. begin
  401. FillChar(seg, sizeof(seg), 0);
  402. seg.initprot:=VM_PROT_ALL;
  403. seg.maxprot:=VM_PROT_ALL;
  404. end;
  405. const
  406. is64MachHeaderSize : array [Boolean] of Integer = ( sizeof(mach_header), sizeof(mach_header_64));
  407. is64SectionSize : array [Boolean] of Integer = ( sizeof(section), sizeof(section_64));
  408. is64SegmentSize : array [Boolean] of Integer = ( sizeof(segment_command), sizeof(segment_command_64));
  409. is64NListSize : array [Boolean] of Integer = (sizeof(nlist), sizeof(nlist_64));
  410. function AlignAddr(cputarget: cpu_type_t; addr: qword): qword;
  411. var
  412. md : array [Boolean] of integer = (4, 8);
  413. p : PtrUInt;
  414. begin
  415. p:=addr;
  416. p:=align(p, md[cputarget and CPU_ARCH_ABI64 > 0]);
  417. Result:=qword(p);
  418. end;
  419. function sizeMachHeader(cputarget: cpu_type_t): integer;
  420. begin
  421. Result:=is64MachHeaderSize[ cputarget and CPU_ARCH_ABI64 > 0];
  422. end;
  423. function sizeSegment(cputarget: cpu_type_t): integer;
  424. begin
  425. Result:=is64SegmentSize[ cputarget and CPU_ARCH_ABI64 > 0];
  426. end;
  427. function sizeSection(cputarget: cpu_type_t): integer;
  428. begin
  429. Result:=is64SectionSize[ cputarget and CPU_ARCH_ABI64 > 0];
  430. end;
  431. function sizeNList(cputarget: cpu_type_t): integer; inline;
  432. begin
  433. Result:=is64NlistSize[ cputarget and CPU_ARCH_ABI64 > 0];
  434. end;
  435. function AllocMachoWriter(cputarget: cpu_type_t; ARawWriter: TRawWriter; AllowFreeWriter: Boolean): TMachoWriter;
  436. begin
  437. case cputarget of
  438. CPU_TYPE_I386,
  439. CPU_TYPE_ARM: Result:=TLE32MachoWriter.Create(ARawWriter, AllowFreeWriter);
  440. CPU_TYPE_X86_64: Result:=TLE64MachoWriter.Create(ARawWriter, AllowFreeWriter);
  441. CPU_TYPE_POWERPC: Result:=TBE32MachoWriter.Create(ARawWriter, AllowFreeWriter);
  442. CPU_TYPE_POWERPC64: Result:=TBE64MachoWriter.Create(ARawWriter, AllowFreeWriter);
  443. else
  444. begin
  445. if AllowFreeWriter then
  446. ARawWriter.Free;
  447. Result:=nil;
  448. end;
  449. end;
  450. end;
  451. { TMachoWriter }
  452. procedure TMachoWriter.WriteData(const data; dataSize: Integer);
  453. begin
  454. if not assigned(fwriter) then
  455. Exit;
  456. fwriter.WriteRaw(data, dataSize);
  457. end;
  458. procedure TMachoWriter.WriteUint8(i: uint8_t);
  459. begin
  460. WriteData(i, sizeof(i));
  461. end;
  462. procedure TMachoWriter.WriteLoadCommand(cmd, cmdsize: Integer);
  463. var
  464. m : load_command;
  465. begin
  466. m.cmd:=cmd;
  467. m.cmdsize:=cmdsize;
  468. WriteLoadCommand(m);
  469. end;
  470. constructor TMachoWriter.Create(ARawWriter: TRawWriter; AllowFreeWriter: Boolean);
  471. begin
  472. inherited Create;
  473. fwriter:=ARawWriter;
  474. fown:=AllowFreeWriter;
  475. end;
  476. destructor TMachoWriter.Destroy;
  477. begin
  478. if fown then
  479. fwriter.Free;
  480. inherited Destroy;
  481. end;
  482. { TLE32MachoWriter }
  483. procedure TLE32MachoWriter.WriteHeader(const hdr: TMachHeader);
  484. var
  485. m : mach_header;
  486. begin
  487. with m do
  488. begin
  489. magic:=NtoLE(MH_MAGIC);
  490. cputype:=NtoLE(hdr.cputype);
  491. cpusubtype:=NtoLE(hdr.cpusubtype);
  492. filetype:=NtoLE(hdr.filetype);
  493. ncmds:=NtoLE(hdr.ncmds);
  494. sizeofcmds:=NtoLE(hdr.sizeofcmds);
  495. flags:=NtoLE(hdr.flags);
  496. end;
  497. WriteData(m, sizeof(m));
  498. end;
  499. procedure TLE32MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; ACmdSize: LongWord);
  500. var
  501. m : segment_command;
  502. begin
  503. with m do
  504. begin
  505. cmd:=NtoLE(LC_SEGMENT);
  506. cmdsize:=NtoLE(ACmdSize);
  507. segname:=seg.segname;
  508. vmaddr:=NtoLE(uint32_t(seg.vmaddr));
  509. vmsize:=NtoLE(uint32_t(seg.vmsize));
  510. fileoff:=NtoLE(uint32_t(seg.fileoff));
  511. filesize:=NtoLE(uint32_t(seg.filesize));
  512. maxprot:=NtoLE(seg.maxprot);
  513. initprot:=NtoLE(seg.initprot);
  514. nsects:=NtoLE(seg.nsects);
  515. flags:=NtoLE(seg.flags);
  516. end;
  517. WriteData(m, sizeof(m));
  518. end;
  519. procedure TLE32MachoWriter.WriteSection(const sec: TMachoSection);
  520. var
  521. m : section;
  522. begin
  523. FillChar(m, sizeof(m), 0);
  524. with m do
  525. begin
  526. sectname:=sec.sectname;
  527. segname:=sec.segname;
  528. addr:=NtoLE(sec.addr);
  529. size:=NtoLE(sec.size);
  530. offset:=NtoLE(sec.offset);
  531. align:=NtoLE(sec.align);
  532. reloff:=NtoLE(sec.reloff);
  533. nreloc:=NtoLE(sec.nreloc);
  534. flags:=NtoLE(sec.flags);
  535. reserved1:=NtoLE( GetReserved1(sec));
  536. reserved2:=NtoLE( GetReserved2(sec));
  537. end;
  538. WriteData(m, sizeof(m));
  539. end;
  540. procedure TLE32MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
  541. var
  542. m : routines_command;
  543. begin
  544. FillChar(m, sizeof(m), 0);
  545. with m do
  546. begin
  547. cmd:=NtoLE(LC_ROUTINES);
  548. cmdsize:=NtoLE(sizeof(m));
  549. init_address:=NtoLE(rt.init_address);
  550. init_module:=NtoLE(rt.init_module);
  551. end;
  552. WriteData(m, sizeof(m));
  553. end;
  554. procedure TLE32MachoWriter.WriteLoadCommand(const cmd: load_command);
  555. var
  556. m : load_command;
  557. begin
  558. m.cmd:=NtoLE(cmd.cmd);
  559. m.cmdsize:=NtoLE(cmd.cmdsize);
  560. WriteData(m, sizeof(m));
  561. end;
  562. procedure TLE32MachoWriter.WriteRelocation(const ri: relocation_info);
  563. var
  564. m : relocation_info;
  565. begin
  566. m.r_address:=NtoLE(ri.r_address);
  567. m.r_info:=NtoLE(ri.r_info);
  568. WriteData(m, sizeof(m));
  569. end;
  570. procedure TLE32MachoWriter.WriteScatterReloc(const ri: scattered_relocation_info);
  571. var
  572. m : LongWord;
  573. begin
  574. m:=LongWord(ri.r_info);
  575. WriteUint32(NtoLE(m));
  576. m:=LongWord(ri.r_value);
  577. WriteUint32(NtoLE(m));
  578. end;
  579. procedure TLE32MachoWriter.WriteNList(const list: nlist_64);
  580. var
  581. m : nlist;
  582. begin
  583. m.n_un.n_strx:=NtoLe(list.n_un.n_strx);
  584. m.n_type:=NtoLe(list.n_type);
  585. m.n_sect:=NtoLe(list.n_sect);
  586. m.n_desc:=NtoLe(list.n_desc);
  587. m.n_value:=NtoLe(list.n_value);
  588. WriteData(m, sizeof(m));
  589. end;
  590. procedure TLE32MachoWriter.WriteUint16(i: uint16_t);
  591. var
  592. m: uint16_t;
  593. begin
  594. m:=NtoLE(i);
  595. WriteData(m, sizeof(m));
  596. end;
  597. procedure TLE32MachoWriter.WriteUint32(i: uint32_t);
  598. var
  599. m: uint32_t;
  600. begin
  601. m:=NtoLE(i);
  602. WriteData(m, sizeof(m));
  603. end;
  604. procedure TLE32MachoWriter.WriteUint64(i: uint64_t);
  605. var
  606. m: uint64_t;
  607. begin
  608. m:=NtoLE(i);
  609. WriteData(m, sizeof(m));
  610. end;
  611. procedure TLE32MachoWriter.WritePtr(ofs: QWord);
  612. var
  613. m: uint32_t;
  614. begin
  615. m:=NtoLE(ofs);
  616. WriteData(m, sizeof(m));
  617. end;
  618. { TLE64MachoWriter }
  619. procedure TLE64MachoWriter.WritePtr(ofs: QWord);
  620. var
  621. m : uint64_t;
  622. begin
  623. m:=NtoLE(ofs);
  624. Writedata(m, sizeof(m));
  625. end;
  626. procedure TLE64MachoWriter.WriteHeader(const hdr: TMachHeader);
  627. var
  628. m : mach_header_64;
  629. begin
  630. with m do
  631. begin
  632. magic:=NtoLE(MH_MAGIC_64);
  633. cputype:=NtoLE(hdr.cputype);
  634. cpusubtype:=NtoLE(hdr.cpusubtype);
  635. filetype:=NtoLE(hdr.filetype);
  636. ncmds:=NtoLE(hdr.ncmds);
  637. sizeofcmds:=NtoLE(hdr.sizeofcmds);
  638. flags:=NtoLE(hdr.flags);
  639. reserved:=0;
  640. end;
  641. WriteData(m, sizeof(m));
  642. end;
  643. procedure TLE64MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
  644. var
  645. m : segment_command_64;
  646. begin
  647. with m do
  648. begin
  649. cmd:=NtoLE(LC_SEGMENT_64);
  650. cmdsize:=NtoLE(acmdSize);
  651. segname:=seg.segname;
  652. vmaddr:=NtoLE(seg.vmaddr);
  653. vmsize:=NtoLE(seg.vmsize);
  654. fileoff:=NtoLE(seg.fileoff);
  655. filesize:=NtoLE(seg.filesize);
  656. maxprot:=NtoLE(seg.maxprot);
  657. initprot:=NtoLE(seg.initprot);
  658. nsects:=NtoLE(seg.nsects);
  659. flags:=NtoLE(seg.flags);
  660. end;
  661. WriteData(m, sizeof(m));
  662. end;
  663. procedure TLE64MachoWriter.WriteSection(const sec: TMachoSection);
  664. var
  665. m : section_64;
  666. begin
  667. FillChar(m, sizeof(m), 0);
  668. with m do
  669. begin
  670. sectname:=sec.sectname;
  671. segname:=sec.segname;
  672. addr:=NtoLE(sec.addr);
  673. size:=NtoLE(sec.size);
  674. offset:=NtoLE(sec.offset);
  675. align:=NtoLE(sec.align);
  676. reloff:=NtoLE(sec.reloff);
  677. nreloc:=NtoLE(sec.nreloc);
  678. flags:=NtoLE(sec.flags);
  679. reserved1:=NtoLE( GetReserved1(sec));
  680. reserved2:=NtoLE( GetReserved2(sec));
  681. end;
  682. WriteData(m, sizeof(m));
  683. end;
  684. procedure TLE64MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
  685. var
  686. m : routines_command_64;
  687. begin
  688. FillChar(m, sizeof(m), 0);
  689. with m do
  690. begin
  691. cmd:=NtoLE(LC_ROUTINES);
  692. cmdsize:=NtoLE(sizeof(m));
  693. init_address:=NtoLE(rt.init_address);
  694. init_module:=NtoLE(rt.init_module);
  695. end;
  696. WriteData(m, sizeof(m));
  697. end;
  698. procedure TLE64MachoWriter.WriteNList(const list: nlist_64);
  699. var
  700. m : nlist_64;
  701. begin
  702. m.n_un.n_strx:=NtoLe(list.n_un.n_strx);
  703. m.n_type:=NtoLe(list.n_type);
  704. m.n_sect:=NtoLe(list.n_sect);
  705. m.n_desc:=NtoLe(list.n_desc);
  706. m.n_value:=NtoLe(list.n_value);
  707. WriteData(m, sizeof(m));
  708. end;
  709. { TBE32MachoWriter }
  710. procedure TBE32MachoWriter.WriteHeader(const hdr: TMachHeader);
  711. var
  712. m : mach_header;
  713. begin
  714. with m do
  715. begin
  716. magic:=NtoBE(MH_MAGIC);
  717. cputype:=NtoBE(hdr.cputype);
  718. cpusubtype:=NtoBE(hdr.cpusubtype);
  719. filetype:=NtoBE(hdr.filetype);
  720. ncmds:=NtoBE(hdr.ncmds);
  721. sizeofcmds:=NtoBE(hdr.sizeofcmds);
  722. flags:=NtoBE(hdr.flags);
  723. end;
  724. WriteData(m, sizeof(m));
  725. end;
  726. procedure TBE32MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
  727. var
  728. m : segment_command;
  729. begin
  730. with m do
  731. begin
  732. cmd:=NtoBE(LC_SEGMENT);
  733. cmdsize:=NtoBE(acmdSize);
  734. segname:=seg.segname;
  735. vmaddr:=NtoBE(uint32_t(seg.vmaddr));
  736. vmsize:=NtoBE(uint32_t(seg.vmsize));
  737. fileoff:=NtoBE(uint32_t(seg.fileoff));
  738. filesize:=NtoBE(uint32_t(seg.filesize));
  739. maxprot:=NtoBE(seg.maxprot);
  740. initprot:=NtoBE(seg.initprot);
  741. nsects:=NtoBE(seg.nsects);
  742. flags:=NtoBE(seg.flags);
  743. end;
  744. WriteData(m, sizeof(m));
  745. end;
  746. procedure TBE32MachoWriter.WriteSection(const sec: TMachoSection);
  747. var
  748. m : section;
  749. begin
  750. FillChar(m, sizeof(m), 0);
  751. with m do
  752. begin
  753. sectname:=sec.sectname;
  754. segname:=sec.segname;
  755. addr:=NtoBE(sec.addr);
  756. size:=NtoBE(sec.size);
  757. offset:=NtoBE(sec.offset);
  758. align:=NtoBE(sec.align);
  759. reloff:=NtoBE(sec.reloff);
  760. nreloc:=NtoBE(sec.nreloc);
  761. flags:=NtoBE(sec.flags);
  762. reserved1:=NtoBE( GetReserved1(sec));
  763. reserved2:=NtoBE( GetReserved2(sec));
  764. end;
  765. WriteData(m, sizeof(m));
  766. end;
  767. procedure TBE32MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
  768. var
  769. m : routines_command;
  770. begin
  771. FillChar(m, sizeof(m), 0);
  772. with m do
  773. begin
  774. cmd:=NtoBE(LC_ROUTINES);
  775. cmdsize:=NtoBE(sizeof(m));
  776. init_address:=NtoBE(rt.init_address);
  777. init_module:=NtoBE(rt.init_module);
  778. end;
  779. WriteData(m, sizeof(m));
  780. end;
  781. procedure TBE32MachoWriter.WriteLoadCommand(const cmd: load_command);
  782. var
  783. m : load_command;
  784. begin
  785. m.cmd:=NtoBE(cmd.cmd);
  786. m.cmdsize:=NtoBE(cmd.cmdsize);
  787. WriteData(m, sizeof(m));
  788. end;
  789. procedure TBE32MachoWriter.WriteRelocation(const ri: relocation_info);
  790. var
  791. m : relocation_info;
  792. begin
  793. m.r_address:=NtoBE(ri.r_address);
  794. m.r_info:=NtoBE(ri.r_info);
  795. WriteData(m, sizeof(m));
  796. end;
  797. procedure TBE32MachoWriter.WriteScatterReloc(const ri: scattered_relocation_info);
  798. var
  799. m : LongWord;
  800. begin
  801. m:=LongWord(ri.r_info);
  802. WriteUint32(NtoBE(m));
  803. m:=LongWord(ri.r_value);
  804. WriteUint32(NtoBE(m));
  805. end;
  806. procedure TBE32MachoWriter.WriteNList(const list: nlist_64);
  807. var
  808. m : nlist;
  809. begin
  810. m.n_un.n_strx:=NtoBe(list.n_un.n_strx);
  811. m.n_type:=NtoBe(list.n_type);
  812. m.n_sect:=NtoBe(list.n_sect);
  813. m.n_desc:=NtoBe(list.n_desc);
  814. m.n_value:=NtoBe(list.n_value);
  815. WriteData(m, sizeof(m));
  816. end;
  817. procedure TBE32MachoWriter.WriteUint16(i: uint16_t);
  818. var
  819. m: uint16_t;
  820. begin
  821. m:=NtoBE(i);
  822. WriteData(m, sizeof(m));
  823. end;
  824. procedure TBE32MachoWriter.WriteUint32(i: uint32_t);
  825. var
  826. m: uint32_t;
  827. begin
  828. m:=NtoBE(i);
  829. WriteData(m, sizeof(m));
  830. end;
  831. procedure TBE32MachoWriter.WriteUint64(i: uint64_t);
  832. var
  833. m: uint64_t;
  834. begin
  835. m:=NtoBE(i);
  836. WriteData(m, sizeof(m));
  837. end;
  838. procedure TBE32MachoWriter.WritePtr(ofs: QWord);
  839. var
  840. m: uint32_t;
  841. begin
  842. m:=NtoBE(ofs);
  843. WriteData(m, sizeof(m));
  844. end;
  845. { TBE64MachoWriter }
  846. procedure TBE64MachoWriter.WritePtr(ofs: QWord);
  847. var
  848. m : uint64_t;
  849. begin
  850. m:=NtoBE(ofs);
  851. Writedata(m, sizeof(m));
  852. end;
  853. procedure TBE64MachoWriter.WriteHeader(const hdr: TMachHeader);
  854. var
  855. m : mach_header_64;
  856. begin
  857. with m do
  858. begin
  859. magic:=NtoBE(MH_MAGIC_64);
  860. cputype:=NtoBE(hdr.cputype);
  861. cpusubtype:=NtoBE(hdr.cpusubtype);
  862. filetype:=NtoBE(hdr.filetype);
  863. ncmds:=NtoBE(hdr.ncmds);
  864. sizeofcmds:=NtoBE(hdr.sizeofcmds);
  865. flags:=NtoBE(hdr.flags);
  866. reserved:=0;
  867. end;
  868. WriteData(m, sizeof(m));
  869. end;
  870. procedure TBE64MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
  871. var
  872. m : segment_command_64;
  873. begin
  874. with m do
  875. begin
  876. cmd:=NtoBE(LC_SEGMENT_64);
  877. cmdsize:=NtoBE(acmdSize);
  878. segname:=seg.segname;
  879. vmaddr:=NtoBE(seg.vmaddr);
  880. vmsize:=NtoBE(seg.vmsize);
  881. fileoff:=NtoBE(seg.fileoff);
  882. filesize:=NtoBE(seg.filesize);
  883. maxprot:=NtoBE(seg.maxprot);
  884. initprot:=NtoBE(seg.initprot);
  885. nsects:=NtoBE(seg.nsects);
  886. flags:=NtoBE(seg.flags);
  887. end;
  888. WriteData(m, sizeof(m));
  889. end;
  890. procedure TBE64MachoWriter.WriteSection(const sec: TMachoSection);
  891. var
  892. m : section_64;
  893. begin
  894. FillChar(m, sizeof(m), 0);
  895. with m do
  896. begin
  897. sectname:=sec.sectname;
  898. segname:=sec.segname;
  899. addr:=NtoBE(sec.addr);
  900. size:=NtoBE(sec.size);
  901. offset:=NtoBE(sec.offset);
  902. align:=NtoBE(sec.align);
  903. reloff:=NtoBE(sec.reloff);
  904. nreloc:=NtoBE(sec.nreloc);
  905. flags:=NtoBE(sec.flags);
  906. reserved1:=NtoBE( GetReserved1(sec));
  907. reserved2:=NtoBE( GetReserved2(sec));
  908. end;
  909. WriteData(m, sizeof(m));
  910. end;
  911. procedure TBE64MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
  912. var
  913. m : routines_command_64;
  914. begin
  915. FillChar(m, sizeof(m), 0);
  916. with m do
  917. begin
  918. cmd:=NtoBE(LC_ROUTINES);
  919. cmdsize:=NtoBE(sizeof(m));
  920. init_address:=NtoBE(rt.init_address);
  921. init_module:=NtoBE(rt.init_module);
  922. end;
  923. WriteData(m, sizeof(m));
  924. end;
  925. procedure TBE64MachoWriter.WriteNList(const list: nlist_64);
  926. var
  927. m : nlist_64;
  928. begin
  929. m.n_un.n_strx:=NtoBe(list.n_un.n_strx);
  930. m.n_type:=NtoBe(list.n_type);
  931. m.n_sect:=NtoBe(list.n_sect);
  932. m.n_desc:=NtoBe(list.n_desc);
  933. m.n_value:=NtoBe(list.n_value);
  934. WriteData(m, sizeof(m));
  935. end;
  936. { TMachoReader }
  937. constructor TMachoReader.Create(ARawReader: TRawReader; StartOfs: QWord=0);
  938. begin
  939. inherited Create;
  940. fReader:=ARawReader;
  941. hdrofs:=StartOfs;
  942. end;
  943. function TMachoReader.IntReadStruct: Boolean;
  944. var
  945. m : mach_header_64;
  946. i : Integer;
  947. p : qword;
  948. begin
  949. Result:=false;
  950. if not fReader.Seek(hdrofs) then
  951. Exit;
  952. //todo:
  953. fReader.ReadRaw(m, sizeof(mach_header_64));
  954. fCnv:=AllocConverter(m.magic);
  955. fCnv.ConvertMachoHeader(pmach_header(@m)^, fhdr);
  956. is64:=fhdr.cputype and CPU_ARCH_ABI64>0;
  957. Result:=true;
  958. SetLength(cmds, fHdr.ncmds);
  959. if fHdr.ncmds>0 then
  960. begin
  961. if is64 then
  962. p:=sizeof(mach_header_64)
  963. else
  964. p:=sizeof(mach_header);
  965. SetLength(cmdofs, fHdr.ncmds);
  966. for i:=0 to fHdr.ncmds - 1 do
  967. begin
  968. cmdofs[i]:=p;
  969. fReader.Seek(p);
  970. fReader.ReadRaw(cmds[i], sizeof(cmds[i]));
  971. fCnv.ConvertLoadCommand(cmds[i]);
  972. inc(p, cmds[i].cmdsize);
  973. end;
  974. end;
  975. end;
  976. function TMachoReader.ReadHeader(var hdr: TMachHeader): Boolean;
  977. begin
  978. if not Assigned(fCnv) then
  979. Result:=IntReadStruct
  980. else
  981. Result:=true;
  982. hdr:=fhdr;
  983. end;
  984. function TMachoReader.ReadCommandID(index: LongWord; var cmd: load_command): Boolean;
  985. begin
  986. if not Assigned(fCnv) then
  987. IntReadStruct;
  988. Result:={(index>=0) and }(index<fHdr.ncmds);
  989. if not Result then
  990. Exit;
  991. Result:=true;
  992. cmd:=cmds[index];
  993. end;
  994. function TMachoReader.ReadSegmentCommand(cmdindex: LongWord; var segment: TMachoSegment): Boolean;
  995. var
  996. seg64 : segment_command_64;
  997. seg32 : segment_command;
  998. begin
  999. if not Assigned(fCnv) then
  1000. IntReadStruct;
  1001. Result:={(cmdindex>=0) and }
  1002. (cmdindex<fHdr.ncmds) and
  1003. (cmds[cmdindex].cmd in [LC_SEGMENT, LC_SEGMENT_64]);
  1004. if Result then
  1005. begin
  1006. fReader.Seek(cmdofs[cmdindex]);
  1007. if is64 then
  1008. begin
  1009. Result:=fReader.ReadRaw(seg64, sizeof(seg64))=sizeof(seg64);
  1010. if Result then
  1011. fCnv.ConvertSegment64(seg64, segment);
  1012. end
  1013. else
  1014. begin
  1015. Result:=fReader.ReadRaw(seg32, sizeof(seg32))=sizeof(seg32);
  1016. if Result then
  1017. fCnv.ConvertSegment(seg32, segment);
  1018. end;
  1019. end;
  1020. end;
  1021. function TMachoReader.GetCmdOfs(index: LongWord): qword;
  1022. begin
  1023. if not Assigned(fCnv) then
  1024. IntReadStruct;
  1025. if {(index<0) or}
  1026. (index>=longword(length(cmdofs))) then
  1027. Result:=0
  1028. else
  1029. Result:=cmdofs[index];
  1030. end;
  1031. function TMachoReader.ReadSection(segindex, secindex: LongWord; var machsection: TMachoSection): Boolean;
  1032. var
  1033. ofs : qword;
  1034. is64bit : Boolean;
  1035. buf : array [0..sizeof(section_64)-1] of byte;
  1036. const
  1037. sectsize : array[Boolean] of LongWord = ( sizeof(macho.section), sizeof(macho.section_64));
  1038. segsize : array[Boolean] of LongWord = ( sizeof(macho.segment_command), sizeof(macho.segment_command_64));
  1039. begin
  1040. if not Assigned(fCnv) then
  1041. IntReadStruct;
  1042. Result:={(secindex>=0) and (segindex>=0) and }(segindex<fHdr.ncmds) and (cmds[segindex].cmd in [LC_SEGMENT, LC_SEGMENT_64]);
  1043. if not Result then
  1044. Exit;
  1045. is64bit:=cmds[segindex].cmd=LC_SEGMENT_64;
  1046. Result:=secindex<(cmds[segindex].cmdsize-segsize[is64bit]) div sectsize[is64bit];
  1047. if not Result then
  1048. Exit;
  1049. ofs:=cmdofs[segindex]+segsize[is64bit]+sectsize[is64]*secindex;
  1050. fReader.Seek(ofs);
  1051. fReader.ReadRaw(buf, segsize[is64bit]);
  1052. if is64bit then
  1053. fCnv.ConvertSection64( psection_64(@buf)^, machsection)
  1054. else
  1055. fCnv.ConvertSection( psection(@buf)^, machsection);
  1056. end;
  1057. function TMachoReader.ReadUInt32(var v: LongWord): Boolean;
  1058. begin
  1059. if not Assigned(fCnv) then
  1060. IntReadStruct;
  1061. Result:=Assigned(fCnv) and (fReader.ReadRaw(v, sizeof(v))=sizeof(v));
  1062. if Result then
  1063. fCnv.ConvertUint32(v);
  1064. end;
  1065. function TMachoReader.ReadData(var data; dataSize: Integer): Integer;
  1066. begin
  1067. Result:=fReader.ReadRaw(data, dataSize);
  1068. end;
  1069. function TMachoReader.GetNListSize: Integer;
  1070. begin
  1071. if is64 then
  1072. Result:=sizeof(nlist_64)
  1073. else
  1074. Result:=sizeof(nlist);
  1075. end;
  1076. function TMachoReader.ReadNList(fileofs: qword; var nsym: nlist_64): Boolean;
  1077. var
  1078. n32 : nlist;
  1079. begin
  1080. fReader.Seek(fileofs);
  1081. if is64 then
  1082. Result:=fReader.ReadRaw(nsym, sizeof(nlist_64))=sizeof(nlist_64)
  1083. else
  1084. begin
  1085. Result:=fReader.ReadRaw(n32, sizeof(nlist))=sizeof(nlist);
  1086. nsym.n_un.n_strx:=n32.n_un.n_strx;
  1087. nsym.n_desc:=n32.n_desc;
  1088. nsym.n_sect:=n32.n_sect;
  1089. nsym.n_type:=n32.n_type;
  1090. nsym.n_value:=n32.n_value;
  1091. end;
  1092. fCnv.ConvertUInt32(nsym.n_un.n_strx);
  1093. fCnv.ConvertUInt16(nsym.n_desc);
  1094. fCnv.ConvertUInt64(nsym.n_value);
  1095. end;
  1096. function TMachoReader.ReadSymTabCmd(var symcmd: symtab_command): Boolean;
  1097. var
  1098. i : Integer;
  1099. p : qword;
  1100. begin
  1101. if not Assigned(fCnv) then
  1102. IntReadStruct;
  1103. for i:=0 to length(cmds)-1 do
  1104. if cmds[i].cmd=LC_SYMTAB then
  1105. begin
  1106. p:=fReader.ReadPos;
  1107. fReader.Seek(cmdofs[i]);
  1108. fReader.ReadRaw(symcmd, sizeof(symcmd));
  1109. fCnv.ConvertUInt32(symcmd.cmd);
  1110. fCnv.ConvertUInt32(symcmd.cmdsize);
  1111. fCnv.ConvertUInt32(symcmd.symoff);
  1112. fCnv.ConvertUInt32(symcmd.nsyms);
  1113. fCnv.ConvertUInt32(symcmd.stroff);
  1114. fCnv.ConvertUInt32(symcmd.strsize);
  1115. fReader.Seek(p);
  1116. Result:=true;
  1117. Exit;
  1118. end;
  1119. Result:=false;
  1120. end;
  1121. procedure TMachoReader.Seek(apos: qword);
  1122. begin
  1123. fReader.Seek(apos);
  1124. end;
  1125. { TLEMachoStructConverter }
  1126. procedure TLEMachoStructConverter.ConvertMachoHeader(const mh: mach_header; var hdr: TMachHeader);
  1127. begin
  1128. hdr.cputype:=LEToN(mh.cputype);
  1129. hdr.cpusubtype:=LEtoN(mh.cpusubtype);
  1130. hdr.filetype:=LEToN(mh.filetype);
  1131. hdr.ncmds:=LEToN(mh.ncmds);
  1132. hdr.sizeofcmds:=LEToN(mh.ncmds);
  1133. hdr.flags:=LEToN(mh.flags);
  1134. end;
  1135. procedure TLEMachoStructConverter.ConvertMachoHeader64(const mh: mach_header_64; var hdr: TMachHeader);
  1136. begin
  1137. hdr.cputype:=LEToN(mh.cputype);
  1138. hdr.cpusubtype:=LEtoN(mh.cpusubtype);
  1139. hdr.filetype:=LEToN(mh.filetype);
  1140. hdr.ncmds:=LEToN(mh.ncmds);
  1141. hdr.sizeofcmds:=LEToN(mh.ncmds);
  1142. hdr.flags:=LEToN(mh.flags);
  1143. end;
  1144. procedure TLEMachoStructConverter.ConvertLoadCommand(var cmd: load_command);
  1145. begin
  1146. cmd.cmd:=LEToN(cmd.cmd);
  1147. cmd.cmdsize:=LEToN(cmd.cmdsize);
  1148. end;
  1149. procedure TLEMachoStructConverter.ConvertSegment(const segcmd: segment_command; var segment: TMachoSegment);
  1150. begin
  1151. FillChar(segment, sizeof(segment), 0);
  1152. segment.segname:=segcmd.segname;
  1153. segment.vmaddr:=LEToN(segcmd.vmaddr);
  1154. segment.vmsize:=LEToN(segcmd.vmsize);
  1155. segment.fileoff:=LEToN(segcmd.fileoff);
  1156. segment.filesize:=LEToN(segcmd.filesize);
  1157. segment.maxprot:=LEToN(segcmd.maxprot);
  1158. segment.initprot:=LEToN(segcmd.initprot);
  1159. writelN('segcmd.nsects = ', segcmd.nsects);
  1160. segment.nsects:=LEToN(segcmd.nsects);
  1161. segment.flags:=LEToN(segcmd.flags);
  1162. //todo: reserved!?
  1163. end;
  1164. procedure TMachoStructConverter.ConvertSegment64(const segcmd: segment_command_64; var segment: TMachoSegment);
  1165. begin
  1166. FillChar(segment, sizeof(segment), 0);
  1167. segment.segname:=segcmd.segname;
  1168. segment.vmaddr:=LEToN(segcmd.vmaddr);
  1169. segment.vmsize:=LEToN(segcmd.vmsize);
  1170. segment.fileoff:=LEToN(segcmd.fileoff);
  1171. segment.filesize:=LEToN(segcmd.filesize);
  1172. segment.maxprot:=LEToN(segcmd.maxprot);
  1173. segment.initprot:=LEToN(segcmd.initprot);
  1174. segment.nsects:=LEToN(segcmd.nsects);
  1175. segment.flags:=LEToN(segcmd.flags);
  1176. //todo: reserved!?
  1177. end;
  1178. procedure TMachoStructConverter.ConvertSection(const sec: section; var section: TMachoSection);
  1179. begin
  1180. FillChar(section, sizeof(section), 0);
  1181. section.sectname:=sec.sectname;
  1182. section.segname:=sec.segname;
  1183. section.addr:=LEToN(sec.addr);
  1184. section.size:=LEToN(sec.size);
  1185. section.offset:=LEToN(sec.offset);
  1186. section.align:=LEToN(sec.align);
  1187. section.reloff:=LEToN(sec.reloff);
  1188. section.nreloc:=LEToN(sec.nreloc);
  1189. section.flags:=LEToN(sec.flags);
  1190. //todo:
  1191. //section.indirectIndex : Integer; // reserved1 for LAZY and NON_LAZY pointers
  1192. //section.stubSize : Integer; // reserved2 for S_SYMBOL_STUBS
  1193. end;
  1194. procedure TMachoStructConverter.ConvertSection64(const sec: section_64; var section: TMachoSection);
  1195. begin
  1196. FillChar(section, sizeof(section), 0);
  1197. section.sectname:=sec.sectname;
  1198. section.segname:=sec.segname;
  1199. section.addr:=LEToN(sec.addr);
  1200. section.size:=LEToN(sec.size);
  1201. section.offset:=LEToN(sec.offset);
  1202. section.align:=LEToN(sec.align);
  1203. section.reloff:=LEToN(sec.reloff);
  1204. section.nreloc:=LEToN(sec.nreloc);
  1205. section.flags:=LEToN(sec.flags);
  1206. //todo:
  1207. //section.indirectIndex : Integer; // reserved1 for LAZY and NON_LAZY pointers
  1208. //section.stubSize : Integer; // reserved2 for S_SYMBOL_STUBS
  1209. end;
  1210. procedure TMachoStructConverter.ConvertUInt32(var v: LongWord);
  1211. begin
  1212. v:=LEtoN(v);
  1213. end;
  1214. procedure TMachoStructConverter.ConvertUInt64(var v: qword);
  1215. begin
  1216. v:=LEtoN(v);
  1217. end;
  1218. procedure TMachoStructConverter.ConvertUInt16(var v: Word);
  1219. begin
  1220. v:=LEToN(v);
  1221. end;
  1222. end.