We all know that the entry function of an APP is main(), but what happens to the APP loading process before main() is called? Next, let’s analyze the APP loading process.
I. Preparation
Since load() is called earlier than main(), we create a project, write a load() function in the controller, and run it at a breakpoint, as shown below:
Dyld :notifySingle(); dyld:notifySingle(); dyld:notifySingle What is it doing?
Simply put, dyld is a dynamic linker that loads all libraries and executables. Next, we will trace what DyLD does by analyzing the dyld source code.
2. Analysis of dyLD loading process
1. Download firstDyld source.
2. Open the dyld source project, according to the figure abovedyldbootstrap::start
Search for the keyworddyldbootstrap
In the callstart()
, as shown below:
3. Enter the dyldstart
function
RebaseDyld () is analyzed as follows:
4. Enter the dyldmain
function
Note: Because the dyld::main() function has a lot of code, the following sections will cover it, as well as the more important functions.
4.1 Kernel Detection
4.2 Obtaining the cdHash Cache of the Main execution file
4.3 Obtaining CPU Information
// Obtain the CPU information
getHostInfo(mainExecutableMH, mainExecutableSlide);
Copy the code
4.4 Setting MachHeader and Memory Offset
// Set the MachHeader and the memory offset Slide
uintptr_t result = 0;
sMainExecutableMachHeader = mainExecutableMH;
sMainExecutableSlide = mainExecutableSlide;
Copy the code
4.5 Setting context
// Set the context and save the information
setContext(mainExecutableMH, argc, argv, envp, apple);
Copy the code
4.6 Configuring Process Restriction
4.7 Checking Environment Variables
4.8 Printing Environment Configuration Information
// Prints the environment configuration information
if ( sEnv.DYLD_PRINT_OPTS )
printOptions(argv);
if ( sEnv.DYLD_PRINT_ENV )
printEnvironmentVariables(envp);
Copy the code
Here you can define your own environment variable configuration, go back to the new project you created, Add DYLD_PRINT_OPTS and DYLD_PRINT_ENV to the Edit Scheme -> Run -> Arguments -> Environment Variables and set the test value as below:
Run the program, you can see the following printed information:
4.9 Loading shared cache (iOS will not run without shared cache)
The main function mapSharedCache() is as follows:
4.10 dyld
configuration
(1) dyld3
(Closure mode)
After iOS11, dyld3 ClosureMode (ClosureMode) was introduced: faster and more efficient loading.
Start executing closure mode
Determine whether closure mode is enabled
Start closure mode loading
The launchWithClosure() function encapsulates most of dyld2’s process in the launchWithClosure() function. I won’t talk about launchWithClosure in detail. This is because the whole process of dyLD loading is explained in detail in dyLD2 (non-closure), which is the launchWithClosure implementation.
(2) dyld2
(Non-closure mode)
Start executing closure mode
Add dyld to the UUID list
// Add dyld to UUID list
addDyldImageToUUIDList();
Copy the code
Configuring the Cache Proxy
4.11 Create the Image of the main program
Start to create the Image of the main program, through the instantiateFromLoadedImage (), call instantiateMainExecutable (), instantiate the concrete Image, finally generated object, set in the gLinkContext.
4.12 Setting the Version of the Dynamic Library
// After loading the shared cache, set the version of the dynamic library
checkVersionedPaths();
Copy the code
4.13 Loading the Inserted dynamic library
// Load the inserted dynamic library
if( sEnv.DYLD_INSERT_LIBRARIES ! =NULL ) {
for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib ! =NULL; ++lib)
loadInsertedDylib(*lib);
}
Copy the code
4.14 Link the main program to the dynamic library
- One of the
link()
Function, function body calledimage->link()
, the function is as follows:
- Determine if all images need to be reloaded
4.15 Bind the main program to the dynamic library
4.16 Initialize the main program
According to the stack information in Demo, it is as follows:
Now that you’ve finally seen the familiar functions, the dyld loading process is almost over. Gets the function call hierarchy based on the stack information.
// Initialize the main program
initializeMainExecutable();
Copy the code
- To find the
runInitializers()
:dyld::initializeMainExecutable()
->ImageLoader::runInitializers()
- To find the
processInitializers()
:ImageLoader::runInitializers()
->ImageLoader::processInitializers()
- To find the
recursiveInitialization()
:ImageLoader::processInitializers()
->ImageLoader::recursiveInitialization()
- To find the
notifySingle()
:ImageLoader::recursiveInitialization()
->dyld::notifySingle()
- To find the
load_images()
In:dyld::notifySingle()
Is not found inload_images()
“, but found itsNotifyObjCInit()
, this field is an objc function callback. indyld::notifySingle()
We need to trace back to who registered the callback. - Global search
sNotifyObjCInit()
Where the value is assigned. inregisterObjCNotifiers()
, as follows:
- Global search
registerObjCNotifiers
In the_dyld_objc_notify_register()
And the second argument is what we need. As follows:
- Global search
_dyld_objc_notify_register()
Not found in the dyld source repository. In this case, you need to sign a breakpoint in the source project_dyld_objc_notify_register
, recompile execution, you can see is_objc_init()
The call. You can only look for itObjc source. objc
Source code analysis, inobjc-os.mm
In the file_objc_init()
Function in which the_dyld_objc_notify_register
The callback.
The second parameter is load_images(), and call_load_methods() is also found in load_images().
Had been completes initialization program at this time to go back to the previous ImageLoader: : recursiveInitialization () method.
- perform
this->doInitialization()
function
- Send a notification that the initialization main program is complete.
4.17 Enter the main program
// Tell the process to enter the program main()
notifyMonitoringDyldMain();
Copy the code
Start () -> main()
3. To summarize
- Dyld (dynamic linker) : an important part of apple’s operating system that loads all libraries and executables.
- Dyld loading process:
- from
_dyld_start()
Start – >dyldbootstrap::start()
- Enter the dyld
main()
- Check the kernel and configure the redirection information:
rebase_dyld()
- Loading the shared cache
dyld2
/dyld3
(Closure mode)- Instantiate the main program
- Load dynamic link library (main program and dynamic library image will load allImage:
loadAllImage
, the main program in the0
Location) - Link main programs, dynamic libraries, binding symbols (non-lazy loading, weak symbols), etc
The most critical
: Indicates the initialization methodinitializeMainExecutable()
ImageLoader::runInitializers()
ImageLoader::processInitializers()
ImageLoader::processInitializers()
ImageLoader::recursiveInitialization()
dyld::notifySingle()
- This function performs a callback
_dyld_objc_notify_register()
- Debug by breakpoint: This callback is
_objc_init()
A function assigned on initializationload_images()
, which is implementedcall_load_methods()
Function that loops through the methods of each class.
- This function performs a callback
doModInitFunctions()
Function: the constructor of the global C++ object is called internally__attribute__((constructor))
The C function
- Return to the main program entry and execute
main
function
- from