STM32 Положение Независимые двоичные файлы - PullRequest
0 голосов
/ 02 июня 2018

Я компилирую свое приложение FreeRTOS для Cortex-M4 (STM32F4) со следующими CFLAGS:

-fpic -msingle-pic-base -mpic-data-is-text-relative -mpic-register=r10

и с флагом -fpic, установленным для компоновщика.

Векторная таблица корректнокопируется в ОЗУ с измененным значением смещения для конкретного слота прошивки. На данный момент устройство запускается с.

Однако после запуска основного приложения из слота прошивки устройство зависает в HardFault с IMPRECISERR установлен в регистр CFSR .Это происходит в vPortSVCHandler при выполнении следующей строки:

ldmia r0!, {r4-r11, r14}

После этой операции значение Link Link равно 0000 0000.

.правильно создать позицию независимого приложения для STM32?Переместить глобальную таблицу смещений?Если да, в какое место в памяти?


EDIT

Согласно приведенным ниже вопросам, моя цель - создать приложение с загрузчиком и 2 слотами для прошивки.Мне нужны слоты прошивки во FLASH, чтобы мое устройство могло обновляться во время выполнения.Зачем мне нужна прошивка для компиляции с флагом PIC?Каждый слот имеет свое место в памяти.По умолчанию он компилируется для адреса первого слота.Запуск такого двоичного файла из второго слота, подготовленного для первого слота, невозможен, потому что доступ к данным и т. Д. (Честно говоря, это мой первый раз при компиляции GOT и PIC) основан на значении регистра счетчика программы (текущая позиция впространство памяти программы).Для обновления прошивки используется следующий свободный слот, который в данный момент не используется.Поскольку я не знаю, какой в ​​данный момент используется, мне нужно собрать двоичный файл, который будет работать правильно во всех слотах (в этом случае 2).Вот почему, после прочтения многих веб-сайтов, потоков и т. Д., Я думаю, что мне это нужно.

Мой процесс при переключении с загрузчика на основное приложение выглядит следующим образом:

  1. Проверьте, какой слот прошивкиследует использовать
  2. Отключить IRQ.
  3. Копировать векторную таблицу в ОЗУ.Эта часть оперативной памяти одинакова для обоих слотов.В процессе копирования я меняю смещение для каждого адреса, чтобы они были совместимы с конкретным слотом прошивки.По умолчанию адреса не имеют смещения, они удаляются на этапе посткомпиляции.
  4. Установить указатель стека в соответствии с первым словом в таблице векторов в ОЗУ.Эти адреса не изменяются при копировании таблицы векторов в ОЗУ.
  5. Установить SCB-> VTOR.
  6. Выполнить DSB ().
  7. Перейти к обработчику сброса из таблицы векторов, скопированной в RAM.

РЕДАКТИРОВАТЬ ПОСЛЕ old_timer POSTED ANSWER

Итак, я попытался скомпилировать код для обоихслоты.Вот результаты GOT-разборки:

Disassembly of section .got:

