Pagini
Workshops
Parteneri
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
sesiuni:memory:2 [2013/07/08 11:42] asendroiu [Tasks] |
sesiuni:memory:2 [2013/07/09 16:07] (current) asendroiu [Virtual Memory. Stack] |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | = Virtual Memory. Stack = | ||
+ | * [[sesiuni:memory:| Back to workshop]] | ||
+ | * {{:sesiuni:memory:session-02.pdf|Download slides}} | ||
+ | * {{:sesiuni:memory:session-02-tasks.zip|Download tasks}} | ||
+ | |||
+ | <html> | ||
+ | <center> | ||
+ | <iframe src="http://docs.google.com/viewer?url=http://workshop.rosedu.org/2013/_media/sesiuni/memory/session-02.pdf&embedded=true&time=0" width="600" height="470" style="border: none;"></iframe> | ||
+ | </center> | ||
+ | </html> | ||
= Tasks = | = Tasks = | ||
+ | |||
+ | Rulați ''make'' pentru a compila sursele din directorul session-02-tasks. | ||
+ | |||
+ | == Memoria Virtuală. Spațiul de adresă == | ||
- Formatul ELF | - Formatul ELF | ||
- | * Compilati programul adr_space.c. Folosiți utilitarul readelf pentru a afisa informații despre secțiunile executabilului adr_space. (Hint: man readelf, search: sections) | + | * Folosiți utilitarul ''readelf'' pentru a afisa informații despre secțiunile executabilului ''adr_space''. (Hint: man readelf, search: sections) |
- | * Identificați secțiunile .text, .rodata, .data și .bss. Observați diferențele în coloana Type între .bss și .data. Ce înseamnă ele? | + | * Identificați secțiunile ''.text'', ''.rodata'', ''.data'' și ''.bss''. Observați diferențele în coloana ''Type'' între ''.bss'' și ''.data''. Ce înseamnă ele? |
- Secțiunile unui executabil | - Secțiunile unui executabil | ||
- | * Urmăriți declarațiile de variabile din fișierul adr_space.c. Determinați secțiunea în care a fost plasată fiecare variabilă. În acest scop folosiți objdump. (Hint: objdump -t) | + | * Urmăriți declarațiile de variabile din fișierul ''adr_space.c''. Determinați secțiunea în care a fost plasată fiecare variabilă. În acest scop folosiți ''objdump''. (Hint: objdump -t) |
- | * Verificați că dimensiunea fiecărei variabile (a 5-a coloană din output-ul lui objdump) corespunde cu declarația corespunzătoare din fișierul adr_space.c. | + | * Verificați că dimensiunea fiecărei variabile (a 5-a coloană din output-ul lui ''objdump'') corespunde cu declarația corespunzătoare din fișierul ''adr_space.c''. |
- | * De ce dimensiunea lui string2 este doar 4? Folosiți readelf pentru a afișa tot conținutul secțiunii .data (Hint: readelf -x). De ce lipsește conținutul variabilei string2. | + | * De ce dimensiunea lui ''string2'' este doar 4? Folosiți ''readelf'' pentru a afișa tot conținutul secțiunii ''.data'' (Hint: readelf -x). De ce lipsește conținutul variabilei ''string2''? |
- | * Folosiți readelf pentru a căuta secțiunea în care este conținutul variabilei string2. Cum explicați? | + | * Folosiți ''readelf'' pentru a căuta secțiunea în care este conținutul variabilei string2. Cum explicați? |
- Layout-ul procesului în memorie | - Layout-ul procesului în memorie | ||
- | * Rulați executabilul adr_space. Folosiți pmap pentru a afișa zonele de memorie mapate. Câte din zonele afișate de pmap sunt asociate executabilului adr_space? Identificați stiva și heap-ul. | + | * Rulați executabilul ''adr_space''. Folosiți ''pmap'' pentru a afișa zonele de memorie mapate. Câte din zonele afișate de pmap sunt asociate executabilului ''adr_space''? Identificați stiva și heap-ul. |
- | * Ne propunem să determinăm pentru fiecare din secțiunile .text, .rodata, .data și .bss în ce zonă de memorie au fost încărcate. Folosiți coloana Addr din output-ul lui readelf de la punctul 1 pentru a asocia fiecare din aceste secțiuni într-o zonă de memorie din cele afișate de pmap. | + | * Ne propunem să determinăm pentru fiecare din secțiunile ''.text'', ''.rodata'', ''.data'' și ''.bss'' în ce zonă de memorie au fost încărcate. Folosiți coloana ''Addr'' din output-ul lui readelf de la punctul 1 pentru a asocia fiecare din aceste secțiuni într-o zonă de memorie din cele afișate de pmap. |
* Cum a știut sistemul de operare să creeze cele 3 zone de memorie? | * Cum a știut sistemul de operare să creeze cele 3 zone de memorie? | ||
* Secțiunile conțin doar informații "statice", care ne ajută să ne organizăm mai bine executabilul. Când un executabil este rulat, însă, se folosesc alte informații din fișierul ELF pentru a stabili ce zone de memorie se creează. Aceste informații se numesc "Program headers" sau "Segmente". | * Secțiunile conțin doar informații "statice", care ne ajută să ne organizăm mai bine executabilul. Când un executabil este rulat, însă, se folosesc alte informații din fișierul ELF pentru a stabili ce zone de memorie se creează. Aceste informații se numesc "Program headers" sau "Segmente". | ||
- | * Afișați segmentele din fișierul adr_space, folosind readelf. Doar segmentele marcate cu "LOAD" vor fi încărcate în memorie. Corespund adresele acestor segmente cu output-ul lui pmap? | + | * Afișați segmentele din fișierul ''adr_space'', folosind ''readelf''. Doar segmentele marcate cu "LOAD" vor fi încărcate în memorie. Corespund adresele acestor segmente cu output-ul lui pmap? |
- | - Stiva | + | |
+ | == Stiva == | ||
+ | - Rulați programul ''return_array''. De ce nu funcționează? Corectați programul astfel încât să funcționeze corect. | ||
+ | - Rulați programul ''params''. Cum explicați comportamentul? | ||
+ | - Rulați programul ''stackframe''. Programul realizează apelurile de funcții ''main'' -> ''f'' -> ''g''. Funcția g afișează conținutul stivei. Identificați frame-urile corespunzătoare funcțiilor ''main'', ''f'' și ''g''. Care sunt adresele de return? Folosiți utilitarul ''addr2line'' pentru a verifica faptul că adresa de return este într-adevăr imediat după apelul funcției. | ||
+ | |||
+ | == GDB == | ||
+ | - Rulați programul ''bug''. Vom folosi GDB pentru a identifica motivul erorii. | ||
+ | |||
+ | <code> | ||
+ | gdb ./bug | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | (gdb) run | ||
+ | </code> | ||
+ | |||
+ | Programul se va opri la linia care a cauzat accesul invalid. Pentru a afișa valorile variabilelor folosim comanda ''print''. | ||
+ | |||
+ | După ce am identificat ce variabilă are o valoare nevalidă vrem să aflăm motivul pentru care a ajuns așa. Folosiți comanda ''backtrace'' pentru a afișa stiva de apeluri. | ||
+ | |||
+ | <code> | ||
+ | (gdb) backtrace | ||
+ | #0 0x0804846a in initialize (entries=0x0, num=5) at bug.c:15 | ||
+ | #1 0x080484c5 in allocate (n=5) at bug.c:31 | ||
+ | #2 0x080484df in main () at bug.c:41 | ||
+ | </code> | ||
+ | |||
+ | Folosiți comanda ''frame'' pentru a vă muta în cadrul unui alt frame din stiva de apeluri | ||
+ | <code> | ||
+ | (gdb) frame 1 | ||
+ | #1 0x080484c5 in allocate (n=5) at bug.c:31 | ||
+ | 31 initialize(w, n); | ||
+ | </code> | ||
- | === Fun === | + | Verificați valorile cu care a fost apelată funcția ''initialize''. De unde provin aceste valori? Folosiți comanda ''list'' pentru a afișa codul sursă din jurul liniei curente. Investigați celelalte variabile din funcție și identificați sursa problemei. |
+ | == Fun == | ||
- Sunt informațiile despre secțiuni absolut necesare? Analizați programul elf_magic. Câte secțiuni conține programul? Câte segmente conține programul? Credeți că programul va rula? | - Sunt informațiile despre secțiuni absolut necesare? Analizați programul elf_magic. Câte secțiuni conține programul? Câte segmente conține programul? Credeți că programul va rula? | ||