代码之家  ›  专栏  ›  技术社区  ›  71GA

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

  •  0
  • 71GA  · 技术社区  · 8 年前

    我有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 我明白了 .bin 文件 48 字节长。这意味着它可以有12个ARM指令,对吗?

    现在我准备16KiB闪存图像,复制 .箱子 文件,并在上启动QEMU模拟 connex 像这样的板:

    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 它是我随命令提供的数组的正确和 .byte 10, 20, 25 .

    我不明白的是,如果我使用 xp /12wi 0x0 ,我明白了:

    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的合理性?我的总数是怎么计算出来的?

    2 回复  |  直到 8 年前
        1
  •  2
  •   OlivierM    8 年前

    ldr r0, =eoa ldr r1, =array 是一个 pseudo instruction 因为它们不存在于 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

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

    注: 也有可能 ldr rN, =#immediate 编码到单个装配线。ARM指令集支持16位立即数(即:从0到65535)。见第2页,共页 ARM指令集 . 编译器将尝试使用最有效的编码。

        2
  •  2
  •   OlivierM    8 年前

    实际上,两者都要替换 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