User Tools

Site Tools


laboratoare:laborator-04

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator-04 [2015/11/04 05:43]
razvan.deaconescu [Breviar: Apelul unei funcții]
laboratoare:laborator-04 [2015/11/11 08:56] (current)
razvan.deaconescu [Alte resurse]
Line 3: Line 3:
 În acest laborator vom prezenta modul în care se realizează apeluri de funcții. Vom vedea cum putem folosi instrucțiunile ''​call''​ și ''​ret''​ pentru a realiza apeluri de funcții și cum folosim stiva pentru a transmite parametrii unei funcții. În acest laborator vom prezenta modul în care se realizează apeluri de funcții. Vom vedea cum putem folosi instrucțiunile ''​call''​ și ''​ret''​ pentru a realiza apeluri de funcții și cum folosim stiva pentru a transmite parametrii unei funcții.
  
-Laboratorul este de forma //learn by doing// partea practică ​alterând ​între secțiuni de tip tutorial, cu parcurgere pas cu pas și prezentarea soluției, și exerciții care trebuie să fie rezolvate.+Laboratorul este de forma //learn by doing// partea practică ​alternând ​între secțiuni de tip tutorial, cu parcurgere pas cu pas și prezentarea soluției, și exerciții care trebuie să fie rezolvate.
  
 ===== Mediul de lucru ===== ===== Mediul de lucru =====
Line 24: Line 24:
 Descărcați arhiva, decomprimați-o și accesați directorul aferent. Descărcați arhiva, decomprimați-o și accesați directorul aferent.
  
-==== [1p] Recapitulare:​ Program în limbaj de asamblare ====+==== [1p] 1. Recapitulare:​ Program în limbaj de asamblare ====
  
 În SASM deschideți fișierul ''​NASMHello.asm'',​ fișier din instalarea implicită de NASM și compilați-l și rulați-l. Observați afișarea mesajului //Hello, world!// În SASM deschideți fișierul ''​NASMHello.asm'',​ fișier din instalarea implicită de NASM și compilați-l și rulați-l. Observați afișarea mesajului //Hello, world!//
Line 40: Line 40:
 Încheierea cu ''​\r\n''​ este, în general, utilă pentru afișarea șirurilor. Întrucât însă funcția ''​puts''​ pune automat o linie nouă după șirul afișat, prezența acestor caractere este opțională. Este, însă, utilă în cazul folosirii funcției ''​printf''​. Încheierea cu ''​\r\n''​ este, în general, utilă pentru afișarea șirurilor. Întrucât însă funcția ''​puts''​ pune automat o linie nouă după șirul afișat, prezența acestor caractere este opțională. Este, însă, utilă în cazul folosirii funcției ''​printf''​.
  
-==== [1p] Dezasamblarea unui program scris în C ====+==== [1p] 2. Dezasamblarea unui program scris în C ====
  
 După cum spuneam, în final, totul ajunge în limbaj de asamblare. Adesea ajungem să avem acces doar la codul obiect al unor programe și vrem să inspectăm modul în care arată. După cum spuneam, în final, totul ajunge în limbaj de asamblare. Adesea ajungem să avem acces doar la codul obiect al unor programe și vrem să inspectăm modul în care arată.
  
-Pentru a observa acest lucru, haideți să compilăm până la codul obiect un program scris în C și apoi să-l dezamblăm. Este vorba de programul ''​test.c''​ din arhiva de laborator.+Pentru a observa acest lucru, haideți să compilăm până la codul obiect un program scris în C și apoi să-l dezasamblăm. Este vorba de programul ''​test.c''​ din arhiva de laborator.
  
 Pentru a compila un program vom folosi linia de comandă și de acolo comanda ''​cl''​ care reprezintă compilatorul și linker-ul din Visual Studio. Pentru a compila un program vom folosi linia de comandă și de acolo comanda ''​cl''​ care reprezintă compilatorul și linker-ul din Visual Studio.
Line 60: Line 60:
 cl /c test.c cl /c test.c
 </​code>​ </​code>​
-În urma rulării comenzii de mai sus în directorul curent vom avea fișierul obiect test.c.+În urma rulării comenzii de mai sus în directorul curent vom avea fișierul obiect test.obj.
  
 Putem obține și forma în limbaj de asamblare a acestuia folosind comanda<​code>​ Putem obține și forma în limbaj de asamblare a acestuia folosind comanda<​code>​
