Zadania przykładowe do ćwiczeń z „Architektury komputerów”
cz. II, maj 2010
1. Podać liczbę, która zostanie wyświetlona na ekranie w wyniku wykonania poniższego fragmentu programu. Podprogram wyswietl32 wyświetla na ekranie w postaci dziesiętnej liczbę binarną zawartą w rejestrze EAX.
qxy dw 254, 255, 256
— — — — — — — —
mov eax, dword PTR qxy + 1
call wyswietl32
2. Funkcja MessageBoxA@16(0, adr1, adr2, 0) wyświetla komunikat na ekranie: adr1 jest adresem tekstu wyświetlanego w okienku komunikatu, adr2 jest adresem tekstu wyświetlanego w tytule komunikatu. Koniec tekstu wskazuje bajt o wartości 0. Rozkaz LEA oblicza adres efektywny rozkazu.
Określić postać komunikatu po wykonaniu poniższego fragmentu programu.
napis db 'informatyka', 0, 4 dup (?)
— — — — — — — — —
mov ecx, 12
przepisz: mov al, napis[ecx-1]
mov napis[ecx+3], al
loop przepisz
push 0
push OFFSET napis
lea eax, napis[3]
push eax
call _MessageBoxA@16
3. W programach obsługi kalendarza MS Visual Studio dni świąteczne w miesiącu koduje się w postaci jedynek umieszczonych na odpowiednich bitach słowa 32-bitowego. Tablica zawierająca 12 takich elementów pozwala zakodować informacje obejmujące rok.
Napisać podprogram w asemblerze wyświetlający na ekranie daty dni świątecznych w podanym miesiącu. Parametry wywołania podprogramu znajdują się w rejestrach:
CL – numer miesiąca (1 – 12)
EBX – adres tablicy zawierającej zakodowane daty dni świątecznych w poszczególnych miesiącach.
4. W rejestrach EDX:EBX:EAX znajduje się 96-bitowy ciąg bitów. Napisać fragment programu, w którym ciąg ten zostanie przesunięty cyklicznie w lewo o 1 pozycję.
Wskazówka: wykorzystać rozkazy przesunięcia w lewo SHL (bity wychodzące z rejestru wpisywane są do CF) i RCL (zawartość CF wpisywana jest na najmłodszy bit rejestru, a bity wychodzące z rejestru wpisywane są do CF). Wykorzystać także rozkaz BT.
5. W programie asemblerowym zdefiniowano format 32-bitowych liczb mieszanych bez znaku, przyjmując, że najmniej znaczący bit ma wagę 2-7.
Napisać fragment programu w asemblerze, który wpisze 1 do znacznika CF (rozkaz STC) jeśli część całkowita liczby zawartej w rejestrze EBX jest różna od zera; w przeciwnym razie CF powinien zostać wyzerowany (rozkaz CLC).
6. Na poniższym rysunku pokazane są dwa formaty 32-bitowych liczb stałoprzecinkowych bez znaku używane w programie.
Zakładając, że w rejestrze ESI znajduje się liczba zakodowana wg pierwszego formatu (najmniej znaczący bit ma wagę 2-8), a w rejestrze EDI liczba zakodowana wg drugiego formatu (najmniej znaczący bit ma wagę 2-7), napisać fragmentu, który porówna obie liczby. Jeśli liczba w rejestrze ESI jest większa od liczby w rejestrze EDI, to do CF należy wpisać 1, w przeciwnym razie 0 (rozkazy STC/CLC).
7. Poniżej podano fragment programu w języku C.
int a, b, * wsk, wynik;
wsk = &b;
a = 21; b = 25;
wynik = roznica(&a, &wsk);
Napisać podprogram w asemblerze przystosowany do wywoływania z poziomu języka C, którego prototyp ma postać:
int roznica (int * odjemna,
int ** odjemnik);
Podprogram ten powinien obliczyć różnicę dwóch liczb całkowitych ze znakiem w kodzie U2.
8. Poniżej podano fragment programu w języku C.
int pomiary[7], * wsk;
- - - - - - - - - - - - - - -
wsk = szukaj_elem_min(pomiary, 7);
printf("\nElement minimalny = %d\n",
* wsk);
int * szukaj_elem_min (
int tablica[ ], int n);
Podprogram ten powinien wyznaczyć najmniejszy element tablicy i zwrócić adres (wskaźnik) tego elementu. Liczbę elementów tablicy określa drugi parametr funkcji.
9. Napisać podprogram w asemblerze przystosowany do wywoływania z poziomu języka C. Prototyp funkcji implementowanej przez ten podprogram ma postać:
void nowy_strcat (char * wynik, char * zrodlo);
gdzie wynik i zrodlo są adresami (wskaźnikami) tablic zawierających ciągi znaków ASCII, przy czym koniec ciągu wskazuje bajt o wartości 0. Podprogram powinien dopisać znaki zawarte w tablicy zrodlo do znaków zawartych w tablicy wynik.
Napisać także krótki program w języku C ilustrujący sposób ilustrujący sposób wywoływania tego podprogramu. W programie tym należy wczytać z klawiatury dwa dowolne teksty (funkcja scanf), a następnie, korzystając z opracowanej funkcji, wyświetlić połączone teksty.
10. Funkcja biblioteczna języka C o prototypie
void * malloc(unsigned int k);
przydziela k-bajtowy obszar pamięci i zwraca adres przydzielonego obszaru. Jeśli wymagany obszar nie może być przydzielony, to funkcja zwraca wartość 0.
Napisać podprogram w asemblerze, przystosowany do wywoływania z poziomu języka C — prototyp tego podprogramu ma postać:
int * kopia_tablicy(int tabl[],
unsigned int n);
Podprogram kopia_tablicy tworzy nową tablicę o rozmiarach identycznych z oryginalną i zwraca adres nowej tablicy (albo 0, jeśli tablicy nie można było utworzyć).
Do nowej tablicy należy skopiować wszystkie elementy tablicy oryginalnej o wartościach będących liczbami parzystymi. Pozostałe elementy nowej tablicy wypełnić zerami.
Wskazówki:
1. Nową tablicę należy utworzyć poprzez przydzielenie odpowiedniego obszaru pamięci za pomocą funkcji malloc.
2. Sprawdzenie czy liczba jest parzysta najłatwiej wykonać poprzez odczytanie najmłodszego bitu liczby (bit nr 0).
11. Napisać podprogram w asemblerze obliczający wartość funkcji kwadrat metodą rekurencyjną korzystając z zależności:
a2 = (a – 2) 2 + 4*a – 4 dla a > 1
a2 = 1 dla a = 1
a2 = 0 dla a = 0
przy czym argument a jest liczbą całkowitą 32-bitową zawartą w przedziale <1, 65535>.
Podprogram powinien być przystosowany do wywoływania z poziomu języka C, a jego prototyp ma postać:
unsigned int kwadrat (
unsigned int a);
W podprogramie nie można używać rozkazów mnożenia i rozkazów przesunięć.
12. Podać wartość zwracaną przez funkcję iteracja w poniższym fragmencie programu w języku C
w = iteracja(32);
Kod funkcji iteracja zapisany w asemblerze ma postać
_iteracja PROC
push ebp
mov ebp, esp
mov al, [ebp+8]
sal al, 1
; SAL wykonuje przesuniecie logiczne
; w lewo
jc zakoncz
inc al
call _iteracja
add esp, 4
pop ebp
ret
zakoncz: rcr al, 1
; rozkaz RCR wykonuje przesunięcie
; cykliczne w prawo przez CF
_iteracja ENDP
13. W pamięci komputera, począwszy od adresu podanego w rejestrze ESI znajduje się 32-bitowa liczba zmiennoprzecinkowa w formacie float. Napisać fragment programu, który przekształci tę liczbę na 64-bitowy format double i uzyskany rezultat wpisze do pamięci począwszy od adresu podanego w rejestrze EDI. W omawianym fragmencie nie można używać rozkazów koprocesora arytmetycznego.
14. W rejestrze EAX znajduje się liczba zmiennoprzecinkowa w formacie float. Napisać fragment programu, który zwiększy tę liczbę o 2, przy czym w fragmencie nie mogą występować rozkazy koprocesora arytmetycznego. Dodatkowo zakładamy, że liczba zmiennoprzecinkowa jest dodatnia.
15. W rejestrze EAX znajduje się liczba zmiennoprzecinkowa w formacie float. Napisać fragment programu, który zwiększy tę liczbę o 0.25, przy czym w fragmencie nie mogą występować rozkazy koprocesora arytmetycznego. Dodatkowo zakładamy, że liczba zmiennoprzecinkowa jest dodatnia.
16. Poniżej podano kod (niepełny) podprogramu w asemblerze, który zwiększa o 1 liczbę zmiennoprzecinkową w formacie double. Podprogram przystosowany jest do wywoływania z poziomu języka C, a jego prototyp ma postać:
double plus_jeden (double x);
Nie używając rozkazów koprocesora, uzupełnić brakujący fragment podprogramu, przy założeniu, że liczba x jest większa od 1, a zawartość pola wykładnika (w formacie double) należy do przedziału <1023, 1075>. Uwaga: po wykonaniu dodawania przeprowadzić normalizację liczby.
_plus_jeden PROC
push ebx
push esi
push edi
; odczytanie liczby
; w formacie double
mov eax, [ebp+8]
mov edx, [ebp+12]
; wpisanie 1 na pozycji o wadze 2^0
; mantysy do EDI:ESI
mov esi, 0
mov edi, 00100000H
; wyodrębnienie pola
; wykładnika (11-bitowy)
; bit znaku liczby z założenia = 0
mov ebx, edx
shr ebx, 20
; obliczenie pierwotnego wykładnika
; potęgi
sub ebx, 1023
; zerowanie wykładnika i bitu znaku
and edx, 000FFFFFH
; dopisanie niejawnej jedynki
or edx, 00100000H
— — — — — — — — — — — — — — — —
; załadowanie obliczonej wartości z
; EDX:EAX na wierzchołek stosu
; koprocesora
push edx
fld qword PTR [esp]
add esp, 8
pop edi
pop esi
...
sote12