Фиксированная переменная адреса в C

mysqldump -h [host] -p -u [user] [database name] > filename.sql

Пример в localhost

mysqldump -h localhost -p -u root cookbook > cookbook.sql
15
задан 2 revs 25 March 2009 в 18:09
поделиться

10 ответов

Ваш компоновщик и компилятор не знают об этом (конечно, вы ничего не сказали). Разработчик ABI вашей платформы должен указать, что они не размещают объекты по этим адресам.

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

Вы можете использовать опцию defsym с GNU ld для выделения некоторого символа по фиксированному адресу:

--defsym symbol=expression

Или, если выражение является более сложным, чем простая арифметика, используйте специальный скрипт компоновщика. Это место, где вы можете определить области памяти и сообщить компоновщику, какие области должны быть заданы для каких разделов / объектов. См. здесь для объяснения. Хотя обычно это работа автора цепочки инструментов, которую вы используете. Они принимают спецификацию ABI, а затем пишут сценарии компоновщика и бэкэнды ассемблера / компилятора, которые отвечают требованиям вашей платформы.

Между прочим, GCC имеет атрибут section , который вы можете использовать, чтобы поместить вашу структуру в определенный раздел. Затем вы можете указать компоновщику разместить этот раздел в регионе, где находятся ваши регистры.

Registers regs __attribute__((section("REGS")));
12
ответ дан 1 December 2019 в 01:53
поделиться

Компоновщик обычно использовал бы сценарий компоновщика для определения, где переменные будут выделены. Это называют разделом "данных" и конечно должно указать на местоположение RAM. Поэтому для переменной невозможно быть выделенным в адресе не в RAM.

Можно читать больше о сценариях компоновщика в GCC здесь.

8
ответ дан 1 December 2019 в 01:53
поделиться

Ваш компоновщик обрабатывает размещение данных и переменных. Он знает о вашей целевой системе через скрипт компоновщика. Сценарий компоновщика определяет области в макете памяти , такие как .text (для постоянных данных и кода) и .bss (для ваших глобальных переменных и кучи), а также создает корреляцию между виртуальной и физический адрес (если он нужен). Работа сопровождающего скрипта компоновщика заключается в том, чтобы убедиться, что секции, используемые компоновщиком, не переопределяют ваши адреса ввода-вывода.

4
ответ дан 1 December 2019 в 01:53
поделиться

То, когда встроенная операционная система загрузит приложение в память, это будет загружать его в обычно в некотором указанном местоположении, позволяет, говорят 0x5000. Вся локальная память, которую Вы используете, будет относительно того адреса, то есть, интервал x будет где-нибудь похож на 0x5000+code size+4... предполагающий, что это - глобальная переменная. Если это - локальная переменная, его расположенный на стеке. При ссылке на 0x100 Вы ссылаетесь на пространство системной памяти, то же пространство, операционная система ответственна за управление и вероятно очень определенное место, которое это контролирует.

Компоновщик не поместит код в определенных ячейках памяти, он работает в 'относительно того, где мой код программы является' пространством памяти.

Это ломается немного, когда Вы входите в виртуальную память, но для встроенных систем, это имеет тенденцию сохраняться.

Удачи!

2
ответ дан 1 December 2019 в 01:53
поделиться

Заставляя набор инструментальных средств GCC дать Вам изображение, подходящее для использования непосредственно на аппаратных средствах без ОС для загрузки его, возможно, но включает несколько шагов, которые не обычно необходимы для нормальных программ.

  1. Необходимо будет почти наверняка настроить модуль запуска времени выполнения C. Это - модуль блока (часто называл что-то как crt0.s) это - ответственная инициализация инициализируемых данных, очистка BSS, вызов конструкторов для глобальных объектов, если модули C++ с глобальными объектами включены и т.д. Типичные настройки включают потребность установить Ваши аппаратные средства для фактического обращения к RAM (возможно включая установку контроллера DRAM также) так, чтобы было место для помещения данных и стека. Некоторым центральным процессорам нужно было сделать эти вещи в определенной последовательности: например, ColdFire MCF5307 имеет один сигнал выбора кристалла, который отвечает на каждый адрес после начальной загрузки, которая в конечном счете должна быть настроена для покрытия просто области карты распределения памяти, запланированной приложенную микросхему.

  2. У Вашей аппаратной команды (или Вы с другой шляпой на, возможно) должно быть документирование карты распределения памяти, что в различных адресах. ROM в 0x00000000, RAM в 0x10000000, устройство регистрируется в 0xD0000000 и т.д. В некоторых процессорах аппаратные команды, возможно, только соединили сигнал выбора кристалла с ЦП на устройство и оставляют его до Вас для решения что триггеры адреса тот избранный контакт.

  3. GNU ld поддерживает очень гибкий язык сценария компоновщика, который позволяет различным разделам исполняемого изображения быть помещенными в определенные адресные пространства. Для нормального программирования Вы никогда не видите сценарий компоновщика начиная с запаса, каждый предоставляется gcc, который настраивается на предположения Вашей ОС для нормального приложения.

  4. Вывод компоновщика находится в перемещаемом формате, который предназначается, чтобы быть загруженным в RAM ОС. Это, вероятно, имеет перемещение fixups, который должен быть завершен и может даже динамично загрузить некоторые библиотеки. В системе ROM (обычно) не поддерживается динамическая загрузка, таким образом, Вы не будете делать этого. Но Вам все еще нужно необработанное двухуровневое изображение (часто в ШЕСТНАДЦАТЕРИЧНОМ формате, подходящем для программиста PROM некоторой формы), таким образом, необходимо будет использовать objcopy утилиту от binutil для преобразования вывода компоновщика к подходящему формату.