Line 70: Line 70:
  
 Pentru a dezasambla codul unui modul obiect vom folosi un utilitar frecvent întâlnit în lumea Unix: ''​objdump''​. Pentru aceasta trebuie ca în prompt-ul Visual Studio sau în alt prompt să accesați directorul de binare al SASM. Este vorba de ''​C:​\Program Files (x86)\SASM\MinGW64\bin''​. De acolo, pentru dezasamblare,​ vom rula comanda<​code>​ Pentru a dezasambla codul unui modul obiect vom folosi un utilitar frecvent întâlnit în lumea Unix: ''​objdump''​. Pentru aceasta trebuie ca în prompt-ul Visual Studio sau în alt prompt să accesați directorul de binare al SASM. Este vorba de ''​C:​\Program Files (x86)\SASM\MinGW64\bin''​. De acolo, pentru dezasamblare,​ vom rula comanda<​code>​
-.\objdump.exe -d <​path-to-obj-file+.\objdump.exe -d <​path-to-obj-file>
 </​code>​ </​code>​
 unde ''<​path-to-obj-file>''​ este calea către fișierul obiect ''​test.obj''​. unde ''<​path-to-obj-file>''​ este calea către fișierul obiect ''​test.obj''​.
  
 Veți obține un output similar celui de mai jos<​code>​ Veți obține un output similar celui de mai jos<​code>​
-C:\Program Files (x86)\SASM\MinGW\bin>​.\objdump.exe -d C:​\Users\razvan\test.obj+C:\Program Files (x86)\SASM\MinGW\bin>​.\objdump.exe -d -M intel C:​\Users\razvan\test.obj
  
 C:​\Users\razvan\test.obj: ​    file format pe-i386 C:​\Users\razvan\test.obj: ​    file format pe-i386
Line 83: Line 83:
  
 00000000 <​_main>:​ 00000000 <​_main>:​
-   ​0: ​  ​55 ​                     push   %ebp +   ​0: ​  ​55 ​                     push   ebp 
-   ​1: ​  8b ec                   ​mov ​   ​%esp,%ebp +   ​1: ​  8b ec                   ​mov ​   ebp,esp 
-   ​3: ​  6a 0f                   ​push ​  $0xf+   ​3: ​  6a 0f                   ​push ​  0xf
    ​5: ​  e8 00 00 00 00          call   a <​_main+0xa>​    ​5: ​  e8 00 00 00 00          call   a <​_main+0xa>​
-   ​a: ​  83 c4 04                add    ​$0x4,%esp +   ​a: ​  83 c4 04                add    esp,0x4 
-   ​d: ​  ​50 ​                     push   %eax +   ​d: ​  ​50 ​                     push   eax 
-   ​e: ​  68 00 00 00 00          push   $0x0+   ​e: ​  68 00 00 00 00          push   0x0
   13:   e8 00 00 00 00          call   18 <​_main+0x18>​   13:   e8 00 00 00 00          call   18 <​_main+0x18>​
-  18:   83 c4 08                add    ​$0x8,%esp +  18:   83 c4 08                add    esp,0x8 
-  1b:   33 c0                   ​xor ​   ​%eax,%eax +  1b:   33 c0                   ​xor ​   eax,eax 
-  1d:   ​5d ​                     pop    ​%ebp+  1d:   ​5d ​                     pop    ebp
   1e:   ​c3 ​                     ret   1e:   ​c3 ​                     ret
   1f:   ​cc ​                     int3   1f:   ​cc ​                     int3
  
 00000020 <​_first_func>:​ 00000020 <​_first_func>:​
-  20:   ​55 ​                     push   %ebp +  20:   ​55 ​                     push   ebp 
-  21:   8b ec                   ​mov ​   ​%esp,%ebp +  21:   8b ec                   ​mov ​   ebp,esp 
-  23:   ​51 ​                     push   %ecx +  23:   ​51 ​                     push   ecx 
-  24:   c7 45 fc 03 00 00 00    ​movl   $0x3,-0x4(%ebp) +  24:   c7 45 fc 03 00 00 00    ​mov    DWORD PTR [ebp-0x4],0x3 
-  2b:   68 00 00 00 00          push   $0x0+  2b:   68 00 00 00 00          push   0x0
   30:   e8 00 00 00 00          call   35 <​_first_func+0x15>​   30:   e8 00 00 00 00          call   35 <​_first_func+0x15>​
