ARM Assembly Basics
In the reverse of a function, it is often necessary to analyze a large number of assembly code, in iOS reverse,ARM assembly is a must master language, this article summarizes the basic knowledge of ARM assembly, if you want to know more, please refer to the dog God small Yellow Book “iOS Reverse Engineering” or ARM official manual.
Registers, memory, and stacks
In ARM assembly, the operation objects are registers, memory and stack. The stack of ARM follows “in” and “out”, which is full and decreasing, growing down, that is, opening down, and new variables are stored at the bottom of the stack. A register named stackPointer holds the address of the bottom of the stack, called the stack address. A variable can be pushed to preserve its value, or it can be pushed out of the stack (pop) to restore its original value. In practice, the stack address changes constantly; But the stack address should be the same before and after executing a piece of code, otherwise the program will break,
Special purpose register
Some of the registers in the ARM processor have special uses as follows:
register | use |
---|---|
R0-R3 | Pass parameters and return values |
R7 | Frame pointer to the interface between the parent function and the called child function on the stack |
R9 | Reserved by the system before iOS3.0 |
R12 | Internal procedure call memory, which is used by Dynamic Linker |
R13 | Sp registers |
R14 | LR register, which holds the return address of the function |
R15 | PC register |
Branch jump and conditional judgment
A processor register named “Program Counter” (PC for short) is used to store the address of the next instruction. Typically, the computer executes instructions sequentially, one after the other, and the processor increments the PC by one to point it to the next instruction. For example, the processor executes instruction 1 to instruction 5 sequentially, but if the value of THE PC is changed, the order of instruction execution will be completely different. The order of instruction execution will be disrupted and become instruction 1, instruction 5, instruction 4, instruction 2, instruction 3, instruction 6. The scientific name of this disorder is “branch” or “jump”, which makes loop and subroutime(subroutine). Become possible, for example:
/ / endless () functionCopy the code
In practice, the branch that can be triggered only when certain conditions are met is the most practical branch, which is called conditional branch. If else and while are realized based on conditional branch, and in ARM assembly, there are generally four conditions for branches:
- □ Operation result is 0(or not 0);
- □ Operation result is negative;
- □ Operation results carry;
- □ Operation overflow (for example, the sum of two positive numbers exceeds the register number).
The judgment criteria (flags) of these conditions are stored in the Program Status Register (PSR). Data processing instructions will change these flags, and branch instructions will decide whether to jump according to these flags. The pseudocode below shows a for loop
for:
Copy the code
ARM/THUMB instruction interpretation
The instruction set used by the ARM processor is divided into ARM and THUMB: the length of ARM instruction is 32 bits, and the length of THUMB instruction is 16 bits. All instructions can be roughly divided into three categories, namely, array operation instructions, memory operation instructions and branch instructions.
Data manipulation instruction
Data manipulation commands have the following two rules:
- All operands are 32bit;
- All results are 32bit and can only be stored in registers. In general, the basic format of data manipulation instructions is:
op{cond}{s} Rd,Rn,Op2
Copy the code
“Cond” and “s” are alternative suffixes; Cond “is used to specify the conditions under which the instruction” op “is executed. There are 17 conditions in total:
instruction | conditions |
---|---|
EQ | EQual to 0 |
NE | Not Equal to 0 |
CS | Have a Carry Set or a borrow |
HS | Same as CS(unsigned Higer or Same) |
CC | Carry Clear no Carry Clear |
LO | With CC (unsigned LOwer) |
MI | The result is less than zero. |
PL | It’s greater than or equal to zero. |
VS | Overflow (Overflow Set) |
VC | Overflow Clear |
HI | Unsigned comparison greater than (unsigned HIger) |
LS | Less than or equal to unsigned Lower or Same |
GE | Signed Greater than or Equal |
LT | Signed Less Than |
GT | Signed Greater Than |
LE | Signed Less than or Equal |
AL | Unconditional (Always, default) |
The use of “cond” is simple, for example:
Compare R0, R1Copy the code
Compare the values of R0 and R1. If R0 is greater than or equal to R1, R2 = R0; Otherwise, R2 = R1. The function of “s” is to specify whether flag is set for instruction “op”, which has the following four flags:
- N(Negative)Set 1 if the result is less than 0, 0 otherwise;
- Z(zero)Set it to 1 if the result is 0, 0 otherwise;
- C(Carry)For add operations (including CMN), set to 1 if a carry occurs and 0 otherwise; For subtraction operations (including CMP),Carry is equivalent to not-borrow, 0 if a debit occurs, and 1 otherwise; For nonaddition/subtraction operations with shifts,C transpose is worth the last bit; For other non-addition/subtraction operations, the value of C is generally unchanged;
- V(overflow)Set to 1 if the operation causes overflow, 0 otherwise
It should be noted that C flag indicates whether the result of unsigned number operation overflows. V flag indicates whether the operation result of signed numbers overflows.
Arithmetic operation instructions can be roughly divided into four categories:
Arithmetic operations
ADD R0,R1,R2; ——————> R0 = R1 + R2ADC R0,R1,R2; ——————> R0 = R1 + R2 + C(array)SUB R0,R1,R2; ——————> R0 = r1-r2sbc R0,R1,R2; ——————> R0 = r1-r2 -! CRSB R0,R1,R2; ——————> R0 = r2-r1rsc R0,R1,R2; ——————> R0 = R2-r1 -! In C arithmetic operation,ADD and SUB are basic operations, and other operations are variations of the two. RSB, short for “Reverse Sub,” simply reverses the two operands of Sub; Variants ending in “C” represent addition and subtraction without carry or debit. When a carry or debit occurs, the Carrry flag is set to 1.
Logical operations
AND R0,R1,R2; ——————> R0 = r1&r2orr R0,R1,R2; — — — > R0 = R1 | R2EOR R0, R1, R2; ——————> R0 = R1 ^ R2BIC R0,R1,R2; ——————> R0 = r1&~ R2MOV RO,R2; ——————> R0 = R2MVN R0,R2; ——————> R0 = ~R2 all logical operation instructions have been explained by the C operator, but there is no corresponding logical operation instruction in the shift operation of the C operator. ARM adopts bucket shift, and there are four kinds of instructions :LSL logical shift left, LSR logical shift right, ASR arithmetic shift right, ROR loop shift right
Comparison operation
CMP R1,R2; ——————> Run r1-r2 and set the flag based on the result
CMN R1,R2; ——————> Execute R1 + R2 and set flagTST R1,R2; ——————> Execute R1 & R2 and set flagTEQ R1,R2 based on the results; ——————> Performing R1 ^ R2 and setting a flag comparison based on the result is an arithmetic or logical operation that changes the flag, except that the result is not stored in the register.
Multiplication operation
MUL R4,R3,R2 ——————> R4 = R3 * R2MLA R4,R3,R2,R1 ——————> R4 = R3 * R2 + R1 The operands of the multiplication operation must come from the register
Memory operation instruction
The basic format of memory operation instructions is:
op{cond}{type} Rd,[Rn,Op2]
Copy the code
Rn is the base address register used to store base addresses. “Cond” has the same function as data manipulation instructions; Type specifies the data type operated by the instruction op. There are four types:
B(unsigned Byte)
Copy the code
If type is not specified, there are only two basic word ARM memory operation instructions by default. LoaD Register (LDR) reads data from the memory and stores the data in the Register. STR(STore Register) reads an array from the Register and stores it in memory. The usage of the two instructions is as follows:
LDR
LDR Rt,[Rn {,#offset}] ; Rt = *(Rn {+ offset}),{} indicates optionalCopy the code
STR
STR Rt,[Rn {,#offset}] ; *(Rn {+ offset}) = Rt
Copy the code
In addition, the LDR and STR variants, LDRD and STRD, can also operate on DoubleWord, that is, two registers at once. The basic format is as follows:
op{cond} Rt,Rt2, [Rn {, #offset}]
Copy the code
The usage is similar to the stereotype, as follows:
STRD
SRTD R4,R5, [R9,#offset] ; *(R9 + offset) = R4; *(R9 + offset + 4) = R5Copy the code
LDRD
LDRD R4,R5,[R9,#offset] ; R4 = *(R9 + offset); R5 = *(R9+offset+4)
Copy the code
In addition to LDR and STR, LoaD Multiple (LDM) and STore Multipe (STM) can also be used for block transfer to operate Multiple registers at once. The basic format of the block transfer instruction is
op{cond}{}mode] Rd{! },reglistCopy the code
Where Rd is the base address register, optional “!” The regList is a series of registers, enclosed in braces, separated by “, “, or a range of “-“. For example,{r4-r6,R8} represents registers,R4,R5,R6,R8. The order of these registers is in ascending order of their own number, regardless of the order in braces. It is important to note that LDM and STM operate in the opposite direction to LDR and STR :LDM stores rD-starting, sequential memory data into regList, while STM stores regList values into RD-starting, sequential memory. It is particularly easy to confuse the “cond” with the same function as a data manipulation instruction. “Mode” specifies the 4 rules of R4 worth variation, as shown below:
IA(Increament After) Increments the value of Rd After each transfer.Copy the code
What does that mean? Here is a simple example represented by LDM. I believe you will understand it at a glance.
After executing the following command, the values of R4,R5, and R6 change to:
foo():
Copy the code
The STM instruction works in a similar way and will not be described again. LDM and STM operate exactly the opposite of LDR and STR
Branch instruction
Branch instructions can be divided into unconditional branch and conditional branch.
Unconditional branch
B Label; PC = LabelCopy the code
Unconditional branch
The conD of the jump branch is determined according to the preceding flag, and their corresponding relationship is as follows:
cond | flag |
---|---|
EQ | Z = 1 |
NE | Z = 0 |
CS | C = 1 |
HS | C = 1 |
CC | C = 0 |
LO | C = 0 |
MI | N = 1 |
PL | N = 0 |
VS | V = 1 |
VC | V = 0 |
HI | C = 1 & Z = 0 |
LS | C = 0 |
GE | N = V |
LT | N ! = V |
GT | Z = 0 & N = V |
LE | Z = 1 |
In the conditional branch instruction, there will be a data operation instruction to set the flag, and the branch instruction determines the direction of the code according to the value of FALg, for example:
Label:
Copy the code
THUMB instruction
THUMB instruction set is a subset of ARM instruction set, each THUMB instruction is 16bit; Thus THUMB instructions save more space than ARM instructions and are more efficient over 16-bit data buses. All THUMB instructions except “B” cannot be conditionally executed; Bucket shift cannot be combined with other instructions; Most THUMB instructions can only use the 8 registers R0-R7 etc. Compared to the ARM instruction, the THUMB instruction has the following characteristics:
- Instruction reduction
- No conditional execution
- All directives come with * by default
- Bucket shifts cannot be combined with other instructions
- Register usage restriction
- The immediate and second operand are in limited use
- Data write back is not supported