отображение памяти с помощью компоновщика

Как я могу заставить компоновщик поместить некоторые из моих переменных в определенное место в памяти. Например, я хочу выделить целое число name в 0x8100000. Если я не пропустил понимание, я могу использовать:

int name __attribute__ ((section ("name_of_section")));

а затем в скриптах компоновщика:

 SECTIONS
 {
   ...
   . = 0x8100000;
   .data : { name_of_section }
   ...
 }

Я хочу использовать что-то подобное для карты порта UC. Но что-то не совпадает, и я не знаю, где я ошибся. (Я никогда не использовал скрипт компоновщика, поэтому извините, если я написал что-то очень глупое).


person qubu    schedule 05.01.2012    source источник


Ответы (3)


Обычно это делается без скрипта компоновщика.

int volatile * const portA = 0x8100000;  //portA is a constant pointer to a volatile int
...

*portA = 53;  //write value 53 to output port

Если вы должны использовать скрипт компоновщика, он будет зависеть от компилятора и/или чипа. Можете ли вы сказать нам, какой чип и набор инструментов вы используете?

person Luke Postema    schedule 06.01.2012
comment
Спасибо за ответ. Я знаю это решение, но я хочу использовать для этого компоновщик. Это для STM32 uC. Я использую eclpis с Sourcery G++ Lite. - person qubu; 06.01.2012
comment
Если вам нужно получить доступ к регистру устройства или чему-то еще в определенном месте памяти, я бы рекомендовал сделать это таким образом (и, возможно, добавить volatile, чтобы убедиться, что это работает). Если вам просто нужны данные в общей области, то я бы сказал, что приведенный выше фрагмент скрипта компоновщика в порядке. Вам придется сказать больше о своей проблеме, чем о том, что что-то не совпадает. - person ams; 06.01.2012
comment
@ams - извините, я забыл volatile. Я исправлю это сейчас. - person Luke Postema; 06.01.2012
comment
Я знаю, что это зависит от чипа, адрес, который я упоминаю, это только пример. Я добился отображения памяти, используя технику, аналогичную вашей, и она работает правильно, но теперь я хочу добиться этого с помощью скриптов компоновщика, и я не знаю, как это сделать правильно. Я попытался найти пример здесь: sourceware.org/binutils/docs-2.21/ld Но я не вижу примера установки адреса для конкретной переменной. Я знаю, что могу использовать атрибут section в компиляторе gcc. Затем я попытался использовать его в скрипте компоновщика, но думаю, что делаю что-то не так. - person qubu; 06.01.2012
comment
вы можете просто определить переменные (ну, метки) в скрипте компоновщика. См. простые задания в документах, на которые вы ссылаетесь. Я думаю, вам нужно будет объявить переменную как extern в исходниках C. - person ams; 06.01.2012
comment
@qubu: Почему вы так настаиваете на использовании компоновщика для этого? Если это чисто для обучения, я могу понять ... но использование компоновщика, IMO, (а) менее очевидно (где порт А? Кто знает ... скрипт компоновщика обычно находится вне дерева исходного кода, и (б) это менее переносимо. Ответ Люка правильный, очевидный, простой и переносимый. Это все, что мне нравится видеть в коде. - person Dan; 07.01.2012

Спасибо за все ваши советы! Теперь это работает. .ld-файл:

SECTIONS
{
...
   .data: {
   ...
   }
   ...
   var_name = 0x40010CA0;
}

.c-файл:

extern volatile int var_name;

После изучения документов, на которые я ссылался выше (пример раздела ввода), я попробовал также что-то вроде этого: файл .ld:

.hrd_map 0x40010CA0 : 
{       
    main.o(.b_section)  
}

Где .b_section была глобальной переменной с атрибутом:

int b __attribute__((section(".b_section")));

Но это не работает, я получил такую ​​ошибку: множественное определение `main'. Я думаю, это потому, что ранее в файле .ld у меня было другое назначение, например: .data: {...} .bss .text. Может быть, кто-то знает, как это исправить или как получить доступ к некоторым переменным без использования атрибута section. Я пытался искать символы для переменных в файле main.o, но я не видел ничего похожего на имя символа для переменной, кроме .b_section, который я создал с использованием атрибута section и других (созданных по умолчанию). ? ) .data .bss .text и т.д.

@ Дэн Ты прав, я делаю это для обучения, и я с тобой согласен. Но, с другой стороны, я думаю, что этот код будет достаточно переносимым, поскольку для каждого чипа требуется .ld и файл запуска, а определение портов также включено в библиотеки.

person qubu    schedule 06.01.2012
comment
Спасибо, я искал это. Я не понимаю всех советов против этого. Я видел, как это делается в коммерческих продуктах. Я не согласен с тем, что ваш код будет намного проще понять и поддерживать и т. д. и т. д. Это необоснованно. В любом случае у вас есть разные скрипты компоновщика для каждого целевого микро. Я нахожу это решение довольно элегантным. - person user7048748; 07.02.2020

Я рекомендую НЕ использовать компоновщик для доступа к аппаратным регистрам. Ваш код будет намного проще понять и поддерживать, если вы явно закодируете адреса. Рекомендуется собрать всю информацию о регистрах конкретного устройства во включаемом файле. Для сложных периферийных устройств обычно рекомендуется типизировать структуру для блока регистров, связанного с периферийным устройством, особенно когда устройство поддерживает несколько экземпляров определенного периферийного устройства. Затем используйте технику из ответа Люка, чтобы получить регистр или регистровый блок в вашем коде. Ключевое слово volatile должно всегда использоваться при доступе к аппаратным регистрам.

person AngCaruso    schedule 06.01.2012