voidenviron_init(void) { ///省略代码 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output. if (PrintHelp || PrintOptions) { if (PrintHelp) { _objc_inform("Objective-C runtime debugging. Set variable=YES to enable."); _objc_inform("OBJC_HELP: describe available environment variables"); if (PrintOptions) { _objc_inform("OBJC_HELP is set"); } _objc_inform("OBJC_PRINT_OPTIONS: list which options are set"); } if (PrintOptions) { _objc_inform("OBJC_PRINT_OPTIONS is set"); } ///这里如果满足条件 会打印所有的环境变量 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) { constoption_t *opt = &Settings[i]; if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help); if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env); } } }
可以看出来就是一些环境变量的初始化,参看这段代码,我们可以打印环境变量。
将条件去掉直接调用for循环
1 2 3 4 5
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) { constoption_t *opt = &Settings[i]; _objc_inform("%s: %s", opt->env, opt->help); _objc_inform("%s is set", opt->env); }
通过终端命令export OBJC_hrlp = 1,打印环境变量
我们平时项目中可能会有几个环境变量可以在我们的xcode配置(target -- Edit Scheme -- Run --Arguments -- Environment Variables)一下对应的值,达到修改环境变量的目的:
staticvoid _objc_terminate(void) { if (PrintExceptions) { _objc_inform("EXCEPTIONS: terminating"); }
if (! __cxa_current_exception_type()) { // No current exception. (*old_terminate)(); } else { // There is a current exception. Check if it's an objc exception. @try { __cxa_rethrow(); } @catch (id e) { // It's an objc object. Call Foundation's handler, if any. (*uncaught_handler)((id)e); (*old_terminate)(); } @catch (...) { // It's not an objc object. Continue to C++ terminate. (*old_terminate)(); } } }
void _imp_implementationWithBlock_init(void) { #if TARGET_OS_OSX // Eagerly load libobjc-trampolines.dylib in certain processes. Some // programs (most notably QtWebEngineProcess used by older versions of // embedded Chromium) enable a highly restrictive sandbox profile which // blocks access to that dylib. If anything calls // imp_implementationWithBlock (as AppKit has started doing) then we'll // crash trying to load it. Loading it here sets it up before the sandbox // profile is enabled and blocks it. // // This fixes EA Origin (rdar://problem/50813789) // and Steam (rdar://problem/55286131) if (__progname && (strcmp(__progname, "QtWebEngineProcess") == 0 || strcmp(__progname, "Steam Helper") == 0)) { Trampolines.Initialize(); } #endif }
// Perform first-time initialization if necessary. // This function is called before ordinary library initializers. // fixme defer initialization until an objc-using image is found? if (firstTime) { preopt_init(); }
if (PrintImages) { _objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount); }
// Find all images with Objective-C metadata. hCount = 0;
// Count classes. Size various table based on the total. int totalClasses = 0; int unoptimizedTotalClasses = 0; { uint32_t i = mhCount; while (i--) { const headerType *mhdr = (const headerType *)mhdrs[i];
auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses); if (!hi) { // no objc data in this entry continue; } if (mhdr->filetype == MH_EXECUTE) { // Size some data structures based on main executable's size #if __OBJC2__ // If dyld3 optimized the main executable, then there shouldn't // be any selrefs needed in the dynamic map so we can just init // to a 0 sized map if ( !hi->hasPreoptimizedSelectors() ) { size_t count; _getObjc2SelectorRefs(hi, &count); selrefCount += count; _getObjc2MessageRefs(hi, &count); selrefCount += count; } #else _getObjcSelectorRefs(hi, &selrefCount); #endif #if SUPPORT_GC_COMPAT // Halt if this is a GC app. if (shouldRejectGCApp(hi)) { _objc_fatal_with_reason (OBJC_EXIT_REASON_GC_NOT_SUPPORTED, OS_REASON_FLAG_CONSISTENT_FAILURE, "Objective-C garbage collection " "is no longer supported."); } #endif } hList[hCount++] = hi; if (PrintImages) { _objc_inform("IMAGES: loading image for %s%s%s%s%s\n", hi->fname(), mhdr->filetype == MH_BUNDLE ? " (bundle)" : "", hi->info()->isReplacement() ? " (replacement)" : "", hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "", hi->info()->optimizedByDyld()?" (preoptimized)":""); } } }
// Perform one-time runtime initialization that must be deferred until // the executable itself is found. This needs to be done before // further initialization. // (The executable may not be present in this infoList if the // executable does not contain Objective-C code but Objective-C // is dynamically loaded later. if (firstTime) { sel_init(selrefCount); arr_init();
#if SUPPORT_GC_COMPAT // Reject any GC images linked to the main executable. // We already rejected the app itself above. // Images loaded after launch will be rejected by dyld.
for (uint32_t i = 0; i < hCount; i++) { auto hi = hList[i]; auto mh = hi->mhdr(); if (mh->filetype != MH_EXECUTE && shouldRejectGCImage(mh)) { _objc_fatal_with_reason (OBJC_EXIT_REASON_GC_NOT_SUPPORTED, OS_REASON_FLAG_CONSISTENT_FAILURE, "%s requires Objective-C garbage collection " "which is no longer supported.", hi->fname()); } } #endif
#if TARGET_OS_OSX // Disable +initialize fork safety if the app is too old (< 10.13). // Disable +initialize fork safety if the app has a // __DATA,__objc_fork_ok section.
// if (!dyld_program_sdk_at_least(dyld_platform_version_macOS_10_13)) { // DisableInitializeForkSafety = true; // if (PrintInitializing) { // _objc_inform("INITIALIZE: disabling +initialize fork " // "safety enforcement because the app is " // "too old.)"); // } // }
for (uint32_t i = 0; i < hCount; i++) { auto hi = hList[i]; auto mh = hi->mhdr(); if (mh->filetype != MH_EXECUTE) continue; unsignedlongsize; if (getsectiondata(hi->mhdr(), "__DATA", "__objc_fork_ok", &size)) { DisableInitializeForkSafety = true; if (PrintInitializing) { _objc_inform("INITIALIZE: disabling +initialize fork " "safety enforcement because the app has " "a __DATA,__objc_fork_ok section"); } } break; // assume only one MH_EXECUTE image } #endif } if (hCount > 0) { ///核心方法 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses); }
firstTime = NO; // Call image load funcs after everything is set up. for (auto func : loadImageFuncs) { for (uint32_t i = 0; i < mhCount; i++) { func(mhdrs[i]); } } }
if (!doneOnce) { doneOnce = YES; launchTime = YES;
#if SUPPORT_NONPOINTER_ISA // Disable non-pointer isa under some conditions.
# if SUPPORT_INDEXED_ISA // Disable nonpointer isa if any image contains old Swift code for (EACH_HEADER) { if (hi->info()->containsSwift() && hi->info()->swiftUnstableVersion() < objc_image_info::SwiftVersion3) { DisableNonpointerIsa = true; if (PrintRawIsa) { _objc_inform("RAW ISA: disabling non-pointer isa because " "the app or a framework contains Swift code " "older than Swift 3.0"); } break; } } # endif
# if TARGET_OS_OSX // Disable non-pointer isa if the app is too old // (linked before OS X 10.11) // if (!dyld_program_sdk_at_least(dyld_platform_version_macOS_10_11)) { // DisableNonpointerIsa = true; // if (PrintRawIsa) { // _objc_inform("RAW ISA: disabling non-pointer isa because " // "the app is too old."); // } // }
// Disable non-pointer isa if the app has a __DATA,__objc_rawisa section // New apps that load old extensions may need this. for (EACH_HEADER) { if (hi->mhdr()->filetype != MH_EXECUTE) continue; unsignedlongsize; if (getsectiondata(hi->mhdr(), "__DATA", "__objc_rawisa", &size)) { DisableNonpointerIsa = true; if (PrintRawIsa) { _objc_inform("RAW ISA: disabling non-pointer isa because " "the app has a __DATA,__objc_rawisa section"); } } break; // assume only one MH_EXECUTE image } # endif
#endif
if (DisableTaggedPointers) { disableTaggedPointers(); } ///初始化TaggedPointer混淆 initializeTaggedPointerObfuscator();
if (PrintConnecting) { _objc_inform("CLASS: found %d classes during launch", totalClasses); } // namedClasses // Preoptimized classes don't go in this table. // 4/3 is NXMapTable's load factor // objc::unattachedCategories.init(32); // objc::allocatedClasses.init(); //负载因子 int namedClassesSize = (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3; //创建一张类的总表,包含所有的类 gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize); ts.log("IMAGE TIMES: first time tasks"); }
// Discover classes. Fix up unresolved future classes. Mark bundle classes. bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
for (EACH_HEADER) { if (! mustReadClasses(hi, hasDyldRoots)) { // Image is sufficiently optimized that we need not call readClass() continue; } //从mach-o读取类 classref_tconst *classlist = _getObjc2ClassList(hi, &count);
for (i = 0; i < count; i++) { //cls 目前没有名字 Class cls = (Class)classlist[i]; //关联类cls的名字 Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
if (newCls != cls && newCls) { // Class was moved but not deleted. Currently this occurs // only when the new class resolved a future class. // Non-lazily realize the class below. resolvedFutureClasses = (Class *) realloc(resolvedFutureClasses, (resolvedFutureClassCount+1) * sizeof(Class)); resolvedFutureClasses[resolvedFutureClassCount++] = newCls; } } } ts.log("IMAGE TIMES: discover classes");
Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized) { constchar *mangledName = cls->nonlazyMangledName(); ///以下代码 为笔者添加 方便调试到自定义的类(因为所以类都会执行这里,我们只关心我们定义的类) constchar *customerClassName = "JSPerson"; if (strcmp(mangledName, LGPersonName) == 0) { //打印类名 printf("%s -: 要研究的类: - %s\n",__func__,mangledName); } if (missingWeakSuperclass(cls)) { // No superclass (probably weak-linked). // Disavow any knowledge of this subclass. if (PrintConnecting) { _objc_inform("CLASS: IGNORING class '%s' with " "missing weak-linked superclass", cls->nameForLogging()); } addRemappedClass(cls, nil); cls->setSuperclass(nil); return nil; } cls->fixupBackwardDeployingStableSwift();
Class replacing = nil; if (mangledName != nullptr) { if (Class newCls = popFutureNamedClass(mangledName)) { //断点调试 这里并没有执行 // This name was previously allocated as a future class. // Copy objc_class to future class's struct. // Preserve future's rw data block.
if (newCls->isAnySwift()) { _objc_fatal("Can't complete future class request for '%s' " "because the real class is too big.", cls->nameForLogging()); }
// Manually set address-discriminated ptrauthed fields // so that newCls gets the correct signatures. newCls->setSuperclass(cls->getSuperclass()); newCls->initIsa(cls->getIsa());
replacing = cls; cls = newCls; } } if (headerIsPreoptimized && !replacing) { // class list built in shared cache // fixme strict assert doesn't work because of duplicates // ASSERT(cls == getClass(name)); ASSERT(mangledName == nullptr || getClassExceptSomeSwift(mangledName)); } else { if (mangledName) { //some Swift generic classes can lazily generate their names ///给类添加名字 addNamedClass(cls, mangledName, replacing); } else { ///元类也处理 Class meta = cls->ISA(); constclass_ro_t *metaRO = meta->bits.safe_ro(); ASSERT(metaRO->getNonMetaclass() && "Metaclass with lazy name must have a pointer to the corresponding nonmetaclass."); ASSERT(metaRO->getNonMetaclass() == cls && "Metaclass nonmetaclass pointer must equal the original class."); } ///添加到class表 addClassTableEntry(cls); } // for future reference: shared cache never contains MH_BUNDLEs if (headerIsBundle) { cls->data()->flags |= RO_FROM_BUNDLE; cls->ISA()->data()->flags |= RO_FROM_BUNDLE; } return cls; }
staticvoidaddNamedClass(Class cls, constchar *name, Class replacing = nil) { runtimeLock.assertLocked(); Class old; if ((old = getClassExceptSomeSwift(name)) && old != replacing) { inform_duplicate(name, old, cls);
// getMaybeUnrealizedNonMetaClass uses name lookups. // Classes not found by name lookup must be in the // secondary meta->nonmeta table. addNonMetaClass(cls); } else { NXMapInsert(gdb_objc_realized_classes, name, cls); } ASSERT(!(cls->data()->flags & RO_META));
// wrong: constructed classes are already realized when they get here // ASSERT(!cls->isRealized()); }
// This class is allowed to be a known class via the shared cache or via // data segments, but it is not allowed to be in the dynamic table already. //// 该类允许通过共享缓存或数据段成为已知类,但不允许已经在动态表中。 auto &set = objc::allocatedClasses.get();
ASSERT(set.find(cls) == set.end());
if (!isKnownClass(cls)) set.insert(cls); if (addMeta) //元类插入到所有类表中 addClassTableEntry(cls->ISA(), false); }