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

0

I have ARM assembly source code:

    .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       

Which is a simple sum of array. So now I compile this using this sequence of commands in my Linux terminal:

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

And if I check size of compiled files:

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

I see that if I strip header from my executable .elf i get .bin file which is exactly 48 Bytes long. This means it can have 12 ARM instructions right?

Now I prepare the 16KiB FLASH image, copy the .bin file to the FLASH image and start QEMU simulation on the connex board like this:

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 

While in simulator if I check registers using info registers, I get:

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

Which looks fine as register R03 holds hexadecimal value 0x37 which is 55 in decimal and it is the correct sum of the array I supplied with a command .byte 10, 20, 25.

What I don't understand is if I dump first 12 commands using xp /12wi 0x0, I get this:

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

How can I justify commands 2-4 and 11-12 to myself? And how the he** is my sum 55 even calculated?

gcc
assembly
arm
qemu
asked on Stack Overflow Jan 3, 2018 by 71GA • edited Jan 3, 2018 by 71GA

2 Answers

2

ldr r0, =eoa and ldr r1, =array are a pseudo instruction as they do not exist in the ARM instruction set. They cannot directly be converted into ARM assembler. When the compiler see these instructions, it converts them into whatever it is most efficient.

If you look at your disassembly:

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

You can see the compiler the base address of you array (ie: 0x4 because it is 32bit aligned) and the end of the array (ie: base address of the array + 3 bytes = 0x7) respectively at the offset 0x28 (pc before 0x8 + 0x24) and 0x2c (pc before 0xc + 0x24).

Note: It is also possible ldr rN, =#immediate be encoded into a single assembly line. ARM instruction set support a 16bit immediate value (ie: from 0 to 65535). See page 2 of ARM instruction set. The compiler will try to use the most efficient encoding.

answered on Stack Overflow Jan 8, 2018 by OlivierM • edited Jan 9, 2018 by OlivierM
2

Actually replacing both ldr rN, =label by adr rN, label would be more efficient! ADR form PC-relative address using label. Your code would be built as:

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>

Note: The only change I made to your original code was to replace:

ldr r0, =eoa            
ldr r1, =array 

By:

adr r0, eoa            
adr r1, array        
answered on Stack Overflow Jan 9, 2018 by OlivierM

User contributions licensed under CC BY-SA 3.0