There have been several recent articles on binary rearrangement boot optimization. In all scenarios, all function calls need to be counted up front and code rearranged based on the frequency of function calls.

Of these function calls, the OC object has the most method calls. Method calls to count OC objects can be Hook all objc_msgSend calls at run time through third-party libraries such as FishHook, or Hook interception can be done statically before compiling and linking.

Generally, there are two schemes for static pile insertion:

  1. Using LLVM syntax tree analysis to achieve code staking.

  2. Compile the source code into a static library, and implement code staking by modifying the snippet of the.o object file in the static library.

The above two methods are complex to implement, and you need to either understand LLVM or be familiar with the underlying knowledge of object file intermediate bytecodes and symbol tables.

This article introduces the third static Hook scheme, which also relies on the premise of static library to Hook objc_msgSend function, so as to achieve the OC object method call peg before compilation.

The implementation principle of this scheme is simple. Because the static library is just a compilation phase of intermediate, static library target file all the references in the external symbol will be saved to a string table, all function calls are recorded the function name in the index position of the string table, when the link will be according to the symbolic names to replace with real function call instruction. So we can replace objc_msgSend in all static library string tables with another string of the same length: hook_msgSend(any name as long as the length is consistent and unique). Then implement a function named hook_msgSend in the main project source code. This function must be consistent with objc_msgSend’s function signature, so that all static library objc_msgSend calls are converted to hook_msgSend calls at link time.

The following are the specific implementation steps:

1. Write implementation of hook_msgSend in the main project.

The hook_msgSend function signature must be consistent with objc_msgSend, implemented in main project code, and must be implemented in assembly code. The implementation logic is the same as the Hook implementation of the objc_msgSend function introduced in many articles.

Many implementations of Hook objc_msgSend are incomplete, so for a complete grasp of the ABI rules for function calls, see: Function Calls in the iOS System

2. Uniformly compile all other code into one or more static libraries.

Source code is functionally compiled into one or more static libraries, and the main project links these static libraries. The most common way to organize your code is through cocoapods, a code-dependency integration tool that I won’t describe here.

3. Add the Run Script Script to Build Phases of the main project.

We need to ensure that this script is executed before linking all static libraries. So it can be put under Compile Sources.

4. Static library symbol replacement Run Script Script.

This is the most critical step, we can implement a symbol substitution program, and then execute the symbol substitution program in the Run Script Script. The input parameter to the symbol substitution program is the path to all static libraries linked in the main project. There is no limit to how this symbol substitution program can be written, you can write it in Ruby, you can write it in Python, you can write it in C. Either way, you need to first understand the file structure of the static library. A. You can learn the structure of a static library file from the article “Deep Into the Static library of iOS system”. Once you know the structure of the static library file, what your symbol replacement program does can be done as follows:

Open the static library. A file.

Find the string table section in the. A file. The string table is described as follows:

struct stringtab { int size; // String table size char strings[0]; // The contents of the string table, with each string delimited by \0. };Copy the code

The contents of strings in the string table are strings separated by \0, and the contents of these strings are actually all the external and internal symbol names referenced by the object file.

Replace objc_msgSend with hook_msgSend in the string table.

Save and close the static library. A file.

5. Compile, link, and run your main project.


The advantage of using the static Hook approach described in this article is that instead of Hook all OC method calls, we can selectively intercept method calls for specific objects and classes. This technique can therefore be applied not only to code rearrangement statistics, but also to other monitoring and statistical applications. Because this mechanism can avoid the problem of function call storms that occur when the program does the objc_msgSend substitution at run time. Another point is that this method is not limited to Hook objc_msgSend, but can Hook any other function. So this technology can be used in other ways as well.