| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| pl:edu:zmitac:n1z:ja:lab1 [2021/03/12 17:41] – [Praktyka: Zadanie do wykonania] pczekalski | pl:edu:zmitac:n1z:ja:lab1 [2022/04/23 19:04] (current) – [Powtórka z teorii: Funkcje i ich wywoływanie z poziomu assemblera] pczekalski |
|---|
| <caption>Opcje instalacyjne część 3 - uwaga - frameworki .NET po prawej stronie trzeba zaznaczyć ręcznie!</caption> | <caption>Opcje instalacyjne część 3 - uwaga - frameworki .NET po prawej stronie trzeba zaznaczyć ręcznie!</caption> |
| </figure> | </figure> |
| | |
| | === Dodatek AsmDude do VS 2019 === |
| | Visual Studio natywnie nie posiada narzędzi wspomagających pracę dewelopera z kodem źródłowym w assemblerze. Jednak ze względu na istniejących mechanizm dodatków, można doinstalować zewnętrzne narzędzia. Nie jest to obowiązkowe, ale upraszcza pracę dewelopera, w szczególności powoduje, że kod w assemblerze zostanie pokolorowany i łatwiej będzie znaleźć ew. błędy, podczas debuggowania będą podpowiadane automatycznie wartości rejestrów, jak równnież będzie się pojawaiała (w ograniczonym zakresie) kontekstowa informacja o znaczeniu instrukcji, dyrektyw, zmiennych, etykiet, etc. Dodatek AsmDude można zainstalować za pomocą mechanizmów VS w automatyczny sposób. |
| | Opis dodatku znajduje się na stronie autora((https://marketplace.visualstudio.com/items?itemName=Henk-JanLebbink.AsmDude)). |
| |
| ==== Wymagania ==== | ==== Wymagania ==== |
| |
| == Zwrot wartości z funkcji == | == Zwrot wartości z funkcji == |
| Wartość całkowita (w tym wskaźnik) zwracana jest w rejestrze RCX.\\ | Wartość całkowita (w tym wskaźnik) zwracana jest w rejestrze RAX.\\ |
| Wartości zmiennoprzecinkowa zwracana jest w rejestrze XMM0. | Wartości zmiennoprzecinkowa zwracana jest w rejestrze XMM0. |
| |
| | == Rejestry "bezpiecznie" i "niebezpieczne" == |
| | <note warning>Niektóre z rejestrów musza pozostać niezmienione w momencie powrotu z funkcji, w stosunku do ich zawartości na początku, zaraz po wywołaniu funkcji (tzw. non-volatile). Inne rejestry można dowolnie zmieniać i nie będzie miało to wpływu na działanie systemu operacyjnego (volatile).\\ W przypadku konieczności skorzystania z tej pierwszej grupy, zawartość rejestru można odłożyć na stos lub zachować w pamięci i przywrócić przed wykonaniem instrukcji ''ret''.</note> |
| | |
| | Rejestry, które można bezkarnie zmieniać wewnątrz kodu assemblerowej funkcji, bez konieczności przywracania oryginalnej wartości, to ([[https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers|x64 calling conventions]]): |
| | * RAX, RCX, RDX, R8, R9, R10, R11, oraz XMM0-XMM5, |
| | * dodatkowo w procesorach, które są wyposażone w rejestry YMM, górne połowy rejestrów YMM0-YMM15 również można zmieniać bez konieczności przywracania ich wartości, |
| | * a ponadto w procesorach wyposażonych w funkcje AVX512VL, wszystkie rejestry ZMM, YMM oraz XMM16-XMM31. |
| | Rejestry, których nie wolno zmieniać (albo raczej należy przywrócić ich oryginalne wartości przed opuszczeniem funkcji) to: |
| | * RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 oraz XMM6-XMM15. |
| ==== Praktyka: Tworzenie projektu C++ i konsersja do ASM ==== | ==== Praktyka: Tworzenie projektu C++ i konsersja do ASM ==== |
| |
| </figure> | </figure> |
| |
| | === Oznaczenie pliku ASM do kompilacji === |
| | W niektórych przypadkach zdarza się, że plik ''.asm'' nie jest automatycznie rozpoznawany jako plik źródłowy z kodem w assemblerze. W związku z tym należy jawnie poinformować o tym środowiko. W tym celu należy kliknąć nazwę pliku w drzewie projektu prawym przyciskiem i wybrać opcję ''Properites'', a następnie w sekcji ''General'' wskazać ''Item Type'' i ustawić jego wartośc na ''Microsoft Macro Assembler''. Szczegóły na rysunku {{ref>jalabstep6}}. |
| | <figure jalabstep6> |
| | {{:pl:edu:zmitac:n1z:ja:virtualbox_msedge_-_win10_27_03_2021_19_44_41.png?600|}} |
| | <caption>Oznaczenie pliku ASM jako pliku z kodem źródłowym w assemblerze</caption> |
| | </figure> |
| |
| | === Instalacja dodatku kolorującego kod źródłowy w assemblerze === |
| | Na sieci jest dostępne rozszerzenie do Visual Studio o nazwie **AsmDude**, które (m.in.) automatycznie koloruje kod źródłowy w assemblerze, pomaga w pisaniu kodu (podaje nazwy etykiet, zmiennych, itp) oraz podczas debbugowania wyświetla okienka z wartościami rejestrów. Plugin ten może zostać zainstalowany poprzez managera rozszerzeń Visual Studio((https://marketplace.visualstudio.com/items?itemName=Henk-JanLebbink.AsmDude)). |
| ==== Praktyka: Zadanie do wykonania ==== | ==== Praktyka: Zadanie do wykonania ==== |
| Zaimplementuj odczyt daty (użyj funkcji ''GetSystemTime''(sysinfoapi.h)((https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime)) odczytującej strukturę ''_SYSTEMTIME''(minwinbase.h)((https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime)). Struktura składa się z 8 wartości szesnastobitowych. | Zaimplementuj odczyt daty (użyj funkcji ''GetSystemTime''(sysinfoapi.h)((https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime)) odczytującej strukturę ''_SYSTEMTIME''(minwinbase.h)((https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime)). Struktura składa się z 8 wartości szesnastobitowych. |
| Przykładowy segment danych, który był używany w prezentacji wygląda tak:\\ | Przykładowy segment danych, który był używany w prezentacji wygląda tak:\\ |
| <code> | <code> |
| | ... |
| | |
| .data | .data |
| STD_INPUT_HANDLE = -10 | STD_INPUT_HANDLE = -10 |
| text_msg db "A to jest bardzo dlugi tekst do wyswietlenia w konsoli, ale bez polskich znakow!",13,10 | text_msg db "A to jest bardzo dlugi tekst do wyswietlenia w konsoli, ale bez polskich znakow!",13,10 |
| dummy dq 0 | dummy dq 0 |
| | |
| | ... |
| |
| </code> | </code> |
| W tym celu trzeba użyć dyrektywy ''EXTERN'' oraz ''PROC'':\\ | W tym celu trzeba użyć dyrektywy ''EXTERN'' oraz ''PROC'':\\ |
| <code> | <code> |
| | |
| | ... |
| | |
| includelib kernel32.lib | includelib kernel32.lib |
| |
| EXTERN GetStdHandle: PROC | EXTERN GetStdHandle: PROC |
| EXTERN GetSystemTime: PROC | EXTERN GetSystemTime: PROC |
| | |
| | ... |
| | |
| </code> | </code> |
| Zwyczajowo umieszczamy również informację o bibliotece. | Zwyczajowo umieszczamy również informację o bibliotece. |
| </code> | </code> |
| |
| W celu wyświetlenia okienka dialogowego, należy użyć wskaźnika do okna głównego aplikacji. Jako parametry przekazywane są w kolejności: uchwyt, dwa wskaźniki, do tekstów (muszą kończyć się zerem), które mają pojawić się w nagłówku oraz treści dialogu oraz jako ostatni, maska binarna określająca, jakie mają być zastosowane przyciski i ikony w okienku dialogowym. | W celu wyświetlenia okienka dialogowego, należy użyć wskaźnika do okna głównego aplikacji. Jako parametry przekazywane są w kolejności: uchwyt, dwa wskaźniki, do tekstów (muszą kończyć się zerem, RDX to wskaźnik do treści, którą wyświetli dialog, a R8 wskaźnik do nagłówka okienka, który zotanie nadany okienku), które mają pojawić się w nagłówku oraz treści dialogu oraz jako ostatni, maska binarna określająca, jakie mają być zastosowane przyciski i ikony w okienku dialogowym((https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa)). |
| <code> | <code> |
| ... | ... |
| mov r8, offset info_msg | mov r8, offset info_msg |
| mov r9, 0 ; MB_OK | mov r9, 0 ; MB_OK |
| and rsp, not 8 ; align stack to 16 bytes prior to API call | and rsp, not 8 |
| call MessageBoxA | call MessageBoxA |
| ... | ... |
| </code> | </code> |
| |
| <note important>Uwaga - w powyższym przypadku wykonano jawnie wyrównanie stosu do wartości podzielnej przez 16 bitów. W większości przypadków nie jest to konieczne, ponieważ organizacja danych najczęściej jest 64-bitowa. Gdyby jednak okazało się, że gdzieś został odłożony na stosie pojedynczy bajt, ulegnie to zmianie i program może rzucić wyjątkiem. W związku z tym w takim przypadku należy zadbać o wyrównanie wskaźnika stosu tak, aby był podzielny przez 16.</note> | <note important>Uwaga - w powyższym przypadku wykonano jawnie wyrównanie stosu do wartości podzielnej przez 16 (''and rsp, not 8''). W większości przypadków nie jest to konieczne, ponieważ organizacja danych najczęściej jest 64-bitowa. Gdyby jednak okazało się, że gdzieś został odłożony na stosie pojedynczy bajt lub słowo, ulegnie to zmianie i program może rzucić wyjątkiem. W związku z tym w takim przypadku należy zadbać o wyrównanie wskaźnika stosu tak, aby był podzielny przez 16.</note> |
| ==== Debuggowanie i uruchamianie ==== | ==== Debuggowanie i uruchamianie ==== |
| Uwagi praktycznie odnośnie debbugowania i podglądania pamięci: | Uwagi praktycznie odnośnie debbugowania i podglądania pamięci: |