使用 = 运算符加载数据或从文字池加载数据有什么区别?

Ham*_*shi 2 assembly arm

因此,我正在学习 ARM 汇编,并遇到了两种从内存加载数据的方法。

方法 1:使用“=”运算符

.section    .data
number:     .word 0x8

.section    .text
.global     _start
_start:
    LDR R1, =number
    LDR R1, [R1]
Run Code Online (Sandbox Code Playgroud)

方法 2:使用文字池

.section    .data
number:     .word 0x8

.section    .text
.global     _start
_start:
    LDR R1, address_of_number
    LDR R1, [R1]

address_of_number: .word number
Run Code Online (Sandbox Code Playgroud)

这两种方法都做同样的事情。它们加载number.data部分中存在的地址,然后加载存储在该地址的实际值。

所以我想知道这两种方法有区别吗?我读到该=运算符与C中的类似。*那么使用Literal Pool whereexistsaddress_of_number来存储地址的目的是什么?

old*_*mer 5

首先,汇编语言特定于工具而不是目标。并非所有 ARM 汇编器都支持此语法,并且支持它的汇编器也不能同等支持该语法。我的理解是,gnu 在这个地址方面是功能最丰富的。

第二……试试吧……

ldr r0,=0x1234567
nop
nop
nop


Disassembly of section .text:

00000000 <.text>:
   0:   e59f0008    ldr r0, [pc, #8]    ; 10 <.text+0x10>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)
  10:   01234567    .word   0x01234567
Run Code Online (Sandbox Code Playgroud)

或者

ldr r0,hello
nop
nop
nop
hello: .word 0x12345678

Disassembly of section .text:

00000000 <hello-0x10>:
   0:   e59f0008    ldr r0, [pc, #8]    ; 10 <hello>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)

00000010 <hello>:
  10:   12345678    .word   0x12345678
Run Code Online (Sandbox Code Playgroud)

相同的机器码,没有区别。

但如果你这样做

ldr r0,=0x00000104
ldr r0,=0x11000000
ldr r0,=0x20000001
ldr r0,=0x0ffffff0

Disassembly of section .text:

00000000 <.text>:
   0:   e3a00f41    mov r0, #260    ; 0x104
   4:   e3a00411    mov r0, #285212672  ; 0x11000000
   8:   e3a00212    mov r0, #536870913  ; 0x20000001
   c:   e3e002ff    mvn r0, #-268435441 ; 0xf000000f
Run Code Online (Sandbox Code Playgroud)

gnu 汇编器至少会为您选择不同的指令(ldr .. = 是伪指令)(其他汇编器可能不会,也不一定期望这样做)。

但正如预期的那样,如果您:

ldr r0,hello
nop
nop
nop
hello: .word 0x11000000
    
Run Code Online (Sandbox Code Playgroud)

你得到

Disassembly of section .text:

00000000 <hello-0x10>:
   0:   e59f0008    ldr r0, [pc, #8]    ; 10 <hello>
   4:   e1a00000    nop         ; (mov r0, r0)
   8:   e1a00000    nop         ; (mov r0, r0)
   c:   e1a00000    nop         ; (mov r0, r0)

00000010 <hello>:
  10:   11000000    .word   0x11000000
Run Code Online (Sandbox Code Playgroud)

有时您可能希望准确控制池的位置,或者您可能特别希望强制执行与 PC 相关的负载。或者希望像人们通常希望用汇编语言那样一对一地控制一切。

现在如果你知道编码是如何工作的

mov r0,#0x00000104
mov r0,#0x00000101

test.s: Assembler messages:
test.s:3: Error: invalid constant (101) after fixup
Run Code Online (Sandbox Code Playgroud)

第一个将编码第二个不会(早期的手臂指令)。然后你必须返回并将代码更改为 ldr r0,=

以 ldr = 开头或以 ldr = 结尾是个人喜好。现在你需要了解有多种arm指令集和不同的架构版本。Thumb、thumb2 和 arm 具有不同的直接编码规则,因此适用于其中之一的规则不一定适用于另一个。但是,至少对于 gnu 汇编器,ldr = 将选择最佳指令。