Принуждение определенных переменных, сгенерированных компилятором, в определенные разделы ELF (с помощью gcc)

Я начну с главного вопроса: В C с gcc можно ли получить значение (я) __ func __ (или, что эквивалентно, __ FUNCTION __ ), сохраненное в разделе, отличном от .rodata ( или где бы то ни было -mrodata = очков) или его часть?

Полное объяснение:

Скажем, у меня есть макрос регистрации:

#define LOG(fmt, ...) log_internal(__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)

(Оператор конкатенации строк ## используется в этом унарном контексте, использует предыдущую запятую тогда и только тогда, когда список __ VA_ARGS __ пуст, что позволяет использовать строку формата с аргументами или без них.)

Затем я могу использовать макрос обычно:

void my_function(void) {
    LOG("foo!");
    LOG("bar: %p", &bar);
}

может печатать (очевидно, в зависимости от реализации log_internal ):

foo.c:201(my_function) foo!
foo.c:202(my_function) bar: 0x12345678

В этом случае строки формата ( "foo" и "bar: % p ") и строки препроцессора (" foo.c " и " my_function ") являются анонимными данными только для чтения, и они помещаются в . rodata автоматически.

Но скажем, я хочу, чтобы они переместились в другое место (я использую встроенную платформу, на которой для скорости работает почти все из ОЗУ, но ограничения памяти подталкивают к перемещению некоторых вещей в ПЗУ). «Легко» переместить __ FILE __ и строку формата:

#define ROM_STR(str) (__extension__({static const __attribute__((__section__(".rom_data"))) char __c[] = (str); (const char *)&__c;}))
#define LOG(fmt, ...) log_internal(ROM_STR(__FILE__), __LINE__, __func__, ROM_STR(fmt), ##__VA_ARGS__)

Вы не можете поместить __ атрибут __ в анонимную строку, поэтому макрос ROM_STR дает это временное имя, прикрепляет его к определенному разделу, затем вычисляет начальный адрес, чтобы его можно было чисто заменить. Это не сработает, если вы попытаетесь передать переменную char * в LOG в качестве строки формата, но я готов исключить этот вариант использования.

Обычно анонимный Строки, которые оказались идентичными, объединяются компилятором в одно место хранения, поэтому каждый экземпляр __ FILE __ в одном файле будет иметь один и тот же адрес времени выполнения. При явном именовании в ROM_STR каждый экземпляр получит свое собственное место хранения, поэтому, вероятно, нет смысла использовать его в __ FILE __ .

Однако я бы хотел хотел бы использовать его на __ func __ . Проблема в том, что __ func __ - это не та же магия, что и __ FILE __ . Из руководства gcc, «Имена функций как строки»:

Идентификатор __ func __ неявно объявляется переводчиком, как если бы сразу после открывающей скобки каждого определения функции появилось объявление

static const char __func__[] = "function-name";

, где имя-функции - это имя функции, включающей лексику. Это имя - простое имя функции. ... Эти идентификаторы не являются макросами препроцессора. В GCC 3.3 и ранее, и только в C, __ FUNCTION __ и __ PRETTY_FUNCTION __ обрабатывались как строковые литералы; их можно использовать для инициализации массивов символов, и они могут быть объединены с другими строковыми литералами. GCC 3.4 и более поздние версии обрабатывают их как переменные, например __ func __ .

Таким образом, если вы заключите __ func __ в ROM_STR ,вы получите

error: invalid initializer

, и если вы попытаетесь поместить атрибут раздела до или после использования __ func __ , вы получите

error: expected expression before ‘__attribute__’

или

error: expected ‘)’ before ‘__attribute__’

И, таким образом, мы вернемся к открывающему вопросу: возможно ли чтобы сохранить __ func __ в выбранном мной разделе? Может быть, я смогу использовать -fdata-section и сделать некоторую магию сценария компоновщика, чтобы исключить .rodata .__ func __. * из остальной части .rodata ? Если да, то каков синтаксис подстановки с исключением в скрипте компоновщика? Другими словами, где-то у вас есть * (. Rodata *) - я мог бы поместить * (. Rodata .__ func __ *) где-нибудь еще, но мне нужно было бы изменить оригинал glob, чтобы исключить его, чтобы я не получил две копии.

11
задан Eric Angell 22 June 2011 в 22:55
поделиться