-  35:   83 c4 04                add    ​$0x4,%esp +  35:   83 c4 04                add    esp,0x4 
-  38:   8b 45 fc                mov    -0x4(%ebp),%eax +  38:   8b 45 fc                mov    ​eax,DWORD PTR [ebp-0x4] 
-  3b:   ​50 ​                     push   %eax +  3b:   ​50 ​                     push   eax 
-  3c:   8d 4d 08                lea    ​0x8(%ebp),%ecx +  3c:   8d 4d 08                lea    ecx,[ebp+0x8] 
-  3f:   ​51 ​                     push   %ecx+  3f:   ​51 ​                     push   ecx
   40:   e8 00 00 00 00          call   45 <​_first_func+0x25>​   40:   e8 00 00 00 00          call   45 <​_first_func+0x25>​
-  45:   83 c4 08                add    ​$0x8,%esp +  45:   83 c4 08                add    esp,0x8 
-  48:   8b 45 08                mov    ​0x8(%ebp),%eax +  48:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8] 
-  4b:   8b e5                   ​mov ​   ​%ebp,%esp +  4b:   8b e5                   ​mov ​   esp,ebp 
-  4d:   ​5d ​                     pop    ​%ebp+  4d:   ​5d ​                     pop    ebp
   4e:   ​c3 ​                     ret   4e:   ​c3 ​                     ret
   4f:   ​cc ​                     int3   4f:   ​cc ​                     int3
  
 00000050 <​_second_func>:​ 00000050 <​_second_func>:​
-  50:   ​55 ​                     push   %ebp +  50:   ​55 ​                     push   ebp 
-  51:   8b ec                   ​mov ​   ​%esp,%ebp +  51:   8b ec                   ​mov ​   ebp,esp 
-  53:   8b 45 08                mov    ​0x8(%ebp),%eax +  53:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8] 
-  56:   8b 08                   ​mov ​   ​(%eax),%ecx +  56:   8b 08                   ​mov ​   ecx,DWORD PTR [eax] 
-  58:   03 4d 0c                add    0xc(%ebp),%ecx +  58:   03 4d 0c                add    ​ecx,DWORD PTR [ebp+0xc] 
-  5b:   8b 55 08                mov    ​0x8(%ebp),%edx +  5b:   8b 55 08                mov    edx,DWORD PTR [ebp+0x8] 
-  5e:   89 0a                   ​mov ​   ​%ecx,(%edx) +  5e:   89 0a                   ​mov ​   ​DWORD PTR [edx],ecx 
-  60:   ​5d ​                     pop    ​%ebp +  60:   ​5d ​                     pop    ebp 
-  61:   ​c3 ​                     ret+  61:   c3
 </​code>​ </​code>​
  
Line 160: Line 160:
 </​code>​ </​code>​
  
-În primă fază am plasat pe stivă argumentul funcției ''​puts''​ adică adresa șirului ''​msg''​. Apoi am apelat funcția ''​puts''​. Apoi am restaurat stiva (care crescuse prin apelul ''​push''​) ​scăzând ''​4''​ octeți (dimensiunea unui cuvânt pe 32 de biți) ​din registrul de stivă (''​esp''​).+În primă fază am plasat pe stivă argumentul funcției ''​puts''​ adică adresa șirului ''​msg''​. Apoi am apelat funcția ''​puts''​. Apoi am restaurat stiva (care crescuse prin apelul ''​push''​) ​adăugând ​''​4''​ octeți (dimensiunea unui cuvânt pe 32 de biți) ​la registrul de stivă (''​esp''​).
  
 Astfel sunt traduse majoritatea apelurilor de funcții. Dacă urmărim dezasamblarea fișierul ''​test.obj''​ putem observa acest șablon de apel și în alte părți. Mai jos sunt secvențele extrase din dezasamblarea de mai sus:<​code>​ Astfel sunt traduse majoritatea apelurilor de funcții. Dacă urmărim dezasamblarea fișierul ''​test.obj''​ putem observa acest șablon de apel și în alte părți. Mai jos sunt secvențele extrase din dezasamblarea de mai sus:<​code>​
Line 180: Line 180:
  
 Contează mai puțin, pentru înțelegerea noastră din acest moment, de ce unele instrucțiuni arată cum arată, este importantă înțelegerea pașilor urmați pentru apelarea unei funcții: plasarea argumentelor pe stivă, apelul funcției, restaurarea stivei. Contează mai puțin, pentru înțelegerea noastră din acest moment, de ce unele instrucțiuni arată cum arată, este importantă înțelegerea pașilor urmați pentru apelarea unei funcții: plasarea argumentelor pe stivă, apelul funcției, restaurarea stivei.
