mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-12 15:29:34 +02:00

and more precisely to cross reading/writing fixes. ------------------------------------------------------------------------ r41896 | pierre | 2019-04-18 14:08:03 +0000 (Thu, 18 Apr 2019) | 15 lines Integrate patch from bug report 35409. Add possibiliy to throw InternalError for unhandled case values inside tentryfile, But avoid adding dependency on verbose unit as this would break ppudump handling of ppu files. Add RaiseAssertion virtual method to tentryfile class. Call RaiseAssertion in tentryfile methods where an internal error is wanted. Override RaiseAssertion method in symtype.pas unit to call InternalError. Add new class tppudumpfile to override RaiseAssertion in utils/ppuutils/ppudump.pp unit. ------------------------------------------------------------------------ --- Merging r41896 into '.': U compiler/entfile.pas U compiler/pcp.pas U compiler/symtype.pas U compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r41896 into '.': U . ------------------------------------------------------------------------ r42111 | pierre | 2019-05-20 22:06:57 +0000 (Mon, 20 May 2019) | 1 line List TSettings partially and improve generic output ------------------------------------------------------------------------ --- Merging r42111 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42111 into '.': G . ------------------------------------------------------------------------ r42322 | pierre | 2019-07-03 13:35:05 +0000 (Wed, 03 Jul 2019) | 1 line Systematically include fpcdefs.inc at sart of all units used by compiler ------------------------------------------------------------------------ --- Merging r42322 into '.': U compiler/aarch64/cpuinfo.pas U compiler/arm/cpuinfo.pas U compiler/avr/cpuinfo.pas U compiler/ccharset.pas U compiler/generic/cpuinfo.pas U compiler/jvm/cpuinfo.pas U compiler/m68k/cpuinfo.pas U compiler/macho.pas U compiler/machoutils.pas U compiler/mips/cpuinfo.pas G compiler/pcp.pas U compiler/powerpc/cpuinfo.pas U compiler/powerpc64/cpuinfo.pas U compiler/systems/i_wii.pas --- Recording mergeinfo for merge of r42322 into '.': G . ------------------------------------------------------------------------ r42323 | pierre | 2019-07-04 15:24:49 +0000 (Thu, 04 Jul 2019) | 7 lines * Set ControllerSupport to false for sparc/sparc64 and x86_64 CPUs. This boolean must only be set to true if TControllerType is not simply (ct_none) * ppu.pas: Increment CurrentPPULongVersion constant as the above modification changes the number of fields of the TSettings record that is saved to PPU in ST_LOADSETTINGS field. { not mereged } ------------------------------------------------------------------------ --- Merging r42323 into '.': C compiler/ppu.pas { not mereged } U compiler/sparc/cpuinfo.pas U compiler/sparc64/cpuinfo.pas U compiler/x86_64/cpuinfo.pas --- Recording mergeinfo for merge of r42323 into '.': G . ------------------------------------------------------------------------ r42324 | pierre | 2019-07-04 15:25:40 +0000 (Thu, 04 Jul 2019) | 1 line Correctly read saved tsettings ------------------------------------------------------------------------ --- Merging r42324 into '.': C compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42324 into '.': G . Summary of conflicts: Text conflicts: 1 ------------------------------------------------------------------------ r42325 | marcus | 2019-07-04 16:49:26 +0000 (Thu, 04 Jul 2019) | 1 line Fixed ppudump compilation on big endian platforms after r42324 ------------------------------------------------------------------------ --- Merging r42325 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42325 into '.': G . ------------------------------------------------------------------------ r42353 | svenbarth | 2019-07-12 16:25:33 +0000 (Fri, 12 Jul 2019) | 1 line * write an entry name for the property options ------------------------------------------------------------------------ --- Merging r42353 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42353 into '.': G . ------------------------------------------------------------------------ r42354 | svenbarth | 2019-07-12 16:25:36 +0000 (Fri, 12 Jul 2019) | 1 line * write a name for the none property access entry (looks nicer than a "(Nil)" at the start of the line) ------------------------------------------------------------------------ --- Merging r42354 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42354 into '.': G . ------------------------------------------------------------------------ r42527 | pierre | 2019-07-29 05:33:00 +0000 (Mon, 29 Jul 2019) | 22 lines Fix recordtoken writing into ppu files to allow correct handling in cross-configuration with different endianess. The code has been modified to use the same scheme as the writing of the other parts of the ppu, i.e. change_endian filed has been added also to tscannerfile class of scanner unit. This field is then used to swap values that required endianess conversion. * scanner.pas: change_endian filed added to tscannerfile class. The value of this field is set as the same field in tentryfile class of entfile unit. Token read and write methods converted to use change_endian field. * ppu.pas: Increase CurrentPPILongVersion * utils/ppuutils/ppudump.pp: Remove unneeded FPC_BIG_ENDIAN code which was needed because tokens were previously written using a different rule. ------------------------------------------------------------------------ --- Merging r42527 into '.': C compiler/ppu.pas U compiler/scanner.pas G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42527 into '.': G . Summary of conflicts: Text conflicts: 1 ------------------------------------------------------------------------ r42528 | pierre | 2019-07-29 11:54:27 +0000 (Mon, 29 Jul 2019) | 1 line Changed paths: M /trunk/compiler/scanner.pas Try to fix bug introduced in previous commit #42527, hopefully fixing bug report 35902 ------------------------------------------------------------------------ --- Merging r42528 into '.': G compiler/scanner.pas --- Recording mergeinfo for merge of r42528 into '.': G .------------------------------------------------------------------------ r42530 | pierre | 2019-07-29 16:40:58 +0000 (Mon, 29 Jul 2019) | 8 lines Try to fix ppudump for generic/inline. * entfile.pas: Differenciate ibsymtableoptions and ibrecsymtableoptions. * ppu.pas: Increase ppu unit CurrentPPULongVersion value. * utils/ppuutils/ppudump.pp: Add current_symtable_options variable. Change readsymtableoptions from procedure to function returning the new tsymtableoptions. ------------------------------------------------------------------------ --- Merging r42530 into '.': G compiler/entfile.pas G compiler/ppu.pas G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42530 into '.': G . ------------------------------------------------------------------------ r42583 | pierre | 2019-08-05 09:15:12 +0000 (Mon, 05 Aug 2019) | 1 line Reorganize token buffer output to be able to use it for generics and inlined functions ------------------------------------------------------------------------ --- Merging r42583 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42583 into '.': G . ------------------------------------------------------------------------ r42591 | pierre | 2019-08-06 06:32:52 +0000 (Tue, 06 Aug 2019) | 1 line Add mode and optimizer switches names, and check that no unknown switch is set ------------------------------------------------------------------------ --- Merging r42591 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42591 into '.': G . ------------------------------------------------------------------------ r42596 | pierre | 2019-08-06 21:32:51 +0000 (Tue, 06 Aug 2019) | 1 line Fix gettokenbufshortint, as shortint is one byte long, not two ------------------------------------------------------------------------ --- Merging r42596 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42596 into '.': G . ------------------------------------------------------------------------ r42609 | pierre | 2019-08-09 09:29:50 +0000 (Fri, 09 Aug 2019) | 1 line Correct size of asizeint, which is still 4-byte long even when CpuAddrBitSize is 16 as for avr and i8086 ------------------------------------------------------------------------ --- Merging r42609 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42609 into '.': G . ------------------------------------------------------------------------ r42670 | pierre | 2019-08-13 06:20:23 +0000 (Tue, 13 Aug 2019) | 1 line Reduce cpu-os dependency on real constant printout by using system.str ------------------------------------------------------------------------ --- Merging r42670 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42670 into '.': G . ------------------------------------------------------------------------ r42906 | pierre | 2019-09-02 16:00:15 +0000 (Mon, 02 Sep 2019) | 1 line Fix problems with big endian systems without 80-bit floating point support ------------------------------------------------------------------------ --- Merging r42906 into '.': G compiler/utils/ppuutils/ppudump.pp --- Recording mergeinfo for merge of r42906 into '.': G . git-svn-id: branches/fixes_3_2@43387 -
1469 lines
43 KiB
ObjectPascal
1469 lines
43 KiB
ObjectPascal
{
|
|
Copyright (c) 2009-2010 by Dmitry Boyarintsev
|
|
|
|
Contains utility routines and types for handling mach-o structure and types.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
|
|
}
|
|
|
|
unit machoutils;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
{$h+}
|
|
|
|
interface
|
|
|
|
uses
|
|
macho;
|
|
|
|
type
|
|
TRawWriter=class(TObject)
|
|
public
|
|
procedure WriteRaw(const data; datasize: Integer); virtual; abstract;
|
|
end;
|
|
|
|
TRawReader=class(TObject)
|
|
public
|
|
function ReadRaw(var data; datasize: Integer): Integer; virtual; abstract;
|
|
function Seek(pos: qword): Boolean; virtual; abstract;
|
|
function ReadPos: qword; virtual; abstract;
|
|
end;
|
|
|
|
TMachHeader=record
|
|
cputype : cpu_type_t;
|
|
cpusubtype : cpu_subtype_t;
|
|
filetype : longword;
|
|
ncmds : longword;
|
|
sizeofcmds : longword;
|
|
flags : longword;
|
|
end;
|
|
|
|
TSegmentName=string[16];
|
|
TSectionName=TSegmentName;
|
|
|
|
TMachoSegment=record
|
|
segname : TSegmentName;
|
|
vmaddr : qword;
|
|
vmsize : qword;
|
|
fileoff : qword;
|
|
filesize : qword;
|
|
maxprot : vm_prot_t;
|
|
initprot : vm_prot_t;
|
|
nsects : longword;
|
|
flags : longword;
|
|
end;
|
|
|
|
TMachoSection=record
|
|
sectname : TSectionName;
|
|
segname : TSegmentName;
|
|
addr : uint64_t;
|
|
size : uint64_t;
|
|
offset : uint32_t;
|
|
align : uint32_t;
|
|
reloff : uint32_t;
|
|
nreloc : uint32_t;
|
|
flags : uint32_t;
|
|
|
|
indirectIndex : Integer; // reserved1 for LAZY and NON_LAZY pointers
|
|
stubSize : Integer; // reserved2 for S_SYMBOL_STUBS
|
|
end;
|
|
|
|
TMachoRoutine=record
|
|
init_address : uint64_t; { address of initialization routine }
|
|
init_module : uint64_t; { index into the module table that }
|
|
end;
|
|
|
|
{ TMachoWriter }
|
|
|
|
TMachoWriter=class(TObject)
|
|
private
|
|
fwriter : TRawWriter;
|
|
fown : Boolean;
|
|
protected
|
|
public
|
|
constructor Create(ARawWriter: TRawWriter; AllowFreeWriter: Boolean);
|
|
destructor Destroy; override;
|
|
|
|
{ non platform specific writer }
|
|
procedure WriteData(const data; dataSize: Integer);
|
|
procedure WriteUint8(i: uint8_t);
|
|
|
|
{ endian specific writer }
|
|
procedure WriteUint16(i: uint16_t); virtual; abstract;
|
|
procedure WriteUint32(i: uint32_t); virtual; abstract;
|
|
procedure WriteUint64(i: uint64_t); virtual; abstract;
|
|
|
|
{ endian and ptr-size specific writer }
|
|
procedure WritePtr(ofs: QWord); virtual; abstract; // ptr is 32 bit for 32-bit platforms
|
|
|
|
{ macro utility methods }
|
|
|
|
procedure WriteHeader(const hdr: TMachHeader); virtual; abstract;
|
|
procedure WriteSegmentCmd(const seg: TMachoSegment; cmdSize: LongWord); virtual; abstract;
|
|
procedure WriteSection(const sec: TMachoSection); virtual; abstract;
|
|
procedure WriteRoutineCmd(const rt: TMachoRoutine); virtual; abstract;
|
|
procedure WriteLoadCommand(const cmd: load_command); virtual; abstract; overload;
|
|
procedure WriteLoadCommand(cmd, cmdsize: Integer); overload;
|
|
procedure WriteRelocation(const ri: relocation_info); virtual; abstract;
|
|
procedure WriteScatterReloc(const ri: scattered_relocation_info); virtual; abstract;
|
|
procedure WriteNList(const list: nlist_64); virtual; abstract;
|
|
end;
|
|
|
|
{ TLE32MachoWriter }
|
|
|
|
TLE32MachoWriter=class(TMachoWriter)
|
|
public
|
|
procedure WriteUint16(i: uint16_t); override;
|
|
procedure WriteUint32(i: uint32_t); override;
|
|
procedure WriteUint64(i: uint64_t); override;
|
|
procedure WritePtr(ofs: QWord); override;
|
|
|
|
procedure WriteHeader(const hdr: TMachHeader); override;
|
|
procedure WriteSegmentCmd(const seg: TMachoSegment; ACmdSize: LongWord); override;
|
|
procedure WriteSection(const sec: TMachoSection); override;
|
|
procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
|
|
procedure WriteLoadCommand(const cmd: load_command); override;
|
|
procedure WriteRelocation(const ri: relocation_info); override;
|
|
procedure WriteScatterReloc(const ri: scattered_relocation_info); override;
|
|
procedure WriteNList(const list: nlist_64); override;
|
|
end;
|
|
|
|
{ TLE64MachoWriter }
|
|
|
|
TLE64MachoWriter=class(TLE32MachoWriter)
|
|
public
|
|
procedure WritePtr(ofs: QWord); override;
|
|
|
|
procedure WriteHeader(const hdr: TMachHeader); override;
|
|
procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
|
|
procedure WriteSection(const sec: TMachoSection); override;
|
|
procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
|
|
procedure WriteNList(const list: nlist_64); override;
|
|
end;
|
|
|
|
{ TBE32MachoWriter }
|
|
|
|
TBE32MachoWriter=class(TMachoWriter)
|
|
public
|
|
procedure WriteUint16(i: uint16_t); override;
|
|
procedure WriteUint32(i: uint32_t); override;
|
|
procedure WriteUint64(i: uint64_t); override;
|
|
procedure WritePtr(ofs: QWord); override;
|
|
|
|
procedure WriteHeader(const hdr: TMachHeader); override;
|
|
procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
|
|
procedure WriteSection(const sec: TMachoSection); override;
|
|
procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
|
|
procedure WriteLoadCommand(const cmd: load_command); override;
|
|
procedure WriteRelocation(const ri: relocation_info); override;
|
|
procedure WriteScatterReloc(const ri: scattered_relocation_info); override;
|
|
procedure WriteNList(const list: nlist_64); override;
|
|
end;
|
|
|
|
{ TBE64MachoWriter }
|
|
|
|
TBE64MachoWriter=class(TBE32MachoWriter)
|
|
public
|
|
procedure WritePtr(ofs: QWord); override;
|
|
|
|
procedure WriteHeader(const hdr: TMachHeader); override;
|
|
procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
|
|
procedure WriteSection(const sec: TMachoSection); override;
|
|
procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
|
|
procedure WriteNList(const list: nlist_64); override;
|
|
end;
|
|
|
|
|
|
{ TLEMachoStructConverter }
|
|
|
|
{ converter for Little-endian structures to Host }
|
|
TLEMachoStructConverter = class(TObject)
|
|
public
|
|
procedure ConvertMachoHeader(const mh: mach_header; var hdr: TMachHeader); virtual;
|
|
procedure ConvertMachoHeader64(const mh: mach_header_64; var hdr: TMachHeader); virtual;
|
|
procedure ConvertLoadCommand(var cmd: load_command); virtual;
|
|
procedure ConvertSegment(const segcmd: segment_command; var segment: TMachoSegment); virtual;
|
|
procedure ConvertSegment64(const segcmd: segment_command_64; var segment: TMachoSegment); virtual;
|
|
procedure ConvertSection(const sec: section; var section: TMachoSection); virtual;
|
|
procedure ConvertSection64(const sec: section_64; var section: TMachoSection); virtual;
|
|
|
|
procedure ConvertUInt16(var v: Word); virtual;
|
|
procedure ConvertUInt32(var v: LongWord); virtual;
|
|
procedure ConvertUInt64(var v: qWord); virtual;
|
|
end;
|
|
|
|
{ converter for Big-endian structures to Host }
|
|
TBEMachoStructConverter = class(TLEMachoStructConverter);
|
|
|
|
{common}
|
|
TMachoStructConverter = TLEMachoStructConverter;
|
|
|
|
{ TMachoReader }
|
|
|
|
TMachoReader=class(TObject)
|
|
private
|
|
fReader : TRawReader;
|
|
HdrOfs : qword;
|
|
fCnv : TMachoStructConverter;
|
|
fHdr : TMachHeader;
|
|
is64 : Boolean;
|
|
cmdofs : array of qword;
|
|
cmds : array of load_command;
|
|
protected
|
|
function IntReadStruct: Boolean;
|
|
public
|
|
constructor Create(ARawReader: TRawReader; StartOfs: QWord=0);
|
|
function ReadHeader(var hdr: TMachHeader): Boolean;
|
|
function ReadCommandID(index: LongWord; var cmd: load_command): Boolean;
|
|
function GetCmdOfs(index: LongWord): qword;
|
|
|
|
function ReadSegmentCommand(cmdindex: LongWord; var segment: TMachoSegment): Boolean;
|
|
function ReadSection(segindex, secindex: LongWord; var machsection: TMachoSection): Boolean;
|
|
|
|
function ReadSymTabCmd(var symcmd: symtab_command): Boolean;
|
|
|
|
function ReadUInt32(var v: LongWord): Boolean;
|
|
function ReadData(var data; dataSize: Integer): Integer;
|
|
|
|
{todo: ReadNList - using index of symbol, instead of file offset?}
|
|
function GetNListSize: Integer;
|
|
function ReadNList(fileofs: qword; var nsym: nlist_64): Boolean;
|
|
|
|
procedure Seek(apos: qword);
|
|
end;
|
|
|
|
const
|
|
seg_TEXT : TSegmentName = '__TEXT';
|
|
seg_DATA : TSegmentName = '__DATA';
|
|
seg_OBJC : TSegmentName = '__OBJC';
|
|
seg_IMPORT : TSegmentName = '__IMPORT';
|
|
seg_DWARF : TSegmentName = '__DWARF';
|
|
|
|
function AllocMachoWriter(cputarget: cpu_type_t; ARawWriter: TRawWriter; AllowFreeWriter: Boolean): TMachoWriter;
|
|
|
|
function sizeMachHeader(cputarget: cpu_type_t): integer; inline;
|
|
function sizeSegment(cputarget: cpu_type_t): integer; inline;
|
|
function sizeSection(cputarget: cpu_type_t): integer; inline;
|
|
function sizeNList(cputarget: cpu_type_t): integer; inline;
|
|
|
|
function AlignAddr(cputarget: cpu_type_t; addr: qword): qword;
|
|
|
|
procedure InitSegment(var seg: TMachoSegment);
|
|
|
|
function MakeSectionName(const segName, secName: shortstring): shortstring;
|
|
function GetSegmentSectionName(const objSecName: shortstring; var segName, secName: shortstring): shortstring;
|
|
|
|
function GetSectionFlags(const segName, secName: shortstring): LongWord;
|
|
|
|
type
|
|
TRelocInfoLength = (ril_byte = 0, ril_word = 1, ril_long = 2, ril_quad = 3);
|
|
|
|
procedure RelocInfo(addr, symnum, reltype: integer; len: TRelocInfoLength; pcrel, extern: Boolean; var info: relocation_info);
|
|
procedure ScatterRelocInfo(value, addr, reltype: integer; len: TRelocInfoLength; pcrel: Boolean; var info: scattered_relocation_info);
|
|
|
|
function GetReserved1(const macho: TMachoSection): integer;
|
|
function GetReserved2(const macho: TMachoSection): integer;
|
|
|
|
function GetStubSize(cputarget: Integer; Pic: Boolean): Integer;
|
|
function MachoAlign(al: integer): integer;
|
|
|
|
implementation
|
|
|
|
function MachoAlign(al: integer): integer;
|
|
begin
|
|
Result:=0;
|
|
al:=al shr 1;
|
|
while al>0 do
|
|
begin
|
|
inc(Result);
|
|
al:=al shr 1;
|
|
end;
|
|
end;
|
|
|
|
|
|
function AllocConverter(magic: LongWord): TMachoStructConverter;
|
|
begin
|
|
{$ifdef ENDIAN_BIG}
|
|
if magic=MH_MAGIC then
|
|
Result:=TBEMachoStructConverter.Create
|
|
else
|
|
Result:=TLEMachoStructConverter.Create;
|
|
{$else}
|
|
if magic=MH_MAGIC then
|
|
Result:=TLEMachoStructConverter.Create
|
|
else
|
|
Result:=TBEMachoStructConverter.Create;
|
|
{$endif}
|
|
end;
|
|
|
|
|
|
{result values are used from aggas.pas, see TGNUAssembler.WriteSection }
|
|
function GetStubSize(cputarget: Integer; Pic: Boolean): Integer;
|
|
begin
|
|
case cputarget of
|
|
CPU_TYPE_I386, CPU_TYPE_X86_64:
|
|
Result:=5;
|
|
CPU_TYPE_POWERPC, CPU_TYPE_POWERPC64:
|
|
if Pic then
|
|
Result:=32
|
|
else
|
|
Result:=16;
|
|
CPU_TYPE_ARM:
|
|
if Pic then
|
|
Result:=16
|
|
else
|
|
Result:=12;
|
|
else
|
|
Result:=-1;
|
|
end;
|
|
end;
|
|
|
|
|
|
function GetReserved1(const macho: TMachoSection): integer;
|
|
begin
|
|
case macho.flags and SECTION_TYPE of
|
|
S_NON_LAZY_SYMBOL_POINTERS, S_LAZY_SYMBOL_POINTERS:
|
|
Result:=macho.indirectIndex;
|
|
else
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
function GetReserved2(const macho: TMachoSection): integer;
|
|
begin
|
|
case macho.flags and SECTION_TYPE of
|
|
S_SYMBOL_STUBS:
|
|
Result:=macho.stubSize
|
|
else
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure RelocInfo(addr, symnum, reltype: integer; len: TRelocInfoLength; pcrel, extern: Boolean; var info: relocation_info);
|
|
{$ifdef ENDIAN_BIG}
|
|
const
|
|
relbit : array [Boolean] of Integer = (0, 1 shl 7);
|
|
extbit : array [Boolean] of Integer = (0, 1 shl 4);
|
|
ri_len_mask : array [TRelocInfoLength] of Integer = (0 shl 5, 1 shl 5, 2 shl 5, 3 shl 5);
|
|
begin
|
|
info.r_address:=addr;
|
|
info.r_info:=((symnum and $FFFFFF) shl 8) or // r_symbolnum:24
|
|
relbit[pcrel] or // r_pcrel:1;
|
|
ri_len_mask[len] or // r_length:2;
|
|
extbit[extern] or // r_extern:1;
|
|
(reltype and $F); // r_type:4;
|
|
end;
|
|
{$else}
|
|
const
|
|
relbit : array [Boolean] of Integer = (0, 1 shl 24);
|
|
extbit : array [Boolean] of Integer = (0, 1 shl 27);
|
|
ri_len_mask : array [TRelocInfoLength] of Integer = (0 shl 25, 1 shl 25, 2 shl 25, 3 shl 25);
|
|
begin
|
|
info.r_address:=addr;
|
|
info.r_info:=(symnum and $FFFFFF) or // r_symbolnum:24
|
|
relbit[pcrel] or // r_pcrel:1;
|
|
extbit[extern] or // r_length:2;
|
|
ri_len_mask[len] or // r_extern:1;
|
|
(reltype shl 28); // r_type:4;
|
|
end;
|
|
{$endif}
|
|
|
|
|
|
const
|
|
si_len_mask: array [TRelocInfoLength] of Integer = (0 shl 28, 1 shl 28, 2 shl 28, 3 shl 28);
|
|
si_type_ofs = 24;
|
|
si_pcrel_bit = 1 shl 30;
|
|
si_scatter_bit = 1 shl 31;
|
|
si_addr_ofs = 0;
|
|
|
|
|
|
procedure ScatterRelocInfo(value, addr, reltype: integer; len: TRelocInfoLength; pcrel: Boolean; var info: scattered_relocation_info);
|
|
const
|
|
relbit : array [Boolean] of Integer = (0, si_pcrel_bit);
|
|
begin
|
|
// big endian
|
|
info.r_info:=si_scatter_bit or // r_scattered:1, /* 1=scattered, 0=non-scattered (see above) */
|
|
relbit[pcrel] or // r_pcrel:1, /* was relocated pc relative already */
|
|
si_len_mask[len] or // r_length:2, /* 0=byte, 1=word, 2=long, 3=quad */
|
|
((reltype and $F) shl si_type_ofs) or // r_type:4, /* if not 0, machine specific relocation type */
|
|
((addr and $FFFFFF) shl si_addr_ofs); // r_address:24; /* offset in the section to what is being relocated */}
|
|
info.r_value:=value;
|
|
// little endian
|
|
// r_address:24, /* offset in the section to what is being relocated */
|
|
// r_type:4, /* if not 0, machine specific relocation type */
|
|
// r_length:2, /* 0=byte, 1=word, 2=long, 3=quad */
|
|
// r_pcrel:1, /* was relocated pc relative already */
|
|
// r_scattered:1; /* 1=scattered, 0=non-scattered (see above) */ *}
|
|
end;
|
|
|
|
|
|
function GetSectionFlags(const segName, secName: shortstring): LongWord;
|
|
begin
|
|
Result:=0;
|
|
if segName = seg_DATA then
|
|
begin
|
|
if secName = '__nl_symbol_ptr' then
|
|
Result:=Result or S_NON_LAZY_SYMBOL_POINTERS
|
|
else if secName = '__la_symbol_ptr' then
|
|
Result:=Result or S_LAZY_SYMBOL_POINTERS
|
|
else if secName = '__common' then
|
|
Result:=Result or S_ZEROFILL
|
|
end
|
|
else if segName = seg_TEXT then
|
|
begin
|
|
if (secName = '__text') then
|
|
Result:=Result or S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS
|
|
else if secName = '__textcoal_nt' then
|
|
Result:=Result or S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS or S_COALESCED
|
|
else if secName = '.fpc' then
|
|
Result:=Result or S_ATTR_NO_DEAD_STRIP
|
|
else if secName = '__cstring' then
|
|
Result:=Result or S_CSTRING_LITERALS;
|
|
end
|
|
else if (segName = seg_IMPORT) then
|
|
begin
|
|
if (secName = '__jump_table') then
|
|
Result:=Result or S_SYMBOL_STUBS or S_ATTR_SELF_MODIFYING_CODE or S_ATTR_SOME_INSTRUCTIONS
|
|
end
|
|
else if (segName=seg_OBJC) then
|
|
begin
|
|
Result:=S_ATTR_NO_DEAD_STRIP;
|
|
if secName='__message_refs' then
|
|
Result:=Result or S_ATTR_NO_DEAD_STRIP or S_LITERAL_POINTERS
|
|
else if secName='__cls_refs' then
|
|
Result:=Result or S_ATTR_NO_DEAD_STRIP or S_LITERAL_POINTERS;
|
|
end;
|
|
end;
|
|
|
|
|
|
function MakeSectionName(const segName, secName: shortstring): shortstring;
|
|
begin
|
|
if segName = '' then
|
|
Result:=secName
|
|
else
|
|
Result:=segName+' '+secName;
|
|
end;
|
|
|
|
|
|
function GetSegmentSectionName(const objSecName: shortstring; var segName, secName: shortstring): shortstring;
|
|
var
|
|
i : integer;
|
|
begin
|
|
i:=Pos(' ', objSecName);
|
|
if i>0 then
|
|
begin
|
|
segName:=copy(objsecName, 1, i-1);
|
|
secName:=copy(objsecName, i+1, length(objsecName)-i);
|
|
end
|
|
else
|
|
begin
|
|
segName:='';
|
|
secName:=objSecName;
|
|
end;
|
|
Result:=objSecName;
|
|
end;
|
|
|
|
|
|
procedure InitSegment(var seg: TMachoSegment);
|
|
begin
|
|
FillChar(seg, sizeof(seg), 0);
|
|
seg.initprot:=VM_PROT_ALL;
|
|
seg.maxprot:=VM_PROT_ALL;
|
|
end;
|
|
|
|
|
|
const
|
|
is64MachHeaderSize : array [Boolean] of Integer = ( sizeof(mach_header), sizeof(mach_header_64));
|
|
is64SectionSize : array [Boolean] of Integer = ( sizeof(section), sizeof(section_64));
|
|
is64SegmentSize : array [Boolean] of Integer = ( sizeof(segment_command), sizeof(segment_command_64));
|
|
is64NListSize : array [Boolean] of Integer = (sizeof(nlist), sizeof(nlist_64));
|
|
|
|
function AlignAddr(cputarget: cpu_type_t; addr: qword): qword;
|
|
var
|
|
md : array [Boolean] of integer = (4, 8);
|
|
p : PtrUInt;
|
|
begin
|
|
p:=addr;
|
|
p:=align(p, md[cputarget and CPU_ARCH_ABI64 > 0]);
|
|
Result:=qword(p);
|
|
end;
|
|
|
|
|
|
function sizeMachHeader(cputarget: cpu_type_t): integer;
|
|
begin
|
|
Result:=is64MachHeaderSize[ cputarget and CPU_ARCH_ABI64 > 0];
|
|
end;
|
|
|
|
|
|
function sizeSegment(cputarget: cpu_type_t): integer;
|
|
begin
|
|
Result:=is64SegmentSize[ cputarget and CPU_ARCH_ABI64 > 0];
|
|
end;
|
|
|
|
|
|
function sizeSection(cputarget: cpu_type_t): integer;
|
|
begin
|
|
Result:=is64SectionSize[ cputarget and CPU_ARCH_ABI64 > 0];
|
|
end;
|
|
|
|
|
|
function sizeNList(cputarget: cpu_type_t): integer; inline;
|
|
begin
|
|
Result:=is64NlistSize[ cputarget and CPU_ARCH_ABI64 > 0];
|
|
end;
|
|
|
|
|
|
function AllocMachoWriter(cputarget: cpu_type_t; ARawWriter: TRawWriter; AllowFreeWriter: Boolean): TMachoWriter;
|
|
begin
|
|
case cputarget of
|
|
CPU_TYPE_I386,
|
|
CPU_TYPE_ARM: Result:=TLE32MachoWriter.Create(ARawWriter, AllowFreeWriter);
|
|
CPU_TYPE_X86_64: Result:=TLE64MachoWriter.Create(ARawWriter, AllowFreeWriter);
|
|
CPU_TYPE_POWERPC: Result:=TBE32MachoWriter.Create(ARawWriter, AllowFreeWriter);
|
|
CPU_TYPE_POWERPC64: Result:=TBE64MachoWriter.Create(ARawWriter, AllowFreeWriter);
|
|
else
|
|
begin
|
|
if AllowFreeWriter then
|
|
ARawWriter.Free;
|
|
Result:=nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TMachoWriter }
|
|
|
|
procedure TMachoWriter.WriteData(const data; dataSize: Integer);
|
|
begin
|
|
if not assigned(fwriter) then
|
|
Exit;
|
|
fwriter.WriteRaw(data, dataSize);
|
|
end;
|
|
|
|
|
|
procedure TMachoWriter.WriteUint8(i: uint8_t);
|
|
begin
|
|
WriteData(i, sizeof(i));
|
|
end;
|
|
|
|
|
|
procedure TMachoWriter.WriteLoadCommand(cmd, cmdsize: Integer);
|
|
var
|
|
m : load_command;
|
|
begin
|
|
m.cmd:=cmd;
|
|
m.cmdsize:=cmdsize;
|
|
WriteLoadCommand(m);
|
|
end;
|
|
|
|
|
|
constructor TMachoWriter.Create(ARawWriter: TRawWriter; AllowFreeWriter: Boolean);
|
|
begin
|
|
inherited Create;
|
|
fwriter:=ARawWriter;
|
|
fown:=AllowFreeWriter;
|
|
end;
|
|
|
|
|
|
destructor TMachoWriter.Destroy;
|
|
begin
|
|
if fown then
|
|
fwriter.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
|
|
{ TLE32MachoWriter }
|
|
|
|
procedure TLE32MachoWriter.WriteHeader(const hdr: TMachHeader);
|
|
var
|
|
m : mach_header;
|
|
begin
|
|
with m do
|
|
begin
|
|
magic:=NtoLE(MH_MAGIC);
|
|
cputype:=NtoLE(hdr.cputype);
|
|
cpusubtype:=NtoLE(hdr.cpusubtype);
|
|
filetype:=NtoLE(hdr.filetype);
|
|
ncmds:=NtoLE(hdr.ncmds);
|
|
sizeofcmds:=NtoLE(hdr.sizeofcmds);
|
|
flags:=NtoLE(hdr.flags);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; ACmdSize: LongWord);
|
|
var
|
|
m : segment_command;
|
|
begin
|
|
with m do
|
|
begin
|
|
cmd:=NtoLE(LC_SEGMENT);
|
|
cmdsize:=NtoLE(ACmdSize);
|
|
segname:=seg.segname;
|
|
vmaddr:=NtoLE(uint32_t(seg.vmaddr));
|
|
vmsize:=NtoLE(uint32_t(seg.vmsize));
|
|
fileoff:=NtoLE(uint32_t(seg.fileoff));
|
|
filesize:=NtoLE(uint32_t(seg.filesize));
|
|
maxprot:=NtoLE(seg.maxprot);
|
|
initprot:=NtoLE(seg.initprot);
|
|
nsects:=NtoLE(seg.nsects);
|
|
flags:=NtoLE(seg.flags);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteSection(const sec: TMachoSection);
|
|
var
|
|
m : section;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
sectname:=sec.sectname;
|
|
segname:=sec.segname;
|
|
addr:=NtoLE(sec.addr);
|
|
size:=NtoLE(sec.size);
|
|
offset:=NtoLE(sec.offset);
|
|
align:=NtoLE(sec.align);
|
|
reloff:=NtoLE(sec.reloff);
|
|
nreloc:=NtoLE(sec.nreloc);
|
|
flags:=NtoLE(sec.flags);
|
|
reserved1:=NtoLE( GetReserved1(sec));
|
|
reserved2:=NtoLE( GetReserved2(sec));
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
|
|
var
|
|
m : routines_command;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
cmd:=NtoLE(LC_ROUTINES);
|
|
cmdsize:=NtoLE(sizeof(m));
|
|
init_address:=NtoLE(rt.init_address);
|
|
init_module:=NtoLE(rt.init_module);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteLoadCommand(const cmd: load_command);
|
|
var
|
|
m : load_command;
|
|
begin
|
|
m.cmd:=NtoLE(cmd.cmd);
|
|
m.cmdsize:=NtoLE(cmd.cmdsize);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteRelocation(const ri: relocation_info);
|
|
var
|
|
m : relocation_info;
|
|
begin
|
|
m.r_address:=NtoLE(ri.r_address);
|
|
m.r_info:=NtoLE(ri.r_info);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteScatterReloc(const ri: scattered_relocation_info);
|
|
var
|
|
m : LongWord;
|
|
begin
|
|
m:=LongWord(ri.r_info);
|
|
WriteUint32(NtoLE(m));
|
|
|
|
m:=LongWord(ri.r_value);
|
|
WriteUint32(NtoLE(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteNList(const list: nlist_64);
|
|
var
|
|
m : nlist;
|
|
begin
|
|
m.n_un.n_strx:=NtoLe(list.n_un.n_strx);
|
|
m.n_type:=NtoLe(list.n_type);
|
|
m.n_sect:=NtoLe(list.n_sect);
|
|
m.n_desc:=NtoLe(list.n_desc);
|
|
m.n_value:=NtoLe(list.n_value);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteUint16(i: uint16_t);
|
|
var
|
|
m: uint16_t;
|
|
begin
|
|
m:=NtoLE(i);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteUint32(i: uint32_t);
|
|
var
|
|
m: uint32_t;
|
|
begin
|
|
m:=NtoLE(i);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WriteUint64(i: uint64_t);
|
|
var
|
|
m: uint64_t;
|
|
begin
|
|
m:=NtoLE(i);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE32MachoWriter.WritePtr(ofs: QWord);
|
|
var
|
|
m: uint32_t;
|
|
begin
|
|
m:=NtoLE(ofs);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
{ TLE64MachoWriter }
|
|
|
|
procedure TLE64MachoWriter.WritePtr(ofs: QWord);
|
|
var
|
|
m : uint64_t;
|
|
begin
|
|
m:=NtoLE(ofs);
|
|
Writedata(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE64MachoWriter.WriteHeader(const hdr: TMachHeader);
|
|
var
|
|
m : mach_header_64;
|
|
begin
|
|
with m do
|
|
begin
|
|
magic:=NtoLE(MH_MAGIC_64);
|
|
cputype:=NtoLE(hdr.cputype);
|
|
cpusubtype:=NtoLE(hdr.cpusubtype);
|
|
filetype:=NtoLE(hdr.filetype);
|
|
ncmds:=NtoLE(hdr.ncmds);
|
|
sizeofcmds:=NtoLE(hdr.sizeofcmds);
|
|
flags:=NtoLE(hdr.flags);
|
|
reserved:=0;
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE64MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
|
|
var
|
|
m : segment_command_64;
|
|
begin
|
|
with m do
|
|
begin
|
|
cmd:=NtoLE(LC_SEGMENT_64);
|
|
cmdsize:=NtoLE(acmdSize);
|
|
segname:=seg.segname;
|
|
vmaddr:=NtoLE(seg.vmaddr);
|
|
vmsize:=NtoLE(seg.vmsize);
|
|
fileoff:=NtoLE(seg.fileoff);
|
|
filesize:=NtoLE(seg.filesize);
|
|
maxprot:=NtoLE(seg.maxprot);
|
|
initprot:=NtoLE(seg.initprot);
|
|
nsects:=NtoLE(seg.nsects);
|
|
flags:=NtoLE(seg.flags);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE64MachoWriter.WriteSection(const sec: TMachoSection);
|
|
var
|
|
m : section_64;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
sectname:=sec.sectname;
|
|
segname:=sec.segname;
|
|
addr:=NtoLE(sec.addr);
|
|
size:=NtoLE(sec.size);
|
|
offset:=NtoLE(sec.offset);
|
|
align:=NtoLE(sec.align);
|
|
reloff:=NtoLE(sec.reloff);
|
|
nreloc:=NtoLE(sec.nreloc);
|
|
flags:=NtoLE(sec.flags);
|
|
reserved1:=NtoLE( GetReserved1(sec));
|
|
reserved2:=NtoLE( GetReserved2(sec));
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE64MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
|
|
var
|
|
m : routines_command_64;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
cmd:=NtoLE(LC_ROUTINES);
|
|
cmdsize:=NtoLE(sizeof(m));
|
|
init_address:=NtoLE(rt.init_address);
|
|
init_module:=NtoLE(rt.init_module);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TLE64MachoWriter.WriteNList(const list: nlist_64);
|
|
var
|
|
m : nlist_64;
|
|
begin
|
|
m.n_un.n_strx:=NtoLe(list.n_un.n_strx);
|
|
m.n_type:=NtoLe(list.n_type);
|
|
m.n_sect:=NtoLe(list.n_sect);
|
|
m.n_desc:=NtoLe(list.n_desc);
|
|
m.n_value:=NtoLe(list.n_value);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
{ TBE32MachoWriter }
|
|
|
|
procedure TBE32MachoWriter.WriteHeader(const hdr: TMachHeader);
|
|
var
|
|
m : mach_header;
|
|
begin
|
|
with m do
|
|
begin
|
|
magic:=NtoBE(MH_MAGIC);
|
|
cputype:=NtoBE(hdr.cputype);
|
|
cpusubtype:=NtoBE(hdr.cpusubtype);
|
|
filetype:=NtoBE(hdr.filetype);
|
|
ncmds:=NtoBE(hdr.ncmds);
|
|
sizeofcmds:=NtoBE(hdr.sizeofcmds);
|
|
flags:=NtoBE(hdr.flags);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
|
|
var
|
|
m : segment_command;
|
|
begin
|
|
with m do
|
|
begin
|
|
cmd:=NtoBE(LC_SEGMENT);
|
|
cmdsize:=NtoBE(acmdSize);
|
|
segname:=seg.segname;
|
|
vmaddr:=NtoBE(uint32_t(seg.vmaddr));
|
|
vmsize:=NtoBE(uint32_t(seg.vmsize));
|
|
fileoff:=NtoBE(uint32_t(seg.fileoff));
|
|
filesize:=NtoBE(uint32_t(seg.filesize));
|
|
maxprot:=NtoBE(seg.maxprot);
|
|
initprot:=NtoBE(seg.initprot);
|
|
nsects:=NtoBE(seg.nsects);
|
|
flags:=NtoBE(seg.flags);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteSection(const sec: TMachoSection);
|
|
var
|
|
m : section;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
sectname:=sec.sectname;
|
|
segname:=sec.segname;
|
|
addr:=NtoBE(sec.addr);
|
|
size:=NtoBE(sec.size);
|
|
offset:=NtoBE(sec.offset);
|
|
align:=NtoBE(sec.align);
|
|
reloff:=NtoBE(sec.reloff);
|
|
nreloc:=NtoBE(sec.nreloc);
|
|
flags:=NtoBE(sec.flags);
|
|
reserved1:=NtoBE( GetReserved1(sec));
|
|
reserved2:=NtoBE( GetReserved2(sec));
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
|
|
var
|
|
m : routines_command;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
cmd:=NtoBE(LC_ROUTINES);
|
|
cmdsize:=NtoBE(sizeof(m));
|
|
init_address:=NtoBE(rt.init_address);
|
|
init_module:=NtoBE(rt.init_module);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteLoadCommand(const cmd: load_command);
|
|
var
|
|
m : load_command;
|
|
begin
|
|
m.cmd:=NtoBE(cmd.cmd);
|
|
m.cmdsize:=NtoBE(cmd.cmdsize);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteRelocation(const ri: relocation_info);
|
|
var
|
|
m : relocation_info;
|
|
begin
|
|
m.r_address:=NtoBE(ri.r_address);
|
|
m.r_info:=NtoBE(ri.r_info);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteScatterReloc(const ri: scattered_relocation_info);
|
|
var
|
|
m : LongWord;
|
|
begin
|
|
m:=LongWord(ri.r_info);
|
|
WriteUint32(NtoBE(m));
|
|
|
|
m:=LongWord(ri.r_value);
|
|
WriteUint32(NtoBE(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteNList(const list: nlist_64);
|
|
var
|
|
m : nlist;
|
|
begin
|
|
m.n_un.n_strx:=NtoBe(list.n_un.n_strx);
|
|
m.n_type:=NtoBe(list.n_type);
|
|
m.n_sect:=NtoBe(list.n_sect);
|
|
m.n_desc:=NtoBe(list.n_desc);
|
|
m.n_value:=NtoBe(list.n_value);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteUint16(i: uint16_t);
|
|
var
|
|
m: uint16_t;
|
|
begin
|
|
m:=NtoBE(i);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteUint32(i: uint32_t);
|
|
var
|
|
m: uint32_t;
|
|
begin
|
|
m:=NtoBE(i);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WriteUint64(i: uint64_t);
|
|
var
|
|
m: uint64_t;
|
|
begin
|
|
m:=NtoBE(i);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE32MachoWriter.WritePtr(ofs: QWord);
|
|
var
|
|
m: uint32_t;
|
|
begin
|
|
m:=NtoBE(ofs);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
{ TBE64MachoWriter }
|
|
|
|
procedure TBE64MachoWriter.WritePtr(ofs: QWord);
|
|
var
|
|
m : uint64_t;
|
|
begin
|
|
m:=NtoBE(ofs);
|
|
Writedata(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE64MachoWriter.WriteHeader(const hdr: TMachHeader);
|
|
var
|
|
m : mach_header_64;
|
|
begin
|
|
with m do
|
|
begin
|
|
magic:=NtoBE(MH_MAGIC_64);
|
|
cputype:=NtoBE(hdr.cputype);
|
|
cpusubtype:=NtoBE(hdr.cpusubtype);
|
|
filetype:=NtoBE(hdr.filetype);
|
|
ncmds:=NtoBE(hdr.ncmds);
|
|
sizeofcmds:=NtoBE(hdr.sizeofcmds);
|
|
flags:=NtoBE(hdr.flags);
|
|
reserved:=0;
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE64MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
|
|
var
|
|
m : segment_command_64;
|
|
begin
|
|
with m do
|
|
begin
|
|
cmd:=NtoBE(LC_SEGMENT_64);
|
|
cmdsize:=NtoBE(acmdSize);
|
|
segname:=seg.segname;
|
|
vmaddr:=NtoBE(seg.vmaddr);
|
|
vmsize:=NtoBE(seg.vmsize);
|
|
fileoff:=NtoBE(seg.fileoff);
|
|
filesize:=NtoBE(seg.filesize);
|
|
maxprot:=NtoBE(seg.maxprot);
|
|
initprot:=NtoBE(seg.initprot);
|
|
nsects:=NtoBE(seg.nsects);
|
|
flags:=NtoBE(seg.flags);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE64MachoWriter.WriteSection(const sec: TMachoSection);
|
|
var
|
|
m : section_64;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
sectname:=sec.sectname;
|
|
segname:=sec.segname;
|
|
addr:=NtoBE(sec.addr);
|
|
size:=NtoBE(sec.size);
|
|
offset:=NtoBE(sec.offset);
|
|
align:=NtoBE(sec.align);
|
|
reloff:=NtoBE(sec.reloff);
|
|
nreloc:=NtoBE(sec.nreloc);
|
|
flags:=NtoBE(sec.flags);
|
|
reserved1:=NtoBE( GetReserved1(sec));
|
|
reserved2:=NtoBE( GetReserved2(sec));
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE64MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
|
|
var
|
|
m : routines_command_64;
|
|
begin
|
|
FillChar(m, sizeof(m), 0);
|
|
with m do
|
|
begin
|
|
cmd:=NtoBE(LC_ROUTINES);
|
|
cmdsize:=NtoBE(sizeof(m));
|
|
init_address:=NtoBE(rt.init_address);
|
|
init_module:=NtoBE(rt.init_module);
|
|
end;
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
procedure TBE64MachoWriter.WriteNList(const list: nlist_64);
|
|
var
|
|
m : nlist_64;
|
|
begin
|
|
m.n_un.n_strx:=NtoBe(list.n_un.n_strx);
|
|
m.n_type:=NtoBe(list.n_type);
|
|
m.n_sect:=NtoBe(list.n_sect);
|
|
m.n_desc:=NtoBe(list.n_desc);
|
|
m.n_value:=NtoBe(list.n_value);
|
|
WriteData(m, sizeof(m));
|
|
end;
|
|
|
|
|
|
{ TMachoReader }
|
|
|
|
constructor TMachoReader.Create(ARawReader: TRawReader; StartOfs: QWord=0);
|
|
begin
|
|
inherited Create;
|
|
fReader:=ARawReader;
|
|
hdrofs:=StartOfs;
|
|
end;
|
|
|
|
|
|
function TMachoReader.IntReadStruct: Boolean;
|
|
var
|
|
m : mach_header_64;
|
|
i : Integer;
|
|
p : qword;
|
|
begin
|
|
Result:=false;
|
|
if not fReader.Seek(hdrofs) then
|
|
Exit;
|
|
//todo:
|
|
fReader.ReadRaw(m, sizeof(mach_header_64));
|
|
fCnv:=AllocConverter(m.magic);
|
|
fCnv.ConvertMachoHeader(pmach_header(@m)^, fhdr);
|
|
is64:=fhdr.cputype and CPU_ARCH_ABI64>0;
|
|
Result:=true;
|
|
|
|
SetLength(cmds, fHdr.ncmds);
|
|
if fHdr.ncmds>0 then
|
|
begin
|
|
if is64 then
|
|
p:=sizeof(mach_header_64)
|
|
else
|
|
p:=sizeof(mach_header);
|
|
|
|
SetLength(cmdofs, fHdr.ncmds);
|
|
for i:=0 to fHdr.ncmds - 1 do
|
|
begin
|
|
cmdofs[i]:=p;
|
|
fReader.Seek(p);
|
|
fReader.ReadRaw(cmds[i], sizeof(cmds[i]));
|
|
fCnv.ConvertLoadCommand(cmds[i]);
|
|
inc(p, cmds[i].cmdsize);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadHeader(var hdr: TMachHeader): Boolean;
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
Result:=IntReadStruct
|
|
else
|
|
Result:=true;
|
|
hdr:=fhdr;
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadCommandID(index: LongWord; var cmd: load_command): Boolean;
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
IntReadStruct;
|
|
Result:={(index>=0) and }(index<fHdr.ncmds);
|
|
if not Result then
|
|
Exit;
|
|
Result:=true;
|
|
cmd:=cmds[index];
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadSegmentCommand(cmdindex: LongWord; var segment: TMachoSegment): Boolean;
|
|
var
|
|
seg64 : segment_command_64;
|
|
seg32 : segment_command;
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
IntReadStruct;
|
|
|
|
Result:={(cmdindex>=0) and }
|
|
(cmdindex<fHdr.ncmds) and
|
|
(cmds[cmdindex].cmd in [LC_SEGMENT, LC_SEGMENT_64]);
|
|
|
|
if Result then
|
|
begin
|
|
fReader.Seek(cmdofs[cmdindex]);
|
|
if is64 then
|
|
begin
|
|
Result:=fReader.ReadRaw(seg64, sizeof(seg64))=sizeof(seg64);
|
|
if Result then
|
|
fCnv.ConvertSegment64(seg64, segment);
|
|
end
|
|
else
|
|
begin
|
|
Result:=fReader.ReadRaw(seg32, sizeof(seg32))=sizeof(seg32);
|
|
if Result then
|
|
fCnv.ConvertSegment(seg32, segment);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TMachoReader.GetCmdOfs(index: LongWord): qword;
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
IntReadStruct;
|
|
|
|
if {(index<0) or}
|
|
(index>=longword(length(cmdofs))) then
|
|
Result:=0
|
|
else
|
|
Result:=cmdofs[index];
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadSection(segindex, secindex: LongWord; var machsection: TMachoSection): Boolean;
|
|
var
|
|
ofs : qword;
|
|
is64bit : Boolean;
|
|
buf : array [0..sizeof(section_64)-1] of byte;
|
|
const
|
|
sectsize : array[Boolean] of LongWord = ( sizeof(macho.section), sizeof(macho.section_64));
|
|
segsize : array[Boolean] of LongWord = ( sizeof(macho.segment_command), sizeof(macho.segment_command_64));
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
IntReadStruct;
|
|
Result:={(secindex>=0) and (segindex>=0) and }(segindex<fHdr.ncmds) and (cmds[segindex].cmd in [LC_SEGMENT, LC_SEGMENT_64]);
|
|
if not Result then
|
|
Exit;
|
|
|
|
is64bit:=cmds[segindex].cmd=LC_SEGMENT_64;
|
|
Result:=secindex<(cmds[segindex].cmdsize-segsize[is64bit]) div sectsize[is64bit];
|
|
if not Result then
|
|
Exit;
|
|
|
|
ofs:=cmdofs[segindex]+segsize[is64bit]+sectsize[is64]*secindex;
|
|
fReader.Seek(ofs);
|
|
fReader.ReadRaw(buf, segsize[is64bit]);
|
|
if is64bit then
|
|
fCnv.ConvertSection64( psection_64(@buf)^, machsection)
|
|
else
|
|
fCnv.ConvertSection( psection(@buf)^, machsection);
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadUInt32(var v: LongWord): Boolean;
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
IntReadStruct;
|
|
Result:=Assigned(fCnv) and (fReader.ReadRaw(v, sizeof(v))=sizeof(v));
|
|
if Result then
|
|
fCnv.ConvertUint32(v);
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadData(var data; dataSize: Integer): Integer;
|
|
begin
|
|
Result:=fReader.ReadRaw(data, dataSize);
|
|
end;
|
|
|
|
|
|
function TMachoReader.GetNListSize: Integer;
|
|
begin
|
|
if is64 then
|
|
Result:=sizeof(nlist_64)
|
|
else
|
|
Result:=sizeof(nlist);
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadNList(fileofs: qword; var nsym: nlist_64): Boolean;
|
|
var
|
|
n32 : nlist;
|
|
begin
|
|
fReader.Seek(fileofs);
|
|
if is64 then
|
|
Result:=fReader.ReadRaw(nsym, sizeof(nlist_64))=sizeof(nlist_64)
|
|
else
|
|
begin
|
|
Result:=fReader.ReadRaw(n32, sizeof(nlist))=sizeof(nlist);
|
|
nsym.n_un.n_strx:=n32.n_un.n_strx;
|
|
nsym.n_desc:=n32.n_desc;
|
|
nsym.n_sect:=n32.n_sect;
|
|
nsym.n_type:=n32.n_type;
|
|
nsym.n_value:=n32.n_value;
|
|
end;
|
|
fCnv.ConvertUInt32(nsym.n_un.n_strx);
|
|
fCnv.ConvertUInt16(nsym.n_desc);
|
|
fCnv.ConvertUInt64(nsym.n_value);
|
|
end;
|
|
|
|
|
|
function TMachoReader.ReadSymTabCmd(var symcmd: symtab_command): Boolean;
|
|
var
|
|
i : Integer;
|
|
p : qword;
|
|
begin
|
|
if not Assigned(fCnv) then
|
|
IntReadStruct;
|
|
|
|
for i:=0 to length(cmds)-1 do
|
|
if cmds[i].cmd=LC_SYMTAB then
|
|
begin
|
|
p:=fReader.ReadPos;
|
|
fReader.Seek(cmdofs[i]);
|
|
fReader.ReadRaw(symcmd, sizeof(symcmd));
|
|
fCnv.ConvertUInt32(symcmd.cmd);
|
|
fCnv.ConvertUInt32(symcmd.cmdsize);
|
|
fCnv.ConvertUInt32(symcmd.symoff);
|
|
fCnv.ConvertUInt32(symcmd.nsyms);
|
|
fCnv.ConvertUInt32(symcmd.stroff);
|
|
fCnv.ConvertUInt32(symcmd.strsize);
|
|
fReader.Seek(p);
|
|
Result:=true;
|
|
Exit;
|
|
end;
|
|
Result:=false;
|
|
end;
|
|
|
|
|
|
procedure TMachoReader.Seek(apos: qword);
|
|
begin
|
|
fReader.Seek(apos);
|
|
end;
|
|
|
|
|
|
{ TLEMachoStructConverter }
|
|
|
|
procedure TLEMachoStructConverter.ConvertMachoHeader(const mh: mach_header; var hdr: TMachHeader);
|
|
begin
|
|
hdr.cputype:=LEToN(mh.cputype);
|
|
hdr.cpusubtype:=LEtoN(mh.cpusubtype);
|
|
hdr.filetype:=LEToN(mh.filetype);
|
|
hdr.ncmds:=LEToN(mh.ncmds);
|
|
hdr.sizeofcmds:=LEToN(mh.ncmds);
|
|
hdr.flags:=LEToN(mh.flags);
|
|
end;
|
|
|
|
|
|
procedure TLEMachoStructConverter.ConvertMachoHeader64(const mh: mach_header_64; var hdr: TMachHeader);
|
|
begin
|
|
hdr.cputype:=LEToN(mh.cputype);
|
|
hdr.cpusubtype:=LEtoN(mh.cpusubtype);
|
|
hdr.filetype:=LEToN(mh.filetype);
|
|
hdr.ncmds:=LEToN(mh.ncmds);
|
|
hdr.sizeofcmds:=LEToN(mh.ncmds);
|
|
hdr.flags:=LEToN(mh.flags);
|
|
end;
|
|
|
|
|
|
procedure TLEMachoStructConverter.ConvertLoadCommand(var cmd: load_command);
|
|
begin
|
|
cmd.cmd:=LEToN(cmd.cmd);
|
|
cmd.cmdsize:=LEToN(cmd.cmdsize);
|
|
end;
|
|
|
|
|
|
procedure TLEMachoStructConverter.ConvertSegment(const segcmd: segment_command; var segment: TMachoSegment);
|
|
begin
|
|
FillChar(segment, sizeof(segment), 0);
|
|
segment.segname:=segcmd.segname;
|
|
segment.vmaddr:=LEToN(segcmd.vmaddr);
|
|
segment.vmsize:=LEToN(segcmd.vmsize);
|
|
segment.fileoff:=LEToN(segcmd.fileoff);
|
|
segment.filesize:=LEToN(segcmd.filesize);
|
|
segment.maxprot:=LEToN(segcmd.maxprot);
|
|
segment.initprot:=LEToN(segcmd.initprot);
|
|
writelN('segcmd.nsects = ', segcmd.nsects);
|
|
segment.nsects:=LEToN(segcmd.nsects);
|
|
segment.flags:=LEToN(segcmd.flags);
|
|
//todo: reserved!?
|
|
end;
|
|
|
|
|
|
procedure TMachoStructConverter.ConvertSegment64(const segcmd: segment_command_64; var segment: TMachoSegment);
|
|
begin
|
|
FillChar(segment, sizeof(segment), 0);
|
|
segment.segname:=segcmd.segname;
|
|
segment.vmaddr:=LEToN(segcmd.vmaddr);
|
|
segment.vmsize:=LEToN(segcmd.vmsize);
|
|
segment.fileoff:=LEToN(segcmd.fileoff);
|
|
segment.filesize:=LEToN(segcmd.filesize);
|
|
segment.maxprot:=LEToN(segcmd.maxprot);
|
|
segment.initprot:=LEToN(segcmd.initprot);
|
|
segment.nsects:=LEToN(segcmd.nsects);
|
|
segment.flags:=LEToN(segcmd.flags);
|
|
//todo: reserved!?
|
|
end;
|
|
|
|
|
|
procedure TMachoStructConverter.ConvertSection(const sec: section; var section: TMachoSection);
|
|
begin
|
|
FillChar(section, sizeof(section), 0);
|
|
section.sectname:=sec.sectname;
|
|
section.segname:=sec.segname;
|
|
section.addr:=LEToN(sec.addr);
|
|
section.size:=LEToN(sec.size);
|
|
section.offset:=LEToN(sec.offset);
|
|
section.align:=LEToN(sec.align);
|
|
section.reloff:=LEToN(sec.reloff);
|
|
section.nreloc:=LEToN(sec.nreloc);
|
|
section.flags:=LEToN(sec.flags);
|
|
//todo:
|
|
//section.indirectIndex : Integer; // reserved1 for LAZY and NON_LAZY pointers
|
|
//section.stubSize : Integer; // reserved2 for S_SYMBOL_STUBS
|
|
end;
|
|
|
|
|
|
procedure TMachoStructConverter.ConvertSection64(const sec: section_64; var section: TMachoSection);
|
|
begin
|
|
FillChar(section, sizeof(section), 0);
|
|
section.sectname:=sec.sectname;
|
|
section.segname:=sec.segname;
|
|
section.addr:=LEToN(sec.addr);
|
|
section.size:=LEToN(sec.size);
|
|
section.offset:=LEToN(sec.offset);
|
|
section.align:=LEToN(sec.align);
|
|
section.reloff:=LEToN(sec.reloff);
|
|
section.nreloc:=LEToN(sec.nreloc);
|
|
section.flags:=LEToN(sec.flags);
|
|
//todo:
|
|
//section.indirectIndex : Integer; // reserved1 for LAZY and NON_LAZY pointers
|
|
//section.stubSize : Integer; // reserved2 for S_SYMBOL_STUBS
|
|
end;
|
|
|
|
|
|
procedure TMachoStructConverter.ConvertUInt32(var v: LongWord);
|
|
begin
|
|
v:=LEtoN(v);
|
|
end;
|
|
|
|
|
|
procedure TMachoStructConverter.ConvertUInt64(var v: qword);
|
|
begin
|
|
v:=LEtoN(v);
|
|
end;
|
|
|
|
|
|
procedure TMachoStructConverter.ConvertUInt16(var v: Word);
|
|
begin
|
|
v:=LEToN(v);
|
|
end;
|
|
|
|
end.
|
|
|