Как преобразовать дамп бинарной прошивки в .elf для отладки на ассемблере?

У меня есть двоичный образ прошивки для ARM Cortex M, который, как я знаю, должен быть загружен по адресу 0x20000000. Я хотел бы преобразовать его в формат, который я могу использовать для отладки на уровне сборки с помощью gdb, что, как я полагаю, означает преобразование в .elf. Но я не смог понять, как добавить достаточно метаданных в .elf, чтобы это произошло. Вот что я пробовал до сих пор.

arm-none-eabi-objcopy -I binary -O elf32-littlearm --set-section-flags \
    .data=alloc,contents,load,readonly \
    --change-section-address .data=0x20000000 efr32.bin efr32.elf

efr32.elf:     file format elf32-little
efr32.elf
architecture: UNKNOWN!, flags 0x00000010:
HAS_SYMS
start address 0x00000000

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000168  20000000  20000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
SYMBOL TABLE:
20000000 l    d  .data  00000000 .data
20000000 g       .data  00000000 _binary_efr32_bin_start
20000168 g       .data  00000000 _binary_efr32_bin_end
00000168 g       *ABS*  00000000 _binary_efr32_bin_size

Нужно ли начинать с преобразования двоичного файла в .o и написания простого скрипта компоновщика? Должен ли я добавить параметр архитектуры в команду objcopy?


person joeforker    schedule 01.09.2017    source источник
comment
есть способы objcopy сделать это, но вам нужен набор инструкций фиксированной длины, thumb без thumb2 (хотя это, вероятно, не будет работать с gnu), arm без thumb, только 32-битные mips (без 16-битных инструкций), не x86, не a ряд других.   -  person old_timer    schedule 01.09.2017


Ответы (1)


