/* p_mach.h -- This file is part of the UPX executable compressor. Copyright (C) 1996-2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2007 Laszlo Molnar All Rights Reserved. UPX and the UCL library are free software; you can redistribute them and/or modify them 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Markus F.X.J. Oberhumer Laszlo Molnar markus@oberhumer.com ml1050@users.sourceforge.net */ #ifndef __UPX_P_MACHO_H #define __UPX_P_MACHO_H // Apparently, Mach_fat_header and Mach_fat_arch have the endianness // of the machine on which they were created. We must deal with both kinds. struct Mach_fat_header { unsigned magic; enum e8 { FAT_MAGIC = 0xcafebabe }; unsigned nfat_arch; // Number of Mach_fat_arch which follow. }; struct Mach_fat_arch { unsigned cputype; unsigned cpusubtype; unsigned offset; unsigned size; unsigned align; /* shift count; log base 2 */ }; /************************************************************************* // Mach Mach Object executable; all structures are target-endian // 'otool' is the Mach analog of 'readelf' (convert executable file to ASCII). **************************************************************************/ namespace N_Mach { // integral types template struct MachITypes { typedef TWord Word; typedef TXword Xword; typedef TAddr Addr; typedef TOff Off; }; template struct Mach_header { typedef typename TMachITypes::Word Word; Word magic; Word cputype; Word cpysubtype; Word filetype; Word ncmds; Word sizeofcmds; Word flags; #define WANT_MACH_HEADER_ENUM 1 #include "p_mach_enum.h" } __attribute_packed; template struct Mach_header64 { // only difference is padding to 0 mod 8 typedef typename TMachITypes::Word Word; Word magic; Word cputype; Word cpysubtype; Word filetype; Word ncmds; Word sizeofcmds; Word flags; Word reserved; // pad to 0 mod 8 #define WANT_MACH_HEADER_ENUM 1 #include "p_mach_enum.h" } __attribute_packed; template struct Mach_segment_command { typedef typename TMachITypes::Word Word; typedef typename TMachITypes::Addr Addr; typedef typename TMachITypes::Off Off; Word cmd; Word cmdsize; char segname[16]; Addr vmaddr; Addr vmsize; Off fileoff; Off filesize; Word maxprot; Word initprot; Word nsects; Word flags; #define WANT_MACH_SEGMENT_ENUM 1 #include "p_mach_enum.h" } __attribute_packed; template struct Mach_section_command { typedef typename TMachITypes::Word Word; typedef typename TMachITypes::Addr Addr; typedef typename TMachITypes::Off Off; char sectname[16]; char segname[16]; Addr addr; /* memory address */ Addr size; /* size in bytes */ Word offset; /* file offset */ // FIXME: 64 bit? Word align; /* power of 2 */ Word reloff; /* file offset of relocation entries */ Word nreloc; /* number of relocation entries */ Word flags; /* section type and attributes */ Word reserved1; Word reserved2; #define WANT_MACH_SECTION_ENUM 1 #include "p_mach_enum.h" } __attribute_packed; template struct Mach_ppc_thread_state { typedef typename TMachITypes::Addr Addr; Addr srr0; /* Instruction address register (PC; entry addr) */ Addr srr1; /* Machine state register (supervisor) */ Addr r0, r1, r2, r3, r4, r5, r6, r7; Addr r8, r9,r10,r11,r12,r13,r14,r15; Addr r16,r17,r18,r19,r20,r21,r22,r23; Addr r24,r25,r26,r27,r28,r29,r30,r31; Addr cr; /* Condition register */ // FIXME: Word? Addr xer; /* User's integer exception register */ Addr lr; /* Link register */ Addr ctr; /* Count register */ Addr mq; /* MQ register (601 only) */ Addr vrsave; /* Vector Save Register */ } __attribute_packed; template struct Mach_i386_thread_state { typedef typename TMachITypes::Word Word; Word eax, ebx, ecx, edx; Word edi, esi, ebp; Word esp, ss; Word eflags; Word eip, cs; Word ds, es, fs, gs; } __attribute_packed; template struct Mach_i386_new_thread_state { typedef typename TMachITypes::Word Word; Word gs, fs, es, ds; Word edi, esi, ebp, esp; Word ebx, edx, ecx, eax; Word eip, cs, efl; Word uesp, ss; } __attribute_packed; } // namespace N_Mach namespace N_Mach32 { } // namespace N_Mach32 namespace N_Mach64 { template struct Mach_ppc_thread_state64 { typedef typename TMachITypes::Word Word; typedef typename TMachITypes::Xword Xword; Xword srr0; /* Instruction address register (PC; entry addr) */ Xword srr1; /* Machine state register (supervisor) */ Xword r0, r1, r2, r3, r4, r5, r6, r7; Xword r8, r9,r10,r11,r12,r13,r14,r15; Xword r16,r17,r18,r19,r20,r21,r22,r23; Xword r24,r25,r26,r27,r28,r29,r30,r31; Word cr; /* Condition register */ Xword xer; /* User's integer exception register */ Xword lr; /* Link register */ Xword ctr; /* Count register */ Word vrsave; /* Vector Save Register */ } __attribute_packed; } // namespace N_Mach64 namespace N_Mach { template struct MachClass_32 { typedef TP BeLePolicy; // integral types typedef typename TP::U16 U16; typedef typename TP::U32 U32; typedef typename TP::U64 U64; typedef N_Mach::MachITypes MachITypes; typedef typename MachITypes::Addr Addr; // Mach types typedef N_Mach::Mach_header Mach_header; typedef N_Mach::Mach_segment_command Mach_segment_command; typedef N_Mach::Mach_section_command Mach_section_command; typedef N_Mach::Mach_ppc_thread_state Mach_ppc_thread_state; typedef N_Mach::Mach_i386_thread_state Mach_i386_thread_state; static void compileTimeAssertions() { BeLePolicy::compileTimeAssertions(); } }; template struct MachClass_64 { typedef TP BeLePolicy; // integral types typedef typename TP::U16 U16; typedef typename TP::U32 U32; typedef typename TP::U64 U64; typedef N_Mach::MachITypes MachITypes; // Mach types typedef N_Mach::Mach_header64 Mach_header; typedef N_Mach::Mach_segment_command Mach_segment_command; typedef N_Mach::Mach_section_command Mach_section_command; }; } // namespace N_Mach typedef N_Mach::MachClass_32 MachClass_Host32; typedef N_Mach::MachClass_64 MachClass_Host64; typedef N_Mach::MachClass_32 MachClass_BE32; typedef N_Mach::MachClass_64 MachClass_BE64; typedef N_Mach::MachClass_32 MachClass_LE32; typedef N_Mach::MachClass_64 MachClass_LE64; // shortcuts typedef MachClass_Host32::Mach_segment_command Mach32_segment_command; typedef MachClass_Host32::Mach_section_command Mach32_section_command; typedef MachClass_Host32::Mach_ppc_thread_state Mach_ppc_thread_state; typedef MachClass_Host32::Mach_i386_thread_state Mach_i386_thread_state; typedef MachClass_Host64::Mach_segment_command Mach64_segment_command; typedef MachClass_Host64::Mach_section_command Mach64_section_command; typedef MachClass_BE32::Mach_segment_command MachBE32_segment_command; typedef MachClass_BE32::Mach_section_command MachBE32_section_command; typedef MachClass_BE64::Mach_segment_command MachBE64_segment_command; typedef MachClass_BE64::Mach_section_command MachBE64_section_command; typedef MachClass_LE32::Mach_segment_command MachLE32_segment_command; typedef MachClass_LE32::Mach_section_command MachLE32_section_command; typedef MachClass_LE64::Mach_segment_command MachLE64_segment_command; typedef MachClass_LE64::Mach_section_command MachLE64_section_command; #include "p_unix.h" template class PackMachBase : public PackUnix { typedef PackUnix super; protected: typedef TMachClass MachClass; typedef typename MachClass::BeLePolicy BeLePolicy; typedef typename MachClass::MachITypes MachITypes; // integral types typedef typename MachClass::U16 U16; typedef typename MachClass::U32 U32; typedef typename MachClass::U64 U64; typedef typename MachClass::Addr Addr; // Mach types typedef typename MachClass::Mach_header Mach_header; typedef typename MachClass::Mach_segment_command Mach_segment_command; typedef typename MachClass::Mach_section_command Mach_section_command; public: PackMachBase(InputFile *, unsigned cpuid, unsigned t_flavor, unsigned ts_word_cnt, unsigned tc_size); virtual ~PackMachBase(); virtual int getVersion() const { return 13; } virtual const int *getCompressionMethods(int method, int level) const; // called by the generic pack() virtual void pack1(OutputFile *, Filter &); // generate executable header virtual void pack2(OutputFile *, Filter &); // append compressed data virtual void pack3(OutputFile *, Filter &) = 0; // append loader virtual void pack4(OutputFile *, Filter &) = 0; // append PackHeader virtual void pack1_setup_threado(OutputFile *const fo) = 0; virtual void unpack(OutputFile *fo); virtual bool canPack(); virtual unsigned find_SEGMENT_gap(unsigned const k); protected: virtual void patchLoader(); virtual void patchLoaderChecksum(); virtual void updateLoader(OutputFile *); virtual void buildMachLoader( upx_byte const *const proto, unsigned const szproto, upx_byte const *const fold, unsigned const szfold, Filter const *ft ); virtual void defineSymbols(Filter const *); virtual void addStubEntrySections(Filter const *); static int __acc_cdecl_qsort compare_segment_command(void const *aa, void const *bb); unsigned my_cputype; unsigned my_thread_flavor; unsigned my_thread_state_word_count; unsigned my_thread_command_size; unsigned n_segment; unsigned sz_segment; unsigned sz_mach_headers; Mach_segment_command *rawmseg; // as input, with sections Mach_segment_command *msegcmd; // LC_SEGMENT first, without sections Mach_header mhdri; Mach_header mhdro; Mach_segment_command segcmdo; struct l_info linfo; }; class PackMachPPC32 : public PackMachBase { typedef PackMachBase super; public: PackMachPPC32::PackMachPPC32(InputFile *f) : super(f, Mach_header::CPU_TYPE_POWERPC, Mach_thread_command::PPC_THREAD_STATE, sizeof(Mach_ppc_thread_state)>>2, sizeof(threado)) { } virtual int getFormat() const { return UPX_F_MACH_PPC32; } virtual const char *getName() const { return "Mach/ppc32"; } virtual const char *getFullName(const options_t *) const { return "powerpc-darwin.macho"; } virtual acc_uint64l_t get_native64(const void *b) const { return get_be64(b); } virtual unsigned get_native32(const void *b) const { return get_be32(b); } virtual unsigned get_native16(const void *b) const { return get_be16(b); } virtual void set_native64(void *b, acc_uint64l_t v) const { set_be64(b, v); } virtual void set_native32(void *b, unsigned v) const { set_be32(b, v); } virtual void set_native16(void *b, unsigned v) const { set_be16(b, v); } protected: virtual const int *getFilters() const; virtual void pack1_setup_threado(OutputFile *const fo); virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack4(OutputFile *, Filter &); // append PackHeader virtual Linker* newLinker() const; virtual void buildLoader(const Filter *ft); struct Mach_thread_command { BE32 cmd; /* LC_THREAD or LC_UNIXTHREAD */ BE32 cmdsize; /* total size of this command */ BE32 flavor; BE32 count; /* sizeof(following_thread_state)/4 */ Mach_ppc_thread_state state; #define WANT_MACH_THREAD_ENUM #include "p_mach_enum.h" } threado __attribute_packed; }; class PackMachI386 : public PackMachBase { typedef PackMachBase super; public: PackMachI386(InputFile *f) : super(f, Mach_header::CPU_TYPE_I386, (unsigned)Mach_thread_command::i386_THREAD_STATE, sizeof(Mach_i386_thread_state)>>2, sizeof(threado)) { } virtual int getFormat() const { return UPX_F_MACH_i386; } virtual const char *getName() const { return "Mach/i386"; } virtual const char *getFullName(const options_t *) const { return "i386-darwin.macho"; } protected: virtual const int *getFilters() const; virtual acc_uint64l_t get_native64(const void *b) const { return get_le64(b); } virtual unsigned get_native32(const void *b) const { return get_le32(b); } virtual unsigned get_native16(const void *b) const { return get_le16(b); } virtual void set_native64(void *b, acc_uint64l_t v) const { set_le64(b, v); } virtual void set_native32(void *b, unsigned v) const { set_le32(b, v); } virtual void set_native16(void *b, unsigned v) const { set_le16(b, v); } virtual void pack1_setup_threado(OutputFile *const fo); virtual void pack3(OutputFile *, Filter &); // append loader virtual void pack4(OutputFile *, Filter &); // append PackHeader virtual Linker* newLinker() const; virtual void buildLoader(const Filter *ft); virtual void addStubEntrySections(Filter const *); struct Mach_thread_command { LE32 cmd; /* LC_THREAD or LC_UNIXTHREAD */ LE32 cmdsize; /* total size of this command */ LE32 flavor; LE32 count; /* sizeof(following_thread_state)/4 */ Mach_i386_thread_state state; #define WANT_MACH_THREAD_ENUM #include "p_mach_enum.h" } threado __attribute_packed; }; #endif /* already included */ /* vi:ts=4:et */