-==== [1p] Afișarea unui șir ====+==== [1p] 3. Afișarea unui șir ====
  
 Pentru afișarea unui string în SASM putem folosi macro-ul ''​PRINT_STRING''​. Sau putem folosi o funcție precum ''​puts''​. În fișierul ''​print-string.asm''​ este implementată afișarea unui string folosind macro-ul ''​PRINT_STRING''​. Pentru afișarea unui string în SASM putem folosi macro-ul ''​PRINT_STRING''​. Sau putem folosi o funcție precum ''​puts''​. În fișierul ''​print-string.asm''​ este implementată afișarea unui string folosind macro-ul ''​PRINT_STRING''​.
Line 190: Line 190:
 </​note>​ </​note>​
  
-==== [2p] Afișarea lungimii unui șir ====+==== [2p] 4. Afișarea lungimii unui șir ====
  
 Programul ''​print-string-len.asm''​ afișează lungimea unui șir folosind macro-ul ''​PRINT_DEC''​. Calculul lungimii șirului ''​mystring''​ are loc în cadrul programului (este deja implementat). Programul ''​print-string-len.asm''​ afișează lungimea unui șir folosind macro-ul ''​PRINT_DEC''​. Calculul lungimii șirului ''​mystring''​ are loc în cadrul programului (este deja implementat).
Line 203: Line 203:
 Pașii de urmat sunt: Pașii de urmat sunt:
   - Marcarea simbolului ''​printf''​ ca simbol extern.   - Marcarea simbolului ''​printf''​ ca simbol extern.
-  - Definirea șirului de formatare ''​%%"​String ​lengths ​is %u", 13, 10, 0%%''​.+  - Definirea șirului de formatare ''​%%"​String ​length ​is %u", 13, 10, 0%%''​.
   - Realizarea apelului funcției ''​printf'',​ adică:   - Realizarea apelului funcției ''​printf'',​ adică:
     - Punerea celor două argumente pe stivă: șirul de formatarea și lungimea.     - Punerea celor două argumente pe stivă: șirul de formatarea și lungimea.
Line 212: Line 212:
 </​note>​ </​note>​
  
-==== [3p] Afișarea șirului inversat ====+==== [3p] 5. Afișarea șirului inversat ====
  
 În soluția de mai sus adăugați funcția ''​reverse_string''​ astfel încât să aveți un listing similar celui de mai jos:<​code>​ În soluția de mai sus adăugați funcția ''​reverse_string''​ astfel încât să aveți un listing similar celui de mai jos:<​code>​
Line 310: Line 310:
     mov edx, dword [ebp+16] ​ ; retrieve third function argument in edx     mov edx, dword [ebp+16] ​ ; retrieve third function argument in edx
 </​code>​ </​code>​
-==== [2p] Implementarea funcției toupper ====+==== [2p] 6. Implementarea funcției toupper ====
  
 Ne propunem implementarea funcției ''​toupper''​ care traduce literele mici în litere mari. Pentru aceasta, porniți de la fișierul ''​toupper.asm''​ din arhiva de exerciții a laboratorului și completați corpul funcției ''​topupper''​. Ne propunem implementarea funcției ''​toupper''​ care traduce literele mici în litere mari. Pentru aceasta, porniți de la fișierul ''​toupper.asm''​ din arhiva de exerciții a laboratorului și completați corpul funcției ''​topupper''​.
Line 343: Line 343:
 în care să rețineți fie lungimea totală a șirului (de la începutul până la ultimul ''​NUL''​-byte),​ fie numărul de șiruri din array. în care să rețineți fie lungimea totală a șirului (de la începutul până la ultimul ''​NUL''​-byte),​ fie numărul de șiruri din array.
 </​note>​ </​note>​
 +===== Soluții =====
 +
 +[[http://​elf.cs.pub.ro/​asm/​res/​laboratoare/​lab-04-sol.zip|Soluții de referință pentru exercițiile de laborator]]
 +
 ===== Alte resurse ===== ===== Alte resurse =====
  
 * [[http://​www.nasm.us/​|nasm]] * [[http://​www.nasm.us/​|nasm]]
 * [[http://​dman95.github.io/​SASM/​english.html|SASM]] * [[http://​dman95.github.io/​SASM/​english.html|SASM]]
laboratoare/laborator-04.1446608583.txt.gz · Last modified: 2015/11/04 05:43 by razvan.deaconescu