080083ac <_got_address>:
 80083ac:   0800beb9    stmdaeq r0, {r0, r3, r4, r5, r7, r9, sl, fp, ip, sp, pc}
 80083b0:   0800bf4c    stmdaeq r0, {r2, r3, r6, r8, r9, sl, fp, ip, sp, pc}
 80083b4:   20000274    andcs   r0, r0, r4, ror r2
 80083b8:   2000022c    andcs   r0, r0, ip, lsr #4
 80083bc:   20012fb4            ; <UNDEFINED> instruction: 0x20012fb4
 80083c0:   080086c5    stmdaeq r0, {r0, r2, r6, r7, r9, sl, pc}
 80083c4:   20000200    andcs   r0, r0, r0, lsl #4
 80083c8:   200132f0    strdcs  r3, [r1], -r0
 80083cc:   20013330    andcs   r3, r1, r0, lsr r3
 80083d0:   080088e1    stmdaeq r0, {r0, r5, r6, r7, fp, pc}
 80083d4:   20013334    andcs   r3, r1, r4, lsr r3
 80083d8:   20013338    andcs   r3, r1, r8, lsr r3
 80083dc:   20000230    andcs   r0, r0, r0, lsr r2
 80083e0:   200132d0    ldrdcs  r3, [r1], -r0
 80083e4:   20012fb8            ; <UNDEFINED> instruction: 0x20012fb8
 80083e8:   20000234    andcs   r0, r0, r4, lsr r2
 80083ec:   200131cc    andcs   r3, r1, ip, asr #3
 80083f0:   0800bed1    stmdaeq r0, {r0, r4, r6, r7, r9, sl, fp, ip, sp, pc}
 80083f4:   080089a1    stmdaeq r0, {r0, r5, r7, r8, fp, pc}
 80083f8:   0800bf7c    stmdaeq r0, {r2, r3, r4, r5, r6, r8, r9, sl, fp, ip, sp, pc}
 80083fc:   080086a5    stmdaeq r0, {r0, r2, r5, r7, r9, sl, pc}
 8008400:   080087f1    stmdaeq r0, {r0, r4, r5, r6, r7, r8, r9, sl, pc}
 8008404:   200132cc    andcs   r3, r1, ip, asr #5

После изменения слота прошивки, как сказал @old_timer, это изменяется:

 Disassembly of section .got:

081043ac <_got_address>:
 81043ac:   08107eb9    ldmdaeq r0, {r0, r3, r4, r5, r7, r9, sl, fp, ip, sp, lr}
 81043b0:   08107f4c    ldmdaeq r0, {r2, r3, r6, r8, r9, sl, fp, ip, sp, lr}
 81043b4:   20000274    andcs   r0, r0, r4, ror r2
 81043b8:   2000022c    andcs   r0, r0, ip, lsr #4
 81043bc:   20012fb4            ; <UNDEFINED> instruction: 0x20012fb4
 81043c0:   081046c5    ldmdaeq r0, {r0, r2, r6, r7, r9, sl, lr}
 81043c4:   20000200    andcs   r0, r0, r0, lsl #4
 81043c8:   200132f0    strdcs  r3, [r1], -r0
 81043cc:   20013330    andcs   r3, r1, r0, lsr r3
 81043d0:   081048e1    ldmdaeq r0, {r0, r5, r6, r7, fp, lr}
 81043d4:   20013334    andcs   r3, r1, r4, lsr r3
 81043d8:   20013338    andcs   r3, r1, r8, lsr r3
 81043dc:   20000230    andcs   r0, r0, r0, lsr r2
 81043e0:   200132d0    ldrdcs  r3, [r1], -r0
 81043e4:   20012fb8            ; <UNDEFINED> instruction: 0x20012fb8
 81043e8:   20000234    andcs   r0, r0, r4, lsr r2
 81043ec:   200131cc    andcs   r3, r1, ip, asr #3
 81043f0:   08107ed1    ldmdaeq r0, {r0, r4, r6, r7, r9, sl, fp, ip, sp, lr}
 81043f4:   081049a1    ldmdaeq r0, {r0, r5, r7, r8, fp, lr}
 81043f8:   08107f7c    ldmdaeq r0, {r2, r3, r4, r5, r6, r8, r9, sl, fp, ip, sp, lr}
 81043fc:   081046a5    ldmdaeq r0, {r0, r2, r5, r7, r9, sl, lr}
 8104400:   081047f1    ldmdaeq r0, {r0, r4, r5, r6, r7, r8, r9, sl, lr}
 8104404:   200132cc    andcs   r3, r1, ip, asr #5

1.Сначала нужно зарезервировать в оперативной памяти пространство для GOT и запросить загрузчик / запуск, чтобы скопировать GOT в это место и добавить смещение слота, если необходимо. Я думаю, что могу сделать это, изменив код компоновщика, чтобы он поместил GOT вVMA RAM.Итак, я предполагаю, что в остальной части приложения адрес GOT изменится на адрес, помещенный в ОЗУ, я прав?

Почему этот двоичный файл не работает в устройстве?Это потому, что я должен добавить флаг компиляции -mpic-register=r10 и установить этот регистр на адрес GOT после копирования GOT в RAM и перед выполнением основного приложения из слота?Ooh!Подождите, это работает на слоте прошивки 0, но я не знаю почему.Я не проверял второй слот, скоро обновлюсь.

1 Ответ

0 голосов
/ 05 июня 2018

Вероятно, существует бесчисленное множество способов сделать это, но, надеюсь, это даст вам некоторые боеприпасы для начала, чтобы посмотреть, что происходит.

boot.s

.thumb
.globl _start
_start:
reset:
    mov r0,pc
    ldr r1,=0xFFFF0000
    and r0,r1
    ldr r1,gotbase
    add r0,r1
    bl centry
    b .
    .align
gotbase:
    .word _GLOBAL_OFFSET_TABLE_-(_start)
    .word _start
    .word _GLOBAL_OFFSET_TABLE_
    .word _GLOBAL_OFFSET_TABLE_

так.c

extern unsigned int fun ( unsigned int );
unsigned int x;
unsigned int y;
unsigned int z;
void centry ( void )
{
    x=5;
    y=6;
    z=fun(77);
}

fun.c

unsigned int fun ( unsigned int x )
{
    return(x+3);
}

flash.ld

MEMORY
{
    rom : ORIGIN = 0x08020000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

build

arm-none-eabi-as --warn  boot.s -o boot.o
arm-none-eabi-gcc -Wall -O2 -mthumb -fpic -mthumb -c so.c -o so.o
arm-none-eabi-gcc -Wall -O2 -mthumb -fpic -mthumb -c fun.c -o fun.o
arm-none-eabi-ld -o so.elf -T flash.ld boot.o so.o fun.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy --srec-forceS3 so.elf -O srec so.srec
arm-none-eabi-objcopy so.elf so.bin -O binary

дизассемблирование

Disassembly of section .text:
08020000 <_start>:
 8020000:   4678        mov r0, pc
 8020002:   4907        ldr r1, [pc, #28]   ; (8020020 <gotbase+0x10>)
 8020004:   4008        ands    r0, r1
 8020006:   4902        ldr r1, [pc, #8]    ; (8020010 <gotbase>)
 8020008:   1840        adds    r0, r0, r1
 802000a:   f000 f80b   bl  8020024 <centry>
 802000e:   e7fe        b.n 802000e <_start+0xe>

08020010 <gotbase>:
 8020010:   00000060
 8020014:   08020000
 8020018:   00000048
 802001c:   00000044
 8020020:   ffff0000

08020024 <centry>:
 8020024:   2205        movs    r2, #5
 8020026:   b510        push    {r4, lr}
 8020028:   4c08        ldr r4, [pc, #32]   ; (802004c <centry+0x28>)
 802002a:   4b09        ldr r3, [pc, #36]   ; (8020050 <centry+0x2c>)
 802002c:   447c        add r4, pc
 802002e:   58e3        ldr r3, [r4, r3]
 8020030:   601a        str r2, [r3, #0]
 8020032:   4b08        ldr r3, [pc, #32]   ; (8020054 <centry+0x30>)
 8020034:   58e3        ldr r3, [r4, r3]
 8020036:   3201        adds    r2, #1
 8020038:   204d        movs    r0, #77 ; 0x4d
 802003a:   601a        str r2, [r3, #0]
 802003c:   f000 f80e   bl  802005c <fun>
 8020040:   4b05        ldr r3, [pc, #20]   ; (8020058 <centry+0x34>)
 8020042:   58e3        ldr r3, [r4, r3]
 8020044:   6018        str r0, [r3, #0]
 8020046:   bc10        pop {r4}
 8020048:   bc01        pop {r0}
 802004a:   4700        bx  r0
 802004c:   00000030
 8020050:   00000000
 8020054:   00000008
 8020058:   00000004

0802005c <fun>:
 802005c:   3003        adds    r0, #3
 802005e:   4770        bx  lr

Disassembly of section .got:

08020060 <.got>:
 8020060:   20000000
 8020064:   20000004
 8020068:   20000008

Disassembly of section .got.plt:

0802006c <_GLOBAL_OFFSET_TABLE_>:
    ...

Disassembly of section .bss:

20000000 <x>:
20000000:   00000000

20000004 <z>:
20000004:   00000000

20000008 <y>:
20000008:   00000000

Это намеренно несколько, ну очень много, минимально.Первый и самый интересный элемент в отношении независимости позиции:

Разборка секции .got:

08020060 <.got>:
 8020060:   20000000
 8020064:   20000004
 8020068:   20000008

И что это, очевидно, три глобальных элемента данных, которые мы имеем впрограмма.Если вы добавите больше элементов, вы увидите это изменение.

Если вы измените адреса в скрипте компоновщика

rom : ORIGIN = 0x08010000, LENGTH = 0x1000
ram : ORIGIN = 0x30000000, LENGTH = 0x1000

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

Быть большим пальцем (вероятно, не имеет значения) и все встроенные позиции независимы и мигания относительно невелики (по сравнению с диапазоном инструкций ветвления и ветвления), у компоновщика не должно быть никаких проблем или магического создания относительных ветвей, поэтому я надеюсь, что нет математики счетчика программ, хотя, если вы действительноЯ действительно постарался поспорить, что вы могли бы сделать это, и я бы предположил, но вы найдете, если вы нажмете, если это так.И, вероятно, если вы нажмете на это, возможно, у вас получится .text или другие смещения на основе здесь:

Disassembly of section .got.plt:

0802006c <_GLOBAL_OFFSET_TABLE_>:
    ...

Так что, если ваши альтернативные местоположения для ваших программ также включают альтернативные местоположения для данных, то вам нужно исправитьвверх по глобальной таблице смещений.

Мой бутстрап более чем минимален, возился с одним грубым способом добраться до адреса ПОЛУЧЕНО.Нет никаких сомнений в том, что скрипт компоновщика и / или код ghee whiz позволяют получить эту информацию.Точно так же вы можете использовать скрипт компоновщика для принудительного / размещения GOT.

 8020024:   2205        movs    r2, #5

 8020028:   4c08        ldr r4, [pc, #32]   ; (802004c <centry+0x28>)

 802002c:   447c        add r4, pc

 8020032:   4b08        ldr r3, [pc, #32]   ; (8020054 <centry+0x30>)
 8020034:   58e3        ldr r3, [r4, r3]
 8020036:   3201        adds    r2, #1

 802003a:   601a        str r2, [r3, #0]

эти элементы делают независимую от позиции версию y = 6;они вычисляют смещение для полученного значения, затем смещение в это и используют его для адресации в памяти, удаляют параметры командной строки pic и видят, как это изменяется.

То же машинный код зависит от полученного значения для полученного значения.фактический адрес для элемента.

если у нас есть 0x20000004, тогда это то место, где живет y, если в таблице 0x30000004, то это место, где живет y.

как закодировано и построено выше

08020060 <.got>:
 8020060:   20000000
 8020064:   20000004
 8020068:   20000008

таблица живет во флэш-памяти, поэтому код, который вы используете для помещения этой программы во флэш-память, должен будет исправить эту таблицу при записи во флэш-память.если вы играете в игры с компоновщиками, чтобы поместить таблицу в оперативную память, но во флэш-памяти, например, .data, это байты в оперативной памяти, которые куда-то идут, но во флэш-памяти затем копируются с помощью начальной загрузки, комбинации начальной загрузки и кода сценария компоновщика.

В любом случае я не понимаю, как это возможно, чтобы любой стандартный загрузчик знал, где вы хотите, чтобы он находился.Предполагается, что код .text можно перемещать с некоторыми предположениями о выравнивании, но предполагается, что .data и другие находятся не в одном и том же пространстве памяти и не перемещаются линейно с .text (нельзя просто взять некоторый связанный адрес .text и обнаруженный адрес .textи скорректируйте смещения данных на эту величину, поскольку предполагается, что эти два значения разделены и в этом случае (микроконтроллер cortex-m))

Таким образом, я бы (кроме ответов здесь никогда не нуждался в этом) начинать с приведенных выше боеприпасов, будь то просто знание того, как разобрать и прочитать код и / или часть кода выше, и изучить, чтоинструменты строят для вас, куда они кладут вещи.Я бы предположил, что вы создаете саму программу (если хотите, .text) как один большой двоичный объект, так что инструменты должны собрать его с относительной адресацией для доступа в этом разделе.Если вы не написали загрузчик, то это не инструментальная цепочка, а библиотека C или другая (RTOS, HAL и т. Д.), И я не ожидал бы, что она будет иметь независимый от позиции глобальный код исправления таблицы смещений, как откуда загрузчик узнаеткуда вы хотите переместить файл .data / .bss?Обдумайте это немного.Еще хуже в этом случае, если GOT находится во флэш-памяти, тогда он должен быть исправлен ДО выполнения, а не во время, поэтому некоторые другие программы должны делать это.Вероятно, поэтому формат файла elf содержит расположение / размер GOT, чтобы загрузчик, операционная система или другой инструмент загружали эту программу перед ее запуском.могу найти и исправить это.

Если вы хотите, чтобы ваши программы загружались в одно из двух разных флеш-пространств, вам нужно решить эту проблему с любой загрузкой.Снова очень грубая грубая сила, способ начать:

.thumb
.globl _start
_start:
reset:
    b skip
    .align
    .word _GLOBAL_OFFSET_TABLE_-(_start)
skip:


08020000 <_start>:
 8020000:   e002        b.n 8020008 <skip>
 8020002:   46c0        nop         ; (mov r8, r8)
 8020004:   00000068    andeq   r0, r0, r8, rrx

08020008 <skip>:

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

EDIT:

08020068 <.got>:
 8020068:   20000000
 802006c:   20000004
 8020070:   20000008

08020068 <.got>:
 8020068:   30000000
 802006c:   30000004
 8020070:   30000008

GOT не / не может перемещаться, он должен быть относительным к ПК, поэтому код, скомпилированный в.text может найти это.На что он указывает, на что должна быть изменена вся идея, если / когда вы переместитесь туда, где вы хотите, чтобы эти предметы.Таким образом, как показано выше, если он был связан таким образом, что x, y, z имеют значения 0x20000000, 0x20000004, 0x20000008.Но если вы хотите работать с x, y, z в 0x30000000, переместить в основном, то вам нужно изменить сам GOT, чтобы он указывал на эти элементы, как во втором примере выше.Потому что значение есть в .text, так что это pc относительно кода (как показано выше, как код создается с использованием опции командной строки, которую я использовал), и это mcu, и если у вас есть .text во флэш-памяти, то получаетсядолжен быть изменен перед помещением во флэш-память, которая не выполняется во время выполнения этого кода.Таким образом, ваш загрузчик или все, что помещает эту программу во флэш-память, должно будет сделать этот патч, ЕСЛИ вы хотите, чтобы .data / .bss находились где-то, кроме связанных.

08020068 <.got>:
 8020068:   20000000
 802006c:   20000004
 8020070:   20000008

08020068 <.got>:
 8020068:   30000000
 802006c:   30000004
 8020070:   30000008

GOT не может / не может двигаться, он долженбыть относительным к ПК, чтобы код, скомпилированный в .text, мог его найтиНа что он указывает, на что должна быть изменена вся идея, если / когда вы переместитесь туда, где вы хотите, чтобы эти предметы.Таким образом, как показано выше, если он был связан таким образом, что x, y, z имеют значения 0x20000000, 0x20000004, 0x20000008.Но если вы хотите работать с x, y, z в 0x30000000, переместить в основном, то вам нужно изменить сам GOT, чтобы он указывал на эти элементы, как во втором примере выше.Потому что значение есть в .text, так что это pc относительно кода (как показано выше, как код создается с использованием опции командной строки, которую я использовал), и это mcu, и если у вас есть .text во флэш-памяти, то получаетсядолжен быть изменен перед помещением во флэш-память, которая не выполняется во время выполнения этого кода.Таким образом, ваш загрузчик или все, что помещает эту программу во флэш-память, должно будет сделать этот патч, ЕСЛИ вы хотите, чтобы .data / .bss находились где-то, кроме связанных.

Использование флагов вашего компилятора

Disassembly of section .text:

08020000 <_start>:
 8020000:   e002        b.n 8020008 <skip>
 8020002:   46c0        nop         ; (mov r8, r8)
 8020004:   00000064    andeq   r0, r0, r4, rrx

08020008 <skip>:
 8020008:   4678        mov r0, pc
 802000a:   4907        ldr r1, [pc, #28]   ; (8020028 <gotbase+0x10>)
 802000c:   4008        ands    r0, r1
 802000e:   4902        ldr r1, [pc, #8]    ; (8020018 <gotbase>)
 8020010:   1840        adds    r0, r0, r1
 8020012:   f000 f80b   bl  802002c <centry>
 8020016:   e7fe        b.n 8020016 <skip+0xe>

08020018 <gotbase>:
 8020018:   00000064    andeq   r0, r0, r4, rrx
 802001c:   08020000    stmdaeq r2, {}  ; <UNPREDICTABLE>
 8020020:   00000044    andeq   r0, r0, r4, asr #32
 8020024:   00000040    andeq   r0, r0, r0, asr #32
 8020028:   ffff0000            ; <UNDEFINED> instruction: 0xffff0000

0802002c <centry>:
 802002c:   b510        push    {r4, lr}
 802002e:   4654        mov r4, r10
 8020030:   2205        movs    r2, #5
 8020032:   4b08        ldr r3, [pc, #32]   ; (8020054 <centry+0x28>)
 8020034:   58e3        ldr r3, [r4, r3]
 8020036:   601a        str r2, [r3, #0]
 8020038:   4b07        ldr r3, [pc, #28]   ; (8020058 <centry+0x2c>)
 802003a:   58e3        ldr r3, [r4, r3]
 802003c:   3201        adds    r2, #1
 802003e:   204d        movs    r0, #77 ; 0x4d
 8020040:   601a        str r2, [r3, #0]
 8020042:   f000 f80d   bl  8020060 <fun>
 8020046:   4b05        ldr r3, [pc, #20]   ; (802005c <centry+0x30>)
 8020048:   58e3        ldr r3, [r4, r3]
 802004a:   6018        str r0, [r3, #0]
 802004c:   bc10        pop {r4}
 802004e:   bc01        pop {r0}
 8020050:   4700        bx  r0
 8020052:   46c0        nop         ; (mov r8, r8)
 8020054:   00000000    andeq   r0, r0, r0
 8020058:   00000008    andeq   r0, r0, r8
 802005c:   00000004    andeq   r0, r0, r4

08020060 <fun>:
 8020060:   3003        adds    r0, #3
 8020062:   4770        bx  lr

Disassembly of section .got:

08020064 <.got>:
 8020064:   20000000    andcs   r0, r0, r0
 8020068:   20000004    andcs   r0, r0, r4
 802006c:   20000008    andcs   r0, r0, r8

который меняет его, чтобы использовать это

 802002e:   4654        mov r4, r10

, но обратите внимание, что инструменты не устанавливают r10, вы должны добавить код к точке r10 в GOT, чтобы это работало вообще даже на связанном адресе.

Итак, опять же, GOT сам не перемещается, вот и весь смысл, содержимое меняется на точку в перемещенном месте для .data / .bss.См. Последний пример выше. GOT находится в том же месте, но адреса для x, y, z были изменены, чтобы отразить их новое местоположение.Разборка показывает адреса на основе связанных адресов, но если вы связываетесь с другим адресом и сравниваете только машинный код, вы увидите, что он не меняется, используемые инструкции относятся к ПК.

...