Zadania przykładowe do ćwiczeń z „Architektury komputerów”
cz. I, kwiecień 2010
1. W czterech kolejnych bajtach pamięci znajdują się liczby:
adres zawartość
65BH 2AH
65AH 00H
659H 37H
658H F2H
Przyjmując, że podane bajty stanowią liczbę binarną 32-bitową podać wartość tej liczby w zapisie szesnastkowym przy założeniu, że stosowana jest konwencja mniejsze wyżej (ang. big endian).
2. Które z podanych niżej mnemoników rozkazów określają ten sam kod maszynowy: jae, jle, jnb, jng.
3. Poniższy fragment programu może służyć do rezerwacji obszaru pamięci na dane o nieokreślonych wartościach początkowych. Podać równoważną deklarację tego obszaru używając dyrektywy dd.
obroty LABEL dword
ORG $ + 28
4. Na czym polega różnica w sposobie wykonania poniższych rozkazów:
push esi
push [esi]
5. Napisać fragment programu, w którym liczba 32-bitowa bez znaku znajdująca się w rejestrze EAX zostanie pomnożona przez 10 (dziesięć). Wynik mnożenia w postaci liczby 32-bitowej powinien zostać wpisany do rejestru EAX. Zakładamy, że mnożenie nie doprowadzi do powstania nadmiaru. W omawianym fragmencie nie mogą być używane rozkazy MUL lub IMUL. Wskazówka: wykorzystać zależność a ⋅ 10 = a ⋅ 8 + a ⋅ 2.
6. W czterech kolejnych bajtach pamięci począwszy od adresu podanego w rejestrze w EBX znajduje się 32-bitowa liczba całkowita bez znaku zakodowana w formacie mniejsze wyżej (big endian). Nie używając rozkazu BSWAP załadować tę liczbę do rejestru EAX w formacie mniejsze niżej (little endian).
7. Napisać fragment programu w asemblerze, który obliczy liczbę bitów o wartości 1 zawartych w rejestrze EAX. Wynik obliczenia wpisać do rejestru CL.
8. Napisać fragment programu, który porówna dwa obszary znaków w kodzie ASCII: położenie pierwszego obszaru określa zawartość rejestru ESI, drugiego obszaru — EDI. Na końcu obszaru źródłowego znajduje się wartość 0. Jeśli obszary zawierają identyczne znaki, to do znacznika ZF należy wpisać 1, w przeciwnym razie 0.
9. Napisać fragment programu w asemblerze, który sprawdzi czy liczba całkowita (w kodzie U2) zawarta w rejestrze EDI jest parzysta. Jeśli tak, to do znacznika CF należy wpisać 1 (rozkaz STC); w przeciwnym razie 0 (rozkaz CLC).
10. W rejestrze EBX znajduje się liczba całkowita w kodzie U2. Zakładamy, że liczba zawarta jest w przedziale <-(231 - 1), 231 - 1>. Napisać fragment, który przekoduje tę liczbę na kod znak-moduł.
11. Napisać fragment programu w asemblerze, który obliczy sumę cyfr dziesiętnych liczby zawartej w rejestrze EAX. Wynik obliczenia wpisać do rejestru CL. Przykład: jeśli w rejestrze EAX znajduje się liczba 1111101 (dziesiętnie 125), to po wykonaniu fragmentu rejestr CL powinien zawierać 00001000.
12. Napisać fragment programu w asemblerze, który zamieni młodszą (bity 15 - 0) i starszą (bity 31 - 16) część rejestru EDX.
13. Jaka wartość zostanie wprowadzona do rejestru EDX po wykonaniu podanego niżej fragmentu programu
linie dd 421, 422, 443, 442, 444, 427, 432
— — — — — — — — — —
mov esi, (OFFSET linie) + 4
mov ebx, 4
mov edx, [ebx] [esi]
14. Ile bajtów zarezerwuje asembler na zmienne opisane przez poniższe wiersze?
v1 dq ?, ?
v2 dw 4 dup (?), 20
v3 db 10 dup (?)
15. Na czym polega błąd w poniższym fragmencie programu?
const2 db ?
- - - - - - - - - - - - - - - - - - - - - -
mov const2, 256
16. Wyjaśnić działanie poniższego fragmentu programu
start: mov ecx, 3
sub ax, 10
loop start
17. Napisać fragment programu wyznaczający wszystkie liczby z przedziału <100, 999>, które są równe sumie sześcianów swoich cyfr dziesiętnych. Przykład:
371 = 3 * 3 * 3 + 7 * 7 * 7 + 1 * 1 * 1 = 27 + 343 + 1
18. Napisać fragment programu, który wpisze do n początkowych elementów tablicy liczby_pierwsze kolejne liczby pierwsze 2, 3, 5, 7, . . . w postaci 32-bitowych liczb binarnych. Liczba n podana jest w rejestrze ECX, a adres obszaru podany jest w rejestrze ESI.
19. Ułożyć podprogram sprawdzający czy 32-bitowa liczba naturalna znajdująca się na wierzchołku stosu jest liczbą pierwszą. Jeśli tak, to znacznik CF powinien być ustawiony w stan 1, a w przeciwnym razie w stan 0.
20. Ułożyć fragment programu przekształcający ciąg n bajtów umieszczonych w pamięci począwszy od lokacji wskazanej przez zawartość rejestru EDI, w taki sposób, że pierwszy i ostatni bajt zostaną zamienione, drugi i przedostatni bajt zostaną zamienione, itd. Liczba bajtów podana jest w rejestrze ECX.
21. Parametry przekazywane do podprogramu umieszcza się zwykle na stosie lub w rejestrach. W pewnych przypadkach parametry można umieścić także bezpośrednio za rozkazem wywołującym podprogram, np.
call oblicz
dd -37
dd 39865
Napisać fragment programu, który skopiuje do rejestrów EAX i EBX dwa parametry podane bezpośrednio za rozkazem CALL.
22. Zakładając, że przed wykonaniem poniższego fragmentu programu w rejestrze AX znajduje się liczba 50, wyznaczyć zawartość rejestru AX po wykonaniu podanych rozkazów.
mov si, 0
mov di, 1
ptl: sub ax, di
; rozkaz SUB ustawia znacznik CF,
; gdy występuje pożyczka przy
; odejmowaniu
jc zak ;skok,gdy CF=1
inc si
add di, 2
jmp ptl
zak: mov ax, si
23. Określić zawartości znaczników OF, ZF i CF po wykonaniu podanego niżej fragmentu programu.
mov ax, 1
add ax, 0FFFFH
24. Jakie wartości zostaną wpisane do rejestrów EDX i EAX po wykonaniu niżej podanego fragmentu programu?
mov eax, 0FFFFFFFFH
mov ebx, 0FFFFFFFFH
imul ebx
25. Określić zawartości znaczników OF, ZF i CF po wykonaniu podanego niżej fragmentu programu.
xor eax, eax
sub eax, 0FFFFFFFFH
26. Napisać podprogram w asemblerze przystosowany do wywoływania z poziomu języka C. Prototyp funkcji implementowanej przez podprogram ma postać:
char zamien_litere (char a);
Podprogram powinien zamienić małą literę w kodzie ASCII na wielką literę i zwrócić ją jako wartość funkcji. Do testowania podprogramu wykorzystać poniższy program w języku C.
#include <stdio.h>
#include <string.h>
char zamien_litere (char a);
int main()
{
char znaki[32];
int dlug, i;
printf("\nProszę napisać \
dowolny wyraz: ");
scanf_s("%s", znaki, 10);
dlug = strlen(znaki);
for (i = 0; i < dlug; i++)
znaki[i] =
zamien_litere(znaki[i]);
printf("\nTekst po zamianie ma \
postać %s\n", znaki);
return 0;
}
27. Napisać podprogram w asemblerze przystosowany do wywoływania z poziomu języka C. Podprogram powinien wyznaczyć największą liczbę spośród dwóch liczb podanych jako argumenty funkcji. Prototyp funkcji implementowanej przez pierwszy podprogram ma postać:
int podaj_max (int a, int b);
Do testowania podprogramu wykorzystać poniższy program w języku C.
#include <stdio.h>
int podaj_max (int a, int b);
int main()
{
int x, y, z;
printf("\nProszę napisać dwie liczby: ");
scanf_s("%d %d", &x, &y, 10);
z = podaj_max(x, y);
printf("\nZ podanych liczb %d i %d \
wieksza jest %d\n", x, y, z);
return 0;
}
28. Poniższy program w języku C wczytuje wiersz z klawiatury, następnie oblicza liczbę wielkich liter w tym wierszu i wyświetla obliczoną wartość na ekranie.
Obliczenie liczby liter wykonuje podprogram zakodowany w asemblerze, przystosowany do wywoływania z poziomu języka C, którego prototyp na poziomie języka C ma postać:
int liczba_wielkich_liter
(char wiersz[ ], int n);
W języku C łańcuch znaków zakończony jest bajtem zerowym. Zakładamy, że wprowadzony wiersz zawiera wyłącznie znaki podstawowe kodu ASCII (z przedziału 32 do 127).
#include <stdio.h>
#include <string.h>
int liczba_wielkich_liter (char \
wiersz[ ], int n);
int main()
{
char tekst[128]; int wynik, dlug;
printf("\nProszę napisać dowolny \
tekst w jednym wierszu: ");
gets(tekst);
dlug = strlen(tekst);
wynik = liczba_wielkich_liter(tekst, dlug);
printf("\nW podanym tekście \
znajduje się %d wielkich liter\n",
wynik);
return 0;
}
29. Poniższy program w języku C wczytuje liczbę całkowitą bez znaku z klawiatury, następnie oblicza ilość cyfr dziesiętnych tej liczby i wyświetla na ekranie wynik obliczenia. Przykładowo, ilość cyfr dziesiętnych liczby 7012 wynosi 4.
Obliczenie ilości cyfr wykonuje podprogram zakodowany w asemblerze, przystosowany do wywoływania z poziomu języka C, którego prototyp na poziomie języka C ma postać:
unsigned int ilosc_cyfr (unsigned int liczba);
Napisać podprogram w asemblerze dokonujący opisanego obliczenia i uruchomić program składający się plików źródłowych w języku C i w asemblerze.
Wskazówka: należy odpowiednio zaadaptować podprogram wyświetlający liczbę binarną w postaci dziesiętnej. Wystarczy tylko obliczyć ile razy w trakcie kolejnego dzielenia przez 10 uzyskano iloraz (w rejestrze EAX) różny od 0.
#include <stdio.h>
unsigned int ilosc_cyfr (unsigned int liczba);
int main()
{
int k, wynik;
printf("\nProsze napisać liczbę \
całkowita bez znaku: ");
scanf_s("%d", &k, 12);
wynik = ilosc_cyfr (k);
printf("\nIlosc cyfr dziesiętnych\
liczby %d wynosi %d\n", k, wynik);
return 0;
}
30. Poniższy program w języku C wczytuje liczbę całkowitą z klawiatury, następnie zmniejsza ją o 1 i wyświetla na ekranie wynik obliczenia.
Zmniejszenie liczby o 1 wykonuje podprogram zakodowany w asemblerze, przystosowany do wywoływania z poziomu języka C, którego prototyp na poziomie języka C ma postać:
void minus_jeden (int * liczba);
Argument liczba jest adresem (wskaźnikiem) zmiennej, w której przechowywana jest liczba.
Napisać podprogram w asemblerze dokonujący opisanego obliczenia i uruchomić program składający się z plików źródłowych w języku C i w asemblerze.
#include <stdio.h>
void minus_jeden (int * liczba);
int main()
{
int k;
printf("\nProsze napisać liczbę \
całkowitą bez znaku: ");
scanf_s("%d", &k, 11);
minus_jeden (&k);
printf("\nLiczba mniejsza o jeden\
wynosi %d\n", k);
return 0;
}