We analyzed it in our last articleallocLater, it was found that some details were not clearly explained. Here we will explore some places that we did not explore before.

This article will introduce the content for you:

1. Alloc content supplement

2. Memory alignment

3. Alignment exercises in the structure

4, some console printing tips


1. Alloc content supplement

1.1 review of the last article

We created a Person object in the OC Object Principle (part 1) and wrote the following code:

Person *p = [Person alloc];
Copy the code

When we explore the source code, we go to _objc_rootAlloc:

// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
Copy the code

This is our normal source code exploration process and there is nothing wrong with it.


1.2. Discovery of problems

Still a break point at this point:Using assembly code, I found a problem:Do you guys see what we’re about to enterobjc_alloc, not_objc_rootAlloc.

That’s weird, because it’s supposed to be _objc_rootAlloc.


1.3, continue to explore the source code

Since when debugging dynamically, the assembly code tells us that the first thing to enter isobjc_alloc, then we will search in the source codeobjc_alloc. (cmd + shift + O)

So let’s break both objc_alloc and _objc_rootAlloc, and let’s see which one comes first. (Note that clean is used before testing to avoid cache impact)

One thing to note here is that both methods call callAlloc, but they take different arguments:

/******** _objc_rootAlloc ********/
id
_objc_rootAlloc(Class cls)
{
   return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}


/******** objc_alloc ********/
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
   return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
Copy the code

You can see that the first thing that goes in isobjc_alloc. Write it down enter itcallAlloc, set a breakpoint in this method:If you keep running, you’ll see that it skips everythingIf judgmentGo to the last line,objc_msgSend:

Next comes the flow we explored in the underlying iOS exploration, OC Object Principles (part 1).

This is true when debugging dynamically; But the problem is, this process doesn’t work for what we’re trying to do, because alloc is _objc_rootAlloc, but when does it become objc_alloc?

My first impression of this was, did Apple swap methods somewhere? Or is itHOOK?With this idea, the next is to look inside the source code. So I found this:

I followed it up and found it was_read_imagesInside call:So we’re right_read_imagesSearch, place breakpoints where it was called, run the project, and find something familiar:See? This isdyldThe load, that is, indyldWhen it loads, the project is rightallocI’m going to make the substitutionIMPPoints to theobjc_alloc; The execution of theobjc_allocAfter that, the message sending process is followedobjc_msgSend. For those of you who are not familiar with this area, please refer to:IOS basic exploration — DyLD loading process IOS Infrastructure Exploration –Runtime (I) — Basics

To sum up, alloc will first go through a special process (objC_alloc), and then through the message sent into the ordinary alloc process.

The main reason for this is that alloc is an operation on memory, and Apple has some control over that operation.


2. Memory alignment

  1. Data member alignment rules:Structure (struct)(or combined (union), the first data member is placed inoffsetfor0Where later each data member is storedThe starting positionFrom you toThe size of the member (current member)orSize of a member's child members(As long as the member has child members, for exampleAn array of.The structure of the body, etc.)Integer timesStart. (such as:intfor4 bytes, from4An integer multiple of the address is stored.
  2. The structure of the bodyAs a member: if oneThe structure of the bodyThere are certain things in itStructural member,Structural memberThe storage starts with an address that is an integer multiple of the size of the largest internal element. (such as:struct aInside therestruct b.bThere is achar.int.doubleAnd so on, thenbShould be from8Integer multiples of start storage.
  3. Finishing touches:The structure of the bodyThe total magnitude of omega, which is omegasizeofThe result must be an integer multiple of the largest internal member, and the less must be made up.
C OC 32 – A 64 – bit
bool BOOL(64位) 1 1
signed char (__signed char)int8_t, BOOL(32 bits) 1 1
unsigned char Boolean 1 1
short Int16_t 2 2
unsigned short unichar 2 2
int int32_t NSInteger(32 bits), Boolean_T (32 bits) 4 4
unsigned int Boolean_t (64 bits), NSUInteger(32 bits) 4 4
long NSInteger(64位) 4 8
unsigned long NSUInteger(64位) 4 8
long long int64_t 8 8
float CGFloat(32位) 4 4
double CGFloat(64位) 8 8

3. Alignment exercises in the structure

  • Practice questions (1) :
struct JaxStruct1 {
    double a;       // 8    [0 7]
    char b;         // 1    [8]
    int c;          // 4    (9 10 11 [12 13 14 15]
    short d;        // 2    [16 17] 24
}struct1;
Copy the code

  • Exercises (2) :
struct JaxStruct2 {
    double a;       // 8    [0 7]
    int b;          // 4    [8 9 10 11]
    char c;         // 1    [12]
    short d;        // 2    (13 [14 15] 16
}struct2;
Copy the code

  • Exercises (3) :
struct JaxStruct3 {
    double a;                   // 8    [0 7]
    int b;                      // 4    [8 9 10 11]
    char c;                     // 1    [12]
    short d;                    // 2    (13 [14 15]
    int e;                      // 4    [16 17 18 19]
    struct JaxStruct1 str;      // 24   (20 21 22 23 [sizeof(struct1)]
}struct3;
Copy the code


4, some console printing tips

When we use the console to print some data in Xcode, we use a form like this:

4.1. Print object memory data

x/nuf <address>
Copy the code

  • n: indicates the number of memory units to be displayed.

  • u: indicates the length of an address unit:
    • b: indicates a single byte
    • h: indicates two bytes
    • w: indicates four bytes
    • g: indicates eight bytes

  • f: indicates the display mode. The value can be:
    • x: Displays variables in hexadecimal format
    • d: Displays variables in decimal format
    • u: Displays an unsigned integer in decimal format
    • o: Displays variables in octal format
    • t: Displays variables in binary format
    • a: Displays variables in hexadecimal format
    • i: Instruction address format
    • c: Displays variables in character format
    • f: Displays variables in floating-point format

  • Generally speaking, ellipsisf, the default ishexadecimal:


4.2. Print object member variables

  • If the member variable isNSStringOr,IntAnd so onpoExecute to print:
$ po <address>
Copy the code
  • If you want to print a floating point number, you can print it like this:
$e -f -- <address> $e -f -- <address>Copy the code