GDB ARM 汇编程序指令以我不理解的方式编译

GDB ARM assembler directives are compiled in a way I don't understand

我有ARM汇编源代码:

    .global _start
    .text

entry:  b _start            
array:  .byte 10, 20, 25    
eoa:                        

    .align                  

_start:     

    ldr r0, =eoa            
    ldr r1, =array        
    mov r3, #0            

loop:   

    ldrb r2, [r1], #1                           
    add r3, r2, r3                                     
    cmp r1, r0                                          
    bne loop                

stop:   b stop       

这是数组的简单求和。所以现在我在 Linux 终端中使用以下命令序列编译它:

arm-none-eabi-as -o program.o program.s
arm-none-eabi-ld -Ttext=0x0 -o program.elf program.o
arm-none-eabi-objcopy -O binary program.elf program.bin

如果我检查编译文件的大小:

ls -l
-rwxrwxrwx 1 ziga ziga       48 Nov 22 12:38 program.bin
-rwxrwxrwx 1 ziga ziga    66396 Nov 22 12:37 program.elf
-rwxrwxrwx 1 ziga ziga      864 Nov 22 12:36 program.o
-rwxrwxrwx 1 ziga ziga     1952 Jan  3 18:50 program.s

我看到,如果我从我的可执行文件 .elf 中删除 header,我会得到 .bin 文件,该文件恰好 48 字节长。这意味着它可以有 12 条 ARM 指令对吗?

现在我准备好16KiB的FLASH镜像,将.bin文件复制到FLASH镜像中,然后在connex板上启动QEMU模拟,如下所示:

dd if=/dev/zero of=flash.bin bs=4096 count=4096
dd if=program.bin of=flash.bin conv=notrunc
qemu-system-arm -M connex -nographic -serial /dev/null -pflash flash.bin 

在模拟器中,如果我使用 info registers 检查寄存器,我会得到:

R00=00000007 R01=00000007 R02=00000019 R03=00000037
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=00000024
PSR=600001d3 -ZC- A svc32
FPSCR: 00000000

这看起来不错,因为寄存器 R03 保存十六进制值 0x37,十进制为 55,它是我用命令 [=25= 提供的数组的正确总和].

我不明白的是,如果我使用 xp /12wi 0x0 转储前 12 个命令,我会得到:

0x00000000:  ea000000      b    0x8
0x00000004:  0019140a      andseq   r1, r9, sl, lsl #8
0x00000008:  e59f0018      ldr  r0, [pc, #24]   ; 0x28
0x0000000c:  e59f1018      ldr  r1, [pc, #24]   ; 0x2c
0x00000010:  e3a03000      mov  r3, #0  ; 0x0
0x00000014:  e4d12001      ldrb r2, [r1], #1
0x00000018:  e0823003      add  r3, r2, r3
0x0000001c:  e1510000      cmp  r1, r0
0x00000020:  1afffffb      bne  0x14
0x00000024:  eafffffe      b    0x24
0x00000028:  00000007      andeq    r0, r0, r7
0x0000002c:  00000004      andeq    r0, r0, r4

我如何为自己证明命令 2-4 和 11-12 的合理性?我的总和 55 是怎么计算出来的?

ldr r0, =eoaldr r1, =array 是一个 pseudo instruction as they do not exist in the ARM instruction set。它们不能直接转换成 ARM 汇编器。当编译器看到这些指令时,它会将它们转换成最有效的形式。

如果你看看你的反汇编:

0x00000008: e59f0018 ldr r0, [pc, #24] ; 0x28 0x0000000c: e59f1018 ldr r1, [pc, #24] ; 0x2c (...) 0x00000028: 00000007 andeq r0, r0, r7 0x0000002c: 00000004 andeq r0, r0, r4

你可以在偏移量处分别看到编译器数组的基地址(即:0x4,因为它是 32 位对齐的)和数组的末尾(即:数组的基地址 + 3 个字节 = 0x7) 0x28(pc 在 0x8 + 0x24 之前)和 0x2c(pc 在 0xc + 0x24 之前)。

注:也可以ldr rN, =#immediate编码成一条流水线。 ARM 指令集支持 16 位立即数(即:从 0 到 65535)。请参阅 ARM instruction set 的第 2 页。编译器将尝试使用最有效的编码。

实际上将 ldr rN, =label 替换为 adr rN, label 会更有效率! ADR 使用标签形成 PC 相对地址。您的代码将构建为:

00000000 <entry>:
   0:   eafffffe    b   8 <_start>

00000004 <array>:
   4:   140a        .short  0x140a
   6:   19          .byte   0x19

00000007 <eoa>:
    ...

00000008 <_start>:
   8:   e24f0009    sub r0, pc, #9
   c:   e24f1010    sub r1, pc, #16
  10:   e3a03000    mov r3, #0

00000014 <loop>:
  14:   e4d12001    ldrb    r2, [r1], #1
  18:   e0823003    add r3, r2, r3
  1c:   e1510000    cmp r1, r0
  20:   1afffffb    bne 14 <loop>

00000024 <stop>:
  24:   eafffffe    b   24 <stop>

注意:我对您的原始代码所做的唯一更改是替换:

ldr r0, =eoa            
ldr r1, =array 

作者:

adr r0, eoa            
adr r1, array