No ACL setup yet! Denying access to everyone.
pl:edu:zmitac:n1z:ja:lab1
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| pl:edu:zmitac:n1z:ja:lab1 [2021/03/12 17:08] – [Wstęp] 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 | ||
|---|---|---|---|
| Line 37: | Line 37: | ||
| < | < | ||
| </ | </ | ||
| + | |||
| + | === 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, | ||
| + | Opis dodatku znajduje się na stronie autora((https:// | ||
| ==== Wymagania ==== | ==== Wymagania ==== | ||
| Line 106: | Line 110: | ||
| == Zwrot wartości z funkcji == | == Zwrot wartości z funkcji == | ||
| - | Wartość całkowita (w tym wskaźnik) zwracana jest w rejestrze | + | Wartość całkowita (w tym wskaźnik) zwracana jest w rejestrze |
| Wartości zmiennoprzecinkowa zwracana jest w rejestrze XMM0. | Wartości zmiennoprzecinkowa zwracana jest w rejestrze XMM0. | ||
| + | == Rejestry " | ||
| + | <note warning> | ||
| + | |||
| + | Rejestry, które można bezkarnie zmieniać wewnątrz kodu assemblerowej funkcji, bez konieczności przywracania oryginalnej wartości, to ([[https:// | ||
| + | * RAX, RCX, RDX, R8, R9, R10, R11, oraz XMM0-XMM5, | ||
| + | * dodatkowo w procesorach, | ||
| + | * 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 ==== | ||
| Line 147: | Line 160: | ||
| </ | </ | ||
| - | === Utworzenie punktu startowego === | + | === Utworzenie punktu startowego |
| W tym kroku poinformujemy linker, jaki punkt startowy ma wpisać do pliku wykonywanego. | W tym kroku poinformujemy linker, jaki punkt startowy ma wpisać do pliku wykonywanego. | ||
| W językach wysokiego poziomu jest to domyślnie funkcja '' | W językach wysokiego poziomu jest to domyślnie funkcja '' | ||
| Line 171: | Line 184: | ||
| </ | </ | ||
| + | === Oznaczenie pliku ASM do kompilacji === | ||
| + | W niektórych przypadkach zdarza się, że plik '' | ||
| + | <figure jalabstep6> | ||
| + | {{: | ||
| + | < | ||
| + | </ | ||
| - | ==== Zadanie do wykonania ==== | + | === Instalacja dodatku kolorującego kod źródłowy w assemblerze |
| + | Na sieci jest dostępne rozszerzenie do Visual Studio o nazwie **AsmDude**, | ||
| + | ==== Praktyka: | ||
| Zaimplementuj odczyt daty (użyj funkcji '' | Zaimplementuj odczyt daty (użyj funkcji '' | ||
| Line 185: | Line 206: | ||
| Możesz dodatkowo wyświetlić bieżącą godzinę, minuty i sekundy. | Możesz dodatkowo wyświetlić bieżącą godzinę, minuty i sekundy. | ||
| + | === Fragmenty kodu do wykorzystania === | ||
| + | Pamiętaj o deklaracji segmentu kodu i danych za pomocą operatorów '' | ||
| + | == Segment danych == | ||
| + | Każdy łańcuch tekstowy musi kończyć się znacznikem o binarnej wartości 0. Nie używamy polskich znaków, ponieważ korzystamy z zestawu znaków ASCII (8-bit), a nie Unicode.\\ | ||
| + | Przykładowy segment danych, który był używany w prezentacji wygląda tak:\\ | ||
| + | < | ||
| + | ... | ||
| + | |||
| + | .data | ||
| + | STD_INPUT_HANDLE = -10 | ||
| + | STD_OUTPUT_HANDLE = -11 | ||
| + | STD_ERROR_HANDLE = -12 | ||
| + | |||
| + | handler dq 0 | ||
| + | stdHandle dq 0 | ||
| + | datetimeStruct dw 16 dup (0) | ||
| + | hello_msg db "Hello world", | ||
| + | info_msg | ||
| + | title_msg db " | ||
| + | text_msg db "A to jest bardzo dlugi tekst do wyswietlenia w konsoli, ale bez polskich znakow!", | ||
| + | dummy dq 0 | ||
| + | |||
| + | ... | ||
| + | |||
| + | </ | ||
| + | |||
| + | Aby móc skorzystać z zewnętrznych funkcji Windows API, trzeba poinformować assembler, jak one się nazywają, aby linker mógł potem dopasować nazwy z Twojego kodu do tych, które znajdują się w bibliotece.\\ | ||
| + | W tym celu trzeba użyć dyrektywy '' | ||
| + | < | ||
| + | |||
| + | ... | ||
| + | |||
| + | includelib | ||
| + | |||
| + | EXTERN MessageBoxA: | ||
| + | EXTERN GetForegroundWindow: | ||
| + | EXTERN WriteConsoleA: | ||
| + | EXTERN SetConsoleTitleA: | ||
| + | EXTERN GetStdHandle: | ||
| + | EXTERN GetSystemTime: | ||
| + | |||
| + | ... | ||
| + | |||
| + | </ | ||
| + | Zwyczajowo umieszczamy również informację o bibliotece. | ||
| + | |||
| + | == Segment kodu == | ||
| + | Po uruchomieniu programu musimy zachować wartości pewnych rejestrów, w celu ich późniejszego przywrócenia. Na sam koniec należy również wywołać funkcję kończącą program i zwracającą tzw kod powrotu do systemu operacyjnego.\\ | ||
| + | |||
| + | Minimalny zestaw instrukcji wygląda następująco: | ||
| + | < | ||
| + | ... | ||
| + | .code | ||
| + | hello_world_asm PROC | ||
| + | push rbp ; save frame pointer | ||
| + | mov rbp, rsp ; fix stack pointer | ||
| + | sub rsp, 8 * (4 + 2) | ||
| + | |||
| + | .... ; tutaj kod Twojego programu | ||
| + | |||
| + | |||
| + | mov rsp, rbp | ||
| + | pop rbp | ||
| + | ret | ||
| + | hello_world_asm ENDP | ||
| + | END | ||
| + | </ | ||
| + | <note tip> | ||
| + | </ | ||
| + | |||
| + | Jak widać, całość sprowadza się do zarezerwowania i odłożenia na stosie przestrzeni na tzw. shadow registry, czyli na zachowanie wartości rejestrów i przywrócenie ich po zakończeniu wykonywania programu. | ||
| + | |||
| + | W programie wykorzystujemy interakcję z elementami graficznymi takimi jak okienko główne (Foreground Window) oraz strumień danych (STD_OUT). Podczas wywoływania funkcji, należy jednoznacznie wskazać, względem którego obiektu graficznego chcemy wykonać interakcję lub stworzyć obiekt potomny (np. MessageBox).\\ | ||
| + | W tym celu musimy pobrać dwa uchwyty (handlery): | ||
| + | * uchwyt do bieżącego głównego okienka aplikacji na poziomie systemu operacyjnego (tzw. Foreground Window) | ||
| + | * uchwyt do strumienia danych typu terminalowego, | ||
| + | <note important> | ||
| + | |||
| + | W celu odczytania uchwytów przydatne będą dwie funkcje z Windows API, które zwrócą nam wskaźniki (uchwyty) do odpowiednich obiektów. Wartości te należy zachować i można je wykorzystywać wielokrotnie. | ||
| + | |||
| + | Odczyt uchwytu do okienka głównego, ten uchwyt należy zastosować przy wywoływaniu okna dialogowego typu Message Box (i każdego innego): | ||
| + | < | ||
| + | ... | ||
| + | call GetForegroundWindow | ||
| + | mov handler, rax | ||
| + | ... | ||
| + | </ | ||
| + | W powyższym przykładzie zwracana przez funkcję wartość (przez rejestr RAX) zapisywana jest w zmiennej '' | ||
| + | |||
| + | Aby odczytać uchwyt do wnętrza terminala, należy skorzystać z innej funkcji: | ||
| + | < | ||
| + | ... | ||
| + | mov rcx, STD_OUTPUT_HANDLE | ||
| + | call GetStdHandle | ||
| + | mov stdHandle, rax | ||
| + | ... | ||
| + | </ | ||
| + | Przy czym ta funkcja wymaga jednego argumentu, o który strumień danych nam chodzi. Są trzy możliwości: | ||
| + | * STD_INPUT_HANDLE = -10 - standardowe wejście - można go użyć do odczytu danych z konsoli | ||
| + | * STD_OUTPUT_HANDLE = -11 - standardowe wyjście - jego używamy aby coś napisać w terminalu; pamiętaj o kończącym ENTER, czyli '' | ||
| + | * STD_ERROR_HANDLE = -12 - strumień dla błędów; | ||
| + | |||
| + | Przykładowy kod wyswietlający na konsoli tekst znajdujący się w zmiennej (pod adresem) '' | ||
| + | < | ||
| + | ... | ||
| + | ; WINAPI WriteConsoleA( | ||
| + | ; RCX => _In_ HANDLE | ||
| + | ; RDX => _In_ const VOID *lpBuffer, | ||
| + | ; R8 => _In_ DWORD | ||
| + | ; R9 => _Out_opt_ LPDWORD lpNumberOfCharsWritten, | ||
| + | mov rcx, stdHandle | ||
| + | lea rdx, text_msg | ||
| + | mov r8, sizeof text_msg | ||
| + | mov r9, dummy | ||
| + | call WriteConsoleA | ||
| + | ... | ||
| + | </ | ||
| + | |||
| + | W celu wyświetlenia okienka dialogowego, | ||
| + | < | ||
| + | ... | ||
| + | ; WINUSERAPI int WINAPI MessageBoxA( | ||
| + | ; RCX => _In_opt_ HWND hWnd, | ||
| + | ; RDX => _In_opt_ LPCSTR lpText, | ||
| + | ; R8 => _In_opt_ LPCSTR lpCaption, | ||
| + | ; R9 => _In_ UINT uType); | ||
| + | mov rcx, handler | ||
| + | mov rdx, offset hello_msg | ||
| + | mov r8, offset info_msg | ||
| + | mov r9, 0 ; MB_OK | ||
| + | and rsp, not 8 | ||
| + | call MessageBoxA | ||
| + | ... | ||
| + | </ | ||
| + | <note important> | ||
| ==== 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: | ||
| Line 207: | Line 363: | ||
| </ | </ | ||
| ==== Metoda weryfikacji wyników ==== | ==== Metoda weryfikacji wyników ==== | ||
| - | Teksty oraz okienka pojawiające się na ekranie zgadzają się z algorytmem. Zwróć szczególną uwagę na to, czy nie są generowane losowe ciągi znaków. | + | Teksty oraz okienka pojawiające się na ekranie zgadzają się z algorytmem. Zwróć szczególną uwagę na to, czy nie są generowane losowe ciągi znaków, co może sugerować, że zapomniałeś o kończącej łańcuch wartości 0. |
| ==== Pomocne zasoby ==== | ==== Pomocne zasoby ==== | ||
| * Visual Studio 2019: [[https:// | * Visual Studio 2019: [[https:// | ||
| * Przydatne funkcje Windows API: [[https:// | * Przydatne funkcje Windows API: [[https:// | ||
pl/edu/zmitac/n1z/ja/lab1.1615565317.txt.gz · Last modified: by pczekalski
