VirtualBox

Ignore:
Timestamp:
Oct 15, 2018 12:51:52 PM (6 years ago)
Author:
vboxsync
Message:

IPRT/ldr: Working on applying fixups to non-object Mach-O binaries. bugref:9232

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/ldr/ldrMachO.cpp

    r74760 r74844  
    8181 * Define RTLDRMODMACHO_STRICT to enabled strict checks in RTLDRMODMACHO. */
    8282#define RTLDRMODMACHO_STRICT 1
     83#define RTLDRMODMACHO_STRICT2
    8384
    8485/** @def RTLDRMODMACHO_ASSERT
     
    9899# define RTLDRMODMACHO_CHECK_RETURN(expr, rc)  AssertReturn(expr, rc)
    99100#else
    100 # define RTLDRMODMACHO_CHECK_RETURN(expr, rc)  do { if (!(expr)) { return (rc); } } while (0)
     101# define RTLDRMODMACHO_CHECK_RETURN(expr, rc)  do { if (RT_LIKELY(expr)) {/* likely */ } else return (rc); } while (0)
    101102#endif
    102103
     
    132133    uint32_t                cFixups;
    133134    /** The array of fixups. (lazy loaded) */
    134     macho_relocation_info_t *paFixups;
     135    macho_relocation_union_t *paFixups;
     136    /** Array of virgin data running parallel to paFixups */
     137    PRTUINT64U              pauFixupVirginData;
    135138    /** The file offset of the fixups for this section.
    136139     * This is -1 if the section doesn't have any fixups. */
     
    224227    /** Pointer to the loaded string table. */
    225228    char                   *pchStrings;
     229    /** Pointer to the dynamic symbol table command if present. */
     230    dysymtab_command_t     *pDySymTab;
     231    /** The indirect symbol table (size given by pDySymTab->nindirectsymb).
     232     * @remarks Host endian. */
     233    uint32_t               *paidxIndirectSymbols;
     234    /** Dynamic relocations, first pDySymTab->nextrel external relocs followed by
     235     *  pDySymTab->nlocrel local ones. */
     236    macho_relocation_union_t *paRelocations;
     237    /** Array of virgin data running parallel to paRelocations */
     238    PRTUINT64U              pauRelocationsVirginData;
    226239
    227240    /** The image UUID, all zeros if not found. */
     
    320333
    321334static int  kldrModMachOLoadObjSymTab(PRTLDRMODMACHO pThis);
    322 static int  kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups);
    323 static int  kldrModMachOMapVirginBits(PRTLDRMODMACHO pThis);
     335static int  kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_union_t **ppaFixups);
    324336
    325337static int  kldrModMachODoQuerySymbol32Bit(PRTLDRMODMACHO pThis, const macho_nlist_32_t *paSyms, uint32_t cSyms, const char *pchStrings,
     
    337349static int  kldrModMachOObjDoImports(PRTLDRMODMACHO pThis, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser);
    338350static int  kldrModMachOObjDoFixups(PRTLDRMODMACHO pThis, void *pvMapping, RTLDRADDR NewBaseAddress);
    339 static int  kldrModMachOFixupSectionGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect,
    340                                                  macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress);
    341 static int  kldrModMachOFixupSectionAMD64(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect,
    342                                           macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress);
     351static int  kldrModMachOApplyFixupsGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, size_t cbSectBits, RTLDRADDR uBitsRva,
     352                                                RTLDRADDR uBitsLinkAddr, const macho_relocation_union_t *paFixups,
     353                                                const uint32_t cFixups, PCRTUINT64U const pauVirginData,
     354                                                macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress);
     355static int  kldrModMachOApplyFixupsAMD64(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, size_t cbSectBits, RTLDRADDR uBitsRva,
     356                                         const macho_relocation_union_t *paFixups,
     357                                         const uint32_t cFixups, PCRTUINT64U const pauVirginData,
     358                                         macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress);
    343359
    344360static int  kldrModMachOMakeGOT(PRTLDRMODMACHO pThis, void *pvBits, RTLDRADDR NewBaseAddress);
     
    549565    pThis->cSymbols = 0;
    550566    pThis->pvaSymbols = NULL;
     567    pThis->pDySymTab = NULL;
     568    pThis->paRelocations = NULL;
     569    pThis->pauRelocationsVirginData = NULL;
     570    pThis->paidxIndirectSymbols = NULL;
    551571    pThis->offStrings = 0;
    552572    pThis->cchStrings = 0;
     
    621641        thread_command_t     *pThread;
    622642        symtab_command_t     *pSymTab;
     643        dysymtab_command_t   *pDySymTab;
    623644        uuid_command_t       *pUuid;
    624645    } u;
    625     const uint64_t cbFile = pRdr->pfnSize(pRdr) - offImage;
     646    const uint64_t cbFile         = pRdr->pfnSize(pRdr) - offImage;
     647    int const      fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
     648                                 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
    626649    uint32_t cSegments = 0;
    627650    uint32_t cSections = 0;
     
    632655    int cSegmentCommands = 0;
    633656    int cSymbolTabs = 0;
    634     int fConvertEndian = pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
    635                       || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE;
     657    uint32_t cSymbols = 0; /* Copy of u.pSymTab->nsyms. */
     658    uint32_t cDySymbolTabs = 0;
     659    bool fDySymbolTabWithRelocs = false;
     660    uint32_t cSectionsWithRelocs = 0;
    636661    uint8_t uEffFileType = *puEffFileType = pHdr->filetype;
    637662
     
    658683        cbLeft -= u.pLoadCmd->cmdsize;
    659684        pb += u.pLoadCmd->cmdsize;
     685
     686        /*
     687         * Segment macros for avoiding code duplication.
     688         */
     689        /* Validation code shared with the 64-bit variant. */
     690        #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \
     691            do { \
     692                bool fSkipSeg = !strcmp(pSrcSeg->segname, "__DWARF")   /* Note: Not for non-object files. */ \
     693                              || (   !strcmp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \
     694                                  && pSrcSeg->vmsize == 0)                   /* overlapping vmaddr and zero vmsize. */ \
     695                              || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \
     696                \
     697                /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \
     698                if (   uEffFileType == MH_DSYM \
     699                    && cSegmentCommands == 0 \
     700                    && pSrcSeg->segname[0] == '\0') \
     701                    *puEffFileType = uEffFileType = MH_OBJECT; \
     702                \
     703                RTLDRMODMACHO_CHECK_RETURN(   pSrcSeg->filesize == 0 \
     704                                          || (   pSrcSeg->fileoff <= cbFile \
     705                                              && (uint64_t)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \
     706                                          VERR_LDRMACHO_BAD_LOAD_COMMAND); \
     707                RTLDRMODMACHO_CHECK_RETURN(   pSrcSeg->filesize <= pSrcSeg->vmsize \
     708                                          || (fSkipSeg && !strcmp(pSrcSeg->segname, "__CTF") /* see above */), \
     709                                          VERR_LDRMACHO_BAD_LOAD_COMMAND); \
     710                RTLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \
     711                                          VERR_LDRMACHO_BAD_LOAD_COMMAND); \
     712                RTLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \
     713                                          VERR_LDRMACHO_BAD_LOAD_COMMAND); \
     714                RTLDRMODMACHO_CHECK_RETURN(   pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \
     715                                          <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \
     716                                          VERR_LDRMACHO_BAD_LOAD_COMMAND); \
     717                RTLDRMODMACHO_CHECK_RETURN(   uEffFileType != MH_OBJECT \
     718                                          || cSegmentCommands == 0 \
     719                                          || (   cSegmentCommands == 1 \
     720                                              && uEffFileType == MH_OBJECT \
     721                                              && pHdr->filetype == MH_DSYM \
     722                                              && fSkipSeg), \
     723                                          VERR_LDRMACHO_BAD_OBJECT_FILE); \
     724                cSegmentCommands++; \
     725                \
     726                /* Add the segment, if not object file. */ \
     727                if (!fSkipSeg && uEffFileType != MH_OBJECT) \
     728                { \
     729                    cbStringPool += RTStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \
     730                    cSegments++; \
     731                    if (cSegments == 1) /* The link address is set by the first segment. */  \
     732                        *pLinkAddress = pSrcSeg->vmaddr; \
     733                } \
     734            } while (0)
     735
     736
     737        /* Validation code shared with the 64-bit variant. */
     738        #define VALIDATE_AND_ADD_SECTION(a_cBits) \
     739            do { \
     740                int fFileBits; \
     741                \
     742                /* validate */ \
     743                if (uEffFileType != MH_OBJECT) \
     744                    RTLDRMODMACHO_CHECK_RETURN(!strcmp(pSect->segname, pSrcSeg->segname),\
     745                                              VERR_LDRMACHO_BAD_SECTION); \
     746                \
     747                switch (pSect->flags & SECTION_TYPE) \
     748                { \
     749                    case S_ZEROFILL: \
     750                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
     751                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
     752                        fFileBits = 0; \
     753                        break; \
     754                    case S_REGULAR: \
     755                    case S_CSTRING_LITERALS: \
     756                    case S_COALESCED: \
     757                    case S_4BYTE_LITERALS: \
     758                    case S_8BYTE_LITERALS: \
     759                    case S_16BYTE_LITERALS: \
     760                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
     761                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
     762                        fFileBits = 1; \
     763                        break; \
     764                    \
     765                    case S_SYMBOL_STUBS: \
     766                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
     767                        /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \
     768                        RTLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, VERR_LDRMACHO_BAD_SECTION); \
     769                        fFileBits = 1; \
     770                        break; \
     771                    \
     772                    case S_NON_LAZY_SYMBOL_POINTERS: \
     773                    case S_LAZY_SYMBOL_POINTERS: \
     774                    case S_LAZY_DYLIB_SYMBOL_POINTERS: \
     775                        /* (reserved 1 = is indirect symbol table index) */ \
     776                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
     777                        Log(("ldrMachO: Can't load because of section flags: %#x\n", pSect->flags & SECTION_TYPE)); \
     778                        *pfCanLoad = false; \
     779                        fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \
     780                        break; \
     781                    \
     782                    case S_MOD_INIT_FUNC_POINTERS: \
     783                        /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \
     784                        RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \
     785                                                  VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION); \
     786                        RT_FALL_THRU(); \
     787                    case S_MOD_TERM_FUNC_POINTERS: \
     788                        /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \
     789                        RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \
     790                                                  VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION); \
     791                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
     792                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
     793                        fFileBits = 1; \
     794                        break; /* ignored */ \
     795                    \
     796                    case S_LITERAL_POINTERS: \
     797                    case S_DTRACE_DOF: \
     798                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
     799                        RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
     800                        fFileBits = 1; \
     801                        break; \
     802                    \
     803                    case S_INTERPOSING: \
     804                    case S_GB_ZEROFILL: \
     805                        RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNSUPPORTED_SECTION); \
     806                    \
     807                    default: \
     808                        RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNKNOWN_SECTION); \
     809                } \
     810                RTLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~(  S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \
     811                                                             | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \
     812                                                             | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \
     813                                                             | S_ATTR_LOC_RELOC | SECTION_TYPE)), \
     814                                          VERR_LDRMACHO_BAD_SECTION); \
     815                RTLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \
     816                                          VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS); \
     817                \
     818                RTLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \
     819                                          VERR_LDRMACHO_BAD_SECTION); \
     820                RTLDRMODMACHO_CHECK_RETURN(   pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \
     821                                          || !strcmp(pSrcSeg->segname, "__CTF") /* see above */, \
     822                                          VERR_LDRMACHO_BAD_SECTION); \
     823                RTLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \
     824                                          VERR_LDRMACHO_BAD_SECTION); \
     825                /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \
     826                /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14.  Just adjust the alignment down. */ \
     827                if (   ((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr) \
     828                    && pSect->align == 4 \
     829                    && strcmp(pSect->sectname, "__unwind_info") == 0) \
     830                    pSect->align = 2; \
     831                RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr), \
     832                                          VERR_LDRMACHO_BAD_SECTION); \
     833                RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSrcSeg->vmaddr), \
     834                                          VERR_LDRMACHO_BAD_SECTION); \
     835                \
     836                /* Adjust the section offset before we check file offset. */ \
     837                offSect = (offSect + RT_BIT_64(pSect->align) - UINT64_C(1)) & ~(RT_BIT_64(pSect->align) - UINT64_C(1)); \
     838                if (pSect->addr) \
     839                { \
     840                    RTLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, VERR_LDRMACHO_BAD_SECTION); \
     841                    if (offSect < pSect->addr - pSrcSeg->vmaddr) \
     842                        offSect = pSect->addr - pSrcSeg->vmaddr; \
     843                } \
     844                \
     845                if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \
     846                    fFileBits = 0; \
     847                if (fFileBits) \
     848                { \
     849                    if (uEffFileType != MH_OBJECT) \
     850                    { \
     851                        RTLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \
     852                                                  VERR_LDRMACHO_NON_CONT_SEG_BITS); \
     853                        RTLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \
     854                                                  VERR_LDRMACHO_BAD_SECTION); \
     855                    } \
     856                    RTLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \
     857                                              VERR_LDRMACHO_BAD_SECTION); \
     858                    RTLDRMODMACHO_CHECK_RETURN((uint64_t)pSect->offset + pSect->size <= cbFile, \
     859                                              VERR_LDRMACHO_BAD_SECTION); \
     860                } \
     861                else \
     862                    RTLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, VERR_LDRMACHO_BAD_SECTION); \
     863                \
     864                if (!pSect->nreloc) \
     865                    RTLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \
     866                                              VERR_LDRMACHO_BAD_SECTION); \
     867                else \
     868                { \
     869                    RTLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \
     870                                              VERR_LDRMACHO_BAD_SECTION); \
     871                    RTLDRMODMACHO_CHECK_RETURN(     (uint64_t)pSect->reloff \
     872                                                 + (RTFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \
     873                                              <= cbFile, \
     874                                              VERR_LDRMACHO_BAD_SECTION); \
     875                    cSectionsWithRelocs++; \
     876                } \
     877                \
     878                /* Validate against file type (pointless?) and count the section, for object files add segment. */ \
     879                switch (uEffFileType) \
     880                { \
     881                    case MH_OBJECT: \
     882                        if (   !(pSect->flags & S_ATTR_DEBUG) \
     883                            && strcmp(pSect->segname, "__DWARF")) \
     884                        { \
     885                            cbStringPool += RTStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \
     886                            cbStringPool += RTStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \
     887                            cSegments++; \
     888                            if (cSegments == 1) /* The link address is set by the first segment. */  \
     889                                *pLinkAddress = pSect->addr; \
     890                        } \
     891                        RT_FALL_THRU(); \
     892                    case MH_EXECUTE: \
     893                    case MH_DYLIB: \
     894                    case MH_BUNDLE: \
     895                    case MH_DSYM: \
     896                    case MH_KEXT_BUNDLE: \
     897                        cSections++; \
     898                        break; \
     899                    default: \
     900                        RTLDRMODMACHO_FAILED_RETURN(VERR_INVALID_PARAMETER); \
     901                } \
     902                \
     903                /* Advance the section offset, since we're also aligning it. */ \
     904                offSect += pSect->size; \
     905            } while (0) /* VALIDATE_AND_ADD_SECTION */
    660906
    661907        /*
     
    675921                RTLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_32_t), VERR_LDRMACHO_BAD_LOAD_COMMAND);
    676922                RTLDRMODMACHO_CHECK_RETURN(   pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
    677                                           || pHdr->magic == IMAGE_MACHO32_SIGNATURE, VERR_LDRMACHO_BIT_MIX);
     923                                           || pHdr->magic == IMAGE_MACHO32_SIGNATURE, VERR_LDRMACHO_BIT_MIX);
    678924                if (fConvertEndian)
    679925                {
     
    688934                }
    689935
    690                 /* Validation code shared with the 64-bit variant. */
    691 #define VALIDATE_AND_ADD_SEGMENT(a_cBits) \
    692                 do { \
    693                     bool fSkipSeg = !strcmp(pSrcSeg->segname, "__DWARF")   /* Note: Not for non-object files. */ \
    694                                   || (   !strcmp(pSrcSeg->segname, "__CTF") /* Their CTF tool did/does weird things, */ \
    695                                       && pSrcSeg->vmsize == 0)                   /* overlapping vmaddr and zero vmsize. */ \
    696                                   || (cSectionsLeft > 0 && (pFirstSect->flags & S_ATTR_DEBUG)); \
    697                     \
    698                     /* MH_DSYM files for MH_OBJECT files must have MH_OBJECT segment translation. */ \
    699                     if (   uEffFileType == MH_DSYM \
    700                         && cSegmentCommands == 0 \
    701                         && pSrcSeg->segname[0] == '\0') \
    702                         *puEffFileType = uEffFileType = MH_OBJECT; \
    703                     \
    704                     RTLDRMODMACHO_CHECK_RETURN(   pSrcSeg->filesize == 0 \
    705                                               || (   pSrcSeg->fileoff <= cbFile \
    706                                                   && (uint64_t)pSrcSeg->fileoff + pSrcSeg->filesize <= cbFile), \
    707                                               VERR_LDRMACHO_BAD_LOAD_COMMAND); \
    708                     RTLDRMODMACHO_CHECK_RETURN(   pSrcSeg->filesize <= pSrcSeg->vmsize \
    709                                               || (fSkipSeg && !strcmp(pSrcSeg->segname, "__CTF") /* see above */), \
    710                                               VERR_LDRMACHO_BAD_LOAD_COMMAND); \
    711                     RTLDRMODMACHO_CHECK_RETURN(!(~pSrcSeg->maxprot & pSrcSeg->initprot), \
    712                                               VERR_LDRMACHO_BAD_LOAD_COMMAND); \
    713                     RTLDRMODMACHO_CHECK_RETURN(!(pSrcSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1)), \
    714                                               VERR_LDRMACHO_BAD_LOAD_COMMAND); \
    715                     RTLDRMODMACHO_CHECK_RETURN(   pSrcSeg->nsects * sizeof(section_##a_cBits##_t) \
    716                                               <= u.pLoadCmd->cmdsize - sizeof(segment_command_##a_cBits##_t), \
    717                                               VERR_LDRMACHO_BAD_LOAD_COMMAND); \
    718                     RTLDRMODMACHO_CHECK_RETURN(   uEffFileType != MH_OBJECT \
    719                                               || cSegmentCommands == 0 \
    720                                               || (   cSegmentCommands == 1 \
    721                                                   && uEffFileType == MH_OBJECT \
    722                                                   && pHdr->filetype == MH_DSYM \
    723                                                   && fSkipSeg), \
    724                                               VERR_LDRMACHO_BAD_OBJECT_FILE); \
    725                     cSegmentCommands++; \
    726                     \
    727                     /* Add the segment, if not object file. */ \
    728                     if (!fSkipSeg && uEffFileType != MH_OBJECT) \
    729                     { \
    730                         cbStringPool += RTStrNLen(&pSrcSeg->segname[0], sizeof(pSrcSeg->segname)) + 1; \
    731                         cSegments++; \
    732                         if (cSegments == 1) /* The link address is set by the first segment. */  \
    733                             *pLinkAddress = pSrcSeg->vmaddr; \
    734                     } \
    735                 } while (0)
    736 
    737936                VALIDATE_AND_ADD_SEGMENT(32);
     937
    738938
    739939                /*
     
    757957                    }
    758958
    759                     /* Validation code shared with the 64-bit variant. */
    760                     #define VALIDATE_AND_ADD_SECTION(a_cBits) \
    761                     do { \
    762                         int fFileBits; \
    763                         \
    764                         /* validate */ \
    765                         if (uEffFileType != MH_OBJECT) \
    766                             RTLDRMODMACHO_CHECK_RETURN(!strcmp(pSect->segname, pSrcSeg->segname),\
    767                                                       VERR_LDRMACHO_BAD_SECTION); \
    768                         \
    769                         switch (pSect->flags & SECTION_TYPE) \
    770                         { \
    771                             case S_ZEROFILL: \
    772                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
    773                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
    774                                 fFileBits = 0; \
    775                                 break; \
    776                             case S_REGULAR: \
    777                             case S_CSTRING_LITERALS: \
    778                             case S_COALESCED: \
    779                             case S_4BYTE_LITERALS: \
    780                             case S_8BYTE_LITERALS: \
    781                             case S_16BYTE_LITERALS: \
    782                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
    783                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
    784                                 fFileBits = 1; \
    785                                 break; \
    786                             \
    787                             case S_SYMBOL_STUBS: \
    788                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
    789                                 /* reserved2 == stub size. 0 has been seen (corecrypto.kext) */ \
    790                                 RTLDRMODMACHO_CHECK_RETURN(pSect->reserved2 < 64, VERR_LDRMACHO_BAD_SECTION); \
    791                                 fFileBits = 1; \
    792                                 break; \
    793                             \
    794                             case S_NON_LAZY_SYMBOL_POINTERS: \
    795                             case S_LAZY_SYMBOL_POINTERS: \
    796                             case S_LAZY_DYLIB_SYMBOL_POINTERS: \
    797                                 /* (reserved 1 = is indirect symbol table index) */ \
    798                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
    799                                 *pfCanLoad = false; \
    800                                 fFileBits = -1; /* __DATA.__got in the 64-bit mach_kernel has bits, any things without bits? */ \
    801                                 break; \
    802                             \
    803                             case S_MOD_INIT_FUNC_POINTERS: \
    804                                 /** @todo this requires a query API or flag... (e.g. C++ constructors) */ \
    805                                 RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \
    806                                                           VERR_LDRMACHO_UNSUPPORTED_INIT_SECTION); \
    807                                 RT_FALL_THRU(); \
    808                             case S_MOD_TERM_FUNC_POINTERS: \
    809                                 /** @todo this requires a query API or flag... (e.g. C++ destructors) */ \
    810                                 RTLDRMODMACHO_CHECK_RETURN(fOpenFlags & RTLDR_O_FOR_DEBUG, \
    811                                                           VERR_LDRMACHO_UNSUPPORTED_TERM_SECTION); \
    812                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
    813                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
    814                                 fFileBits = 1; \
    815                                 break; /* ignored */ \
    816                             \
    817                             case S_LITERAL_POINTERS: \
    818                             case S_DTRACE_DOF: \
    819                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved1, VERR_LDRMACHO_BAD_SECTION); \
    820                                 RTLDRMODMACHO_CHECK_RETURN(!pSect->reserved2, VERR_LDRMACHO_BAD_SECTION); \
    821                                 fFileBits = 1; \
    822                                 break; \
    823                             \
    824                             case S_INTERPOSING: \
    825                             case S_GB_ZEROFILL: \
    826                                 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNSUPPORTED_SECTION); \
    827                             \
    828                             default: \
    829                                 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_UNKNOWN_SECTION); \
    830                         } \
    831                         RTLDRMODMACHO_CHECK_RETURN(!(pSect->flags & ~(  S_ATTR_PURE_INSTRUCTIONS | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS \
    832                                                                      | S_ATTR_NO_DEAD_STRIP | S_ATTR_LIVE_SUPPORT | S_ATTR_SELF_MODIFYING_CODE \
    833                                                                      | S_ATTR_DEBUG | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_EXT_RELOC \
    834                                                                      | S_ATTR_LOC_RELOC | SECTION_TYPE)), \
    835                                                   VERR_LDRMACHO_BAD_SECTION); \
    836                         RTLDRMODMACHO_CHECK_RETURN((pSect->flags & S_ATTR_DEBUG) == (pFirstSect->flags & S_ATTR_DEBUG), \
    837                                                   VERR_LDRMACHO_MIXED_DEBUG_SECTION_FLAGS); \
    838                         \
    839                         RTLDRMODMACHO_CHECK_RETURN(pSect->addr - pSrcSeg->vmaddr <= pSrcSeg->vmsize, \
    840                                                   VERR_LDRMACHO_BAD_SECTION); \
    841                         RTLDRMODMACHO_CHECK_RETURN(   pSect->addr - pSrcSeg->vmaddr + pSect->size <= pSrcSeg->vmsize \
    842                                                   || !strcmp(pSrcSeg->segname, "__CTF") /* see above */, \
    843                                                   VERR_LDRMACHO_BAD_SECTION); \
    844                         RTLDRMODMACHO_CHECK_RETURN(pSect->align < 31, \
    845                                                   VERR_LDRMACHO_BAD_SECTION); \
    846                         /* Workaround for buggy ld64 (or as, llvm, ++) that produces a misaligned __TEXT.__unwind_info. */ \
    847                         /* Seen: pSect->align = 4, pSect->addr = 0x5ebe14.  Just adjust the alignment down. */ \
    848                         if (   ((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr) \
    849                             && pSect->align == 4 \
    850                             && strcmp(pSect->sectname, "__unwind_info") == 0) \
    851                             pSect->align = 2; \
    852                         RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSect->addr), \
    853                                                   VERR_LDRMACHO_BAD_SECTION); \
    854                         RTLDRMODMACHO_CHECK_RETURN(!((RT_BIT_32(pSect->align) - UINT32_C(1)) & pSrcSeg->vmaddr), \
    855                                                   VERR_LDRMACHO_BAD_SECTION); \
    856                         \
    857                         /* Adjust the section offset before we check file offset. */ \
    858                         offSect = (offSect + RT_BIT_64(pSect->align) - UINT64_C(1)) & ~(RT_BIT_64(pSect->align) - UINT64_C(1)); \
    859                         if (pSect->addr) \
    860                         { \
    861                             RTLDRMODMACHO_CHECK_RETURN(offSect <= pSect->addr - pSrcSeg->vmaddr, VERR_LDRMACHO_BAD_SECTION); \
    862                             if (offSect < pSect->addr - pSrcSeg->vmaddr) \
    863                                 offSect = pSect->addr - pSrcSeg->vmaddr; \
    864                         } \
    865                         \
    866                         if (fFileBits && pSect->offset == 0 && pSrcSeg->fileoff == 0 && pHdr->filetype == MH_DSYM) \
    867                             fFileBits = 0; \
    868                         if (fFileBits) \
    869                         { \
    870                             if (uEffFileType != MH_OBJECT) \
    871                             { \
    872                                 RTLDRMODMACHO_CHECK_RETURN(pSect->offset == pSrcSeg->fileoff + offSect, \
    873                                                           VERR_LDRMACHO_NON_CONT_SEG_BITS); \
    874                                 RTLDRMODMACHO_CHECK_RETURN(pSect->offset - pSrcSeg->fileoff <= pSrcSeg->filesize, \
    875                                                           VERR_LDRMACHO_BAD_SECTION); \
    876                             } \
    877                             RTLDRMODMACHO_CHECK_RETURN(pSect->offset <= cbFile, \
    878                                                       VERR_LDRMACHO_BAD_SECTION); \
    879                             RTLDRMODMACHO_CHECK_RETURN((uint64_t)pSect->offset + pSect->size <= cbFile, \
    880                                                       VERR_LDRMACHO_BAD_SECTION); \
    881                         } \
    882                         else \
    883                             RTLDRMODMACHO_CHECK_RETURN(pSect->offset == 0, VERR_LDRMACHO_BAD_SECTION); \
    884                         \
    885                         if (!pSect->nreloc) \
    886                             RTLDRMODMACHO_CHECK_RETURN(!pSect->reloff, \
    887                                                       VERR_LDRMACHO_BAD_SECTION); \
    888                         else \
    889                         { \
    890                             RTLDRMODMACHO_CHECK_RETURN(pSect->reloff <= cbFile, \
    891                                                       VERR_LDRMACHO_BAD_SECTION); \
    892                             RTLDRMODMACHO_CHECK_RETURN(     (uint64_t)pSect->reloff \
    893                                                          + (RTFOFF)pSect->nreloc * sizeof(macho_relocation_info_t) \
    894                                                       <= cbFile, \
    895                                                       VERR_LDRMACHO_BAD_SECTION); \
    896                         } \
    897                         \
    898                         /* Validate against file type (pointless?) and count the section, for object files add segment. */ \
    899                         switch (uEffFileType) \
    900                         { \
    901                             case MH_OBJECT: \
    902                                 if (   !(pSect->flags & S_ATTR_DEBUG) \
    903                                     && strcmp(pSect->segname, "__DWARF")) \
    904                                 { \
    905                                     cbStringPool += RTStrNLen(&pSect->segname[0], sizeof(pSect->segname)) + 1; \
    906                                     cbStringPool += RTStrNLen(&pSect->sectname[0], sizeof(pSect->sectname)) + 1; \
    907                                     cSegments++; \
    908                                     if (cSegments == 1) /* The link address is set by the first segment. */  \
    909                                         *pLinkAddress = pSect->addr; \
    910                                 } \
    911                                 RT_FALL_THRU(); \
    912                             case MH_EXECUTE: \
    913                             case MH_DYLIB: \
    914                             case MH_BUNDLE: \
    915                             case MH_DSYM: \
    916                             case MH_KEXT_BUNDLE: \
    917                                 cSections++; \
    918                                 break; \
    919                             default: \
    920                                 RTLDRMODMACHO_FAILED_RETURN(VERR_INVALID_PARAMETER); \
    921                         } \
    922                         \
    923                         /* Advance the section offset, since we're also aligning it. */ \
    924                         offSect += pSect->size; \
    925                     } while (0) /* VALIDATE_AND_ADD_SECTION */
    926 
    927959                    VALIDATE_AND_ADD_SECTION(32);
    928960
     
    944976                RTLDRMODMACHO_CHECK_RETURN(u.pLoadCmd->cmdsize >= sizeof(segment_command_64_t), VERR_LDRMACHO_BAD_LOAD_COMMAND);
    945977                RTLDRMODMACHO_CHECK_RETURN(   pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE
    946                                           || pHdr->magic == IMAGE_MACHO64_SIGNATURE, VERR_LDRMACHO_BIT_MIX);
     978                                           || pHdr->magic == IMAGE_MACHO64_SIGNATURE, VERR_LDRMACHO_BIT_MIX);
    947979                if (fConvertEndian)
    948980                {
     
    10091041                    RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_LOAD_COMMAND);
    10101042
    1011                 /* only one string in objects, please. */
     1043                /* Only one object table, please. */
    10121044                cSymbolTabs++;
    1013                 if (    uEffFileType == MH_OBJECT
    1014                     &&  cSymbolTabs != 1)
     1045                if (cSymbolTabs != 1)
    10151046                    RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_OBJECT_FILE);
     1047
     1048                cSymbols = u.pSymTab->nsyms;
    10161049                break;
    10171050            }
    10181051
    10191052            case LC_DYSYMTAB:
    1020                 /** @todo deal with this! */
     1053            {
     1054                if (pHdr->filetype == MH_OBJECT)
     1055                    RTLDRMODMACHO_FAILED_RETURN(RTErrInfoSet(pErrInfo, VERR_LDRMACHO_BAD_OBJECT_FILE,
     1056                                                             "Not expecting LC_DYSYMTAB in MH_OBJECT"));
     1057                if (fConvertEndian)
     1058                {
     1059                    u.pDySymTab->ilocalsym       = RT_BSWAP_U32(u.pDySymTab->ilocalsym);
     1060                    u.pDySymTab->nlocalsym       = RT_BSWAP_U32(u.pDySymTab->nlocalsym);
     1061                    u.pDySymTab->iextdefsym      = RT_BSWAP_U32(u.pDySymTab->iextdefsym);
     1062                    u.pDySymTab->nextdefsym      = RT_BSWAP_U32(u.pDySymTab->nextdefsym);
     1063                    u.pDySymTab->iundefsym       = RT_BSWAP_U32(u.pDySymTab->iundefsym);
     1064                    u.pDySymTab->nundefsym       = RT_BSWAP_U32(u.pDySymTab->nundefsym);
     1065                    u.pDySymTab->tocoff          = RT_BSWAP_U32(u.pDySymTab->tocoff);
     1066                    u.pDySymTab->ntoc            = RT_BSWAP_U32(u.pDySymTab->ntoc);
     1067                    u.pDySymTab->modtaboff       = RT_BSWAP_U32(u.pDySymTab->modtaboff);
     1068                    u.pDySymTab->nmodtab         = RT_BSWAP_U32(u.pDySymTab->nmodtab);
     1069                    u.pDySymTab->extrefsymoff    = RT_BSWAP_U32(u.pDySymTab->extrefsymoff);
     1070                    u.pDySymTab->nextrefsym      = RT_BSWAP_U32(u.pDySymTab->nextrefsym);
     1071                    u.pDySymTab->indirectsymboff = RT_BSWAP_U32(u.pDySymTab->indirectsymboff);
     1072                    u.pDySymTab->nindirectsymb   = RT_BSWAP_U32(u.pDySymTab->nindirectsymb);
     1073                    u.pDySymTab->extreloff       = RT_BSWAP_U32(u.pDySymTab->extreloff);
     1074                    u.pDySymTab->nextrel         = RT_BSWAP_U32(u.pDySymTab->nextrel);
     1075                    u.pDySymTab->locreloff       = RT_BSWAP_U32(u.pDySymTab->locreloff);
     1076                    u.pDySymTab->nlocrel         = RT_BSWAP_U32(u.pDySymTab->nlocrel);
     1077                }
     1078
     1079                /* verify */
     1080                RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->ilocalsym + u.pDySymTab->nlocalsym <= cSymbols,
     1081                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1082                                                         "ilocalsym=%#x + nlocalsym=%#x vs cSymbols=%#x",
     1083                                                         u.pDySymTab->ilocalsym, u.pDySymTab->nlocalsym, cSymbols));
     1084                RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->iextdefsym + u.pDySymTab->nextdefsym <= cSymbols,
     1085                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1086                                                         "iextdefsym=%#x + nextdefsym=%#x vs cSymbols=%#x",
     1087                                                         u.pDySymTab->iextdefsym, u.pDySymTab->nextdefsym, cSymbols));
     1088                RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->iundefsym + u.pDySymTab->nundefsym <= cSymbols,
     1089                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1090                                                         "iundefsym=%#x + nundefsym=%#x vs cSymbols=%#x",
     1091                                                         u.pDySymTab->iundefsym, u.pDySymTab->nundefsym, cSymbols));
     1092                RTLDRMODMACHO_CHECK_RETURN(   (uint64_t)u.pDySymTab->tocoff + u.pDySymTab->ntoc * sizeof(dylib_table_of_contents_t)
     1093                                           <= cbFile,
     1094                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1095                                                         "tocoff=%#x + ntoc=%#x vs cbFile=%#RX64",
     1096                                                         u.pDySymTab->tocoff, u.pDySymTab->ntoc, cbFile));
     1097                const uint32_t cbModTabEntry = pHdr->magic == IMAGE_MACHO32_SIGNATURE
     1098                                            || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
     1099                                             ? sizeof(dylib_module_32_t) : sizeof(dylib_module_64_t);
     1100                RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->modtaboff + u.pDySymTab->nmodtab * cbModTabEntry <= cbFile,
     1101                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1102                                                         "modtaboff=%#x + nmodtab=%#x cbModTabEntry=%#x vs cbFile=%#RX64",
     1103                                                         u.pDySymTab->modtaboff, u.pDySymTab->nmodtab, cbModTabEntry, cbFile));
     1104                RTLDRMODMACHO_CHECK_RETURN(   (uint64_t)u.pDySymTab->extrefsymoff + u.pDySymTab->nextrefsym * sizeof(dylib_reference_t)
     1105                                           <= cbFile,
     1106                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1107                                                         "extrefsymoff=%#x + nextrefsym=%#x vs cbFile=%#RX64",
     1108                                                         u.pDySymTab->extrefsymoff, u.pDySymTab->nextrefsym, cbFile));
     1109                RTLDRMODMACHO_CHECK_RETURN(   (uint64_t)u.pDySymTab->indirectsymboff + u.pDySymTab->nindirectsymb * sizeof(uint32_t)
     1110                                           <= cbFile,
     1111                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1112                                                         "indirectsymboff=%#x + nindirectsymb=%#x vs cbFile=%#RX64",
     1113                                                         u.pDySymTab->indirectsymboff, u.pDySymTab->nindirectsymb, cbFile));
     1114                RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->extreloff + u.pDySymTab->nextrel * sizeof(macho_relocation_info_t) <= cbFile,
     1115                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1116                                                         "extreloff=%#x + nextrel=%#x vs cbFile=%#RX64",
     1117                                                         u.pDySymTab->extreloff, u.pDySymTab->nextrel, cbFile));
     1118                RTLDRMODMACHO_CHECK_RETURN((uint64_t)u.pDySymTab->locreloff + u.pDySymTab->nlocrel * sizeof(macho_relocation_info_t) <= cbFile,
     1119                                           RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1120                                                         "locreloff=%#x + nlocrel=%#x vs cbFile=%#RX64",
     1121                                                         u.pDySymTab->locreloff, u.pDySymTab->nlocrel, cbFile));
     1122                cDySymbolTabs++;
     1123                fDySymbolTabWithRelocs |= (u.pDySymTab->nlocrel + u.pDySymTab->nextrel) != 0;
    10211124                break;
     1125            }
    10221126
    10231127            case LC_THREAD:
     
    10981202                    RTLDRMODMACHO_FAILED_RETURN(RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_UNSUPPORTED_LOAD_COMMAND,
    10991203                                                             "cmd=%#x", u.pLoadCmd->cmd));
     1204                Log(("ldrMachO: Can't load because of load command: %#x\n", u.pLoadCmd->cmd));
    11001205                *pfCanLoad = false;
    11011206                break;
     
    11281233        RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_LOAD_COMMAND);
    11291234
     1235    RTLDRMODMACHO_CHECK_RETURN(cDySymbolTabs <= 1,
     1236                               RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1237                                             "More than one LC_DYSYMTAB command: %u", cDySymbolTabs));
     1238    RTLDRMODMACHO_CHECK_RETURN(!fDySymbolTabWithRelocs || cSectionsWithRelocs == 0,
     1239                               RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1240                                             "Have relocations both in sections and LC_DYSYMTAB"));
     1241    if (!cSegments)
     1242        RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_OBJECT_FILE);
     1243
    11301244    switch (uEffFileType)
    11311245    {
    11321246        case MH_OBJECT:
    11331247        case MH_EXECUTE:
     1248            RTLDRMODMACHO_CHECK_RETURN(!fDySymbolTabWithRelocs,
     1249                                       RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1250                                                     "Did not expect relocations in LC_DYSYMTAB (file type %u)", uEffFileType));
     1251            break;
     1252
    11341253        case MH_DYLIB:
    11351254        case MH_BUNDLE:
     1255        case MH_KEXT_BUNDLE:
     1256            RTLDRMODMACHO_CHECK_RETURN(cDySymbolTabs > 0,
     1257                                       RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1258                                                     "No LC_DYSYMTAB command (file type %u)", uEffFileType));
     1259            RTLDRMODMACHO_CHECK_RETURN(fDySymbolTabWithRelocs || cSectionsWithRelocs == 0,
     1260                                       RTErrInfoSetF(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND,
     1261                                                     "Expected relocations in LC_DYSYMTAB (file type %u)", uEffFileType));
     1262            break;
     1263
    11361264        case MH_DSYM:
    1137         case MH_KEXT_BUNDLE:
    1138             if (!cSegments)
    1139                 RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_BAD_OBJECT_FILE);
    11401265            break;
    11411266    }
    11421267
     1268    /*
     1269     * Set return values and return.
     1270     */
    11431271    *pcSegments = cSegments;
    11441272    *pcSections = cSections;
     
    12011329                /* Adds a segment, used by the macro below and thus shared with the 64-bit segment variant. */
    12021330#define NEW_SEGMENT(a_cBits, a_achName1, a_fObjFile, a_achName2, a_SegAddr, a_cbSeg, a_fFileBits, a_offFile, a_cbFile) \
    1203                 do { \
    1204                     pDstSeg->SegInfo.pszName = pbStringPool; \
    1205                     pDstSeg->SegInfo.cchName = (uint32_t)RTStrNLen(a_achName1, sizeof(a_achName1)); \
    1206                     memcpy(pbStringPool, a_achName1, pDstSeg->SegInfo.cchName); \
    1207                     pbStringPool += pDstSeg->SegInfo.cchName; \
    1208                     if (a_fObjFile) \
    1209                     {   /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \
    1210                         size_t cchName2 = RTStrNLen(a_achName2, sizeof(a_achName2)); \
    1211                         *pbStringPool++ = '.'; \
    1212                         memcpy(pbStringPool, a_achName2, cchName2); \
    1213                         pbStringPool += cchName2; \
    1214                         pDstSeg->SegInfo.cchName += (uint32_t)cchName2; \
    1215                     } \
    1216                     *pbStringPool++ = '\0'; \
    1217                     pDstSeg->SegInfo.SelFlat = 0; \
    1218                     pDstSeg->SegInfo.Sel16bit = 0; \
    1219                     pDstSeg->SegInfo.fFlags = 0; \
    1220                     pDstSeg->SegInfo.fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC; /** @todo fixme! */ \
    1221                     pDstSeg->SegInfo.cb = (a_cbSeg); \
    1222                     pDstSeg->SegInfo.Alignment = 1; /* updated while parsing sections. */ \
    1223                     pDstSeg->SegInfo.LinkAddress = (a_SegAddr); \
    1224                     if (a_fFileBits) \
    1225                     { \
    1226                         pDstSeg->SegInfo.offFile = (RTFOFF)((a_offFile) + pThis->offImage); \
    1227                         pDstSeg->SegInfo.cbFile  = (RTFOFF)(a_cbFile); \
    1228                     } \
    1229                     else \
    1230                     { \
    1231                         pDstSeg->SegInfo.offFile = -1; \
    1232                         pDstSeg->SegInfo.cbFile  = -1; \
    1233                     } \
    1234                     pDstSeg->SegInfo.RVA = (a_SegAddr) - pThis->LinkAddress; \
    1235                     pDstSeg->SegInfo.cbMapped = 0; \
    1236                     \
    1237                     pDstSeg->iOrgSegNo = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \
    1238                     pDstSeg->cSections = 0; \
    1239                     pDstSeg->paSections = pSectExtra; \
    1240                 } while (0)
    1241 
    1242                 /* Closes the new segment - part of NEW_SEGMENT. */
     1331    do { \
     1332        pDstSeg->SegInfo.pszName = pbStringPool; \
     1333        pDstSeg->SegInfo.cchName = (uint32_t)RTStrNLen(a_achName1, sizeof(a_achName1)); \
     1334        memcpy(pbStringPool, a_achName1, pDstSeg->SegInfo.cchName); \
     1335        pbStringPool += pDstSeg->SegInfo.cchName; \
     1336        if (a_fObjFile) \
     1337        {   /* MH_OBJECT: Add '.sectname' - sections aren't sorted by segments. */ \
     1338            size_t cchName2 = RTStrNLen(a_achName2, sizeof(a_achName2)); \
     1339            *pbStringPool++ = '.'; \
     1340            memcpy(pbStringPool, a_achName2, cchName2); \
     1341            pbStringPool += cchName2; \
     1342            pDstSeg->SegInfo.cchName += (uint32_t)cchName2; \
     1343        } \
     1344        *pbStringPool++ = '\0'; \
     1345        pDstSeg->SegInfo.SelFlat = 0; \
     1346        pDstSeg->SegInfo.Sel16bit = 0; \
     1347        pDstSeg->SegInfo.fFlags = 0; \
     1348        pDstSeg->SegInfo.fProt = RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC; /** @todo fixme! */ \
     1349        pDstSeg->SegInfo.cb = (a_cbSeg); \
     1350        pDstSeg->SegInfo.Alignment = 1; /* updated while parsing sections. */ \
     1351        pDstSeg->SegInfo.LinkAddress = (a_SegAddr); \
     1352        if (a_fFileBits) \
     1353        { \
     1354            pDstSeg->SegInfo.offFile = (RTFOFF)((a_offFile) + pThis->offImage); \
     1355            pDstSeg->SegInfo.cbFile  = (RTFOFF)(a_cbFile); \
     1356        } \
     1357        else \
     1358        { \
     1359            pDstSeg->SegInfo.offFile = -1; \
     1360            pDstSeg->SegInfo.cbFile  = -1; \
     1361        } \
     1362        pDstSeg->SegInfo.RVA = (a_SegAddr) - pThis->LinkAddress; \
     1363        pDstSeg->SegInfo.cbMapped = 0; \
     1364        \
     1365        pDstSeg->iOrgSegNo = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \
     1366        pDstSeg->cSections = 0; \
     1367        pDstSeg->paSections = pSectExtra; \
     1368    } while (0)
     1369
     1370    /* Closes the new segment - part of NEW_SEGMENT. */
    12431371#define CLOSE_SEGMENT() \
    1244                 do { \
    1245                     pDstSeg->cSections = (uint32_t)(pSectExtra - pDstSeg->paSections); \
    1246                     pDstSeg++; \
    1247                 } while (0)
    1248 
    1249 
    1250                 /* Shared with the 64-bit variant. */
     1372    do { \
     1373        pDstSeg->cSections = (uint32_t)(pSectExtra - pDstSeg->paSections); \
     1374        pDstSeg++; \
     1375    } while (0)
     1376
     1377
     1378    /* Shared with the 64-bit variant. */
    12511379#define ADD_SEGMENT_AND_ITS_SECTIONS(a_cBits) \
    1252                 do { \
    1253                     bool fAddSegOuter = false; \
    1254                     \
    1255                     /* \
    1256                      * Check that the segment name is unique.  We couldn't do that \
    1257                      * in the preparsing stage. \
    1258                      */ \
    1259                     if (pThis->uEffFileType != MH_OBJECT) \
    1260                         for (pSegItr = &pThis->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \
    1261                             if (!strncmp(pSegItr->SegInfo.pszName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \
    1262                                 RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_DUPLICATE_SEGMENT_NAME); \
    1263                     \
    1264                     /* \
    1265                      * Create a new segment, unless we're supposed to skip this one. \
    1266                      */ \
    1267                     if (   pThis->uEffFileType != MH_OBJECT \
    1268                         && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \
    1269                         && strcmp(pSrcSeg->segname, "__DWARF") \
    1270                         && strcmp(pSrcSeg->segname, "__CTF") ) \
    1271                     { \
    1272                         NEW_SEGMENT(a_cBits, pSrcSeg->segname, false /*a_fObjFile*/, "" /*a_achName2*/, \
    1273                                     pSrcSeg->vmaddr, pSrcSeg->vmsize, \
    1274                                     pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \
    1275                         fAddSegOuter = true; \
    1276                     } \
    1277                     \
    1278                     /* \
    1279                      * Convert and parse the sections. \
    1280                      */ \
    1281                     while (cSectionsLeft-- > 0) \
    1282                     { \
    1283                         /* New segment if object file. */ \
    1284                         bool fAddSegInner = false; \
    1285                         if (   pThis->uEffFileType == MH_OBJECT \
    1286                             && !(pSect->flags & S_ATTR_DEBUG) \
    1287                             && strcmp(pSrcSeg->segname, "__DWARF") \
    1288                             && strcmp(pSrcSeg->segname, "__CTF") ) \
    1289                         { \
    1290                             Assert(!fAddSegOuter); \
    1291                             NEW_SEGMENT(a_cBits, pSect->segname, true /*a_fObjFile*/, pSect->sectname, \
    1292                                         pSect->addr, pSect->size, \
    1293                                         pSect->offset != 0, pSect->offset, pSect->size); \
    1294                             fAddSegInner = true; \
    1295                         } \
    1296                         \
    1297                         /* Section data extract. */ \
    1298                         pSectExtra->cb = pSect->size; \
    1299                         pSectExtra->RVA = pSect->addr - pDstSeg->SegInfo.LinkAddress; \
    1300                         pSectExtra->LinkAddress = pSect->addr; \
    1301                         if (pSect->offset) \
    1302                             pSectExtra->offFile = pSect->offset + pThis->offImage; \
    1303                         else \
    1304                             pSectExtra->offFile = -1; \
    1305                         pSectExtra->cFixups = pSect->nreloc; \
    1306                         pSectExtra->paFixups = NULL; \
    1307                         if (pSect->nreloc) \
    1308                             pSectExtra->offFixups = pSect->reloff + pThis->offImage; \
    1309                         else \
    1310                             pSectExtra->offFixups = -1; \
    1311                         pSectExtra->fFlags = pSect->flags; \
    1312                         pSectExtra->iSegment = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \
    1313                         pSectExtra->pvMachoSection = pSect; \
    1314                         \
    1315                         /* Update the segment alignment, if we're not skipping it. */ \
    1316                         if (   (fAddSegOuter || fAddSegInner) \
    1317                             && pDstSeg->SegInfo.Alignment < ((RTLDRADDR)1 << pSect->align)) \
    1318                             pDstSeg->SegInfo.Alignment = (RTLDRADDR)1 << pSect->align; \
    1319                         \
    1320                         /* Next section, and if object file next segment. */ \
    1321                         pSectExtra++; \
    1322                         pSect++; \
    1323                         if (fAddSegInner) \
    1324                             CLOSE_SEGMENT(); \
    1325                     } \
    1326                     \
    1327                     /* Close the segment and advance. */ \
    1328                     if (fAddSegOuter) \
    1329                         CLOSE_SEGMENT(); \
    1330                     \
    1331                     /* Take down 'execSeg' info for signing */ \
    1332                     if (fFirstSeg) \
    1333                     { \
    1334                         fFirstSeg = false; \
    1335                         pThis->offSeg0ForCodeSign = pSrcSeg->fileoff; \
    1336                         pThis->cbSeg0ForCodeSign  = pSrcSeg->filesize; /** @todo file or vm size? */ \
    1337                         pThis->fSeg0ForCodeSign   = pSrcSeg->flags; \
    1338                     } \
    1339             } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */
     1380    do { \
     1381        bool fAddSegOuter = false; \
     1382        \
     1383        /* \
     1384         * Check that the segment name is unique.  We couldn't do that \
     1385         * in the preparsing stage. \
     1386         */ \
     1387        if (pThis->uEffFileType != MH_OBJECT) \
     1388            for (pSegItr = &pThis->aSegments[0]; pSegItr != pDstSeg; pSegItr++) \
     1389                if (!strncmp(pSegItr->SegInfo.pszName, pSrcSeg->segname, sizeof(pSrcSeg->segname))) \
     1390                    RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_DUPLICATE_SEGMENT_NAME); \
     1391        \
     1392        /* \
     1393         * Create a new segment, unless we're supposed to skip this one. \
     1394         */ \
     1395        if (   pThis->uEffFileType != MH_OBJECT \
     1396            && (cSectionsLeft == 0 || !(pFirstSect->flags & S_ATTR_DEBUG)) \
     1397            && strcmp(pSrcSeg->segname, "__DWARF") \
     1398            && strcmp(pSrcSeg->segname, "__CTF") ) \
     1399        { \
     1400            NEW_SEGMENT(a_cBits, pSrcSeg->segname, false /*a_fObjFile*/, "" /*a_achName2*/, \
     1401                        pSrcSeg->vmaddr, pSrcSeg->vmsize, \
     1402                        pSrcSeg->filesize != 0, pSrcSeg->fileoff, pSrcSeg->filesize); \
     1403            fAddSegOuter = true; \
     1404        } \
     1405        \
     1406        /* \
     1407         * Convert and parse the sections. \
     1408         */ \
     1409        while (cSectionsLeft-- > 0) \
     1410        { \
     1411            /* New segment if object file. */ \
     1412            bool fAddSegInner = false; \
     1413            if (   pThis->uEffFileType == MH_OBJECT \
     1414                && !(pSect->flags & S_ATTR_DEBUG) \
     1415                && strcmp(pSrcSeg->segname, "__DWARF") \
     1416                && strcmp(pSrcSeg->segname, "__CTF") ) \
     1417            { \
     1418                Assert(!fAddSegOuter); \
     1419                NEW_SEGMENT(a_cBits, pSect->segname, true /*a_fObjFile*/, pSect->sectname, \
     1420                            pSect->addr, pSect->size, \
     1421                            pSect->offset != 0, pSect->offset, pSect->size); \
     1422                fAddSegInner = true; \
     1423            } \
     1424            \
     1425            /* Section data extract. */ \
     1426            pSectExtra->cb = pSect->size; \
     1427            pSectExtra->RVA = pSect->addr - pDstSeg->SegInfo.LinkAddress; \
     1428            pSectExtra->LinkAddress = pSect->addr; \
     1429            if (pSect->offset) \
     1430                pSectExtra->offFile = pSect->offset + pThis->offImage; \
     1431            else \
     1432                pSectExtra->offFile = -1; \
     1433            pSectExtra->cFixups = pSect->nreloc; \
     1434            pSectExtra->paFixups = NULL; \
     1435            pSectExtra->pauFixupVirginData = NULL; \
     1436            if (pSect->nreloc) \
     1437                pSectExtra->offFixups = pSect->reloff + pThis->offImage; \
     1438            else \
     1439                pSectExtra->offFixups = -1; \
     1440            pSectExtra->fFlags = pSect->flags; \
     1441            pSectExtra->iSegment = (uint32_t)(pDstSeg - &pThis->aSegments[0]); \
     1442            pSectExtra->pvMachoSection = pSect; \
     1443            \
     1444            /* Update the segment alignment, if we're not skipping it. */ \
     1445            if (   (fAddSegOuter || fAddSegInner) \
     1446                && pDstSeg->SegInfo.Alignment < ((RTLDRADDR)1 << pSect->align)) \
     1447                pDstSeg->SegInfo.Alignment = (RTLDRADDR)1 << pSect->align; \
     1448            \
     1449            /* Next section, and if object file next segment. */ \
     1450            pSectExtra++; \
     1451            pSect++; \
     1452            if (fAddSegInner) \
     1453                CLOSE_SEGMENT(); \
     1454        } \
     1455        \
     1456        /* Close the segment and advance. */ \
     1457        if (fAddSegOuter) \
     1458            CLOSE_SEGMENT(); \
     1459        \
     1460        /* Take down 'execSeg' info for signing */ \
     1461        if (fFirstSeg) \
     1462        { \
     1463            fFirstSeg = false; \
     1464            pThis->offSeg0ForCodeSign = pSrcSeg->fileoff; \
     1465            pThis->cbSeg0ForCodeSign  = pSrcSeg->filesize; /** @todo file or vm size? */ \
     1466            pThis->fSeg0ForCodeSign   = pSrcSeg->flags; \
     1467        } \
     1468    } while (0) /* ADD_SEGMENT_AND_ITS_SECTIONS */
    13401469
    13411470                ADD_SEGMENT_AND_ITS_SECTIONS(32);
     
    13591488                    case MH_OBJECT:
    13601489                    case MH_EXECUTE:
    1361                     case MH_DYLIB: /** @todo ??? */
    1362                     case MH_BUNDLE:  /** @todo ??? */
     1490                    case MH_DYLIB:
     1491                    case MH_BUNDLE:
    13631492                    case MH_DSYM:
    13641493                    case MH_KEXT_BUNDLE:
     
    13691498                        break;
    13701499                }
     1500                break;
     1501
     1502            case LC_DYSYMTAB:
     1503                pThis->pDySymTab = (dysymtab_command_t *)u.pb;
    13711504                break;
    13721505
     
    15391672            RTMemFree(pThis->aSegments[i].paSections[j].paFixups);
    15401673            pThis->aSegments[i].paSections[j].paFixups = NULL;
     1674            RTMemFree(pThis->aSegments[i].paSections[j].pauFixupVirginData);
     1675            pThis->aSegments[i].paSections[j].pauFixupVirginData = NULL;
    15411676        }
    15421677    }
     
    15481683    RTMemFree(pThis->pvaSymbols);
    15491684    pThis->pvaSymbols = NULL;
     1685    RTMemFree(pThis->paidxIndirectSymbols);
     1686    pThis->paidxIndirectSymbols = NULL;
     1687    RTMemFree(pThis->paRelocations);
     1688    pThis->paRelocations = NULL;
     1689    RTMemFree(pThis->pauRelocationsVirginData);
     1690    pThis->pauRelocationsVirginData = NULL;
    15501691    RTMemFree(pThis->PtrCodeSignature.pb);
    15511692    pThis->PtrCodeSignature.pb = NULL;
     
    26302771#endif
    26312772
     2773
     2774/**
     2775 * Worker for resolving an undefined 32-bit symbol table entry.
     2776 *
     2777 * @returns IPRT status code.
     2778 * @param   pThis           The Mach-O module interpreter instance.
     2779 * @param   pSym            The symbol table entry.
     2780 * @param   BaseAddress     The module base address.
     2781 * @param   pfnGetImport    The callback for resolving an imported symbol.
     2782 * @param   pvUser          User argument to the callback.
     2783 */
     2784DECLINLINE(int) rtdlrModMachOHandleUndefinedSymbol32(PRTLDRMODMACHO pThis, macho_nlist_32_t *pSym,
     2785                                                     RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
     2786{
     2787    RTLDRADDR Value = NIL_RTLDRADDR;
     2788
     2789    /** @todo Implement N_REF_TO_WEAK. */
     2790    RTLDRMODMACHO_CHECK_RETURN(!(pSym->n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO);
     2791
     2792    /* Get the symbol name. */
     2793    RTLDRMODMACHO_CHECK_RETURN((uint32_t)pSym->n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL);
     2794    const char *pszSymbol = &pThis->pchStrings[pSym->n_un.n_strx];
     2795    size_t      cchSymbol = strlen(pszSymbol);
     2796
     2797    /* Check for linker defined symbols relating to sections and segments. */
     2798    int rc;
     2799    if (   cchSymbol <= sizeof("section$end$") - 1
     2800        ||  *pszSymbol != 's'
     2801        || memchr(pszSymbol, '$', cchSymbol) == NULL)
     2802        rc = VERR_SYMBOL_NOT_FOUND;
     2803    else
     2804        rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value);
     2805
     2806    /* Ask the user for an address to the symbol. */
     2807    //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT;
     2808    /** @todo figure out a better way to deal with underscore prefixes. sigh. */
     2809    if (RT_FAILURE_NP(rc))
     2810        rc = pfnGetImport(&pThis->Core, NULL /*pszModule*/, pszSymbol + (pszSymbol[0] == '_'),
     2811                          UINT32_MAX, &Value/*, &fKind*/, pvUser);
     2812    if (RT_SUCCESS(rc))
     2813    { /* likely */ }
     2814    /* If weak reference we can continue, otherwise fail? */
     2815    else if (pSym->n_desc & N_WEAK_REF)
     2816        Value = 0;
     2817    else
     2818        return rc;
     2819
     2820    /* Update the symbol. */
     2821    pSym->n_value = (uint32_t)Value;
     2822    if (pSym->n_value == Value)
     2823        return VINF_SUCCESS;
     2824    return VERR_LDR_ADDRESS_OVERFLOW;
     2825}
     2826
     2827
     2828/**
     2829 * Worker for resolving an undefined 64-bit symbol table entry.
     2830 *
     2831 * @returns IPRT status code.
     2832 * @param   pThis           The Mach-O module interpreter instance.
     2833 * @param   pSym            The symbol table entry.
     2834 * @param   BaseAddress     The module base address.
     2835 * @param   pfnGetImport    The callback for resolving an imported symbol.
     2836 * @param   pvUser          User argument to the callback.
     2837 */
     2838DECLINLINE(int) rtdlrModMachOHandleUndefinedSymbol64(PRTLDRMODMACHO pThis, macho_nlist_64_t *pSym,
     2839                                                     RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
     2840{
     2841    RTLDRADDR Value = NIL_RTLDRADDR;
     2842
     2843    /** @todo Implement N_REF_TO_WEAK. */
     2844    RTLDRMODMACHO_CHECK_RETURN(!(pSym->n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO);
     2845
     2846    /* Get the symbol name. */
     2847    RTLDRMODMACHO_CHECK_RETURN((uint32_t)pSym->n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL);
     2848    const char *pszSymbol = &pThis->pchStrings[pSym->n_un.n_strx];
     2849    size_t      cchSymbol = strlen(pszSymbol);
     2850
     2851    /* Check for linker defined symbols relating to sections and segments. */
     2852    int rc;
     2853    if (   cchSymbol <= sizeof("section$end$") - 1
     2854        ||  *pszSymbol != 's'
     2855        || memchr(pszSymbol, '$', cchSymbol) == NULL)
     2856        rc = VERR_SYMBOL_NOT_FOUND;
     2857    else
     2858        rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value);
     2859
     2860    /* Ask the user for an address to the symbol. */
     2861    //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT;
     2862    /** @todo figure out a better way to deal with underscore prefixes. sigh. */
     2863    if (RT_FAILURE_NP(rc))
     2864        rc = pfnGetImport(&pThis->Core, NULL /*pszModule*/, pszSymbol + (pszSymbol[0] == '_'),
     2865                          UINT32_MAX, &Value/*, &fKind*/, pvUser);
     2866    if (RT_SUCCESS(rc))
     2867    { /* likely */ }
     2868    /* If weak reference we can continue, otherwise fail? */
     2869    else if (pSym->n_desc & N_WEAK_REF)
     2870        Value = 0;
     2871    else
     2872        return rc;
     2873
     2874    /* Update the symbol. */
     2875    pSym->n_value = (uint64_t)Value;
     2876    if (pSym->n_value == Value)
     2877        return VINF_SUCCESS;
     2878    return VERR_LDR_ADDRESS_OVERFLOW;
     2879}
     2880
     2881
    26322882/**
    26332883 * MH_OBJECT: Resolves undefined symbols (imports).
     
    26412891static int  kldrModMachOObjDoImports(PRTLDRMODMACHO pThis, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
    26422892{
    2643     const uint32_t cSyms = pThis->cSymbols;
    2644     uint32_t iSym;
    2645 
    2646     /*
    2647      * Ensure that we've got the symbol table and section fixups handy.
     2893
     2894    /*
     2895     * Ensure that we've got the symbol table.
    26482896     */
    26492897    int rc = kldrModMachOLoadObjSymTab(pThis);
     
    26552903     * We currently ignore REFERENCE_TYPE.
    26562904     */
     2905    const uint32_t cSyms = pThis->cSymbols;
    26572906    if (    pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE
    26582907        ||  pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
    26592908    {
    26602909        macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pThis->pvaSymbols;
    2661         for (iSym = 0; iSym < cSyms; iSym++)
     2910        for (uint32_t iSym = 0; iSym < cSyms; iSym++)
    26622911        {
    26632912            /* skip stabs */
     
    26672916            if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
    26682917            {
    2669                 const char *pszSymbol;
    2670                 size_t cchSymbol;
    2671                 //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT;
    2672                 RTLDRADDR Value = NIL_RTLDRADDR;
    2673 
    2674                 /** @todo Implement N_REF_TO_WEAK. */
    2675                 RTLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO);
    2676 
    2677                 /* Get the symbol name. */
    2678                 RTLDRMODMACHO_CHECK_RETURN((uint32_t)paSyms[iSym].n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL);
    2679                 pszSymbol = &pThis->pchStrings[paSyms[iSym].n_un.n_strx];
    2680                 cchSymbol = strlen(pszSymbol);
    2681 
    2682                 /* Check for linker defined symbols relating to sections and segments. */
    2683                 if (   cchSymbol > sizeof("section$end$") - 1
    2684                     && *pszSymbol == 's'
    2685                     && memchr(pszSymbol, '$', cchSymbol))
    2686                     rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value);
    2687                 else
    2688                     rc = VERR_SYMBOL_NOT_FOUND;
    2689 
    2690                 /* Ask the user for an address to the symbol. */
    2691                 /** @todo figure out a better way to deal with underscore prefixes. sigh. */
    2692                 if (RT_FAILURE_NP(rc))
    2693                     rc = pfnGetImport(&pThis->Core, NULL /*pszModule*/, pszSymbol + (pszSymbol[0] == '_'),
    2694                                       UINT32_MAX, &Value/*, &fKind*/, pvUser);
     2918                rc = rtdlrModMachOHandleUndefinedSymbol32(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser);
    26952919                if (RT_FAILURE(rc))
    2696                 {
    2697                     /* weak reference? */
    2698                     if (!(paSyms[iSym].n_desc & N_WEAK_REF))
    2699                         break;
    2700                     Value = 0;
    2701                 }
    2702 
    2703                 /* Update the symbol. */
    2704                 paSyms[iSym].n_value = (uint32_t)Value;
    2705                 if (paSyms[iSym].n_value != Value)
    2706                 {
    2707                     rc = VERR_LDR_ADDRESS_OVERFLOW;
    27082920                    break;
    2709                 }
    27102921            }
    27112922            else if (paSyms[iSym].n_desc & N_WEAK_DEF)
     
    27202931        /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
    27212932        macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pThis->pvaSymbols;
    2722         for (iSym = 0; iSym < cSyms; iSym++)
     2933        for (uint32_t iSym = 0; iSym < cSyms; iSym++)
    27232934        {
    27242935            /* skip stabs */
     
    27282939            if ((paSyms[iSym].n_type & MACHO_N_TYPE) == MACHO_N_UNDF)
    27292940            {
    2730                 const char *pszSymbol;
    2731                 size_t cchSymbol;
    2732                 //uint32_t fKind = RTLDRSYMKIND_REQ_FLAT;
    2733                 RTLDRADDR Value = NIL_RTLDRADDR;
    2734 
    2735                 /** @todo Implement N_REF_TO_WEAK. */
    2736                 RTLDRMODMACHO_CHECK_RETURN(!(paSyms[iSym].n_desc & N_REF_TO_WEAK), VERR_LDRMACHO_TODO);
    2737 
    2738                  /* Get the symbol name. */
    2739                 RTLDRMODMACHO_CHECK_RETURN(paSyms[iSym].n_un.n_strx < pThis->cchStrings, VERR_LDRMACHO_BAD_SYMBOL);
    2740                 pszSymbol = &pThis->pchStrings[paSyms[iSym].n_un.n_strx];
    2741                 cchSymbol = strlen(pszSymbol);
    2742 
    2743                 /* Check for linker defined symbols relating to sections and segments. */
    2744                 if (   cchSymbol > sizeof("section$end$") - 1
    2745                     && *pszSymbol == 's'
    2746                     && memchr(pszSymbol, '$', cchSymbol))
    2747                     rc = kldrModMachOQueryLinkerSymbol(pThis, pszSymbol, cchSymbol, BaseAddress, &Value);
    2748                 else
    2749                     rc = VERR_SYMBOL_NOT_FOUND;
    2750 
    2751                 /* Ask the user for an address to the symbol. */
    2752                 /** @todo figure out a better way to deal with underscore prefixes. sigh. */
    2753                 if (RT_FAILURE_NP(rc))
    2754                     rc = pfnGetImport(&pThis->Core, NULL, pszSymbol + (*pszSymbol == '_'),
    2755                                       UINT32_MAX, &Value, /*&fKind,*/ pvUser);
     2941                rc = rtdlrModMachOHandleUndefinedSymbol64(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser);
    27562942                if (RT_FAILURE(rc))
    2757                 {
    2758                     /* weak reference? */
    2759                     if (!(paSyms[iSym].n_desc & N_WEAK_REF))
    2760                         break;
    2761                     Value = 0;
    2762                 }
    2763 
    2764                 /* Update the symbol. */
    2765                 paSyms[iSym].n_value = Value;
    2766                 if (paSyms[iSym].n_value != Value)
    2767                 {
    2768                     rc = VERR_LDR_ADDRESS_OVERFLOW;
    27692943                    break;
    2770                 }
    27712944            }
    27722945            else if (paSyms[iSym].n_desc & N_WEAK_DEF)
     
    27832956
    27842957/**
    2785  * MH_OBJECT: Applies base relocations to a (unprotected) image mapping.
     2958 * Dylib: Resolves undefined symbols (imports).
     2959 *
     2960 * This is conceptually identically to kldrModMachOObjDoImports, only
     2961 * LC_DYSYMTAB helps us avoid working over the whole symbol table.
     2962 *
     2963 * @returns IPRT status code.
     2964 * @param   pThis           The Mach-O module interpreter instance.
     2965 * @param   BaseAddress     The module base address.
     2966 * @param   pfnGetImport    The callback for resolving an imported symbol.
     2967 * @param   pvUser          User argument to the callback.
     2968 */
     2969static int  kldrModMachODylibDoImports(PRTLDRMODMACHO pThis, RTLDRADDR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
     2970{
     2971    /*
     2972     * There must be a LC_DYSYMTAB.
     2973     * We might be lucky, though, and not have any imports.
     2974     */
     2975    dysymtab_command_t const *pDySymTab = pThis->pDySymTab;
     2976    AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2);
     2977    if (pDySymTab->nundefsym == 0)
     2978        return VINF_SUCCESS;
     2979
     2980    /*
     2981     * Ensure that we've got the symbol table.
     2982     */
     2983    int rc = kldrModMachOLoadObjSymTab(pThis);
     2984    if (RT_FAILURE(rc))
     2985        return rc;
     2986
     2987    /*
     2988     * Iterate the give symbol table section containing undefined symbols and resolve them.
     2989     */
     2990    uint32_t const cSyms = pDySymTab->iundefsym + pDySymTab->nundefsym;
     2991    if (   pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE
     2992        || pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
     2993    {
     2994        macho_nlist_32_t *paSyms = (macho_nlist_32_t *)pThis->pvaSymbols;
     2995        for (uint32_t iSym = pDySymTab->iundefsym; RT_SUCCESS(rc) && iSym < cSyms; iSym++)
     2996        {
     2997            AssertContinue((paSyms[iSym].n_type & (MACHO_N_TYPE | MACHO_N_STAB)) == MACHO_N_UNDF);
     2998            rc = rtdlrModMachOHandleUndefinedSymbol32(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser);
     2999        }
     3000    }
     3001    else
     3002    {
     3003        /* (Identical to the 32-bit code, just different paSym type. (and n_strx is unsigned)) */
     3004        macho_nlist_64_t *paSyms = (macho_nlist_64_t *)pThis->pvaSymbols;
     3005        for (uint32_t iSym = pDySymTab->iundefsym; RT_SUCCESS(rc) && iSym < cSyms; iSym++)
     3006        {
     3007            AssertContinue((paSyms[iSym].n_type & (MACHO_N_TYPE | MACHO_N_STAB)) == MACHO_N_UNDF);
     3008            rc = rtdlrModMachOHandleUndefinedSymbol64(pThis, &paSyms[iSym], BaseAddress, pfnGetImport, pvUser);
     3009        }
     3010    }
     3011
     3012    return rc;
     3013}
     3014
     3015
     3016static int kldrModMachODylibDoIndirectSymbols(PRTLDRMODMACHO pThis, void *pvBits, RTLDRADDR offDelta)
     3017{
     3018    /*
     3019     * There must be a LC_DYSYMTAB.
     3020     * We might be lucky, though, and not have any imports.
     3021     */
     3022    dysymtab_command_t const *pDySymTab = pThis->pDySymTab;
     3023    AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2);
     3024    uint32_t const cIndirectSymbols = pDySymTab->nindirectsymb;
     3025    if (cIndirectSymbols == 0)
     3026        return VINF_SUCCESS;
     3027
     3028    /*
     3029     * Ensure that we've got the symbol table.
     3030     */
     3031    int rc = kldrModMachOLoadObjSymTab(pThis);
     3032    if (RT_FAILURE(rc))
     3033        return rc;
     3034
     3035    /*
     3036     * Load the indirect symbol table.
     3037     */
     3038    if (!pThis->paidxIndirectSymbols)
     3039    {
     3040        uint32_t *paidxIndirectSymbols = (uint32_t *)RTMemAlloc(cIndirectSymbols * sizeof(uint32_t));
     3041        if (!paidxIndirectSymbols)
     3042            return VERR_NO_MEMORY;
     3043        rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, paidxIndirectSymbols, cIndirectSymbols * sizeof(uint32_t),
     3044                                          pDySymTab->indirectsymboff);
     3045        if (RT_SUCCESS(rc))
     3046            pThis->paidxIndirectSymbols = paidxIndirectSymbols;
     3047        else
     3048        {
     3049            RTMemFree(paidxIndirectSymbols);
     3050            return rc;
     3051        }
     3052
     3053        /* Byte swap if needed. */
     3054        if (   pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
     3055            || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
     3056            for (uint32_t i = 0; i < cIndirectSymbols; i++)
     3057                paidxIndirectSymbols[i] = RT_BSWAP_U32(paidxIndirectSymbols[i]);
     3058    }
     3059    uint32_t const *paidxIndirectSymbols = pThis->paidxIndirectSymbols;
     3060
     3061    /*
     3062     * Process the sections using indirect symbols.
     3063     */
     3064    const uint32_t cSymbols = pThis->cSymbols;
     3065    if (   pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE
     3066        || pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE)
     3067    {
     3068        macho_nlist_32_t const *paSymbols = (macho_nlist_32_t *)pThis->pvaSymbols;
     3069        for (uint32_t iSect = 0; iSect < pThis->cSections; iSect++)
     3070        {
     3071            section_32_t const *pSect = (section_32_t const *)pThis->paSections[iSect].pvMachoSection;
     3072            switch (pSect->flags & SECTION_TYPE)
     3073            {
     3074                case S_NON_LAZY_SYMBOL_POINTERS:
     3075                case S_LAZY_SYMBOL_POINTERS:
     3076                {
     3077                    uint32_t       *pauDstPtrs = (uint32_t *)((uintptr_t)pvBits + pThis->paSections[iSect].RVA);
     3078                    uint32_t  const cDstPtrs   = pThis->paSections[iSect].cb / sizeof(pauDstPtrs[0]);
     3079                    uint32_t  const idxSrcSkip = pSect->reserved1;
     3080                    if ((uint64_t)idxSrcSkip + cDstPtrs > cIndirectSymbols)
     3081                        return VERR_BAD_EXE_FORMAT; /// @todo better error code.
     3082
     3083                    for (uint32_t i = 0; i < cDstPtrs; i++)
     3084                    {
     3085                        uint32_t const idxSym = paidxIndirectSymbols[idxSrcSkip + i];
     3086                        if (idxSym == INDIRECT_SYMBOL_LOCAL)
     3087                            pauDstPtrs[i] += (int32_t)offDelta;
     3088                        else if (idxSym != INDIRECT_SYMBOL_ABS)
     3089                        {
     3090                            AssertMsgReturn(idxSym < cSymbols,
     3091                                            ("i=%#x idxSym=%#x cSymbols=%#x iSect=%#x\n", i, idxSym, cSymbols, iSect),
     3092                                            VERR_BAD_EXE_FORMAT); /// @todo better error code.
     3093                            pauDstPtrs[i] = paSymbols[idxSym].n_value;
     3094                        }
     3095                    }
     3096                    break;
     3097                }
     3098
     3099                case S_SYMBOL_STUBS:
     3100                    if (   pThis->Core.enmArch == RTLDRARCH_X86_32
     3101                        && (pSect->flags & S_ATTR_SELF_MODIFYING_CODE)
     3102                        && pSect->reserved2 == 5)
     3103                    {
     3104                        uint32_t        uDstRva    = pThis->paSections[iSect].RVA;
     3105                        uint8_t        *pbDst      = (uint8_t *)((uintptr_t)pvBits + uDstRva);
     3106                        uint32_t  const cDstPtrs   = pThis->paSections[iSect].cb / 5;
     3107                        uint32_t  const idxSrcSkip = pSect->reserved1;
     3108                        if ((uint64_t)idxSrcSkip + cDstPtrs > cIndirectSymbols)
     3109                            return VERR_BAD_EXE_FORMAT; /// @todo better error code.
     3110
     3111                        for (uint32_t i = 0; i < cDstPtrs; i++, uDstRva += 5, pbDst += 5)
     3112                        {
     3113                            uint32_t const idxSym = paidxIndirectSymbols[idxSrcSkip + i];
     3114                            if (idxSym != INDIRECT_SYMBOL_ABS && idxSym != INDIRECT_SYMBOL_LOCAL)
     3115                            {
     3116                                AssertMsgReturn(idxSym < cSymbols,
     3117                                                ("i=%#x idxSym=%#x cSymbols=%#x iSect=%#x\n", i, idxSym, cSymbols, iSect),
     3118                                                VERR_BAD_EXE_FORMAT); /// @todo better error code.
     3119                                pbDst[0] = 0xeb; /* JMP rel32 */
     3120                                uint32_t offDisp = paSymbols[idxSym].n_value - (uint32_t)uDstRva - 5;
     3121                                pbDst[1] = (uint8_t)offDisp;
     3122                                offDisp >>= 8;
     3123                                pbDst[2] = (uint8_t)offDisp;
     3124                                offDisp >>= 8;
     3125                                pbDst[3] = (uint8_t)offDisp;
     3126                                offDisp >>= 8;
     3127                                pbDst[4] = (uint8_t)offDisp;
     3128                            }
     3129                        }
     3130                        break;
     3131                    }
     3132                    break;
     3133            }
     3134
     3135        }
     3136    }
     3137    else
     3138    {
     3139        /* Exact like for 32-bit, except for 64-bit symbol table, 64-bit addresses and no need to process S_SYMBOL_STUBS. */
     3140        macho_nlist_64_t const *paSymbols = (macho_nlist_64_t *)pThis->pvaSymbols;
     3141        for (uint32_t iSect = 0; iSect < pThis->cSections; iSect++)
     3142        {
     3143            section_64_t const *pSect = (section_64_t const *)pThis->paSections[iSect].pvMachoSection;
     3144            switch (pSect->flags & SECTION_TYPE)
     3145            {
     3146                case S_NON_LAZY_SYMBOL_POINTERS:
     3147                case S_LAZY_SYMBOL_POINTERS:
     3148                {
     3149                    uint64_t       *pauDstPtrs = (uint64_t *)((uintptr_t)pvBits + pThis->paSections[iSect].RVA);
     3150                    uint32_t  const cDstPtrs   = pThis->paSections[iSect].cb / sizeof(pauDstPtrs[0]);
     3151                    uint32_t  const idxSrcSkip = pSect->reserved1;
     3152                    if ((uint64_t)idxSrcSkip + cDstPtrs > cIndirectSymbols)
     3153                        return VERR_BAD_EXE_FORMAT; /// @todo better error code.
     3154
     3155                    for (uint32_t i = 0; i < cDstPtrs; i++)
     3156                    {
     3157                        uint32_t const idxSym = paidxIndirectSymbols[idxSrcSkip + i];
     3158                        if (idxSym == INDIRECT_SYMBOL_LOCAL)
     3159                            pauDstPtrs[i] += (int64_t)offDelta;
     3160                        else if (idxSym != INDIRECT_SYMBOL_ABS)
     3161                        {
     3162                            AssertMsgReturn(idxSym < cSymbols,
     3163                                            ("i=%#x idxSym=%#x cSymbols=%#x iSect=%#x\n", i, idxSym, cSymbols, iSect),
     3164                                            VERR_BAD_EXE_FORMAT); /// @todo better error code.
     3165                            pauDstPtrs[i] = paSymbols[idxSym].n_value;
     3166                        }
     3167                    }
     3168                    break;
     3169                }
     3170
     3171                case S_SYMBOL_STUBS:
     3172                    if (   pThis->Core.enmArch == RTLDRARCH_X86_32
     3173                        && (pSect->flags & S_ATTR_SELF_MODIFYING_CODE)
     3174                        && pSect->reserved2 == 5)
     3175                        return VERR_BAD_EXE_FORMAT;
     3176                    break;
     3177            }
     3178        }
     3179    }
     3180
     3181    return VINF_SUCCESS;
     3182}
     3183
     3184
     3185/**
     3186 * MH_OBJECT: Applies base relocations to an (unprotected) image mapping.
    27863187 *
    27873188 * @returns IPRT status code.
     
    27933194{
    27943195    /*
    2795      * Ensure that we've got the symbol table and section fixups handy.
     3196     * Ensure that we've got the symbol table.
    27963197     */
    27973198    int rc = kldrModMachOLoadObjSymTab(pThis);
     
    28133214            if (!pSect->cFixups)
    28143215                continue;
    2815 
    2816             /* lazy load (and endian convert) the fixups. */
    2817             if (!pSect->paFixups)
    2818             {
    2819                 rc = kldrModMachOLoadFixups(pThis, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
    2820                 if (RT_FAILURE(rc))
    2821                     break;
    2822             }
     3216            AssertReturn(pSect->paFixups, VERR_INTERNAL_ERROR_4);
     3217            AssertReturn(pSect->pauFixupVirginData, VERR_INTERNAL_ERROR_4);
    28233218
    28243219            /*
     
    28273222            uint8_t *pbSectBits = (uint8_t *)pvMapping + (uintptr_t)pSect->RVA;
    28283223            if (pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
    2829                 rc = kldrModMachOFixupSectionGeneric32Bit(pThis, pbSectBits, pSect,
    2830                                                           (macho_nlist_32_t *)pThis->pvaSymbols,
    2831                                                           pThis->cSymbols, NewBaseAddress);
     3224                rc = kldrModMachOApplyFixupsGeneric32Bit(pThis, pbSectBits, (size_t)pSect->cb, pSect->RVA, pSect->LinkAddress,
     3225                                                         pSect->paFixups, pSect->cFixups, pSect->pauFixupVirginData,
     3226                                                         (macho_nlist_32_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress);
    28323227            else if (   pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE
    28333228                     && pThis->Hdr.cputype == CPU_TYPE_X86_64)
    2834                 rc = kldrModMachOFixupSectionAMD64(pThis, pbSectBits, pSect,
    2835                                                    (macho_nlist_64_t *)pThis->pvaSymbols,
    2836                                                   pThis->cSymbols, NewBaseAddress);
     3229                rc = kldrModMachOApplyFixupsAMD64(pThis, pbSectBits, (size_t)pSect->cb, pSect->RVA,
     3230                                                  pSect->paFixups, pSect->cFixups, pSect->pauFixupVirginData,
     3231                                                  (macho_nlist_64_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress);
    28373232            else
    28383233                RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_TODO);
     
    28433238
    28443239    return rc;
     3240}
     3241
     3242
     3243/**
     3244 * Dylib: Applies base relocations to an (unprotected) image mapping.
     3245 *
     3246 * @returns IPRT status code.
     3247 * @param   pThis           The Mach-O module interpreter instance.
     3248 * @param   pvMapping       The mapping to fixup.
     3249 * @param   NewBaseAddress  The address to fixup the mapping to.
     3250 */
     3251static int  kldrModMachODylibDoFixups(PRTLDRMODMACHO pThis, void *pvMapping, RTLDRADDR NewBaseAddress)
     3252{
     3253    /*
     3254     * There must be a LC_DYSYMTAB.
     3255     * We might be lucky, though, and not have any imports.
     3256     */
     3257    dysymtab_command_t const *pDySymTab = pThis->pDySymTab;
     3258    AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2);
     3259    uint32_t cRelocations = pDySymTab->nlocrel + pDySymTab->nextrel;
     3260    if (cRelocations == 0)
     3261        return VINF_SUCCESS;
     3262
     3263    /*
     3264     * Ensure that we've got the symbol table.
     3265     */
     3266    int rc = kldrModMachOLoadObjSymTab(pThis);
     3267    if (RT_FAILURE(rc))
     3268        return rc;
     3269
     3270    /*
     3271     * Load the relocations if needed.
     3272     */
     3273    macho_relocation_union_t const *paRelocations = pThis->paRelocations;
     3274    if (!paRelocations)
     3275    {
     3276        uint32_t *paRawRelocs = (uint32_t *)RTMemAlloc(cRelocations * sizeof(macho_relocation_union_t));
     3277        if (!paRawRelocs)
     3278            return VERR_NO_MEMORY;
     3279        if (pDySymTab->nextrel)
     3280            rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, paRawRelocs, pDySymTab->nextrel * sizeof(macho_relocation_union_t),
     3281                                              pDySymTab->extreloff);
     3282        if (pDySymTab->nlocrel && RT_SUCCESS(rc))
     3283            rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader,
     3284                                              (uint8_t *)paRawRelocs + pDySymTab->nextrel * sizeof(macho_relocation_union_t),
     3285                                              pDySymTab->nlocrel * sizeof(macho_relocation_union_t), pDySymTab->locreloff);
     3286        if (RT_SUCCESS(rc))
     3287            pThis->paRelocations = (macho_relocation_union_t *)paRawRelocs;
     3288        else
     3289        {
     3290            RTMemFree(paRawRelocs);
     3291            return rc;
     3292        }
     3293
     3294        /* Byte swap if needed. */
     3295        if (   pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
     3296            || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
     3297        {
     3298            for (uint32_t i = 0; i < cRelocations; i++)
     3299            {
     3300                paRawRelocs[i * 2]     = RT_BSWAP_U32(paRawRelocs[i * 2]);
     3301                paRawRelocs[i * 2 + 1] = RT_BSWAP_U32(paRawRelocs[i * 2 + 1]);
     3302            }
     3303            ASMCompilerBarrier();
     3304        }
     3305
     3306        paRelocations = pThis->paRelocations;
     3307    }
     3308
     3309    /*
     3310     * Apply the fixups.
     3311     */
     3312    if (pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE) /** @todo this aint right. */
     3313        return kldrModMachOApplyFixupsGeneric32Bit(pThis, (uint8_t *)pvMapping, (size_t)pThis->cbImage, 0, pThis->LinkAddress,
     3314                                                   paRelocations, cRelocations, pThis->pauRelocationsVirginData,
     3315                                                   (macho_nlist_32_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress);
     3316    if (   pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE
     3317        && pThis->Hdr.cputype == CPU_TYPE_X86_64)
     3318        return kldrModMachOApplyFixupsAMD64(pThis, (uint8_t *)pvMapping, (size_t)pThis->cbImage, 0,
     3319                                            paRelocations, cRelocations, pThis->pauRelocationsVirginData,
     3320                                            (macho_nlist_64_t *)pThis->pvaSymbols, pThis->cSymbols, NewBaseAddress);
     3321    RTLDRMODMACHO_FAILED_RETURN(VERR_LDRMACHO_TODO);
    28453322}
    28463323
     
    28523329 * @returns IPRT status code.
    28533330 * @param   pThis           The Mach-O module interpreter instance.
    2854  * @param   pbSectBits      Pointer to the section bits.
    2855  * @param   pFixupSect      The section being fixed up.
     3331 * @param   pbBits          Pointer to the bits to fix up.
     3332 * @param   cbBits          Size of the bits to fix up.
     3333 * @param   uBitsRva        The RVA of the bits.
     3334 * @param   uBitsLinkAddr   The link address of the bits.
     3335 * @param   paFixups        The fixups.
     3336 * @param   cFixups         Number of fixups.
     3337 * @param   pauVirginData   The virgin data / addends.  Parallel to paFixups.
    28563338 * @param   paSyms          Pointer to the symbol table.
    28573339 * @param   cSyms           Number of symbols.
    28583340 * @param   NewBaseAddress  The new base image address.
    28593341 */
    2860 static int  kldrModMachOFixupSectionGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect,
    2861                                                  macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress)
    2862 {
    2863     const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
    2864     const uint32_t cFixups = pFixupSect->cFixups;
    2865     size_t cbSectBits = (size_t)pFixupSect->cb;
    2866     const uint8_t *pbSectVirginBits;
    2867     uint32_t iFixup;
    2868     RTLDRADDR SymAddr = ~(RTLDRADDR)0;
    2869     int rc;
    2870 
    2871     /*
    2872      * Find the virgin bits.
    2873      */
    2874     if (pFixupSect->offFile != -1)
    2875     {
    2876         rc = kldrModMachOMapVirginBits(pThis);
    2877         if (RT_FAILURE(rc))
    2878             return rc;
    2879         pbSectVirginBits = (const uint8_t *)pThis->pvBits + pFixupSect->offFile;
    2880     }
    2881     else
    2882         pbSectVirginBits = NULL;
    2883 
     3342static int  kldrModMachOApplyFixupsGeneric32Bit(PRTLDRMODMACHO pThis, uint8_t *pbBits, size_t cbBits, RTLDRADDR uBitsRva,
     3343                                                RTLDRADDR uBitsLinkAddr, const macho_relocation_union_t *paFixups,
     3344                                                const uint32_t cFixups, PCRTUINT64U const pauVirginData,
     3345                                                macho_nlist_32_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress)
     3346{
    28843347    /*
    28853348     * Iterate the fixups and apply them.
    28863349     */
    2887     for (iFixup = 0; iFixup < cFixups; iFixup++)
    2888     {
    2889         RTPTRUNION uFix;
    2890         RTPTRUNION uFixVirgin;
    2891         union
    2892         {
    2893             macho_relocation_info_t     r;
    2894             scattered_relocation_info_t s;
    2895         } Fixup;
    2896         Fixup.r = paFixups[iFixup];
     3350    for (uint32_t iFixup = 0; iFixup < cFixups; iFixup++)
     3351    {
     3352        macho_relocation_union_t Fixup   = paFixups[iFixup];
     3353        RTLDRADDR                SymAddr = ~(RTLDRADDR)0;
     3354        RTPTRUNION               uFix;
    28973355
    28983356        if (!(Fixup.r.r_address & R_SCATTERED))
    28993357        {
    29003358            /* sanity */
    2901             if ((uint32_t)Fixup.r.r_address >= cbSectBits)
    2902                 return VERR_LDR_BAD_FIXUP;
    2903 
    2904             /* calc fixup addresses. */
    2905             uFix.pv = pbSectBits + Fixup.r.r_address;
    2906             uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0;
     3359            RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.r.r_address + RT_BIT_32(Fixup.r.r_length) <= cbBits, VERR_LDR_BAD_FIXUP);
     3360
     3361            /* Calc the fixup address. */
     3362            uFix.pv = pbBits + Fixup.r.r_address;
    29073363
    29083364            /*
     
    29123368            switch (Fixup.r.r_length)
    29133369            {
    2914                 /** @todo Deal with unaligned accesses on non x86 platforms. */
    2915                 case 0: SymAddr = *uFixVirgin.pi8; break;
    2916                 case 1: SymAddr = *uFixVirgin.pi16; break;
    2917                 case 2: SymAddr = *uFixVirgin.pi32; break;
    2918                 case 3: SymAddr = *uFixVirgin.pi64; break;
     3370                case 0: SymAddr = (int8_t)pauVirginData[iFixup].au8[0]; break;
     3371                case 1: SymAddr = (int16_t)pauVirginData[iFixup].au16[0]; break;
     3372                case 2: SymAddr = (int32_t)pauVirginData[iFixup].au32[0]; break;
     3373                case 3: SymAddr = (int64_t)pauVirginData[iFixup].u; break;
     3374                default: RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP);
    29193375            }
    29203376            if (Fixup.r.r_pcrel)
    2921                 SymAddr += Fixup.r.r_address + pFixupSect->LinkAddress;
     3377                SymAddr += Fixup.r.r_address + uBitsLinkAddr;
    29223378
    29233379            /* Add symbol / section address. */
     
    29693425            /* adjust for PC relative */
    29703426            if (Fixup.r.r_pcrel)
    2971                 SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
     3427                SymAddr -= Fixup.r.r_address + uBitsRva + NewBaseAddress;
    29723428        }
    29733429        else
     
    29793435            /* sanity */
    29803436            RTLDRMODMACHO_ASSERT(Fixup.s.r_scattered);
    2981             if ((uint32_t)Fixup.s.r_address >= cbSectBits)
    2982                 return VERR_LDR_BAD_FIXUP;
    2983 
    2984             /* calc fixup addresses. */
    2985             uFix.pv = pbSectBits + Fixup.s.r_address;
    2986             uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.s.r_address : 0;
     3437            RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.s.r_address + RT_BIT_32(Fixup.s.r_length) <= cbBits, VERR_LDR_BAD_FIXUP);
     3438
     3439            /* Calc the fixup address. */
     3440            uFix.pv = pbBits + Fixup.s.r_address;
    29873441
    29883442            /*
     
    29923446            switch (Fixup.s.r_length)
    29933447            {
    2994                 case 0: SymAddr = *uFixVirgin.pi8; break;
    2995                 case 1: SymAddr = *uFixVirgin.pi16; break;
    2996                 case 2: SymAddr = *uFixVirgin.pi32; break;
    2997                 case 3: SymAddr = *uFixVirgin.pi64; break;
     3448                case 0: SymAddr = (int8_t)pauVirginData[iFixup].au8[0]; break;
     3449                case 1: SymAddr = (int16_t)pauVirginData[iFixup].au16[0]; break;
     3450                case 2: SymAddr = (int32_t)pauVirginData[iFixup].au32[0]; break;
     3451                case 3: SymAddr = (int64_t)pauVirginData[iFixup].u; break;
     3452                default: RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP);
    29983453            }
    29993454            if (Fixup.s.r_pcrel)
     
    30213476            SymAddr += Value - pSymSect->LinkAddress + pSymSect->RVA + NewBaseAddress;
    30223477            if (Fixup.s.r_pcrel)
    3023                 SymAddr -= Fixup.s.r_address + pFixupSect->RVA + NewBaseAddress;
     3478                SymAddr -= Fixup.s.r_address + uBitsRva + NewBaseAddress;
    30243479
    30253480            Fixup.r.r_length = ((scattered_relocation_info_t *)&paFixups[iFixup])->r_length;
     
    30553510 * @returns IPRT status code.
    30563511 * @param   pThis           The Mach-O module interpreter instance.
    3057  * @param   pbSectBits      Pointer to the section bits.
     3512 * @param   pbBits          Pointer to the section bits.
     3513 * @param   cbBits          Size of the bits to fix up.
     3514 * @param   uBitsRva        The RVA of the bits.
     3515 * @param   paFixups        The fixups.
     3516 * @param   cFixups         Number of fixups.
     3517 * @param   pauVirginData   The virgin data / addends.  Parallel to paFixups.
    30583518 * @param   pFixupSect      The section being fixed up.
    30593519 * @param   paSyms          Pointer to the symbol table.
     
    30613521 * @param   NewBaseAddress  The new base image address.
    30623522 */
    3063 static int  kldrModMachOFixupSectionAMD64(PRTLDRMODMACHO pThis, uint8_t *pbSectBits, PRTLDRMODMACHOSECT pFixupSect,
    3064                                           macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress)
    3065 {
    3066     const macho_relocation_info_t *paFixups = pFixupSect->paFixups;
    3067     const uint32_t cFixups = pFixupSect->cFixups;
    3068     size_t cbSectBits = (size_t)pFixupSect->cb;
    3069     const uint8_t *pbSectVirginBits;
    3070     uint32_t iFixup;
    3071     RTLDRADDR SymAddr;
    3072     int rc;
    3073 
    3074     /*
    3075      * Find the virgin bits.
    3076      */
    3077     if (pFixupSect->offFile != -1)
    3078     {
    3079         rc = kldrModMachOMapVirginBits(pThis);
    3080         if (RT_FAILURE(rc))
    3081             return rc;
    3082         pbSectVirginBits = (const uint8_t *)pThis->pvBits + pFixupSect->offFile;
    3083     }
    3084     else
    3085         pbSectVirginBits = NULL;
    3086 
     3523static int  kldrModMachOApplyFixupsAMD64(PRTLDRMODMACHO pThis, uint8_t *pbBits, size_t cbBits, RTLDRADDR uBitsRva,
     3524                                         const macho_relocation_union_t *paFixups,
     3525                                         const uint32_t cFixups, PCRTUINT64U const pauVirginData,
     3526                                         macho_nlist_64_t *paSyms, uint32_t cSyms, RTLDRADDR NewBaseAddress)
     3527{
    30873528    /*
    30883529     * Iterate the fixups and apply them.
    30893530     */
    3090     for (iFixup = 0; iFixup < cFixups; iFixup++)
    3091     {
    3092         union
    3093         {
    3094             macho_relocation_info_t     r;
    3095             scattered_relocation_info_t s;
    3096         } Fixup;
    3097         Fixup.r = paFixups[iFixup];
     3531    for (uint32_t iFixup = 0; iFixup < cFixups; iFixup++)
     3532    {
     3533        macho_relocation_union_t Fixup = paFixups[iFixup];
    30983534
    30993535        /* AMD64 doesn't use scattered fixups. */
     
    31013537
    31023538        /* sanity */
    3103         RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.r.r_address < cbSectBits, VERR_LDR_BAD_FIXUP);
     3539        RTLDRMODMACHO_CHECK_RETURN((uint32_t)Fixup.r.r_address + RT_BIT_32(Fixup.r.r_length) <= cbBits, VERR_LDR_BAD_FIXUP);
    31043540
    31053541        /* calc fixup addresses. */
    31063542        RTPTRUNION uFix;
    3107         uFix.pv = pbSectBits + Fixup.r.r_address;
    3108         RTPTRUNION uFixVirgin;
    3109         uFixVirgin.pv = pbSectVirginBits ? (uint8_t *)pbSectVirginBits + Fixup.r.r_address : 0;
     3543        uFix.pv = pbBits + Fixup.r.r_address;
    31103544
    31113545        /*
     
    31133547         */
    31143548        /* Calc the linked symbol address / addend. */
     3549        RTLDRADDR SymAddr;
    31153550        switch (Fixup.r.r_length)
    31163551        {
    3117             /** @todo Deal with unaligned accesses on non x86 platforms. */
    3118             case 2: SymAddr = *uFixVirgin.pi32; break;
    3119             case 3: SymAddr = *uFixVirgin.pi64; break;
     3552            case 2: SymAddr = (int32_t)pauVirginData[iFixup].au32[0]; break;
     3553            case 3: SymAddr = (int64_t)pauVirginData[iFixup].u; break;
    31203554            default:
    31213555                RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP);
     
    31643598                default:
    31653599                {
    3166                     /* Adjust with fixup specific addend and vierfy unsigned/r_pcrel. */
     3600                    /* Adjust with fixup specific addend and verify unsigned/r_pcrel. */
    31673601                    switch (Fixup.r.r_type)
    31683602                    {
     
    31983632                            /* branch to an external symbol may have to take a short detour. */
    31993633                            if (   Fixup.r.r_type == X86_64_RELOC_BRANCH
    3200                                 &&       SymAddr + Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress
     3634                                &&       SymAddr + Fixup.r.r_address + uBitsRva + NewBaseAddress
    32013635                                       - pSym->n_value
    32023636                                       + UINT64_C(0x80000000)
     
    32223656                /*
    32233657                 * This is a weird customer, it will always be follows by an UNSIGNED fixup.
     3658                 * The value is calculated: target - pair_target.
     3659                 * Note! The linker generally eliminate these when linking modules rather
     3660                 *       than objects (-r).
    32243661                 */
    32253662                case X86_64_RELOC_SUBTRACTOR:
    32263663                {
    3227                     macho_relocation_info_t Fixup2;
    3228 
    32293664                    /* Deal with the SUBTRACT symbol first, by subtracting it from SymAddr. */
    32303665                    switch (pSym->n_type & MACHO_N_TYPE)
     
    32543689                    iFixup++;
    32553690                    RTLDRMODMACHO_CHECK_RETURN(!Fixup.r.r_pcrel && iFixup < cFixups, VERR_LDR_BAD_FIXUP);
    3256                     Fixup2 = paFixups[iFixup];
     3691                    macho_relocation_info_t const Fixup2 = paFixups[iFixup].r;
    32573692                    RTLDRMODMACHO_CHECK_RETURN(   Fixup2.r_address == Fixup.r.r_address
    32583693                                              && Fixup2.r_length == Fixup.r.r_length
     
    32683703                        RTLDRMODMACHO_CHECK_RETURN(!(pSym->n_type & MACHO_N_STAB), VERR_LDR_BAD_FIXUP);
    32693704
    3270                         /* Add it's value to SymAddr. */
     3705                        /* Add its value to SymAddr. */
    32713706                        switch (pSym->n_type & MACHO_N_TYPE)
    32723707                        {
     
    32973732                        RTLDRMODMACHO_CHECK_RETURN(Fixup2.r_symbolnum <= pThis->cSections, VERR_LDR_BAD_FIXUP);
    32983733                        pSymSect = &pThis->paSections[Fixup2.r_symbolnum - 1];
    3299                         SymAddr += pSymSect->RVA + NewBaseAddress;
     3734                        SymAddr += pSymSect->RVA - pSymSect->LinkAddress + NewBaseAddress;
    33003735                    }
    33013736                    else
     
    33443779        /* adjust for PC relative */
    33453780        if (Fixup.r.r_pcrel)
    3346             SymAddr -= Fixup.r.r_address + pFixupSect->RVA + NewBaseAddress;
     3781            SymAddr -= Fixup.r.r_address + uBitsRva + NewBaseAddress;
    33473782
    33483783        /*
     
    33693804
    33703805/**
    3371  * Loads the symbol table for a MH_OBJECT file.
     3806 * Loads the symbol table (LC_SYMTAB).
    33723807 *
    33733808 * The symbol table is pointed to by RTLDRMODMACHO::pvaSymbols.
     
    34133848                rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvSyms, cbSyms, pThis->offSymbols);
    34143849                if (RT_SUCCESS(rc) && pThis->cchStrings)
    3415                     rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvStrings,
    3416                                                           pThis->cchStrings, pThis->offStrings);
     3850                    rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvStrings, pThis->cchStrings, pThis->offStrings);
    34173851                if (RT_SUCCESS(rc))
    34183852                {
     
    34703904 * @param   ppaFixups       Where to put the pointer to the allocated fixup array.
    34713905 */
    3472 static int  kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_info_t **ppaFixups)
    3473 {
    3474     macho_relocation_info_t *paFixups;
     3906static int kldrModMachOLoadFixups(PRTLDRMODMACHO pThis, RTFOFF offFixups, uint32_t cFixups, macho_relocation_union_t **ppaFixups)
     3907{
     3908    macho_relocation_union_t *paFixups;
    34753909    size_t cbFixups;
    34763910
     
    34783912    cbFixups = cFixups * sizeof(*paFixups);
    34793913    RTLDRMODMACHO_CHECK_RETURN(cbFixups / sizeof(*paFixups) == cFixups, VERR_LDRMACHO_BAD_SYMTAB_SIZE);
    3480     paFixups = (macho_relocation_info_t *)RTMemAlloc(cbFixups);
     3914    paFixups = (macho_relocation_union_t *)RTMemAlloc(cbFixups);
    34813915    if (!paFixups)
    34823916        return VERR_NO_MEMORY;
     
    34893923
    34903924        /* do endian conversion if necessary. */
    3491         if (    pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
    3492             ||  pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
     3925        if (   pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
     3926            || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
    34933927        {
    34943928            uint32_t iFixup;
     
    35083942
    35093943/**
    3510  * Maps the virgin file bits into memory if not already done.
     3944 * Loads virgin data (addends) for an array of fixups.
    35113945 *
    35123946 * @returns IPRT status code.
    3513  * @param   pThis       The Mach-O module interpreter instance.
    3514  */
    3515 static int kldrModMachOMapVirginBits(PRTLDRMODMACHO pThis)
    3516 {
     3947 * @param   pThis           The Mach-O module interpreter instance.
     3948 * @param   pbBits          The virgin bits to lift the data from
     3949 * @param   cbBits          The number of virgin bytes.
     3950 * @param   paFixups        The fixups.
     3951 * @param   cFixups         Number of fixups
     3952 * @param   pszName         Name for logging.
     3953 * @param   ppauVirginData  Where to return the virgin data.
     3954 */
     3955static int rtldrMachOLoadVirginData(PRTLDRMODMACHO pThis, uint8_t const *pbBits, size_t cbBits,
     3956                                    macho_relocation_union_t const *paFixups, uint32_t cFixups, const char *pszName,
     3957                                    PRTUINT64U *ppauVirginData)
     3958{
     3959    /*
     3960     * In case we jettisoned the fixups, we will leave virgin data.
     3961     */
     3962    if (*ppauVirginData)
     3963        return VINF_SUCCESS;
     3964
     3965#ifdef LOG_ENABLED
     3966    /*
     3967     * Ensure that we've got the symbol table if we're logging fixups.
     3968     */
     3969    if (LogIs5Enabled())
     3970    {
     3971        int rc = kldrModMachOLoadObjSymTab(pThis);
     3972        if (RT_FAILURE(rc))
     3973            return rc;
     3974    }
     3975#endif
     3976
     3977
     3978    /*
     3979     * Allocate memory and iterate the fixups to get the data.
     3980     */
     3981    PRTUINT64U pauVirginData = *ppauVirginData = (PRTUINT64U)RTMemAllocZ(sizeof(uint64_t) * cFixups);
     3982    if (pauVirginData)
     3983    {
     3984        Log5(("Fixups for %s: (%u)\n", pszName, cFixups));
     3985        for (uint32_t i = 0; i < cFixups; i++)
     3986        {
     3987            uint32_t off;
     3988            uint32_t cShift;
     3989            if (!paFixups[i].s.r_scattered)
     3990            {
     3991                off    = paFixups[i].r.r_address;
     3992                cShift = paFixups[i].r.r_length;
     3993            }
     3994            else
     3995            {
     3996                off    = paFixups[i].s.r_address;
     3997                cShift = paFixups[i].s.r_length;
     3998            }
     3999            RTLDRMODMACHO_CHECK_RETURN(off + RT_BIT_32(cShift) <= cbBits, VERR_LDR_BAD_FIXUP);
     4000
     4001            /** @todo This ASSUMES same endian in the image and on the host.  Would need
     4002             * to check target cpu (pThis->Core.enmArch) endianness against host to get
     4003             * it right... (outside the loop, obviously) */
     4004            switch (cShift)
     4005            {
     4006                case 3:
     4007                    pauVirginData[i].u = RT_MAKE_U64_FROM_U8(pbBits[off],     pbBits[off + 1], pbBits[off + 2], pbBits[off + 3],
     4008                                                             pbBits[off + 4], pbBits[off + 5], pbBits[off + 6], pbBits[off + 7]);
     4009                    break;
     4010                case 2:
     4011                    pauVirginData[i].u = (int32_t)RT_MAKE_U32_FROM_U8(pbBits[off], pbBits[off + 1], pbBits[off + 2], pbBits[off + 3]);
     4012                    break;
     4013                case 1:
     4014                    pauVirginData[i].u = (int16_t)RT_MAKE_U16(pbBits[off], pbBits[off + 1]);
     4015                    break;
     4016                case 0:
     4017                    pauVirginData[i].u = (int8_t)pbBits[off];
     4018                    break;
     4019                default:
     4020                    RTLDRMODMACHO_FAILED_RETURN(VERR_LDR_BAD_FIXUP);
     4021            }
     4022
     4023#ifdef LOG_ENABLED
     4024            if (LogIs5Enabled())
     4025            {
     4026                if (!paFixups[i].s.r_scattered)
     4027                {
     4028                    Log5((" #%06x: %#08x LB %u: t=%#x pc=%u ex=%u sym=%#010x add=%#RX64\n",
     4029                          i, off, RT_BIT_32(cShift), paFixups[i].r.r_type, paFixups[i].r.r_pcrel, paFixups[i].r.r_extern,
     4030                          paFixups[i].r.r_symbolnum, pauVirginData[i].u));
     4031                    if (paFixups[i].r.r_symbolnum < pThis->cSymbols)
     4032                    {
     4033                        if (pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
     4034                        {
     4035                            macho_nlist_64_t const *pSym = (macho_nlist_64_t const *)pThis->pvaSymbols + paFixups[i].r.r_symbolnum;
     4036                            Log5(("     sym: %#04x:%#018RX64 t=%#04x d=%#06x %s\n",
     4037                                  pSym->n_sect, pSym->n_value, pSym->n_type, pSym->n_desc,
     4038                                  pSym->n_un.n_strx < pThis->cchStrings ? &pThis->pchStrings[pSym->n_un.n_strx] : ""));
     4039
     4040                        }
     4041                        else
     4042                        {
     4043                            macho_nlist_32_t const *pSym = (macho_nlist_32_t const *)pThis->pvaSymbols + paFixups[i].r.r_symbolnum;
     4044                            Log5(("     sym: %#04x:%#010RX32 t=%#04x d=%#06x %s\n",
     4045                                  pSym->n_sect, pSym->n_value, pSym->n_type, pSym->n_desc,
     4046                                  (uint32_t)pSym->n_un.n_strx < pThis->cchStrings ? &pThis->pchStrings[pSym->n_un.n_strx] : ""));
     4047                        }
     4048                    }
     4049                }
     4050                else
     4051                    Log5((" #%06x: %#08x LB %u: t=%#x pc=%u  val=%#010x add=%#RX64\n", i, off, RT_BIT_32(cShift),
     4052                          paFixups[i].s.r_type, paFixups[i].s.r_pcrel, paFixups[i].s.r_value, pauVirginData[i].u));
     4053            }
     4054#endif
     4055        }
     4056        return VINF_SUCCESS;
     4057    }
     4058    RT_NOREF(pThis, pszName);
     4059    return VERR_NO_MEMORY;
     4060}
     4061
     4062
     4063/**
     4064 * MH_OBJECT: Loads fixups and addends for each section.
     4065 *
     4066 * @returns IPRT status code.
     4067 * @param   pThis           The Mach-O module interpreter instance.
     4068 * @param   pbBits          The image bits.  First time we're called, these are
     4069 *                          ASSUMED to be in virgin state and suitable for
     4070 *                          saving addends.
     4071 */
     4072static int rtldrMachOObjLoadFixupsAndVirginData(PRTLDRMODMACHO pThis, uint8_t const *pbBits)
     4073{
     4074    PRTLDRMODMACHOSECT pSect = pThis->paSections;
     4075    for (uint32_t i = 0; i < pThis->cSections; i++, pSect++)
     4076        if (   !pSect->paFixups
     4077            && pSect->cFixups > 0)
     4078        {
     4079            /*
     4080             * Load and endian convert the fixups.
     4081             */
     4082            int rc = kldrModMachOLoadFixups(pThis, pSect->offFixups, pSect->cFixups, &pSect->paFixups);
     4083            if (RT_SUCCESS(rc))
     4084            {
     4085                /*
     4086                 * Save virgin data (addends) for each fixup.
     4087                 */
     4088                rc = rtldrMachOLoadVirginData(pThis, &pbBits[(size_t)pSect->RVA], (size_t)pSect->cb, pSect->paFixups, pSect->cFixups,
     4089                                              pThis->aSegments[pSect->iSegment].SegInfo.pszName, &pSect->pauFixupVirginData);
     4090                if (RT_SUCCESS(rc))
     4091                    continue;
     4092
     4093                RTMemFree(pSect->pauFixupVirginData);
     4094                pSect->pauFixupVirginData = NULL;
     4095                RTMemFree(pSect->paFixups);
     4096                pSect->paFixups = NULL;
     4097            }
     4098            return rc;
     4099        }
     4100
     4101    return VINF_SUCCESS;
     4102}
     4103
     4104
     4105/**
     4106 * Dylib: Loads fixups and addends.
     4107 *
     4108 * @returns IPRT status code.
     4109 * @param   pThis           The Mach-O module interpreter instance.
     4110 * @param   pbBits          The image bits.  First time we're called, these are
     4111 *                          ASSUMED to be in virgin state and suitable for
     4112 *                          saving addends.
     4113 */
     4114static int rtldrMachODylibLoadFixupsAndVirginData(PRTLDRMODMACHO pThis, uint8_t const *pbBits)
     4115{
     4116    /*
     4117     * Don't do it again if we already loaded them.
     4118     */
     4119    if (pThis->paRelocations)
     4120    {
     4121        Assert(pThis->pauRelocationsVirginData);
     4122        return VINF_SUCCESS;
     4123    }
     4124
     4125    /*
     4126     * There must be a LC_DYSYMTAB.  Fixups are optionals.
     4127     */
     4128    dysymtab_command_t const *pDySymTab = pThis->pDySymTab;
     4129    AssertReturn(pDySymTab, VERR_INTERNAL_ERROR_2);
     4130    uint32_t cRelocations = pDySymTab->nlocrel + pDySymTab->nextrel;
     4131    if (cRelocations == 0)
     4132        return VINF_SUCCESS;
     4133
     4134    /*
     4135     * Load fixups.
     4136     */
    35174137    int rc = VINF_SUCCESS;
    3518     if (!pThis->pvBits)
    3519         rc = pThis->Core.pReader->pfnMap(pThis->Core.pReader, &pThis->pvBits);
     4138    uint32_t *paRawRelocs = (uint32_t *)RTMemAlloc(cRelocations * sizeof(macho_relocation_union_t));
     4139    if (paRawRelocs)
     4140    {
     4141        pThis->paRelocations = (macho_relocation_union_t *)paRawRelocs;
     4142
     4143        if (pDySymTab->nextrel)
     4144            rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, paRawRelocs,
     4145                                              pDySymTab->nextrel * sizeof(macho_relocation_union_t), pDySymTab->extreloff);
     4146        if (pDySymTab->nlocrel && RT_SUCCESS(rc))
     4147            rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader,
     4148                                              (uint8_t *)paRawRelocs + pDySymTab->nextrel * sizeof(macho_relocation_union_t),
     4149                                              pDySymTab->nlocrel * sizeof(macho_relocation_union_t), pDySymTab->locreloff);
     4150        if (RT_SUCCESS(rc))
     4151        {
     4152            /* Byte swap if needed. */
     4153            if (   pThis->Hdr.magic == IMAGE_MACHO32_SIGNATURE_OE
     4154                || pThis->Hdr.magic == IMAGE_MACHO64_SIGNATURE_OE)
     4155            {
     4156                for (uint32_t i = 0; i < cRelocations; i++)
     4157                {
     4158                    paRawRelocs[i * 2]     = RT_BSWAP_U32(paRawRelocs[i * 2]);
     4159                    paRawRelocs[i * 2 + 1] = RT_BSWAP_U32(paRawRelocs[i * 2 + 1]);
     4160                }
     4161                ASMCompilerBarrier();
     4162            }
     4163
     4164            /*
     4165             * Load virgin data (addends).
     4166             */
     4167            rc = rtldrMachOLoadVirginData(pThis, pbBits, (size_t)pThis->cbImage, pThis->paRelocations, cRelocations,
     4168                                          "whole-image", &pThis->pauRelocationsVirginData);
     4169            if (RT_SUCCESS(rc))
     4170                return VINF_SUCCESS;
     4171
     4172            RTMemFree(pThis->pauRelocationsVirginData);
     4173            pThis->pauRelocationsVirginData = NULL;
     4174        }
     4175        RTMemFree(pThis->paRelocations);
     4176        pThis->paRelocations = NULL;
     4177    }
     4178    else
     4179        rc = VERR_NO_MEMORY;
    35204180    return rc;
    35214181}
     
    35584218#endif
    35594219
    3560 
    35614220/**
    35624221 * @interface_method_impl{RTLDROPS,pfnGetImageSize}
     
    35934252        if (   pThis->aSegments[i].SegInfo.cbFile == -1
    35944253            || pThis->aSegments[i].SegInfo.offFile == -1
    3595             || pThis->aSegments[i].SegInfo.LinkAddress == NIL_RTLDRADDR
     4254            || pThis->aSegments[i].SegInfo.RVA == NIL_RTLDRADDR
     4255            || pThis->aSegments[i].SegInfo.cbMapped == 0
    35964256            || !pThis->aSegments[i].SegInfo.Alignment)
    35974257            continue;
     
    36194279    PRTLDRMODMACHO pThis = RT_FROM_MEMBER(pMod, RTLDRMODMACHO, Core);
    36204280    int rc;
    3621     RT_NOREF(OldBaseAddress);
    36224281
    36234282    /*
     
    36264285    if (pThis->Hdr.filetype == MH_OBJECT)
    36274286    {
    3628         rc = kldrModMachOObjDoImports(pThis, NewBaseAddress, pfnGetImport, pvUser);
     4287        rc = rtldrMachOObjLoadFixupsAndVirginData(pThis, (uint8_t const *)pvBits);
     4288        if (RT_SUCCESS(rc))
     4289            rc = kldrModMachOObjDoImports(pThis, NewBaseAddress, pfnGetImport, pvUser);
    36294290        if (RT_SUCCESS(rc))
    36304291            rc = kldrModMachOObjDoFixups(pThis, pvBits, NewBaseAddress);
     
    36324293    }
    36334294    else
    3634         rc = VERR_LDRMACHO_TODO;
    3635     /*{
    3636         rc = kldrModMachODoFixups(pThis, pvBits, NewBaseAddress, OldBaseAddress, pfnGetImport, pvUser);
     4295    {
     4296        rc = rtldrMachODylibLoadFixupsAndVirginData(pThis, (uint8_t const *)pvBits);
    36374297        if (RT_SUCCESS(rc))
    3638             rc = kldrModMachODoImports(pThis, pvBits, pfnGetImport, pvUser);
    3639     }*/
     4298            rc = kldrModMachODylibDoImports(pThis, NewBaseAddress, pfnGetImport, pvUser);
     4299        if (RT_SUCCESS(rc))
     4300            rc = kldrModMachODylibDoIndirectSymbols(pThis, pvBits, NewBaseAddress - OldBaseAddress);
     4301        if (RT_SUCCESS(rc))
     4302            rc = kldrModMachODylibDoFixups(pThis, pvBits, NewBaseAddress);
     4303    }
    36404304
    36414305    /*
     
    40694733    for (uint32_t iSlot = 0; iSlot < cSlots; iSlot++)
    40704734    {
     4735        /*
     4736         * Check that the data offset is valid.  There appears to be no alignment
     4737         * requirements here, which is a little weird consindering the PPC heritage.
     4738         */
    40714739        uint32_t const offData = RT_BE2H_U32(pSuper->aSlots[iSlot].offData);
    40724740        if (   offData < offFirst
    4073             || offData > cbBlob - sizeof(RTCRAPLCSHDR)
    4074             || (offData & 3))
     4741            || offData > cbBlob - sizeof(RTCRAPLCSHDR))
    40754742            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_FORMAT,
    40764743                                 "Slot #%u has an invalid data offset: %#x (min %#x, max %#x-4)",
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette