4. IOS enhancements – links and symbols

Time:2022-1-11

First, let’s understand what links are:

  • The essence of linking is to combine one or more target files and the required libraries (static / dynamic libraries, if necessary) into one file(Mach-OExecutable file)
    usually.oThe file is called the target file.
    Let’s take a look at the generation process of the target file:
4. IOS enhancements - links and symbols

image.png
  • Here we should pay attention to:
    In the process of generating the target file
    1. Linker(llvm-ld)Not implemented.
    2. The target file does not containUnixThe program is beingloadandimplementThe information that must be included when.
    So what exactly does the above sentence mean?
    Next, let’s explore:
    First of all, we areMach-o fileThis article has a simple understandingMach-oThe format of the file, here we will deepen our impression, here we will print it through the terminalMach-oSome relevant information.
    1. Prime minister, we set up a command line projecttest, introduce a script into the projectScript address, the configuration is as follows:
    4. IOS enhancements - links and symbols

    image.png

2. Create our ownxcconfigFile (students who do not understand this step can read itConfiguration of Xcode multi environmentThis batch of articles)
3. InxcconfigEnter some parameters to be used in the script in the file (Note: 1. Not here)shellInstruction is in the form of key value. 2. We haven’t written any code at this time)

Two variables need to be entered in the script:
CMD: instruction
and
TTYEnter the specified terminal (terminal can be used):tty, the information of the current terminal will be printed)

At the same time, we also need to know the current situationMach-OAddress of:

