У меня есть некоторые вопросы о макете памяти программы в Linux. Я знаю из разных источников (я читаю «Программирование с нуля»), что каждый раздел загружается в свою область памяти. Текстовый раздел загружается сначала с виртуального адреса 0x8048000, секция данных загружается сразу после этого, следующая - раздел bss, за которым следуют куча и стек.О макете памяти программ в Linux
Чтобы поэкспериментировать с макетом, я сделал эту программу в сборке. Сначала он печатает адреса некоторых меток и вычисляет точку разрыва системы. Затем он входит в бесконечный цикл. Цикл увеличивает указатель, а затем пытается получить доступ к памяти по этому адресу, в какой-то момент ошибка сегментации выйдет из программы (я сделал это намеренно).
Это программа:
.section .data
start_data:
str_mem_access:
.ascii "Accessing address: 0x%x\n\0"
str_data_start:
.ascii "Data section start at: 0x%x\n\0"
str_data_end:
.ascii "Data section ends at: 0x%x\n\0"
str_bss_start:
.ascii "bss section starts at: 0x%x\n\0"
str_bss_end:
.ascii "bss section ends at: 0x%x\n\0"
str_text_start:
.ascii "text section starts at: 0x%x\n\0"
str_text_end:
.ascii "text section ends at: 0x%x\n\0"
str_break:
.ascii "break at: 0x%x\n\0"
end_data:
.section .bss
start_bss:
.lcomm buffer, 500
.lcomm buffer2, 250
end_bss:
.section .text
start_text:
.globl _start
_start:
# print address of start_text label
pushl $start_text
pushl $str_text_start
call printf
addl $8, %esp
# print address of end_text label
pushl $end_text
pushl $str_text_end
call printf
addl $8, %esp
# print address of start_data label
pushl $start_data
pushl $str_data_start
call printf
addl $8, %esp
# print address of end_data label
pushl $end_data
pushl $str_data_end
call printf
addl $8, %esp
# print address of start_bss label
pushl $start_bss
pushl $str_bss_start
call printf
addl $8, %esp
# print address of end_bss label
pushl $end_bss
pushl $str_bss_end
call printf
addl $8, %esp
# get last usable virtual memory address
movl $45, %eax
movl $0, %ebx
int $0x80
incl %eax # system break address
# print system break
pushl %eax
pushl $str_break
call printf
addl $4, %esp
movl $start_text, %ebx
loop:
# print address
pushl %ebx
pushl $str_mem_access
call printf
addl $8, %esp
# access address
# segmentation fault here
movb (%ebx), %dl
incl %ebx
jmp loop
end_loop:
movl $1, %eax
movl $0, %ebx
int $0x80
end_text:
И это соответствующие части вывода (это Debian 32bit):
text section starts at: 0x8048190
text section ends at: 0x804823b
Data section start at: 0x80492ec
Data section ends at: 0x80493c0
bss section starts at: 0x80493c0
bss section ends at: 0x80493c0
break at: 0x83b4001
Accessing address: 0x8048190
Accessing address: 0x8048191
Accessing address: 0x8048192
[...]
Accessing address: 0x8049fff
Accessing address: 0x804a000
Violación de segmento
Мои вопросы:
1) Почему моя программа начинается с адреса 0x8048190 вместо 0x8048000? С этим я думаю, что инструкция на ярлыке «_start» не является первой загрузкой, так что между адресами 0x8048000 и 0x8048190?
2) Почему существует разрыв между концом текстового раздела и началом раздела данных?
3) Начальные и конечные адреса bss совпадают. Я предполагаю, что два буфера хранятся где-то в другом месте, это правильно?
4) Если точка разрыва системы находится в 0x83b4001, почему я получил ошибку сегментации раньше на 0x804a000?
Почти полностью не по теме, если вы никогда [читайте это, не смотрите на него] (http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html) - это отлично читал. –
Обратите внимание, что загрузчик ELF заботится только о * сегментах * исполняемого файла. Во многих случаях есть отображение 1: 1, например, раздел '.text' (после ссылки) является единственным в текстовом сегменте. Компилятор объединяет разделы, такие как '.rodata', в' .text'. Кроме того, «куча» на самом деле не вещь, которая существует и является скорее концепцией (выделения с mmap (MAP_ANONYMOUS) не смежны с «brk»).Я не уверен, считают ли люди BSS и статические данные частью кучи. Также не уверен, что Linux ставит исходный 'brk' сразу после BSS. –