Так, для ответа на фактический вопрос, Вы спросили...

Вы используете сценарий компоновщика для определения целевых адресов каждого раздела изображения программы. В том сценарии у Вас есть несколько опций для контакта с регистрами устройства, но все они включают помещение текста, данных, bss стек и сегменты "кучи" в диапазонах адресов, которые избегают аппаратных регистров. Существуют также механизмы, доступные, который может удостовериться, что ld бросает ошибку, если Вы переполняете свой ROM или RAM, и необходимо использовать их также.

На самом деле получение адресов устройства в Ваш код C может быть, покончили #define как в Вашем примере, или путем объявления символа непосредственно в сценарии компоновщика, который разрешен к базовому адресу регистров с соответствием extern объявление в заголовочном файле C.

Хотя возможно использовать GCC's section атрибут для определения экземпляра неинициализированного struct столь же будучи расположенным в определенном разделе (такой как FPGA_REGS), я нашел что не работать хорошо в реальных системах. Это может создать проблемы обслуживания, и это становится дорогим способом описать полную карту регистра устройств на микросхеме. При использовании той техники сценарий компоновщика затем был бы ответственен за отображение FPGA_REGS к его корректному адресу.

В любом случае Вы испытываете необходимость для получения хорошего понимания понятий объектного файла, таких как "разделы" (конкретно текст, данные и разделы bss в минимуме), и, возможно, должны упорно искать детали, которые устраняют разрыв между аппаратным и программным обеспечением, таким как таблица векторов прерываний, прерывают приоритеты, супервизор по сравнению с непривилегированными режимами (или звонит от 0 до 3 на x86 вариантах), и т.п..

2
ответ дан 1 December 2019 в 01:53
поделиться

Обычно эти адреса вне досягаемости Вашего процесса. Так, Ваш компоновщик не смел бы помещать материал там.

1
ответ дан 1 December 2019 в 01:53
поделиться

Если ячейка памяти имеет особое значение на Вашей архитектуре, компилятор должен знать, что и не помещают любые переменные там. Это было бы подобно IO отображенное пространство на большей части архитектуры. Это не знает, что Вы используете его для хранения значений, это просто знает, что нормальные переменные не должны идти туда. Много встроенных компиляторов поддерживают расширения языка, которые позволяют Вам объявлять переменные и функции в определенных местоположениях, обычно с помощью #pragma. Кроме того, обычно способ, которым я видел, что люди реализуют вид размещения в ОЗУ, которое Вы пытаетесь сделать, состоит в том, чтобы объявить интервал в желаемой ячейке памяти, затем просто рассматривать его как глобальную переменную. Поочередно, Вы могли объявить указатель на интервал и инициализировать его к тому адресу. Оба из них обеспечивают больше безопасности типов, чем макрос.

1
ответ дан 1 December 2019 в 01:53
поделиться

Чтобы подробно остановиться на ответе litb, можно также использовать --just-symbols=опция {symbolfile} определить несколько символов, в случае, если у Вас есть больше чем несколько устройств с отображенной памятью. Файл символов должен быть в формате

symbolname1 = address;
symbolname2 = address;
...

(Пробелы вокруг равняются знаку, кажется, требуются.)

1
ответ дан 1 December 2019 в 01:53
поделиться

Зачастую для встроенного программного обеспечения вы можете определить в файле компоновщика одну область ОЗУ для переменных, назначенных компоновщиком, и отдельную область для переменных в абсолютных местоположениях, которые компоновщик не будет касаться.

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

1
ответ дан 1 December 2019 в 01:53
поделиться

Это зависит немного от того, что ОС Вы используете. Я предполагаю, что Вы используете что-то как DOS или vxWorks. Обычно система будет иметь certian области пространства памяти зарезервированными для аппаратных средств, и компиляторы для той платформы всегда будут достаточно умны для предотвращения тех областей для их собственных выделений. Иначе Вы постоянно писали бы случайный мусор в диск или построчные принтеры, когда Вы означали получать доступ к переменным.

В случае, если что-то еще смущало Вас, я должен также указать на это #define директива препроцессору. Никакой код не сгенерирован для этого. Это просто говорит компилятору дословно заменять любого foo_reg это видит в Вашем исходном файле с *(int *)0x100. Это не отличается, чем просто ввод *(int *)0x100 в себе везде Вы имели foo_reg, кроме него может выглядеть более чистым.

То, что я, вероятно, сделал бы вместо этого (в современном компиляторе C):

// access register 'foo_reg', which is located at address 0x100
const int* foo_reg = (int *)0x100;
*foo_reg = 1;  // write to foo_regint 
x = *foo_reg;  // read from foo_reg
0
ответ дан 1 December 2019 в 01:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: