The previous post looked at message forwarding. This post explores what our APP does when it launches. Does the APP launch directly into the main function? When does the runloop start before main happen? Take a sneak peek at Dyld today.

The preparatory work

  • libdispatch
  • Libsystem
  • objc4
  • dyld

foreplay

Before we explore that, how do we find the process of loading an application? I think a lot of people think about break mode, but where should we break? Is it in main? So let’s try it:

We can see that we can’t see the loading process, we just know that main called start before main, so we can’t see the actual loading process, and we know that the load method loads before main, so can we put a breakpoint in the load function? As expected, we create an empty project, add a breakpoint to main, and then implement the load function in viewController.m with a breakpoint. Then let’s run the project and see what happens:

We can see that the load breakpoint does go ahead of the main breakpoint, and look at the stack information on the left. It starts with _dyLD_start and then loads after load_images. So let’s see what happens.

Dyld source exploration –_dyld_start

1. Search globally for _dyLD_start and you will find the following code:

__i386__ = _dyLD_start = __i386__ = __i386__ = __i386__ = __i386__ = __i386__ = __i386__

# call dyLDbootstrap ::start(app_mh, argc, argv, dyLD_MH, &startglue) We can see from the function format that this is a C++ function, so we can search the dyldbootstrap namespace directly and find the implementation of the start function:

4. We can see that this section mainly does some processing of macho_header and then calls the main function of dyld. The main function of this section is not the main function of our program main.m.

  • Additional knowledge points

    Macho_header: this is part of the Mach-o executable file, which is its header. We can open a mach-o running APP with MachOView and see something similar to the following:

    2. Mach-o generally consists of the following three parts:

    • Header: This contains some basic information about Mach-o, including platform, file type, number of instructions, total size of instructions, dyld flag Flags, etc.

    • Load Commands: This data is used when loading Mach-o files following headers to determine memory distribution and guide system kernel loaders and dynamic linkers.

    • Data: The specific Data of each segment is stored here, including specific code, Data, and so on.

Dyld source exploration –_main

1. Test and prepare the running environment, etc.

2. Dyld starts to load

3. Share the cache

4. Initialize the main program

5. Load libraries

6. Linked libraries

7. Run all initialization methods

8, find the main function of the main program

9, through the above main program entry to the main function.

sMainExecutable

1, we looked at dyld loading process, see through instantiateFromLoadedImage sMainExecutable is get, then we look at the realization of the function:

2, in the above function through instantiateMainExecutable capturing the initialize a ImageLoader type of object, then we look at the function of concrete realization:

3. As you can see from apple’s comment, this function is used to create an image of the main program, and then obtain the segCount and libCount of the Mach-o file for verification in the main function of dyld, and also to instantiate concrete classes based on the contents of the load command.

initializeMainExecutable

This function runs all initializations, so let’s look at the implementation of this function:

The main function in this function is to run the Initialzers for any inserted dylibs, then we’ll move on to runInitializers:

The processInitializers function is called in the processInitializers function. Let’s look at the code below:

In this function, recursive init is called for all images in the list of images to build a new list of uninitialized dependencies. Then let’s look at recursiveInitialization:

5. In this function we can see that it first determines if the dependency is up, then notifies objC that it is going to initialize, then initializes, and finally notifies all listeners that the initialization is complete.

6. We will focus on preparing the initialization, initializing, and notifying the initialization to complete.

notifySingle

1. In the process above, we see that both the preparation and completion of initialization are notified by a notifySingle, so let’s look at the implementation of this function:

2. In this function, we look at sNotifyObjCInit, and then we look at the implementation:

This function is not implemented, but initialized in the registerObjCNotifiers, so let’s take a look at where the registerObjCNotifiers are called:

This function _dyLD_objC_notify_register is called at the same time. After searching for the method, I did not find it, so I looked at the annotation information of the method, and found a more useful one, as follows:

5. The comment explicitly states that it is only for use by the OBJC runtime, so I immediately thought of the objC source code, so I searched in the objC source code and found the following code:

6. Then we can come to the following conclusion:

SNotifyObjCMapped = mapped = &map_images; sNotifyObjCInit = init = load_images; sNotifyObjCUnmapped = unmapped = unmap_image;Copy the code

Objc_init starts the _dyLD_OBJC_notify_register function of dyld and loads the image file.

conclusion

In this article we’ve taken a look at some of the processes that dyld uses to load an image file. We know that this is called with objc_init, so when is this called? Listen to the next analysis.