The application loads examples

  1. Create a simple project to add print to the entry main function1223333, plus a c++ function called kcFunc(), and a load() method on the viewcontroller

C++ function 3 is called. Load is called. C++ function 3 is called. Finally, enter main and print 1223333

3. I don’t understand why I called load and c++ functions before entering main, which is the entrance of app. Tell me what the system did before the app started.

1.1, libraries,

Every application relies on some basic library, such as UIKit, CoreFoundation, etc. Libraries are executable binaries that can be loaded into memory by the operating system. There are two types of libraries, static libraries (.a,.lib) and dynamic libraries (.so,.dll), the main difference between the two libraries is the link.

  • Static libraryThe static library is loaded at compile time and copied to the executable in its entirety when linked. The static library does not change because it is copied directly at compile time.copyTo the target program.
    • Advantages: Compiled executables do not require external library support and can be used directly.
    • Disadvantages: If multiple apps are used, multiple copies will be made. They cannot be shared and occupy more redundant memory. All functions are in the library, so you need to recompile them when you modify them.

  • The dynamic library: a programIt does not link to the target program at compile timeThe target program will onlyStores references to dynamic libraries, dynamically loaded into memory by the system while the program is running.
    • Advantage:

      • Reduce the size of the packaged APP: because it does not need to be copied to the target app, it does not affect the size of the target app, which reduces the size of the APP compared to the static library
      • Shared memory saves resources: The same library can be used by multiple programs
      • The purpose of updating the program is to update the dynamic library: because of features that are loaded at runtime, the library can be replaced at any time without the need to recompile the code
    • Disadvantages: Dynamic loading incurs a performance penalty. Using dynamic libraries also makes the application dependent on the external environment. If the environment lacks dynamic libraries, or the version of the library is incorrect, the application will not run

The build process

The source fileH,. M, and. CPP files are loaded

precompiled: Replaces macros, deletes comments, expands header files, and generates.i files

compileThe compiler converts the. I file into assembly language, producing. S files

assembly: Converts assembly files to machine code files to generate. O files

link: References other libraries in the.o file to generate the final executable

The compilation process is shown in the figure below, which is mainly divided into the following steps:

  • The generated executable file

dyly

My understanding is that the executable file is linked to the library of the mobile phone system. The executable file can be dynamically linked to some system libraries to run on the mobile phone.

Dyld full nameThe dynamic link editor. It isApple's dynamic linkerIs an important part of Apple operating system. After the application is compiled and packaged into an executable file format, DyLD is responsible for linking and loading programs.

  • Runtime register callback function:_dyld_objc_notify_register(&map_images, load_images, unmap_image);
  • Image: image file after library mapping,
    • Mapping: Copy a copy from disk to memory
  • Do an extension tip to find the system library files.
    • 1. Breakpoint (any breakpoint)
    • 2.LLDB enter the image list command
    • 3. Search CoreFoundation

    • 4. Copy the path to the file to find the system library.

    • 5. I have this on the simulator.

