Я работаю над проектом ARM7TDMI с использованием GCC 4.3, и у меня возникли сложности с указанием компилятору использовать длинные вызовы в некоторых случаях, но не в других.
Процесс сборки запускается arm-eabi-gcc
для генерации перемещаемых объектных файлов ELF для каждого исходного файла .c (большинство соответствующих CFLAGS включают -Os -ffunction-sections -fdata-sections -mthumb -mthumb-interwork
), затем связывает их все в исполняемый файл ELF (наиболее важные LDFLAGS включают -Wl,--gc-sections -Wl,-static -Wl,-n -nostdlib
, и пользовательский скрипт компоновщика). Затем этот файл ELF преобразуется в необработанный исполняемый файл с arm-eabi-objcopy -O binary
, и пользовательский загрузчик копирует его из ПЗУ в ОЗУ (одну SRAM с кодом и данными) при запуске. Таким образом, все затем выполняется из ОЗУ, .rodata
присутствует в ОЗУ, и все происходит быстро, полностью игнорируя ПЗУ после загрузки.
Сейчас я пытаюсь это изменить, чтобы некоторые выбранные фрагменты данных RO и текст функций выбора могли жить только в ПЗУ и быть доступными во время выполнения по мере необходимости. Я изменил скрипт компоновщика, чтобы узнать о двух новых разделах ".flashdata"
и ".flashtext"
, которые должны быть размещены по фиксированному адресу в ПЗУ. Я также разбросал __attribute__((__section__(".flashdata")))
и __attribute__((__section__(".flashtext"),__long_call__))
по всему коду C, в зависимости от ситуации, и перенастроил процесс сборки так, чтобы старая objcopy теперь добавила -R .flashdata -R .flashtext
, и я делаю вторую objcopy с -j
для каждого из этих разделов я объединяю два выходных файла, чтобы загрузчик мог делать правильные вещи, и разделы ПЗУ появлялись в ожидаемом месте отображения памяти.
Это все работает нормально - я могу распечатать строки, помеченные в разделе .flashdata
, и я могу вызвать функцию .flashtext
из кода, работающего вне ОЗУ (который знает, что использовать длинный вызов из-за атрибута __long_call__
рядом с атрибутом __section__(".flashtext")
). Эта основанная на ПЗУ функция может с радостью вызывать другие функции на основе ПЗУ и возвращаться обратно к вызывающей программе на основе ОЗУ.
Проблема заключается в попытке вызвать функцию из ПЗУ в функцию, основанную на ОЗУ, что также должно быть длительным вызовом. Я не хочу использовать длинные вызовы везде, поэтому я не хочу -mlong_calls в моих CFLAGS. Если я сгруппирую все функции для жизни в ПЗУ в один rom.c
, я могу создать этот один файл с -mlong-calls
, и все будет работать. Тем не менее, я настоятельно предпочитаю избегать этого и сохранять функции, сгруппированные, как правило, по назначению, просто помечая некоторые из них здесь и там при необходимости для запуска из ПЗУ.
Кстати, этого было недостаточно при gcc 3.4. Использование -mlong-calls
заставило компилятор думать правильно, но он не мог выполнить его, потому что он был готов выполнять длинные прыжки только со своими помощниками _call_via_rX
..., которые все жили в ОЗУ и могли быть доступны только через длинные вызов. Это было исправлено в компоновщике в gcc 4.0, но не перенесено ни на что в дереве 3.x .
Так что замечательно, что теперь я могу вообще перезванивать в ОЗУ, так как я использую gcc 4.3. Было бы еще лучше, если бы я мог как-то пометить код в функциях на основе ПЗУ, чтобы заставить его использовать длинные вызовы. Существует #pragma long_calls
, но он влияет только на объявления, поэтому я мог бы использовать его вместо __attribute__((__long_call__))
. К сожалению, он волшебным образом не заставляет компилятор использовать длинные вызовы для всех вызовов функций, с которыми он сталкивался, пока он действует.
С организационной точки зрения просто неправильно делать группу медленно работающего кода в одном файле вне контекста и отдельно от другого кода в его общей категории. Пожалуйста, скажите мне, что есть вариант, который я еще не рассматривал. Почему -ffunction-section или просто тот факт, что код находится в разных разделах (.text
против .flashtext
), автоматически не решают мою проблему?
Кстати, ошибка компоновщика, когда он обнаруживает, что компилятор использовал короткий вызов, который не оставил ему достаточно места для управления перемещением, это: relocation truncated to fit: R_ARM_THM_CALL against symbol
foo ', определенный в разделе .text.foo в objs / foo.o (and the section
.text.foo is used instead of
.text because of
-функция-секции` в CFLAGS).