machoutils.pas 43 KB

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