Распределение памяти
Что такое программа?
Давайте предположим, что программа - это набор инструкций машинного кода (не обращая внимания на язык, на котором она была написана), т.е. то, что мы обычно называем двоичным кодом. При первой компиляции, для получения двоичного файла, исходный код программы содержит переменные, константы и инструкции. В этом разделе рассматривается распределение памяти в различных частях двоичного файла.
Различные области
Чтобы понять, что происходит при выполнении двоичного кода, давайте посмотрим на организацию памяти. Она зависит от различных областей:
Вообще говоря это не все, однако мы рассмотрим только те части, которые наиболее важны в этой статье.
Команда size -A file --radix 16 выдает размер каждой области, зарезервированый при компиляции. Отсюда можно взять адреса областей в памяти (вы можете также использовать команду objdump , чтобы узнать эти данные). Вот вывод size для двоичного файла "fct":
>>size -A fct --radix 16
fct :
section size addr
.interp 0x13 0x80480f4
.note.ABI-tag 0x20 0x8048108
.hash 0x30 0x8048128
.dynsym 0x70 0x8048158
.dynstr 0x7a 0x80481c8
.gnu.version 0xe 0x8048242
.gnu.version_r 0x20 0x8048250
.rel.got 0x8 0x8048270
.rel.plt 0x20 0x8048278
.init 0x2f 0x8048298
.plt 0x50 0x80482c8
.text 0x12c 0x8048320
.fini 0x1a 0x804844c
.rodata 0x14 0x8048468
.data 0xc 0x804947c
.eh_frame 0x4 0x8049488
.ctors 0x8 0x804948c
.dtors 0x8 0x8049494
.got 0x20 0x804949c
.dynamic 0xa0 0x80494bc
.bss 0x18 0x804955c
.stab 0x978 0x0
.stabstr 0x13f6 0x0
.comment 0x16e 0x0
.note 0x78 0x8049574
Total 0x23c8
Область text содержит инструкции программы. Эта область предназначена только для чтения. Она общая для всех процессов, выполняющих один и тот же двоичный файл. Попытка писать в эту область вызывает ошибку segmentation violation - нарушение сегментации.
Перед объяснением предназначения других областей, вспомним кое-что о переменных в Си. Глобальные переменные используются во всей программе, в то время как локальные переменные - только в функциях, где они определены. Статические переменные имеют известный размер, зависящий от их типа, при их определении. Тип может быть char , int , double , указатель и т.д. На машине типа PC, указатель представляет собой 32-х битный целый адрес в памяти. Размер области на который он указывает не известен явно при компиляции. Динамическая переменная представляет собой явно выделенную область памяти - на самом деле, это указатель, указывающий на этот выделенный адрес. Глобальные/локальные, статические/динамические переменные могут быть комбинированы без всяких проблем.
Вернемся к организации памяти для данного процесса. Область data содержит инициализированные глобальные статические данные (значения предоставляются во время компиляции), в то время как сегмент bss содержит неинициализированные глобальные данные. Эти области зарезервированы при компиляции, т.к. их размеры определены в соответствии с объектами, которые они хранят.
А что насчет локальных и динамических переменных? Они сгруппированы в область памяти, зарезервированную для выполнения программы (стековый фрейм пользователя). Т.к. функции могут вызываться рекурсивно, количество экземпляров локальных переменных заранее неизвестно. При их создании, они будут помещены в стек. Этот стек находится в области высших адресов в адресном пространстве пользователя и работает по принципу LIFO(Последний вошел, первым вышел). Нижняя часть области пользовательского фрейма используется для размещения динамических переменных. Эта область называется "куча": она содержит память, адресуемую указателями, и динамические переменные. При объявлении, указатель - это 32-х битная переменная в BSS или в стеке, не указывающая ни на какой действительный адрес. Когда процесс выделяет память (например используя malloc), адрес первого байта этой памяти (также 32-х битное число) помещается в указатель.
Назад |
Содержание |
Вперед
Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
|