First, the basic concept of stack

A stack is a linear list of data structures that can only be inserted and deleted at one end. The end that can be inserted or deleted is the “top of the stack”, and the other end is the “bottom of the stack”.

The model of the stack

By default, programmers often refer to the stack in memory, but the stack is a basic data structure that can be seen in other fields, not only in computers.

For example, when containers are stored at the dock, when trucks come, boxes are stacked one by one, and when ships come, boxes are moved from the top to the bottom, which means they are pushed out of the stack. The ground is the bottom of the stack, and the highest position is only the top.

How to arrange the stack in memory

The top is the regular stack model, with the top of the stack and the bottom of the stack. In memory, however, the stack layout is reversed, with the top of the stack at the bottom and the bottom of the stack at the bottom.

Memory has N gigabytes in size and is divided in bytes. To facilitate addressing, each byte is numbered sequentially. This number is called memory address. Addresses with small values are called low address 0x000000001, and addresses with large values are called high address 0xC00000000.

While the stack in memory is from the high address to the low address, generally used to describe the memory address layout, the high address will be on the top, the low address will be below, so from the diagram, the bottom of the stack is on the top, the top of the stack is below.

Note: why does the stack grow from high address to low address in memory?Copy the code

Memory layout model for stacks

Call stack

What is the call stack?

The sequence of function calls in a thread, stored using the data structure of the stack, is called the call stack. The first step is to understand the concept of threads. A thread is the smallest body of execution that an operating system can schedule. It is a single sequential flow of control, and the CPU only processes tasks for one thread at a time.

The CPU supports multithreading, and each time a thread is switched, the context of the thread is switched. Context includes data in registers, data stored in the stack. This includes local variables, the address of the currently executing code, intermediate variables, and so on.

The threading tasks that the CPU performs can be thought of as a tree of methods that are called sequentially, with nested submethods that are the child nodes of the tree.

When iOS is running, if Crash occurs, the call stack of the current thread can be captured by using “[NSThread callStackSymbols]”.

Thread 17 Crashed:
0   libGPUSupportMercury.dylib      0x000000022d873fe4 _gpus_ReturnNotPermittedKillClient
1   AGXGLDriver                     0x0000000231f21ed8 0x0000000231efd000 + 151256
2   libGPUSupportMercury.dylib      0x000000022d874fac _gpusSubmitDataBuffers
Copy the code

The call stack is a method tracing back, with number 0 being the last method to fail, number 1 calling the method at number 0, and so on. With the thread call stack back in place, we can trace the source of the Crash.

How is the thread call stack laid out in memory

The thread call stack above is made up of function call symbols from high-level languages (OC, C, C++, SWIFT). Based on high-level language analysis, we can locate the cause of 80%Crash.

Twenty percent of the cases need to be analyzed at the assembly level, so we need to understand how the call stack is laid out in memory when the CPU executes a thread task.

We do not need to worry about multithreading, multithreading switches are accompanied by thread switches, and only one thread call stack needs to be considered at a time.

Note: iOS programs only need to master ARM64 assemblerCopy the code

OC functions are multiple assembly instructions compiled into ARM assembly language using LLVM. Arm assembler lays out instructions on a function basis, calls another function using jump instruction BL, and returns to the previous function using ret instruction after the function is executed.

When executing an instruction, the CPU maps a function to a stack frame, which is equivalent to a substack nested in the call stack of the current thread. The FP register points to the bottom of the stack frame, and the SP register points to the top of the stack frame.

Stack frame layout model

The Stack Frame (Stack Frame)

A Stack Frame is a group of data stored from the highest address on the Stack to the lowest address in the method invocation sequence. It is used to store the key information of the last method invocation. It is part of the stack used by a function, and the stack frames of all functions are strung together to form a complete stack.

reference

Introduction to the FP register and frame Pointer

ARM64 Function Calling Conventions

Stack Frames

Procedure Call Standard for the ARM 64-bit Architecture (AArch64)

ARM Reference Manual:

The article summary

IOS internal power series

[iOS internal functions] Crash analysis model

In-depth analysis of the memory layout of Crash call stack

[iOS internal functions] ARM black magic – stack frame on and off the stack

Use Hopper to locate difficult problems

Architecture series

What do architects often mean by “technical architecture”?

How to build APP stability system?

Series of thinking

The “Work Mindset Model” of high Performance Engineers