Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Страницы в этом регионе доступны для чтения



Страницы в этом регионе доступны для записи

Страницы в этом регионе могут быть выполнены

Страницы в этом регионе могут быть доступны сразу для нескольких процессов

Линейные адреса добавляются начиная с нижнего

Линейные адреса добавляются начиная с верхнего

Запись на страницы запрещена

Страницы в этом регионе состоят из исполнимого кода

Страницы блокированы

Страницы нельзя скопировать

Эта виртуальная область памяти не может быть расширена


а.В оригинальном тексте опечатка - должно быть VM_DONTEXPAND. Примеч. науч. ред.


Размещение образа процесса и линейное адресное пространство 219

4.7.2.5 vm_rb

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

4.7.2.6 vm_ops

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

Размещение образа процесса и линейное адресное пространство

Когда в память загружается программа пользовательского пространства, она получает линейное адресное пространство, разделенное на области памяти (memory_areas), или сегменты. Эти сегменты выполняют различные функции при выполнении процесса. Функционально разделенные сегменты отображаются в адресное пространство процесса. С выполнением процесса связано 6 главных сегментов.

• TeKCT(text). Этот сегмент, также известный как сегмент кода, хранит исполнимые инструкции программы. Поэтому он обычно имеет атрибуты execute и read. В случае, когда из одной программы может быть загружено много процессов, загружать одни и те же инструкции несколько раз слишком расточительно. Linux позволяет нескольким процессам разделять в памяти текстовые сегменты. Поля start_code и end_code структуры mm_struct хранят адреса начала и конца текстового сегмента.

• Данные(сШа). Этот сегмент хранит все инициализированные данные. Инициа­лизированные данные включают статически выделенные и глобальные инициа­лизированные данные. Следующий фрагмент кода демонстрирует пример инициализированных данных.

example.с

int gvar = 10;

int main(){

}

• gvar. Глобальная переменная, которая инициализируется и хранится в сегменте дан­ных. Эта секция имеет атрибуты чтения-записи, но не может быть разделена между несколькими процессами, выполняющими одну и ту же программу. Поля



Глава 4 • Управление памятью


start_data и end_data структуры mm_struct хранят адреса начала и конца сегмента данных.

• BSS. Эта секция хранит неинициализированные данные. Эти данные состоят из гло­бальных переменных, инициализируемых в 0 при запуске программы. Также эта секция называется секцией инициализируемых нулем данных. Следующий фраг­мент кода демонстрирует неинициализируемые данные.

example2.с int gvarl[10]; long gvar2; int main(){

}

Объекты в этой секции имеют только атрибуты name и size.

Куча (Heap). Используется для наращивания линейного адресного пространства процесса. Когда программа использует mall ос () для динамического получения памяти, эта память выделяется из кучи. Поля start_brk и brk структуры mm_struct хранят адреса начала и конца кучи. При вызове mall ос () для динамического получения памяти вызов системного вызова sys_brk () переме­щает указатель brk на новую позицию, увеличивая при этом кучу.

Стек (Stack). Хранит все выделяемые локальные переменные. Когда вызываются функции, локальные переменные для этих функций помещаются в стек. Как только функции завершаются, связанные с ними переменные извлекаются из стека. Осталь­ная информация, включая адреса возврата и параметры, также размещается в стеке. Поле start_stack структуры mm_struct помечает начальный адрес стека процесса.

Несмотря на то что с выполняемым процессом связано 6 сегментов, они отобра­жаются только в 3 области памяти адресного пространства. Эти области памяти назы­ваются text, data и stack. Сегмент data включает инициализированный выполняе­мый сегмент data, bss и кучу. Сегмент text включает исполнимый сегмент text. Рис. 4.11 показывает, как выглядит линейное адресное пространство и как mm_struct следит за этими сегментами.

Различные области памяти отображаются в файловую систему /ргос. К отобра­женной для процесса памяти можно получить доступ через вывод /ргос/< pid> /maps. Теперь рассмотрим пример программы и посмотрим список адресов памяти в адресном пространстве процесса. Код в example3.с показывает отображенную в память про­грамму.


Размещение образа процесса и линейное адресное пространство



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

            , к OxCOOOOOOO OxOOOOOOOO  
      arguments & environmental variables  
        stack  
   
start_stack  
     
start_brk  
     
brk      
       
start_data      
     
end_data  
start_code      
     
end.code  
     
   
    heap  
          BSS  
    Initialized Global data  
    Executable Instructions  
       
                 

Рис. 4.11. Адресное пространство процесса

example3.с

#include < stdio.h>

int main(){

while(1);

return(O); }

Вывод /proc/< pid> /maps для этого примера содержит то, что представлено на рис. 4.12.



Глава 4 • Управление памятью


 

               
  08048000-08049000 r-xp 03: 05 /home/1 kp/example3  
  08049000-0804а000   03: 05 /home/1 kp/example3  
  40000000-40015000 r-xp 03: 05 /lib/ld-2.3.2.so  
  40015000-40016000 rw-p 03: 05 /liMd-2.3.2.so  
  40016000-40017000 rw-p 00: 00    
  42000000-4212е000 r-xp 03: 05 /lib/tls/Iibc-2.3.2.so  
  42126000-42131000 rw-p 03: 05 /lib/tls/libc-2.3.2.so  
  42131000-42133000 rw-p 00: 00    
  bfffeOOO-cOOOOOOO rwxp fffffOOO 00: 00    
               