2 dyld process

  • 1. Add the +load method to the controller and set a breakpoint. LLDB BT printing function stack, look at the left stack printing, in fact, is one – to – one correspondence.
  • The process is basically this
    • 1._dyld_start
    • 2.dyldbootstrap::start
    • 3.dyld::_main
    • Dyld ::useSimulatorDyld ::useSimulatorDyld ::useSimulatorDyld
    • 5.start_sim
    • 6.dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*)
    • 7.dyld::initializeMainExecutable()
    • 8.ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&)
    • 9.ImageLoader::processInitializers(
    • 10.ImageLoader::recursiveInitialization
    • 11.dyld::notifySingle
    • 12.load_images

  • APP loading process
    • 1. Start the app
    • 2. Loading libSystem
    • 3.Runtime registers the callback function with dyLD
    • 4. Load new image
    • 5. Run map_images and load_images
    • 6. Call main
  • Now let’s make a breakpoint at the main entrance. Go over the last breakpoint and go over here, and this is the entry point to the program, indicating that the controller was loaded before the program came in.

The target looks at what the program load does from dyldstart -> main

  • 1. Just figure out what the paragraph does.

  • 2. Download DYLD 852

The source address

  • 3. Load is called before main

  • Load -> LLDB bt
    1. frame #12: 0x00000001130d4025 dyld_DYLD_START + 37 ‘knows this is the dyLD entry

1. Find your goal

  • 1. Find assembler _dyLD_start

  • 2. Find the target, different architectures, different choices, but the main process is the same.

  • 3. This function is calleddyldbootstrap::start(app_mh, argc, argv, dyld_mh, &startGlue)

  • 4. Search nextdyldbootstrapThat’s the namespace, and I’m going to keep finding itstartMethod to find that it is returneddyld::_mainThe result of the function. C++ syntax problems. Similar to the start method of the dyldBootstrap class.

  • 5. Return _main

  • 6. Go to main

1000+ lines of code for selective viewing learning

2. Enter the main function in the main flow

  • Step 1 – Conditions: Environment, platform, version, path, host information…

      1. getHostInfo(mainExecutableMH, mainExecutableSlide);Preparation of architectural information
      1. Image file platform information

      1. The file path

    • checkEnvironmentVariables(envp); // Check the environment variables set

    • defaultUninitializedFallbackPaths(envp); // If DYLD_FALLBACK is nil, set it to the default value

    • The environment variable DYLD_PRINT_OPTS is printed if set, and the environment variable DYLD_PRINT_ENV is printed if set

    1. Load the shared cache, system level processing.
    • 2.1 callcheckSharedRegionDisableFunction checks and loads shared cache libraries (iOS cannot disable shared cache libraries)

    • mapSharedCache(mainExecutableSlide);Check whether the shared cache maps to the shared region

  • 3.addDyldImageToUUIDList();Add dyly itself to the UUID list

  • 4. The main program initializes sMainExecutable

    • 4.1 We infer from the backwardness of resultsMainExecutablecreate

    • 4.2. Push back tosMainExecutableCreate by looking at the source view, combined with the function call stack, we follow in the call process to findsMainExecutable

      • Load the executable and generate an ImageLoader instance object

  • 5. Load and link the dynamic library

    • 5.1loadInsertedDylib(*lib);Load the inserted dynamic library and iterateDYLD_INSERT_LIBRARIESEnvironment variable, callloadInsertedDylibloading

    • 5.2. Link library

      • Through:sInsertedDylibCount
      • ImageLoader* image = sAllImages[i+1];
      • link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1);Link inserts a dynamic library
      • this->recursiveApplyInterposing(context);Insert any dynamically loaded image files

  • 6. The link of the main program

  • 7. WeakBind weak reference binding main program

  • 8. Initialize the main program and run all initializers

  • 9. Address the main program entry

  • Listen to Dyly’s main notifyMonitoringDyldMain();

3. The main program runs process initializeMainExecutable();

Now we probe into the main program initialization what did sMainExecutable said the main program variables, view its assignment, is the method instantiateFromLoadedImage initialization

1.instantiateFromLoadedImage->instantiateMainExecutable

  • Enter theinstantiateFromLoadedImageThe function view

  • Enter theinstantiateMainExecutableThe function view

  • Among themIn the sniffLoadCommandsIs to get a Mach-O type fileLoad CommandAnd carry out all kinds of verification on it.Determine if this Mach-O file has a compressed LINKEDIT and the number of segments

  • Enter theIn the sniffLoadCommandsThe function view

2. Run the main program

