]> git.saurik.com Git - apple/dyld.git/blobdiff - launch-cache/MachOFileAbstraction.hpp
dyld-551.3.tar.gz
[apple/dyld.git] / launch-cache / MachOFileAbstraction.hpp
index dadec7b716543c437db8971f33ee97c84662cfbf..ebd298d46a876d870923ab5e6f4c0d0659b76094 100644 (file)
@@ -43,59 +43,110 @@ struct uuid_command {
        #define S_16BYTE_LITERALS 0xE
 #endif
 
-#include "FileAbstraction.hpp"
-#include "Architectures.hpp"
+#ifndef CPU_SUBTYPE_ARM_V5TEJ
+       #define CPU_SUBTYPE_ARM_V5TEJ           ((cpu_subtype_t) 7)
+#endif
+#ifndef CPU_SUBTYPE_ARM_XSCALE
+       #define CPU_SUBTYPE_ARM_XSCALE          ((cpu_subtype_t) 8)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7
+       #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7F
+       #define CPU_SUBTYPE_ARM_V7F                     ((cpu_subtype_t) 10)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7K
+       #define CPU_SUBTYPE_ARM_V7K                     ((cpu_subtype_t) 12)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7S
+       #define CPU_SUBTYPE_ARM_V7S                     ((cpu_subtype_t) 11)
+#endif
+#ifndef CPU_SUBTYPE_ARM64_ALL
+       #define CPU_SUBTYPE_ARM64_ALL           ((cpu_subtype_t) 0)
+#endif
+#ifndef CPU_TYPE_ARM64
+       #define CPU_TYPE_ARM64                          ((cpu_type_t) (CPU_TYPE_ARM | CPU_ARCH_ABI64))
+#endif
 
+#define ARM64_RELOC_UNSIGNED            0 // for pointers
 
 
-//
-// This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
-//
+#ifndef LC_LOAD_UPWARD_DYLIB
+       #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
+#endif
 
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+       #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
+#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
+       #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
+#endif
 
+#ifndef LC_FUNCTION_STARTS
+       #define LC_FUNCTION_STARTS 0x26
+#endif
 
-//
-// mach-o file header
-//
-template <typename P> struct macho_header_content {};
-template <> struct macho_header_content<Pointer32<BigEndian> >    { mach_header                fields; };
-template <> struct macho_header_content<Pointer64<BigEndian> >   { mach_header_64      fields; };
-template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header                fields; };
-template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64     fields; };
+#ifndef LC_DATA_IN_CODE
+       #define LC_DATA_IN_CODE 0x29
+#endif
 
-template <typename P>
-class macho_header {
-public:
-       uint32_t                magic() const                                   INLINE { return E::get32(header.fields.magic); }
-       void                    set_magic(uint32_t value)               INLINE { E::set32(header.fields.magic, value); }
+#ifndef LC_DYLIB_CODE_SIGN_DRS
+       #define LC_DYLIB_CODE_SIGN_DRS 0x2B
+#endif
 
-       uint32_t                cputype() const                                 INLINE { return E::get32(header.fields.cputype); }
-       void                    set_cputype(uint32_t value)             INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
+#ifndef CPU_SUBTYPE_X86_64_H
+       #define CPU_SUBTYPE_X86_64_H            ((cpu_subtype_t) 8) 
+#endif
 
-       uint32_t                cpusubtype() const                              INLINE { return E::get32(header.fields.cpusubtype); }
-       void                    set_cpusubtype(uint32_t value)  INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
 
-       uint32_t                filetype() const                                INLINE { return E::get32(header.fields.filetype); }
-       void                    set_filetype(uint32_t value)    INLINE { E::set32(header.fields.filetype, value); }
+#define DYLD_CACHE_ADJ_V2_FORMAT                               0x7F
 
-       uint32_t                ncmds() const                                   INLINE { return E::get32(header.fields.ncmds); }
-       void                    set_ncmds(uint32_t value)               INLINE { E::set32(header.fields.ncmds, value); }
+#define DYLD_CACHE_ADJ_V2_POINTER_32                   0x01
+#define DYLD_CACHE_ADJ_V2_POINTER_64                   0x02
+#define DYLD_CACHE_ADJ_V2_DELTA_32                         0x03
+#define DYLD_CACHE_ADJ_V2_DELTA_64                         0x04
+#define DYLD_CACHE_ADJ_V2_ARM64_ADRP                   0x05
+#define DYLD_CACHE_ADJ_V2_ARM64_OFF12                  0x06
+#define DYLD_CACHE_ADJ_V2_ARM64_BR26                   0x07
+#define DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT                        0x08
+#define DYLD_CACHE_ADJ_V2_ARM_BR24                             0x09
+#define DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT              0x0A
+#define DYLD_CACHE_ADJ_V2_THUMB_BR22                   0x0B
+#define DYLD_CACHE_ADJ_V2_IMAGE_OFF_32                 0x0C
 
-       uint32_t                sizeofcmds() const                              INLINE { return E::get32(header.fields.sizeofcmds); }
-       void                    set_sizeofcmds(uint32_t value)  INLINE { E::set32(header.fields.sizeofcmds, value); }
+#define MH_HAS_OBJC                    0x40000000
 
-       uint32_t                flags() const                                   INLINE { return E::get32(header.fields.flags); }
-       void                    set_flags(uint32_t value)               INLINE { E::set32(header.fields.flags, value); }
+#ifndef CPU_SUBTYPE_ARM64_E
+       #define CPU_SUBTYPE_ARM64_E    2
+#endif
 
-       uint32_t                reserved() const                                INLINE { return E::get32(header.fields.reserved); }
-       void                    set_reserved(uint32_t value)    INLINE { E::set32(header.fields.reserved, value); }
+#include "FileAbstraction.hpp"
+#include "Architectures.hpp"
 
-       typedef typename P::E           E;
-private:
-       macho_header_content<P> header;
+// utility to pair together a cpu-type and cpu-sub-type
+struct ArchPair
+{
+       uint32_t        arch;
+       uint32_t        subtype;
+       
+       ArchPair(uint32_t cputype, uint32_t cpusubtype) : arch(cputype), subtype(cpusubtype) {}
+       
+       bool operator<(const ArchPair& other) const { 
+               if ( this->arch != other.arch )
+                       return (this->arch < other.arch);
+               return (this->subtype < other.subtype);
+       }
+
+       bool operator==(const ArchPair& other) const { 
+        return this->arch == other.arch  &&  this->subtype == other.subtype;
+       }
 };
 
 
+//
+// This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
+//
+
 //
 // mach-o load command
 //
@@ -729,8 +780,187 @@ private:
 };
 
 
