10.2 Загрузка и выполнение программ

Предыдущая  Содержание  Следующая V*D*V

Стандартные приложения Linux связаны (слинкованы) с абсолютными адресами. Другими словами, компилятор и компоновщик собирают приложения с предположением, что каждому приложению доступен весь диапазон виртуальных адресов памяти.

Мы напишем небольшую программу для x86, чтобы получить представление о том, как организованы различные сегменты в доступном адресном пространстве. (* Каждое приложение на x86 способно адресовать диапазон из 4 Гб виртуальных адресов. 1 Гб этого пространства отведено для пространства ядра, а остальные 3 Гб доступны для приложений пользовательского пространства.)

 

int data1=1; // будет располагаться в секции .data

int data2=2; // также будет располагаться в секции .data

int main(int argc, char *argv[]) // .text

{

  int stack1=1; // программный стек

  int stack2=2; // программный стек

  char *heap1 = malloc(0x100); // выделение памяти в "куче"

  char *heap2 = malloc(0x100); // также выделение памяти в "куче"

 

  printf(“ text %p\n”, main);

  printf(“ data %p %p\n”, &data1, &data2);

  printf(“ heap %p %p\n”, heap1, heap2);

  printf(“ stack %p %p\n”, &stack1, &stack2);

}

 

Вывод программы:

 

text    0x804835c

data    0x80494f0 0x80494f4

heap    0x8049648 0x8049750

stack   0xbfffe514 0xbfffe510

 

Вывод программы делает ясным, где находится каждый раздел, и в каком направлении растёт каждый сегмент. Стек расположен около верхней части PAGE_OFFSET (0xC000_0000) и растёт вниз. Текст находится ближе к нижней части памяти (библиотеки имеют некоторые области, зарезервированные ещё ниже), следом идёт раздел данных. После окончания данных (то есть инициализированные данные + bss) начинается распределение "кучи", растущее вверх, в направлении растущего стека. Что происходит, когда "куча" и стек встречаются? В этом случае обработчик ошибки страницы посылает в программу сигнал SIGSEGV. Рисунок 10.1 показывает стандартную карту памяти приложения Linux.

 

Рисунок 10.1 Карта памяти приложения для Linux.

Рисунок 10.1 Карта памяти приложения для Linux.

 

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

Теперь же из-за отсутствия VM не может быть создано отдельное виртуальное адресное пространство для каждой программы. Поэтому в uClinux приложения вынуждены использовать совместно всё свободное адресное пространство как один большой непрерывный физический кусок. Программы загружаются в доступную свободную часть памяти, в любом произвольном месте памяти. Напомним, что на системах с MMU это произвольное расположение будет связано с нулевым виртуальным адресом в карте памяти процесса. В отличие от стандартного Linux это означает, что начальный адрес программы неизвестен (а не произвольный адрес) и адресация, используемая в инструкциях, не может быть абсолютной. (* Эта проблема называется проблемой неизвестного адреса.) Загрузчики uClinux занимаются этой дополнительной работой по модификации программы при запуске на основе доступного начального адреса. Компиляторам и компоновщикам также необходимо взаимодействовать с загрузчиком для оказания помощи в этой работе. uClinux имеет два различных метода для решения этой проблемы неизвестного адреса.

 

Предыдущая  Содержание  Следующая