After the main program initialization is complete and the main program is running, we return the code back here initializeMainExecutable();

  • Enter theinitializeMainExecutable()To view
    • Insert dynamic library traversals with runInitializers
    • Main program calls runInitializers

  • Global search entryrunInitializers()To view

  • 1. Initialization preparation: processInitializers Preparation Image files are ready
    • 1. Enter theprocessInitializersFunction source code implementation, which on the mirror list callrecursiveInitializationFunction is instantiated recursively

    • 2. RecursiveInitialization dependence on the underlying file to load

    • NotifySingle ->2. DoInitialization, then notifySingle


  • So let’s look for thiscontext.notifySingle
  • To find the(*notifySingle)(dyld_image_states, const ImageLoader* image, InitializerTimingList*);

  • Global search to find here

  • Global searchsNotifyObjCInit, found no implementation found, assignment operation

  • To viewregisterObjCNotifiersCall timing of_dyld_objc_notify_registerA function call

  • Call this method in objC_init of the OBJC source library.

  • Let me rearrange the order
    • context.notifySingle -> (*sNotifyObjCInit)
    • SNotifyObjcInit is assigned to init in the registerOBjCNotifiers call, that is, sNotifyObjcInit = init
    • _dyly_objc_notify_register calls the registerObjCNotifiers, init = init
    • _dyly_objc_notify_register passes three parameters
      • &map_images
      • load_images
      • unmap_image
    • We get load_images = init = sNotifyObjcInit

load_images

  • load_images -> call_load_methods()

  • prepare_load_methods
    • classref_t const *classlist = _getObjc2NonlazyClassList(mhdr, &count); Get a list of all the loaded classes

    • Traversal: schedule_class_load

      • (CLS ->superclass) (CLS ->superclass)
      • Add_class_to_loadable_list adds this class’s load method to the list
    • classref_t *classlist = getObjc2NonlazyClassList(mhdr,&count);

  • Enter the viewcall_load_methodsLoop callcall_calss_loads()There arecall_category_loads();Classification of the load

  • Enter thecall_calss_loads()See what is called hereloadMethod validates the class we mentioned earlierloadMethod,

  • Objc_autoreleasePoolPush () pushes the pool automatically

  • class_class_loads()

  • call_category_loads()

  • Objc_autoreleasePoolPop (pool); Out of the stack

  • So load_images calls all the load functions, and the above source code analysis corresponds exactly to the printed stack information

map_images

-> map_images_nolock -> _read_images

  • Class gdb_objc_readied_classes
  • Methods nameSelectors
  • Agreement protocol_map
  • The main role
    • Initialize class: realizeClass sets RW/RO
    • Processing classes: Add methods, protocols, and attributes from a class to a class
    • Load the corresponding hash table

Now the sNotifyObjcInit can only be assigned if you know to start calling objC_init. NotifySingle

  • Global search is completely absent

  • So let’s play that for a seconddoInitialization

doInitialization

  • Now let’s go backthis->doInitialization(context)Image file initialization look at line 1657,

  • Enter thedoInitializationYou see that two methods are called. 1.doImageInit(). 2.DoModInitFunctions ()We don’t know what they’ve been up to

  • Enter thedoImageInit(context)Check and find this.Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);// Mach-o address offset, get a function,libSystemInitializedLibSystem initialization must not be abandoned in advance

  • Enter doModInitFunctions (context); Dylib ‘libSystem_initializer:-> -libdispatch_init :-> – _os_object_init(libdispatch.dylib)-> – _objc_init(libobjc)

  • The stack information here prints out a reminder to look at this.

Enter thedoModInitFunctionsSource code implementation, this method loaded allCxxfile

  • inlibsystemLook forlibSystem_initializerTo see the implementation \

  • Based on the previous stack information, we find that the path islibSystem_initializerWill calllibdispatch_initFunction, and the source of this function is inlibdispatchOpen source library, inlibdispatchIn the searchlibdispatch_init\

  • Enter the_os_object_initSource code implementation, its source code implementation called_objc_initfunction

  • So the whole idea is to look at the function call stack to explain this process, and find the corresponding source code to learn.

4. Flow chart interpretation

Refer to blog – Month big guy