+//
+// mach-o file header
+//
+template <typename P> struct macho_header_content {};
+template <> struct macho_header_content<Pointer32<BigEndian> >    { mach_header                fields; };
+template <> struct macho_header_content<Pointer64<BigEndian> >   { mach_header_64      fields; };
+template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header                fields; };
+template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64     fields; };
+
+template <typename P>
+class macho_header {
+public:
+       uint32_t                magic() const                                   INLINE { return E::get32(header.fields.magic); }
+       void                    set_magic(uint32_t value)               INLINE { E::set32(header.fields.magic, value); }
+
+       uint32_t                cputype() const                                 INLINE { return E::get32(header.fields.cputype); }
+       void                    set_cputype(uint32_t value)             INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
+
+       uint32_t                cpusubtype() const                              INLINE { return E::get32(header.fields.cpusubtype); }
+       void                    set_cpusubtype(uint32_t value)  INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
+
+       uint32_t                filetype() const                                INLINE { return E::get32(header.fields.filetype); }
+       void                    set_filetype(uint32_t value)    INLINE { E::set32(header.fields.filetype, value); }
+
+       uint32_t                ncmds() const                                   INLINE { return E::get32(header.fields.ncmds); }
+       void                    set_ncmds(uint32_t value)               INLINE { E::set32(header.fields.ncmds, value); }
+
+       uint32_t                sizeofcmds() const                              INLINE { return E::get32(header.fields.sizeofcmds); }
+       void                    set_sizeofcmds(uint32_t value)  INLINE { E::set32(header.fields.sizeofcmds, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(header.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(header.fields.flags, value); }
+
+       uint32_t                reserved() const                                INLINE { return E::get32(header.fields.reserved); }
+       void                    set_reserved(uint32_t value)    INLINE { E::set32(header.fields.reserved, value); }
+
+    const macho_segment_command<P>* getSegment(const char *segname) const
+    {
+        const macho_load_command<P>* cmds = (macho_load_command<P>*)((uint8_t*)this + sizeof(macho_header<P>));
+        uint32_t cmd_count = this->ncmds();
+        const macho_load_command<P>* cmd = cmds;
+        for (uint32_t i = 0; i < cmd_count; ++i) {
+            if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                const macho_segment_command<P>* segcmd = (macho_segment_command<P>*)cmd;
+                if (0 == strncmp(segname, segcmd->segname(), 16)) {
+                    return segcmd;
+              }
+            }
+            cmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+        }
+        return NULL;
+    }
+
+    const macho_section<P>* getSection(const char *segname, const char *sectname) const
+    {
+       const  macho_segment_command<P>* segcmd = getSegment(segname);
+        if (!segcmd) return NULL;
+
+        const macho_section<P>* sectcmd = (macho_section<P>*)(segcmd+1);
+        uint32_t section_count = segcmd->nsects();
+        for (uint32_t j = 0; j < section_count; ++j) {
+            if (0 == ::strncmp(sectcmd[j].sectname(), sectname, 16)) {
+                return sectcmd+j;
+            }
+        }
+
+               if (strcmp(segname, "__DATA") == 0)
+                       return getSection("__DATA_CONST", sectname);
+        return NULL;
+    }
+
+    const macho_load_command<P>* getLoadCommand(int query) const
+    {
+        const macho_load_command<P>* cmds = (macho_load_command<P>*)((uint8_t*)this + sizeof(macho_header<P>));
+        uint32_t cmd_count = this->ncmds();
+        const macho_load_command<P>* cmd = cmds;
+        for (uint32_t i = 0; i < cmd_count; ++i) {
+            if ( cmd->cmd() == query ) {
+                return cmd;
+            }
+            cmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+        }
+        return NULL;
+    }
+
+       typedef typename P::E           E;
+private:
+       macho_header_content<P> header;
+};
+
+
+
+//
+// compressed dyld info load command
+//
+template <typename P>
+class macho_dyld_info_command {
+public:
+       uint32_t                cmd() const                                     INLINE { return E::get32(fields.cmd); }
+       void                    set_cmd(uint32_t value)         INLINE { E::set32(fields.cmd, value); }
+
+       uint32_t                cmdsize() const                         INLINE { return E::get32(fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)     INLINE { E::set32(fields.cmdsize, value); }
 
+       uint32_t                rebase_off() const                              INLINE { return E::get32(fields.rebase_off); }
+       void                    set_rebase_off(uint32_t value)  INLINE { E::set32(fields.rebase_off, value);  }
+       
+       uint32_t                rebase_size() const                             INLINE { return E::get32(fields.rebase_size); }
+       void                    set_rebase_size(uint32_t value) INLINE { E::set32(fields.rebase_size, value);  }
+       
+       uint32_t                bind_off() const                                INLINE { return E::get32(fields.bind_off); }
+       void                    set_bind_off(uint32_t value)    INLINE { E::set32(fields.bind_off, value);  }
+       
+       uint32_t                bind_size() const                               INLINE { return E::get32(fields.bind_size); }
+       void                    set_bind_size(uint32_t value)   INLINE { E::set32(fields.bind_size, value);  }
+       
+       uint32_t                weak_bind_off() const                           INLINE { return E::get32(fields.weak_bind_off); }
+       void                    set_weak_bind_off(uint32_t value)       INLINE { E::set32(fields.weak_bind_off, value);  }
+       
+       uint32_t                weak_bind_size() const                          INLINE { return E::get32(fields.weak_bind_size); }
+       void                    set_weak_bind_size(uint32_t value)      INLINE { E::set32(fields.weak_bind_size, value);  }
+       
+       uint32_t                lazy_bind_off() const                           INLINE { return E::get32(fields.lazy_bind_off); }
+       void                    set_lazy_bind_off(uint32_t value)       INLINE { E::set32(fields.lazy_bind_off, value);  }
+       
+       uint32_t                lazy_bind_size() const                          INLINE { return E::get32(fields.lazy_bind_size); }
+       void                    set_lazy_bind_size(uint32_t value)      INLINE { E::set32(fields.lazy_bind_size, value);  }
+       
+       uint32_t                export_off() const                              INLINE { return E::get32(fields.export_off); }
+       void                    set_export_off(uint32_t value)  INLINE { E::set32(fields.export_off, value);  }
+       
+       uint32_t                export_size() const                             INLINE { return E::get32(fields.export_size); }
+       void                    set_export_size(uint32_t value) INLINE { E::set32(fields.export_size, value);  }
+       
+       
+       typedef typename P::E           E;
+private:
+       dyld_info_command       fields;
+};
 
+#ifndef NO_ULEB 
+inline uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end) {
+       uint64_t result = 0;
+       int              bit = 0;
+       do {
+               if (p == end)
+                       throw "malformed uleb128 extends beyond trie";
+
+               uint64_t slice = *p & 0x7f;
+
+               if (bit >= 64 || slice << bit >> bit != slice)
+                       throw "uleb128 too big for 64-bits";
+               else {
+                       result |= (slice << bit);
+                       bit += 7;
+               }
+       } 
+       while (*p++ & 0x80);
+       return result;
+}
+       
+
+inline int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
+{
+       int64_t result = 0;
+       int bit = 0;
+       uint8_t byte;
+       do {
+               if (p == end)
+                       throw "malformed sleb128";
+               byte = *p++;
+               result |= (((int64_t)(byte & 0x7f)) << bit);
+               bit += 7;
+       } while (byte & 0x80);
+       // sign extend negative numbers
+       if ( (byte & 0x40) != 0 )
+               result |= (-1LL) << bit;
+       return result;
+}
+
+#endif
 
 
 #endif // __MACH_O_FILE_ABSTRACTION__