Небольшой эксперимент...

  58:   480a        ldr r0, [pc, #40]   ; (84 <spi_write_byte+0x38>)
  5a:   bf08        it  eq
  5c:   4809        ldreq   r0, [pc, #36]   ; (84 <spi_write_byte+0x38>)
  5e:   f04f 01ff   mov.w   r1, #255    ; 0xff

у вас, конечно, этого нет, но вы можете прочитать двоичный файл и сделать с ним следующее:

.thumb
.globl _start
_start:
.inst.n 0x480a
.inst.n 0xbf08
.inst.n 0x4809
.inst.n 0xf04f
.inst.n 0x01ff

затем посмотрите, что произойдет.

arm-none-eabi-as test.s -o test.o
arm-none-eabi-ld -Ttext=0x58 test.o -o test.elf
arm-none-eabi-objdump -D test.elf

test.elf:     file format elf32-littlearm


Disassembly of section .text:

00000058 <_start>:
  58:   480a        ldr r0, [pc, #40]   ; (84 <_start+0x2c>)
  5a:   bf08        it  eq
  5c:   4809        ldreq   r0, [pc, #36]   ; (84 <_start+0x2c>)
  5e:   f04f 01ff   mov.w   r1, #255    ; 0xff

но на самом деле это не сработает... если этот двоичный файл имеет какие-либо расширения thumb2, он не будет работать, вы не сможете линейно дизассемблировать инструкции переменной длины. Вы должны иметь дело с ними в порядке выполнения. Итак, чтобы сделать это правильно, вы должны написать дизассемблер, который проходит код в порядке выполнения, определяя инструкции, которые вы можете понять, помечая их как инструкции...

  80:   d1e8        bne.n   54 <spi_write_byte+0x8>
  82:   bd70        pop {r4, r5, r6, pc}
  84:   40005200
  88:   F7FF4000
  8c:   e92d 41f0   stmdb   sp!, {r4, r5, r6, r7, r8, lr}
  90:   4887        ldr r0, [pc, #540]  ; (2b0 <notmain+0x224>)
.thumb
.globl _start
_start:
.inst.n 0xd1e8
.inst.n 0xbd70
.inst.n 0x5200
.inst.n 0x4000
.inst.n 0x4000
.inst.n 0xF7FF
.inst.n 0xe92d
.inst.n 0x41f0
.inst.n 0x4887

  80:   d1e8        bne.n   54 <_start-0x2c>
  82:   bd70        pop {r4, r5, r6, pc}
  84:   5200        strh    r0, [r0, r0]
  86:   4000        ands    r0, r0
  88:   4000        ands    r0, r0
  8a:   f7ff e92d           ; <UNDEFINED> instruction: 0xf7ffe92d
  8e:   41f0        rors    r0, r6
  90:   4887        ldr r0, [pc, #540]  ; (2b0 <_start+0x230>)

будет восстанавливаться, ломаться и восстанавливаться и т.д...

вместо этого вам нужно написать дизассемблер, который проходит через код (не обязательно дизассемблировать на ассемблере, но достаточно, чтобы пройти код и рекурсивно пройти по всем возможным ветвям). все данные, не определенные как инструкции, пометить как инструкции

.thumb
.globl _start
_start:
.inst.n 0xd1e8
.inst.n 0xbd70
.word 0x40005200
.word 0xF7FF4000
.inst.n 0xe92d
.inst.n 0x41f0
.inst.n 0x4887

00000080 <_start>:
  80:   d1e8        bne.n   54 <_start-0x2c>
  82:   bd70        pop {r4, r5, r6, pc}
  84:   40005200    andmi   r5, r0, r0, lsl #4
  88:   f7ff4000            ; <UNDEFINED> instruction: 0xf7ff4000
  8c:   e92d 41f0   stmdb   sp!, {r4, r5, r6, r7, r8, lr}
  90:   4887        ldr r0, [pc, #540]  ; (2b0 <_start+0x230>)

и наша инструкция stmdb теперь верна.

удачи.

person old_timer    schedule 01.09.2017
comment
какие параметры objdump вы использовали для отображения строк .inst.n? - person joeforker; 01.09.2017
comment
они были созданы вручную, в этом случае вы должны написать инструмент, который читает двоичный файл и создает такой файл. - person old_timer; 01.09.2017
comment
обратите внимание, что я продемонстрировал, что, несмотря на то, что я сказал, что это инструкция большого пальца inst.n, когда я поместил туда расширения thumb2 вместо одного 32-битного inst.w как два 16-битных inst.n, дизассемблер понял, что это thumb2.. . - person old_timer; 01.09.2017
comment
Я не знаю, какое ядро/набор инструкций вы используете, но если это cortex-m, то armv6-m и arm7-m (и armv-8m) имеют расширения thumb2, с которыми нужно иметь дело, возможно, но был ли этот двоичный файл построен с использованием любой из них или это был чистый большой палец? Я также пропустил векторную таблицу, которая довольно проста и может быть понята визуально, поместив туда .words для этой части двоичного файла. - person old_timer; 01.09.2017
comment
Он имеет несколько 32-битных инструкций перехода. - person joeforker; 05.09.2017
comment
не отвечает на вопрос, какой именно чип вы используете? - person old_timer; 05.09.2017
comment
рука-нет-eabi-gcc -mcpu = cortex-m0 -mthumb - person joeforker; 05.09.2017
comment
это не тот тип чипа, который является ядром, которое купил поставщик чипа, и/или вы используете наименьший общий знаменатель в своей системе сборки для создания кода для любого из ядер cortex-m... - person old_timer; 05.09.2017
comment
на данный момент не имеет значения, ответ остается в силе. если у вас есть доступ к gcc для исходников, то почему вы пытаетесь вернуть двоичный файл обратно в эльфа, просто сохраните эльфа при его сборке... - person old_timer; 05.09.2017
comment
это флэш-заглушка для отладчика зонда черной магии, который, как ожидается, сгенерирует короткую программу, которую можно загрузить в ОЗУ без сценария компоновщика, а затем выполнить операцию флэш-программирования. если восходящий поток не примет сценарий компоновщика, альтернативой может быть создание эльфа по адресу 0x0, использование objcopy для перемещения раздела без исправления смещений и отладка для поиска инструкции, вызывающей нарушение. также у gdb, вероятно, есть способ загрузки и отладки необработанных двоичных файлов? - person joeforker; 06.09.2017
comment
.word 0x40005200 и .word 0xF7FF4000 выглядят неправильно. Я думаю, что это помещает байты в раздел данных на ARM с прямым порядком байтов, а не в раздел .code. .inst.w работает? См. также синтаксис arm thumb2 ldr.w? в GCC-Help. список рассылки. - person jww; 21.05.2019