ber das Speicherlayout von Programmen unter Lin

Ich habe einige Fragen zum Speicherlayout eines Programms unter Linux. Ich weiß aus verschiedenen Quellen (ich lese "Programming from the Ground Up"), dass jeder Abschnitt in seine eigene Speicherregion geladen wird. Der Textabschnitt wird zuerst unter der virtuellen Adresse 0x8048000 geladen, der Datenabschnitt wird sofort danach geladen, als nächstes folgt der bss-Abschnitt, gefolgt vom Heap und dem Stack.

Um mit dem Layout zu experimentieren, habe ich dieses Programm in Assembler erstellt. Zuerst werden die Adressen einiger Etiketten gedruckt und der Systembruchpunkt berechnet. Dann tritt es in eine Endlosschleife ein. Die Schleife inkrementiert einen Zeiger und versucht dann, an dieser Adresse auf den Speicher zuzugreifen. Irgendwann wird das Programm durch einen Segmentierungsfehler beendet (ich habe dies absichtlich getan).

Dies ist das Programm:

.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:

Und dies sind die relevanten Teile der Ausgabe (das ist 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

Meine Fragen sind:

1) Warum beginnt mein Programm mit der Adresse 0x8048190 anstelle von 0x8048000? Mit diesem denke ich, dass die Anweisung am "_start" Etikett nicht das erste ist, was zu laden ist, also was ist zwischen den Adressen 0x8048000 und 0x8048190?

2) Warum gibt es eine Lücke zwischen dem Ende des Textabschnitts und dem Beginn des Datenabschnitts?

3) Die Start- und Endadresse von bss sind identisch. Ich gehe davon aus, dass die beiden Puffer woanders gespeichert sind, stimmt das?

4) Wenn der Systembruchpunkt bei 0x83b4001 liegt, warum erhalte ich den Segmentierungsfehler früher bei 0x804a000?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage