This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
bune-practici [2015/11/30 15:19] catalin.vasile3004 [Confuzii la accesarea datelor în memorie (operatorul de dereferenţiere)] |
bune-practici [2015/11/30 16:03] catalin.vasile3004 [Încărcarea datelor în registre] |
||
---|---|---|---|
Line 26: | Line 26: | ||
add eax, var ; add to eax, the >>address<< of var | add eax, var ; add to eax, the >>address<< of var | ||
</code> | </code> | ||
- | Acest cod este echivalent cu următorul cod din C: | + | Acest cod este echivalent cu următorul cod din **C**: |
<code c> | <code c> | ||
int var = 34; | int var = 34; | ||
Line 38: | Line 38: | ||
section .text | section .text | ||
mov eax, [var] ; put var's >>value<< into eax | mov eax, [var] ; put var's >>value<< into eax | ||
- | add eax, [var] ; add to eax, the >>value** of var | + | add eax, [var] ; add to eax, the >>value<< of var |
</code> | </code> | ||
+ | Acest lucru ar fi echivalent în **C** cu: | ||
+ | <code c> | ||
+ | int var = 34; | ||
+ | eax = var; /* mov eax, [var] */ | ||
+ | eax = eax + var; /* add eax, [var] */ | ||
+ | </code> | ||
+ | Printre singurele instrucţiuni care fac abatare de la aceste reguli, este **lea** (load effective address). | ||
+ | <code asm> | ||
+ | section .data | ||
+ | var: DD 34 | ||
+ | section .text | ||
+ | lea eax, [var] ; put var's >>address<< into the eax register | ||
+ | </code> | ||
+ | În rest, toate celelalte instrucţiuni aderă la regulile enunţate mai sus. Dacă or mai exista şi alte instrucţiuni care se comportă ca **lea**, cel mai probabil nu vor fi tratate în aceste laboratoare. | ||
==== Încărcarea datelor în registre ==== | ==== Încărcarea datelor în registre ==== | ||
Adesea apar erori chiar la încărcarea datelor în registre. | Adesea apar erori chiar la încărcarea datelor în registre. | ||
Line 137: | Line 151: | ||
</code> | </code> | ||
Poate că nu ai un cod care compilează, dar măcar nu ai un cod care compilează şi ruleaza greşit. | Poate că nu ai un cod care compilează, dar măcar nu ai un cod care compilează şi ruleaza greşit. | ||
+ | |||
+ | ==== Segmentation Fault debugging: GDB quicky ==== | ||
+ | **gdb** este un debugger în linie de comandă. Unul din lucrurile la care ne poate ajuta acesta este să găsim punctele în care ne dă **Segmentation Fault** un program. Mulţi abordează această problemă prin imbricarea de **printf**-uri în puncte intermediare în program. Acest lucru nu prea ajută. Uitaţi cam cum este prelucrat un program de un procesor: | ||
+ | - Într-o singură etapă se aduc mai multe instrucţiuni din memorie. Accesul la memorie este scump, şi dacă la fiecare instrucţiune de 5-6 bytes ne-am duce în memorie, nu am avea o performanţă foarte bună. Din acest motiv s-a inventat un modul în procesor, numit prefetching, în care un procesor înmagazinează mai multe instrucţiuni de la adresa de la care aduce cod, pentru ca execuţia să fie mai fluidă. | ||
+ | - În momentul în care procesorul îşi dă seama că una din instrucţiuni accesează o zonă nevalidă din memorie, trimite un semnal către sistemul de operare. Şi sistemul de operare este tot o bucată de cod care se execută pe procesor. Până când acest semnal trezeşte codul din sistemul de operare, e foarte posibil ca programul să mai fi executat o căruţă de instrucţiuni, din acest motiv, o înşiruire de printf-uri s-ar putea executa şi după instrucţiunea care a produs Segmentation Fault-ul. | ||
+ | - Sistemul de operare se trezeşte şi închide forţat programul care a cauzat probleme. Printre datele primite de la semnal se regăseşte şi adresa instrucţiunii care a cauzat Segmentation Fault. Cu un debugger, se pot afla şi din userspace ce instrucţiune a cauzat Segmentation Fault. | ||
+ | Exemplu de cod cu probleme: | ||
+ | <file asm segfault.asm> | ||
+ | extern printf | ||
+ | |||
+ | section .data | ||
+ | str: DB `number: %d\n` | ||
+ | nr: DD 1, 2, 3, 4, 5 | ||
+ | len: DD 4000 | ||
+ | |||
+ | section .text | ||
+ | |||
+ | global main | ||
+ | |||
+ | main: | ||
+ | xor ecx, ecx | ||
+ | keep_printing: | ||
+ | push ecx ; save ecx, because it will be destroyed by printf call | ||
+ | push dword [nr + 4*ecx] | ||
+ | push str | ||
+ | call printf | ||
+ | add esp, 8 | ||
+ | pop ecx ; restore ecx | ||
+ | inc ecx | ||
+ | cmp ecx, [len] | ||
+ | jl keep_printing | ||
+ | ret | ||
+ | </file> | ||
+ | Programul parcurge un vector şi afişează valorile sale. Deşi programul are doar 5 elemente, **len**-ul este setat greşit la 4000 de elemente. Dacă compilăm şi rulam programul acesta ne va da un **segfault**: | ||
+ | <code bash> | ||
+ | # ... | ||
+ | number: 0 | ||
+ | number: 0 | ||
+ | number: 0 | ||
+ | Segmentation fault | ||
+ | </code> | ||
===== Categorie 3 ===== | ===== Categorie 3 ===== | ||
* TODO | * TODO | ||
* TODO | * TODO |