Рис. 4.12. /prod< pid> /maps

Самая левая колонка показывает диапазон сегментов памяти. Это начальные и ко­нечные адреса отдельных сегментов. Следующая колонка показывает разрешение на дос­туп к этим сегментам. Эти флаги похожи на разрешения доступа к файлам: г означает чте­ние, w - запись, а х - возможность выполнения. Последним флагом может быть р, обо­значающее частный (private) сегмент, или s, означающее разделяемый (shared) сегмент. (Частный сегмент не обязательно неразделяемый.); р указывает, что текущий сегмент не был разделен. Следующая колонка содержит отступ для сегмента. Четвертая колонка сле­ва хранит два числа, разделенные двоеточием. Она означают максимальное и минималь­ное число файлов файловой системы, связанных с данным сегментом. (Некоторые сегмен­ты не имеют ассоциированных с ними файлов, и для них эти значения будут равны 00: 00.) Пятая колонка хранит inode файла, а самая правая колонка- имя файла. Для сегментов без имен файлов эта колонка остается пустой, а колонка inode равна 0.

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

Наша программа связывается динамически, что означает, что используемые ей функ­ции принадлежат к загружаемой во время ее выполнения библиотеке. Эти функции необ­ходимо отобразить в адресное пространство, чтобы к ним можно было получить доступ. Следующие 6 строк работают с динамически загружаемыми библиотеками. Следующие 3 строчки описывают text, data и bss библиотеки Id. За этими тремя строчками следу­ет описание секций библиотеки test, data и bss в том же порядке.

Последняя строчка обладает разрешением на чтение, запись и выполнение, представ­ляет стек процесса и расширяется до 0х0С0000000, т. е. до наибольшего адреса в памяти, доступного для процесса из пользовательского пространства.


Таблицы страниц



Таблицы страниц

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

Таблицы страниц следят за памятью в элементах фреймов страниц. Они хранятся в оперативной памяти в течение всей жизни ядра. Linux использует так называемую трех­уровневую схему подкачки. Трехуровневая подкачка необходима для того, чтобы даже 64-битовая архитектура смогла отобразить в виртуальную память все свои физические адреса. Как следует из названия схемы, трехуровневая система подкачки имеет 3 типа таб­лиц подкачки: таблицы верхнего уровня, называемые глобальной директорией страниц (Page Global Directory) (PGD), представляемой с помощью типа данных pgd_t; таблицы средней директории страниц (Page Middle Directory, PMD), представляемой с помощью типа данных pmd_t, и таблицы страницы (Page Table, РТЕ), представляемая в виде типа данных pte__t. Таблицы страниц изображены на рис. 4.13.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  task_struct                            
       
mm w mm_struct    
    РПП РМП DTC Don»  
   
PQd         > rayc    
                     
        1—►    
               
       
       
           
                             

Рис. 4.13. Таблицы страниц в Linux

PGD хранит вхождения, связанные с PMD. PMD хранит вхождения, связанные с РТЕ, а РТЕ хранит вхождения ссылок на отдельные страницы. Каждая страница обладает соб­ственным набором таблиц страниц. Поле mm_strue t-> pgd хранит указатель на PGD процесса; 32- и 654-битовые виртуальные адреса разделяются (в зависимости от архитек­туры) на поля отступа различного размера. Каждому полю соответствует отступ в PGD, PMD, РТЕ и в самой странице.



Глава 4 • Управление памятью


Ошибка страницы

На протяжении жизни процесса он может попытаться получить доступ к адресам, ко­торые принадлежат адресному пространству, но не загружены в оперативную память. Вместо этого он может попытаться получить доступ к странице памяти, для которой у него нет разрешения на доступ (например, может попытаться произвести запись в об­ласть только для чтения). Когда это происходит, система генерирует ошибку страницы (page fault). Ошибка страницы - это обработчик исключения, обрабатывающий ошибки доступа программы к странице. Когда аппаратное обеспечение порождает исключение ошибки страницы, перехватываемое ядром, страница достается из хранилища. После это­го ядро выделяет недостающую страницу.

На каждой архитектуре есть своя архитектурно-зависимая функция для обработки ошибки страницы. На х86 и РРС вызывается функция do__page_f ault (). Обработчик ошибки страницы х86 do_page__f ault (*regs, error_code) находится в /arch/ i3 8 6/mm/fault, с. Обработчик ошибки памяти PowerPC do_page_fault (*regs, address, error__code) находится в /arch/ppc/mm/fault. с. Они настолько по­хожи, что для того, чтобы понять функционирование версии для PowerPC, нам будет дос­таточно рассмотреть только вариант do_page__f ault () для х86.

Основная разница в обработке ошибки страницы этими двумя архитектурами проявляется на этапе сбора и сохранения информации об ошибке, предшествующем вы­зову do_page__f ault (). Для начала рассмотрим особенности обработки ошибки стра­ницы на х86, а затем перейдем к функции do_page_fault (). После этого мы рас­смотрим отличия версии для PowerPC.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-25; Просмотров: 969; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.047 с.)
Главная | Случайная страница | Обратная связь