MACH_PATH=${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/${PRODUCT_NAME}
  • MACH_PATH: we define our own variables to storeMach-OAddress of
  • ${BUILD_DIR}: the path of the current compilation
  • $(CONFIGURATION): build a catalog of products
  • $(EFFECTIVE_PLATFORM_NAME)Mach-ODirectory where
  • ${PRODUCT_NAME}: project name, i.eMach-OName of

① First, let’s print itMach header

//View Mach header
CMD = objdump --macho -private-header ${MACH_PATH}

4. IOS enhancements - links and symbols

image.png

Here you can seeMach headerSome original information.
② Now let’s take a lookMach-oInside__TEXTParagraph (because:mainAfter the function is compiled, it will be placed in__TEXT(of segment)

4. IOS enhancements - links and symbols

image.png

You can see the displayed__TEXTParagraph__text sectionMachine instructions (e.g.:55), the assembly code followed is for developers.
At the bottom, there will be something similar to a dictionaryAssembly instructionandMachine codeOne by one
Here we aremain.mAdd some code to the file. Let’s have a look__TEXTSnippet (code snippet):

///Global variable
int global_uninit_value;

int global_init_value = 10;
//__ attribute__ Keyword is mainly used to set its properties in function or data declaration. The main purpose of assigning attributes to functions is to let the compiler optimize.
double defaule_x __attribute__((visibility("hidden")));
///Static variables - local symbols
static int static_uninit_value;

int main(int argc, const char * argv[]) {
    static_uninit_value = 10;
    NSLog(@"%d", static_uninit_value);
    return 0;
}

4. IOS enhancements - links and symbols

image.png

We’ll find out__TEXTThere are a lot of things in the paragraph.
Can seeNSLogIt just becomescallq 0x100003f90Instruction, an instruction with a definite address.

  • In fact, it is compiled and generated.oIn the process of filing the document, such a thing has been done:
    1. Can become assembly, try to become machine code
    2. Symbol classification (e.g. putting data into data segments, etc.); Another exampleNSLog, when generating the target file, we don’t know its address. At this time, we need to send it to a place temporarily. After classifying the symbols, put them inRelocation symbol tableInside.

  • WhyRelocation symbol tableInside?
    1. Because it’s generating.oFile time, the entire addressNo Virtualization (address of virtual memory)
    2. In generation.oIn the process, we link symbols, some of which we know its location (such as:global_init_valueBecause in the same placeMach-oIn, we can passOffset addressGet the symbol directly); However, there are some import symbols that we do not know (for example:NSLog
    in other words:Relocation symbol tableWhat’s in it.oThe API used in the file is not used here.
    sinceRelocation symbol tableWell, then we can pass the inspection.oIn the fileRelocation symbol tableTo view the use of an API in the file.

  • next.oWill enter the link process to handle our compilation; Will generate multiple.oThe files are merged into one, which means that everyone’s symbol table (including relocation symbol table) will be merged into one table.

  • Finally, the executable file (exec) is generated

  • So what we call links is processing.oProcess of symbols in files

Global and local symbols

Combined with the above code:

  • Global symbol:int global_uninit_value;
    The global symbol is visible to the entire project and to the project that uses it
  • Local symbols:static int static_uninit_value;
    The local symbol is visible only to the file that defines it

Next, let’s look at the symbol table:

//View symbol table
CMD = objdump --syms ${MACH_PATH}
4. IOS enhancements - links and symbols

image.png

There is a difference in the figure above. I wonder if you have noticed:
defaule_xThis symbol we define is a global symbol, but in the end it is a global symbolLocal symbol, why?
Because we wrote this:

double defaule_x __attribute__((visibility("hidden")));

Here we will introducevisibilityProperties:

//Visibility property, which controls the export of symbols from the file and limits the visibility of symbols
/**
    -Fvisibility: clang parameter
    Default: the symbols defined with it will be exported.
    Hidden: symbols defined with it will not be exported.
 */
//Hide - > local
int hidden_y __attribute__((visibility("hidden"))) = 99;
//Symbols
double default_y __attribute__((visibility("default"))) = 100;

Here’s an explanation. We often encounter methods abandoned by apple in development. There will be a yellow line warning. In fact, this attribute is also used.

Import & Export symbols

Or the code above, we used itNSLog(it exists inFoundationDynamic library); So for our own executableNSLognamelyImport symbol; aboutFoundationDynamic libraryNSLognamelyExport symbol
Which meansExport symbolyesGlobal symbol
Now let’s print itExport symbol

//View exported symbols
CMD = objdump --macho --exports-trie ${MACH_PATH}

4. IOS enhancements - links and symbols

image.png

You can see that it exactly corresponds to the global variable we set.
In daily development, we should pay attention to: when we set the variable to global variable, it means that it will be set to global variable by defaultExport symbol

  • Here we add,Indirect symbol tableIt holds our currentExecutable fileOther dynamic libraries usedExport symbol
    Now let’s print itIndirect symbol table
//View indirect symbol table
CMD = objdump --macho --indirect-symbols ${MACH_PATH}
4. IOS enhancements - links and symbols

image.png
  • There’s a problem here. We’re herestripWhen the symbol is stripped,Indirect symbol tableWe can’t peel off the symbols of the inner surface. If we push up in turn, it means that we can’t peel off the symbols we don’t expose when writing our own OC dynamic library. Here to tell you, the default symbols of OC areGlobal symbol, and the global symbol isExport symbol, let’s verify:
    4. IOS enhancements - links and symbols

    image.png

    4. IOS enhancements - links and symbols

    image.png

    Then let’s print itExport symbol

//View exported symbols
CMD = objdump --macho --exports-trie ${MACH_PATH}
4. IOS enhancements - links and symbols

image.png
  • Do not export symbols
OTHER_LDFLAGS=$(inherited) -Xlinker -unexported_symbol -Xlinker _OBJC_METACLASS_$_YSOneObject
4. IOS enhancements - links and symbols

image .png

We succeeded in putting the symbol_OBJC_METACLASS_$_YSOneObjectSet to non exported symbol
In this way, we can align and split symbols to further reduce the volume of the dynamic library; At the same time, the outside world can’t see our symbols.
⚠️ In development, we don’t have to set symbols to not export one by one. We can specify a file to set the export properties of symbols and use-unexported_symbol_listThis instruction

  • We can also view all the symbols we use and write them to the corresponding files:
OTHER_LDFLAGS=$(inherited) -Xlinker -S -Xlinker -map -Xlinker /Users/aaron/Desktop/test-02/Source.text
4. IOS enhancements - links and symbols

image.png
Weak symbol

Weak symbols are divided into:

  • Weak reference symbol: indicates that this undefined symbol is a weak reference. If the dynamic connector cannot find the definition of the symbol, set it to 0. The linker sets this symbol as a weak link flag.
  • Weak definition symbol: indicates that this symbol is a weak definition symbol. If a static or dynamic linker finds another (non weak) definition for this symbol, the weak definition is ignored. Only symbols in merged sections can be marked as weak definitions.

So how do you understand the above two sentences?
First, let’s look at how to write in the code:

//Weak reference
void weak_import_function(void) __attribute__((weak_import));

//Weak definition
// weak def
void weak_function(void)  __attribute__((weak));
//Weak local symbol
void weak_hidden_function(void) __attribute__((weak, visibility("hidden")));

First, let’s look at:

  • Weak definition symbol
    amongweak_functionDefining symbols for global weak;weak_hidden_functionDefine symbols for local weak.
    Next, let’s look at the symbol table:
CMD = objdump --macho --exports-trie ${MACH_PATH}

4. IOS enhancements - links and symbols

image.png

Can seeWeak definitionDoes not affect its actionsExport symbol
Then we define a military symbol with the same name in other places, as follows:

4. IOS enhancements - links and symbols

image.png

We will find that the project will not report errors. There is no problem running, which is what we said above: if the static linker or dynamic linker finds another (non weak) definition for this symbol, the weak definition will be ignored.

Next, let’s look at:

  • Weak reference symbol
    First of all, we only declare that we do not realize:
void weak_import_function(void) __attribute__((weak_import));

Same viewExport symbol table

4. IOS enhancements - links and symbols

image.png

We’ll find outExport symbol tableThere is no sign in it.
Next, we implement the following function:

void weak_import_function(void) {
    NSLog(@"weak_import_function");
}

Then check it againExport symbol table:

4. IOS enhancements - links and symbols

image.png

This means that when the dynamic linker cannot find its definition, it will be defined as 0 and will not appear in theExport symbol tableInside.

  • In that case, we only declare and do not define the symbol. By judging whether the symbol is 0, do something?
if (weak_import_function) {
        weak_import_function();
        
        /**
         Some other business
         */
    }

Wecmd + BIt will be found that the project reports an error:

4. IOS enhancements - links and symbols

image.png

In other words, in the process of linking, the linker can’t find the symbol (I don’t know where the symbol is).

At this time, we can tell the linker to ignore the symbol, even if it is undefined. My symbol isdynamic linkYes, I’ll find this symbol myself. Then we can achieve this through the following instructions:

OTHER_LDFLAGS=$(inherited) -Xlinker -U -Xlinker _weak_import_function

Re export symbols

For example:
Where is the code abovemian.mUsed in the documentNSLogThis function. howeverNSLogIt is a challenge for the current projectUndefined symbol

4. IOS enhancements - links and symbols

image.png

At this time, if we want to use the project of our library, we can also use itNSLogAt this point, we need toNSLogExport from as an alias.
⚠️ Note here: onlyIndirect symbol tableAliases symbols in.

OTHER_LDFLAGS=$(inherited) -Xlinker -alias -Xlinker _NSLog -Xlinker YS_NSLog

Let’s look at the export symbol table again:

4. IOS enhancements - links and symbols

image.png

You can see itYS_NSLogAsExport symbol, and marked asre-export

Swift symbol

First of all, we areswiftSome are defined in the filestructural morphologymethod

struct YSSwiftStructSymbol {
    func testSwiftStructSymbol(o: Int) {}
}

private protocol YSSwiftProtocolSymbol: class {
    func testSwiftProtocolSymbol()
}

private class YSSwiftClassSymbol {
    func testSwiftSymbol() {}
}

Next, let’s look at the current symbol table:

//View symbol table
CMD = objdump --syms ${MACH_PATH}

4. IOS enhancements - links and symbols

image.png

You will find a lot of symbols in it.
So let’s find the directionswiftGenerated symbols:

CMD = objdump --syms ${MACH_PATH} | grep "SwiftClass"

4. IOS enhancements - links and symbols

image.png

This is much less, and all are local symbols. Let’s revise itswiftPermissions for methods in:

public class YSSwiftClassSymbol {
    func testSwiftSymbol() {}
}

Check it againswiftSymbol:

4. IOS enhancements - links and symbols

image.png

You can see that some symbols have becomeGlobal symbol

Conclusion: Swift is a static language, which is different from OC. Swift can determine the category of symbols when compiling.