Introduction to the

In this article, you will learn how to embed assembly code in C or Objective-C projects. In this article, you will learn how to embed assembly code in C or Objective-C projects.

Pay attention to

When debugging an ARM assembly, Xcode’s Build object must be a real machine or an x86 assembly if the object is an emulator.

Inline assembly

Assembles indirect communication with C

Assembly code can be directly inserted into a function to affect the running logic of the function. The syntax is __asm__. Assembly code may be ignored by the compiler, so __volatile__ is added to ensure the effectiveness of assembly code.

To give a simple example, let’s say we want to implement a simple function that doubles the value.

int double_num(int num) {
    return num * 2;
}
Copy the code

Let’s double the value of num in inline assembly.

int double_num(int num) {
    __asm__ __volatile__(
        "lsl x0, x0, 1\n"
        "str x0, [sp, #12]\n"
    );
    return num;
}
Copy the code

LSL is a left-shift instruction, x0 stores the value of the input parameter num. Since this function does not call other functions, there is no need to protect the field. There is only one input parameter of int type, which requires 4 bytes. So the num variable will be stored in the sp+12~sp+16 area of the high address, so it will be retrieved from sp+12 when the function returns. We can use STR instruction to store the doubled value in the corresponding area.

Assembler communicates directly with C

In the above example, in order to use the computed value as the return value, we used the static method of calculating the variable address. Here we use another method, which stores the result of the assembly directly in the C variable. For example, the following function doubles the input value several times.

int double_num_times(int num, int times) {
    int ret;
    __asm__ __volatile__(
        "lsl x0, x0, x1\n"
        "mov %0, x0"
        : "=r" (ret)
        :
        :
    );
    return ret;
}
Copy the code

Here x0 stores num, x1 stores times, so communication from C to assembly is very natural; You can see that the last three lines of the assembly use three colons, which is the syntax for inline assembly to communicate with C, where the first action outputs instructions, the second action inputs instructions, and the third action changes the variable list. For assembler to C assignments, just declare “=r” (variable identifier) on the first line. After assembly execution, the value of register %0 (actually modeled using registers X8 and X9, often used in conjunction with temporary value registers X12, and using %0 May taint x8 and X9) is stored in the variable identifier. If more than one variable needs to be assigned, use %1, %2, and so on. See this article for basic syntax for inline assembly input and output.

Implement functions using pure assembly

Note: Because C++ has a special name Mangling rule, this method only works with C

In addition to embedded inline assembly, we can also use assembly files to define functions directly. When creating a file in Xcode, select the assembly file in the Other group to create an assembly file and add it to the compilation unit of the project.

To implement the double_num_times function above in pure assembly, write the following code in the assembly file.

; example.s
.section __TEXT,__text,regular,pure_instructions
.ios_version_min 11.2
.p2align 2
.global _double_num_times_asm
_double_num_times_asm:
    lsl x0, x0, x1
    ret
Copy the code

The first is a fixed way of writing a section, which will be defined in more detail in a later tutorial. The fourth line leads to the global symbol. From the fifth line, the function logic of _double_num_times_ASM is defined. The symbols are mapped to the C language’s global function symbol double_NUM_TIMES_ASM, where since _doubLE_NUM_TIMES_ASM calls no other symbols, there is no need to deal with x29 and X30 staging.

With the above assembly code, we have finished defining the function, just declaring it in a header file.

// example.h
int double_num_times_asm(int num, int times);
Copy the code

Once the header file is introduced, the function can be used normally.

conclusion

Embedding assembly code in Xcode mainly relies on the C language to support the function of introducing assembly code through __ASm__, and directly using assembly to realize function logic is equivalent to manually helping the compiler to complete the process of generating assembly code, through embedding assembly can control the operation of the program to a greater extent.