Как получить конечный адрес моего кода - PullRequest
3 голосов
/ 05 июня 2009

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

Я слышал, что переменная __end, предоставляемая GCC, является концом кода, но я понятия не имею, что означает __end и как использовать его в моем коде. Может ли кто-нибудь объяснить это немного или дать ссылки на некоторые материалы, потому что я не могу google __end?

Большое спасибо.

Ответы [ 4 ]

3 голосов
/ 06 июня 2009

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

Для gcc и binutils вы будете использовать синтаксис сценария компоновщика ld. Обратитесь к руководству ld для всех деталей, которые я здесь опускаю. Это немного непрозрачно, но вы должны потратить некоторое время с ним, если вы собираетесь потратить значительное количество усилий во встроенном мире. Это окупится за вас.

В скрипте компоновщика вы хотите определить символ перед вашим сегментом .text и один после.

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

В моем сценарии я просто использую что-то вроде:

__SDRAM_CS1 = 0x10000000;

чтобы определить символ с постоянным адресом, который ссылается (в данном случае) на местоположение, мы решили, что контроллер SDRAM отобразит память SDRAM, и в C я объявляю его следующим образом:

extern unsigned char __SDRAM_CS1[];

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

Для символа, определяющего конец сегмента .text, в скрипте компоновщика должно быть что-то похожее на следующее

SECTIONS
{
    ...
    .text {
        _start_text = .;
        *(.text);
        ...
        _end_text = .;
    }
    ...
}

и объявить начальный и конечный символы как

extern unsigned char _start_text[];
extern unsigned char _end_text[];

в C. Тогда начальный адрес просто _start_text, а длина в байтах текстового сегмента равна _end_text - _start_text.

Обратите внимание, что я упустил много деталей. Возможно, у вас есть разделы с именами, отличными от .text, которые должны обрабатываться так, как если бы они были в текстовом сегменте. Ярким примером являются данные только для чтения, которые часто можно безопасно размещать в текстовом сегменте, поскольку известно, что это const, а во встроенной системе вы не захотите копировать их в ценную оперативную память, если в этом нет необходимости. Кроме того, инициализаторы для сегмента данных и внутренние списки конструкторов глобальных объектов расположены рядом с текстовым сегментом.

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

2 голосов
/ 05 июня 2009

Вы можете использовать скрипт компоновщика. В вашем коде C объявите:

// call this whatever you want; the linker will fill this in with the address
// of the end of code
extern uint32_t endOfCode;

Затем в своем сценарии компоновщика сразу после определения раздела .text добавьте следующее:

PROVIDE(endOfCode = .);

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

0 голосов
/ 06 июня 2009

Вместо того, чтобы ставить его в конце, не могли бы вы просто объявить большой статический массив и использовать его, без каких-либо хитрых компиляторов или трюков с компоновщиками?

0 голосов
/ 05 июня 2009

Ну, я не , который знаком с GCC, но, возможно, вы можете сделать что-то вроде этого:

long foo()
{
    int anything[0];
    return *(&anything - 1);
}

long endOfProgram()
{
    return stackPointer();
}

Я пытаюсь сделать следующее:

  1. Вызов endOfProgram ()
  2. endOfProgram вызывает foo, поэтому адрес endOfProgram помещается в стек.
  3. Вставьте что-нибудь [0] в стек foo.
  4. Захватите расположение элемента прямо перед адресом чего-либо, что должно быть местоположением в памяти endOfProgram.

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

EDIT:

... или просто захватите значение указателя на функцию endOfProgram. Я думаю, это тоже сработает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...