ARM Thumb-2, GCC, изменения кода и инструкция `stmdaeq`

Я использую MCU STM32F4 (Cortex-M4) и компилирую с помощью arm-none-eabi-g++ (я использую C++).

У меня есть требование сократить время, необходимое для загрузки моего двоичного файла во флэш-память MCU. Я понял, что могу сделать это, только загружая изменения в свой двоичный файл между модификациями. Однако компилятор генерирует интересный код, который делает это невозможным.

Рассмотрим следующие 2 программы:

(1)

int main()
{
    printf("hello");
    return 0
}

(2)

int main()
{
    //printf("hello");
    return 0
}

Просто удалив вызов printf, двоичный файл кардинально изменится. Я вижу это, разобрав код с помощью arm-none-eabi-objdump -D mybinary. Вот пример различий в WinMerge:

введите здесь описание изображения

Как видно на изображении, почти все функции имеют немного другую инструкцию stmdaeq, и я хочу узнать об этом больше.

Ответ на этот вопрос будет включать следующее:

  • Я знаю, что такое инструкция stmdaeq, но почему она стоит в конце почти всех функций? Это эпилог функции?
  • Могу ли я что-нибудь сделать (параметры компилятора или иным образом), чтобы незначительные изменения кода, как в моем примере выше, не вызывали таких изменений во всем двоичном коде?

Я использую набор инструментов GNU Tools для встроенных процессоров ARM GCC.

Ваша помощь будет высоко оценена.


person Verax    schedule 09.07.2014    source источник
comment
Ваша попытка, вероятно, бесполезна. На практике, несмотря на то, что большие фрагменты кода могут оставаться неизменными с точки зрения инструкций, они почти наверняка обычно меняют адрес при вставке или удалении кода. Кроме того, флэш-память стирается по блокам, поэтому шансы на отсутствие изменений в конкретном блоке минимальны - в любом случае придется стирать и записывать весь блок. В зависимости от конкретной части фактический размер блока Flash может быть очень большим. Вы можете добиться большего, применив агрессивную оптимизацию размера и указав компоновщику заполнять неиспользуемые пробелы 0xFF.   -  person Clifford    schedule 09.07.2014
comment
@Clifford, вы правы в том, что вы должны написать весь блок, даже если изменен 1 байт. Я уже предусмотрел это в своей флеш-программе. @Сева Алексеев был прав. Строки stmdaeq на самом деле являются адресами, вставленными во время компоновки. Я обнаружил, что путем кропотливой организации и сортировки символов в моем скрипте компоновщика я могу сделать двоичный файл более последовательным между изменениями и достичь желаемого результата.   -  person Verax    schedule 10.07.2014
comment
Возможно, для этого небольшого примера, но для реального (и большого) приложения?   -  person Clifford    schedule 10.07.2014
comment
@Clifford, да, но я признаю, что это зависит от изменений. Некоторые изменения потребуют перепрошивки всей программы, но мои модификации скрипта компоновщика уменьшили частоту этого. Довольно приятно обновлять только 1 блок для незначительного изменения.   -  person Verax    schedule 11.07.2014


Ответы (1)


Это не инструкция, это константа в разделе кода. Вы можете сказать, потому что это сразу за оператором возврата, то есть pop ...,pc или bx lr.

Его цель? Единственная цель, которую я вижу, это то, что он хранит адрес глобальной переменной. Скорее всего, это константа времени связи - т.е. е. это разрешено компоновщиком, а не компилятором. Но его код присутствует в системных функциях (связанных с alloc и т.д.). Таким образом, вы не можете избавиться от него - байты для константы находятся в объектном файле RTL вместе с инструкцией по перемещению для компоновщика.

Вероятно, это артефакт C++ RTL. Попробуйте перейти на С.

person Seva Alekseyev    schedule 09.07.2014