Let's take a look at the LDR command.
The LDR Command Format of the LDR command is LDR {condition} destination register. The <memory address> LDR command is used to transmit a 32-bit word base from the memory to the destination register. This command is usually used to read 32-bit word data from memory to General registers and then process the data. When the program counter PC is used as the destination register, the word data read from the memory by the instruction is used as the destination address, so as to redirect the program flow. This command is commonly used in programming and has various addressing methods. Please master it carefully. Command example: LDR r0, [R1]; read the word data with the memory address R1 into the register R0. LDR r0, [R1, R2]; read the word data with the memory address R1 + R2 into the register R0. LDR r0, [R1, #8]; read the word data with the memory address R1 + 8 into the register R0. LDR r0, [R1, R2]! Read the word data with the memory address R1 + R2 into the register r0, and write the new address R1 + R2. LDR r0, [R1, #8]! Read the word data with the memory address R1 + 8 into the register r0, and write the new address R1 + 8 into R1. LDR r0, [R1], R2; read the word data with the memory address R1 into the register r0, and write the new address R1 + R2. LDR r0, [R1, R2, LSL #2]! Read the word data with the memory address R1 + R2 × 4 into the registers r0, and write the new address R1 + R2 × 4 into R1. LDR r0, [R1], R2, LSL #2; read the word data with the memory address R1 into the register r0, and write the new address R1 + R2 × 4 to R1.
ADR: This command reads PC-based address values or register-based address values to registers. It performs address operations based on PC values.
Comparison between the LDR command and the ADR command:
LDR Reg, = {lab} OR = {num} is a pseudo command used to load the label address and the immediate number. If no "=" sign is added, it indicates memory addressing. ADR is a pseudo command that reads the address value based on the relative offset of the PC or the relative address value of the Register.
In fact, both are pseudo commands: ADR is a small range of address read pseudo commands, LDR is a large range of read address pseudo commands. In fact, ADR uses the address value based on the relative offset of the PC or the instruction based on the relative address value of the Register, and LDR is used to load 32 as the immediate number or an address to the specified register. Here we will see the difference. If you want to load a function in a program or specify an address during connection, use ADR, for example, the address to be located in the LDS. Use LDR when loading the 32-bit immediate number or external address.
An online example:
AREA test,CODE,READONLY ENTRYSTART ldr r0,_start adr r0,_start ldr r0,=_start nop _start nop END
This code has no practical significance, just for convenience. Let's take a look at the disassembly:
START $a test 0x00000000: e59f0008 .... LDR r0,_start ; [0x10] = 0xe1a00000 0x00000004: e28f0004 .... ADR r0,{pc}+0xc ; 0x10 0x00000008: e59f0004 .... LDR r0,[pc,#4] ; [_start = 0x14] = 0 0x0000000c: e1a00000 .... MOV r0,r0 _start 0x00000010: e1a00000 .... MOV r0,r0 $d 0x00000014: 00000000 .... DCD 0 ; _start
/***********************************
Axd simulation determines Ro segment address: 0x50200000
Decompilation
********************************/
LDR r0, _ start
Read the value from the memory address _ start. After executing this command, R0 = 0xe1a00000
ADR r0, _ start
Get the address of _ start to R0. However, please refer to the decompilation result. It is irrelevant to the location. In fact, the obtained location is relative. For example, if this code is run in 0x00000000, R0 = 0x00000010 is obtained for ADR R0 and _ start;
LDR r0, = _ start
Obtain the absolute address of _ start. This absolute address is determined during link. It seems that this is only an instruction, but it takes up two 32bit spaces. One is the instruction and the other is the data of _ start (because the value of _ start cannot be determined during compilation, in addition, the mov command cannot be used to assign a 32bit constant to R0. Therefore, an extra space is required to store the real data of _ start. Here it is 0x0000000c ).
Therefore, we can see that this is an absolute addressing. No matter where the code runs, the result is R0 = 0x0000000c.
Let's look at another piece of code:
ldr r0, _start adr r0, _start ldr r0, =_start_start: b _start
The following is the result of disassembly:
START $a $v0 test 0x00000000: e59f0004 .... LDR r0,_start ; [0xc] = 0xeafffffe 0x00000004: e28f0000 .... ADR r0,{pc}+8 ; 0xc 0x00000008: e59f0000 .... LDR r0,[pc,#0] ; [_start = 0x10] = 0 _start 0x0000000c: eafffffe .... B {pc} ; 0xc $d 0x00000010: 00000000 .... DCD 0 ; _start
Set Ro to 0x50200000 axd simulation decompilation:
1. LDR R0, _ start
This is an instruction that reads the value from the memory address _ start.
Here _ start is a label (a relative program expression). The assembler calculates the offset relative to the PC and generates the command relative to the pre-index of the PC: LDRR0, [0xc]. After the command is executed, R0 = 0 xeafffffe.
2. ADR R0, _ start
This is a pseudocommand, which is always compiled into an instruction by the assembler. The assembler attempts to generate a single add or sub command to load the address. If the address cannot be constructed in a command, an error is generated and the Assembly fails.
Here we get the address number _ start to R0. Because the address is relative to the program, the ADR generates code dependent on the location. In this example, It is compiled into: addR0, PC, #0. Therefore, the code can be moved without changing the relative position of the label. After execution, R0 = 0x5020000c
If this code is run in 0x50200000, the "R0" and "_ start" operations result in R0 = 0x5020000c. If the code is run in address 0, it is 0x0000000c.
This can be used to determine where the program is running. The relocate code in U-boot is to use ADR to implement whether the current program is in Ram or flash. The following is a brief analysis.
3. LDR R0, = _ start
This is a pseudo command, a relative program or an external expression. The assembler places the value of label-expr of the relative program in a text pool and generates a LDR command for the relative program to load the value from the text pool, in this example, the command is LDR.R0, [PC, #0], corresponding address and value in the text pool: 0x50200010: 5020000c. If label-expr is an external expression or is not included in the current segment, the assembler places a link program relocation command in the target file. The link program generates an address when linking.
Therefore, the absolute address of the label _ start is obtained, which is determined during connection. It occupies 2 32bit space, one is the instruction, and the other is the absolute address for storing _ start in the text pool. Therefore, no matter where the code runs in the future, the result is R0 = 0x5020000c. Because LDR R0 and = _ start obtain the absolute address of _ start, this code can be moved without changing the absolute position of the _ start label; if you use the register PC, you can implement absolute transfer in the program.