kubo39's blog

ただの雑記です。

LDCでSTM32F103のバイナリを作ろうとしてできなかった

Cortex-M3な環境を試してみる。

コードを以下のようなかんじで用意する。

import ldc.attributes;

extern(C):
@nogc:
nothrow:

pragma(LDC_no_moduleinfo);

@(section("_reset"))
void _reset()
{
    int y = void;
    auto x = 42;
    y = x;

    while (true) {}
}
ENTRY(_reset);

MEMORY
{
  FLASH : ORIGIN = 0x08000000, LENGTH = 128K
  RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

SECTIONS
{
  .text :
  {
    /* Vector table */
    LONG(ORIGIN(RAM) + LENGTH(RAM))
    LONG(_reset + 1);

    /* Reset handler */
    _reset = .;
    *(.text._reset)

    *(.text*)
  } > FLASH

  /DISCARD/ :
  {
    *(.ARM.exidx*)
    *(.note.gnu.build-id*)
  }
}

実行バイナリを作る。

$ ldc2 -march=thumb -mcpu=cortex-m3 -c -g main.d
$ arm-none-eabi-ld main.o -T layout.ld -nostartfiles -o main.bin

OpenOCDを起動。

$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg

gdbからプログラムを流しこもうとするとコネクションが閉じられる。

$ gdb -q main.bin
Reading symbols from main.bin...done.
(gdb) target remote :3333
Remote debugging using :3333
warning: Architecture rejected target-supplied description
0xffbefdde in ?? ()
(gdb) load
Loading section .text, size 0x8 lma 0x8000000
Loading section _reset, size 0x1a lma 0x8000008
Start address 0x8000008, load size 34
Remote connection closed

OpenOCD側の出力はこのような感じ。

他のボードと同じように Error: gdb requested a non-existing register が出力されている。

Info : accepting 'gdb' connection on tcp/3333
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000008 msp: 0x20005000
target state: halted
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20005000
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000008 msp: 0x20005000
Error: gdb requested a non-existing register
Info : dropped 'gdb' connection

objdumpで実行バイナリをみる。があまりよくわからない。

$ arm-none-eabi-objdump -Cd main.bin

main.bin:     file format elf32-littlearm


Disassembly of section .text:

08000000 <_reset-0x8>:
 8000000:       20005000        .word   0x20005000
 8000004:       08000009        .word   0x08000009

Disassembly of section _reset:

08000008 <_reset>:
 8000008:       b082            sub     sp, #8
 800000a:       202a            movs    r0, #42 ; 0x2a
 800000c:       9000            str     r0, [sp, #0]
 800000e:       9001            str     r0, [sp, #4]
 8000010:       e7ff            b.n     8000012 <_reset+0xa>
 8000012:       2000            movs    r0, #0
 8000014:       2800            cmp     r0, #0
 8000016:       d102            bne.n   800001e <_reset+0x16>
 8000018:       e7ff            b.n     800001a <_reset+0x12>
 800001a:       e7ff            b.n     800001c <_reset+0x14>
 800001c:       e7f9            b.n     8000012 <_reset+0xa>
 800001e:       b002            add     sp, #8
 8000020:       4770            bx      lr

Rustで生成したものとreadelfを比較してみると、エントリポイントが0x1ずれているのが問題であることに気づいた。

以前書いた記事 で書いたfloat ABIの違いは関係ないようだ。さらに調べるとLLVMに渡すtripleのオプションでhardware floatを渡すことができた。ただしOSの関してはunknownを渡すことはできないようだ。

エントリポイントを外からいじってみる。

$ ldc2 -mtriple=thumbv7m-none-linux-eabi -c -g main.d
$ arm-none-eabi-ld main.o -e 0x8000009 -T layout.ld -nostartfiles -o main.bin
$ arm-none-eabi-objdump -Cd main.bin

main.bin:     file format elf32-littlearm


Disassembly of section .text:

08000000 <_reset-0x8>:
 8000000:       20005000        .word   0x20005000
 8000004:       08000009        .word   0x08000009

Disassembly of section _reset:

08000008 <_reset>:
 8000008:       b082            sub     sp, #8
 800000a:       202a            movs    r0, #42 ; 0x2a
 800000c:       9000            str     r0, [sp, #0]
 800000e:       9001            str     r0, [sp, #4]
 8000010:       e7ff            b.n     8000012 <_reset+0xa>
 8000012:       2000            movs    r0, #0
 8000014:       2800            cmp     r0, #0
 8000016:       d102            bne.n   800001e <_reset+0x16>
 8000018:       e7ff            b.n     800001a <_reset+0x12>
 800001a:       e7ff            b.n     800001c <_reset+0x14>
 800001c:       e7f9            b.n     8000012 <_reset+0xa>
 800001e:       b002            add     sp, #8
 8000020:       4770            bx      lr

エントリポイントが0x8000009になっていることを確認。

$ arm-none-eabi-readelf -h main.bin
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x8000009
  Start of program headers:          52 (bytes into file)
  Start of section headers:          1548 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         16
  Section header string table index: 13

しかし結果は変わらず、うまくいかなかった。