This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
laboratoare:laborator-11 [2016/01/06 04:03] razvan.deaconescu [[2p] 7. Extindere calcul maxim în C cu apel în assembly] |
laboratoare:laborator-11 [2016/01/09 13:39] (current) razvan.deaconescu [[2p] Bonus: Calcul maxim în C cu apel din assembly pe 64 de biți] |
||
---|---|---|---|
Line 31: | Line 31: | ||
Este necesar ca procedura să conserve valoarea registrelor ESI, EDI, EBP și a registrelor segment. În cazul în care aceste registre sunt corupte, este posibil ca programul să producă erori la întoarcerea din procedura assembly. | Este necesar ca procedura să conserve valoarea registrelor ESI, EDI, EBP și a registrelor segment. În cazul în care aceste registre sunt corupte, este posibil ca programul să producă erori la întoarcerea din procedura assembly. | ||
- | ==== Pasararea parametrilor în C către procedura assembly ==== | + | ==== Transmiterea parametrilor din C către procedura assembly ==== |
Programele C trimit parametrii către procedurile assembly folosind stiva. Să considerăm următoarea secvență de program C: | Programele C trimit parametrii către procedurile assembly folosind stiva. Să considerăm următoarea secvență de program C: | ||
Line 176: | Line 176: | ||
La afișare se va afișa și poziția din vector pe care se găsește maximul. | La afișare se va afișa și poziția din vector pe care se găsește maximul. | ||
- | ==== [1p] 6. Tutorial: Calcul maxim în C cu apel în assembly ==== | ||
- | În subdirectorul ''max-c-calls/'' din arhiva de sarcini a laboratorului găsiți o implementare de calcul a maximului unui număr în care funcția ''main()'' este definită în limbaj de asamblare de unde se apelează funcția ''get_max()'' definită în C. | + | <note tip> |
+ | Pentru reținerea poziției, cel mai bine este definiți o variabilă locală ''pos'' în funcția ''main'' din fișierul C (''main.c'') în forma<code> | ||
+ | unsigned int pos; | ||
+ | </code> | ||
+ | iar apelul funcției ''get_max'' îl veți face în forma:<code> | ||
+ | max = get_max(arr, 10, &pos); | ||
+ | </code> | ||
+ | </note> | ||
+ | ==== [1p] 6. Tutorial: Calcul maxim în C cu apel din assembly ==== | ||
+ | |||
+ | În subdirectorul ''max-assembly-calls/'' din arhiva de sarcini a laboratorului găsiți o implementare de calcul a maximului unui număr în care funcția ''main()'' este definită în limbaj de asamblare de unde se apelează funcția ''get_max()'' definită în C. | ||
Urmăriți codul din cele două fișiere și modul în care se transmit argumentele funcției și valoarea de retur. | Urmăriți codul din cele două fișiere și modul în care se transmit argumentele funcției și valoarea de retur. | ||
Line 187: | Line 196: | ||
Acordați atenție înțelegerii codului înainte de a trece la exercițiul următor. | Acordați atenție înțelegerii codului înainte de a trece la exercițiul următor. | ||
</note> | </note> | ||
- | ==== [2p] 7. Extindere calcul maxim în C cu apel în assembly ==== | + | ==== [2p] 7. Extindere calcul maxim în C cu apel din assembly ==== |
Extindeți programul de la exercițiul anterior (în limbaj de asamblare și C) astfel încât funcția ''get_max()'' să aibă acum signatura ''unsigned int get_max(unsigned int *arr, unsigned int len, unsigned int *pos)''. Al treilea argument al funcției este adresa în care se va reține poziția din vector pe care se găsește maximul. | Extindeți programul de la exercițiul anterior (în limbaj de asamblare și C) astfel încât funcția ''get_max()'' să aibă acum signatura ''unsigned int get_max(unsigned int *arr, unsigned int len, unsigned int *pos)''. Al treilea argument al funcției este adresa în care se va reține poziția din vector pe care se găsește maximul. | ||
La afișare se va afișa și poziția din vector pe care se găsește maximul. | La afișare se va afișa și poziția din vector pe care se găsește maximul. | ||
- | ==== [2p] Bonus: Calcul maxim în C cu apel în assembly pe 64 de biți ==== | ||
- | ==== [2p] Bonus: Calcul maxim în assembly cu apel în C pe 64 de biți ==== | + | <note tip> |
+ | Pentru a reține poziția, cel mai bine este să definiți o variabilă globală în fișierul assembly (''main.asm'') în secțiunea ''.data'', în forma<code> | ||
+ | pos: dd 0 | ||
+ | </code> | ||
+ | Această variabilă o veți transmite (prin adresă) către apelul ''get_max'' și prin valoare pentru apelul ''printf'' pentru afișare. | ||
+ | |||
+ | Pentru afișare modificați șirul ''print_format'' și apelul ''printf'' în fișierul assembly (''main.asm'') ca să permită afișare a două valori: maximul și poziția. | ||
+ | </note> | ||
+ | ==== [2p] Bonus: Calcul maxim în assembly cu apel din C pe 64 de biți ==== | ||
+ | |||
+ | Actualizați programul de la exercițiile 4 și 5 în așa fel încât să îl rulați folosind un sistem pe 64 de biți. Pentru aceasta, va trebui să asamblați programul în limbaj de asamblare pentru un executabil pe 64 de biți și să folosiți consola Visual Studio pe 64 de biți. | ||
+ | |||
+ | <note tip> | ||
+ | [[https://msdn.microsoft.com/en-us/library/windows/hardware/ff561499%28v=vs.85%29.aspx|Calling convention in Windows x64 binaries]]. | ||
+ | |||
+ | Pe arhitectura x64 parametri nu se mai trimit stivă, ci se pun registre. Primii 3 parametri se pun în: RCX, RDX, R8. Aceasta nu este o convenţie adoptată uniform. Această conveţie este este doar pe Windows, pe Linux având alte registre care sunt folosite pentru a transmite parametri unei funcţii. | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | Trebuie să aveți în vedere următorii pași: | ||
+ | * Să folosiți pentru dezvoltare consola ''VS2015 x64 Native Tools Command Prompt''. | ||
+ | * Să folosiți opțiunea ''-f win64'' la ''nasm''. | ||
+ | * Să folosiți [[https://msdn.microsoft.com/en-us/library/windows/hardware/ff561499%28v=vs.85%29.aspx|convenția de apel Windows x64]]. | ||
+ | * Să înlocuiți numele ''_get_max'' cu ''get_max'' (fără undescore-ul de la început) în fișierul ''max.asm''. | ||
+ | |||
+ | </note> | ||
+ | ==== [2p] Bonus: Calcul maxim în C cu apel din assembly pe 64 de biți ==== | ||
+ | |||
+ | Actualizați programul de la exercițiile 6 și 7 în așa fel încât să îl rulați folosind un sistem pe 64 de biți. Pentru aceasta, va trebui să asamblați programul în limbaj de asamblare pentru un executabil pe 64 de biți și să folosiți consola Visual Studio pe 64 de biți. | ||
+ | |||
+ | <note tip> | ||
+ | Să folosiți binarul ''gcc'' din calea cu MinGW64, adică ''%%C:\"Program Files (x86)"\SASM\MinGW64\bin\gcc%%''. | ||
+ | </note> | ||
+ | |||
+ | <note> | ||
+ | E suficient să obțineți executabilul ''main.exe''. Programul nu va funcționa din cauza unor probleme neelucidate de linking. Vom depana problema în următoarea perioadă :-) | ||
+ | </note> | ||
+ | |||
+ | ===== Soluții ===== | ||
+ | |||
+ | [[http://elf.cs.pub.ro/asm/res/laboratoare/lab-11-sol.zip|Soluții de referință pentru exercițiile de laborator]] | ||