2018 oefeningen hoofdstuk 4 de stapel oplossingen
DE STAPEL
Korte vraag
-----------
Gegeven volgend programma om de rij van Fibonacci te berekenen:
fibGetallen: dd 0
dd 1
resd 98
...
mov ecx, 98
mov eax, fibGetallen + 8
lus: push eax
call berekenVolgendFibGetal
add eax, 4
loop lus
De code definieert een rij van 100 getallen, waarvan de eerste twee getallen (0 en 1) als constanten gedefiniëerd worden. De volgende 98 getallen worden berekend door middel van een lus waar telkens de 'berekenVolgendFibGetal'-methode opgeroepen wordt. Deze methode berekent één getal. Het adres waar het te berekenen getal moet worden opgeslagen wordt via de stapel doorgegeven. De methode kan dan aan de hand van dat adres (dat dus wijst naar een getal in de 'fibGetallen'-rij) de twee voorgaande getallen ophalen, optellen en het resultaat wegschrijven.
Teken de inhoud van de stack op de moment dat de subroutine 'berekenVolgendFibGetal' begint. Vul daarna de subruoutine aan:
berekenVolgendFibGetal:
push ebp
mov ebp, esp
push eax
push esi
; kopieer het adres van het ide
; getal (dat op de stack staat)
; naar ESI
mov esi, [ebp + 8]
; kopieer de waarde van het getal
; ervoor naar eax
mov eax, [esi - 4]
; tel de waarde van het getal dat
; twee plaatsen ervoor staat erbij op
add eax, [esi - 8]
; kopieer de berekende waarde naar de array
mov [esi], eax
pop esi
pop eax
pop ebp
ret 4
De stapelwijzer (1)
-------------------
Bepaal voor onderstaand stuk code de uiteindelijke waarde van de stapelwijzer (register ESP), als je weet dat de initiële waarde van ESP 0000029Ah is.
PROGRAMMA
De volgende instructies worden uitgevoerd.
pop ecx
push dword [520h]
sub eax, [404h]
idiv dword [404h]
pop ah
pop ch
mov eax, [520h]
STAPELWIJZER (na uitvoering, in hexadecimaal)
De waarde van ESP is:
0000029C
De stapelwijzer (2)
-------------------
Bepaal voor onderstaand stuk code de uiteindelijke waarde van de stapelwijzer (register ESP), als je weet dat de initiële waarde van ESP 0000011Ah is.
PROGRAMMA
De volgende instructies worden uitgevoerd.
pop dword [700h]
push dword [248h]
pop dl
push dword [700h]
pop cx
add eax, [248h]
STAPELWIJZER (na uitvoering, in hexadecimaal)
De waarde van ESP is:
00000119
De stapelwijzer (3)
-------------------
Bepaal voor onderstaand stuk code de uiteindelijke waarde van de stapelwijzer (register ESP), als je weet dat de initiële waarde van ESP 0000016Ch is.
PROGRAMMA
De volgende instructies worden uitgevoerd.
pop dword [62Ch]
pop al
add eax, [62Ch]
push dword [62Ch]
push dword [438h]
push dword [408h]
pop dword [62Ch]
STAPELWIJZER (na uitvoering, in hexadecimaal)
De waarde van ESP is:
00000169
De stapelwijzer (4)
-------------------
Bepaal voor onderstaand stuk code de uiteindelijke waarde van de stapelwijzer (register ESP), als je weet dat de initiële waarde van ESP 0000006Eh is.
PROGRAMMA
De volgende instructies worden uitgevoerd.
pop dword [324h]
idiv dword [324h]
add eax, 5
mov [324h], eax
push bl
sub eax, 39
add eax, [324h]
idiv dword [61Ch]
STAPELWIJZER (na uitvoering, in hexadecimaal)
De waarde van ESP is:
00000071
De stapelwijzer (5)
-------------------
Bepaal voor onderstaand stuk code de uiteindelijke waarde van de stapelwijzer (register ESP), als je weet dat de initiële waarde van ESP 0000025Ah is.
PROGRAMMA
De volgende instructies worden uitgevoerd.
push dword [208h]
push dword [208h]
mov eax, 53
push dword [924h]
imul dword [908h]
STAPELWIJZER (na uitvoering, in hexadecimaal)
De waarde van ESP is:
0000024E
De stapelwijzer (6)
-------------------
Bepaal voor onderstaand stuk code de uiteindelijke waarde van de stapelwijzer (register ESP), als je weet dat de initiële waarde van ESP 000002A4h is.
PROGRAMMA
De volgende instructies worden uitgevoerd.
add eax, 27
pop ah
idiv dword [73Ch]
push ch
imul dword [638h]
pop dword [638h]
sub eax, [73Ch]
sub [638h], eax
STAPELWIJZER (na uitvoering, in hexadecimaal)
De waarde van ESP is:
000002A8
SUBROUTINES
ASCII-omzetting
---------------
Het stukje programma om een integer om te rekenen naas ASCII komt in vele programma's (soms meermaals) voor. Schrijf een programma dat een getal aan de gebruiker vraagt, dit getal omzet naar ASCII, en wegschrijft naar een uitvoerbestand. Zorg er voor dat het stukje code dat gebruikt wordt om een getal om te zetten naar ASCII als een subroutine geschreven is (d.w.z.: met call en ret instructies). Het getal dat de gebruiker invoert is niet langer dan 10 cijfers.
%include "gt.asm"
covar
outarea: resb 70
db 0Dh, 0Ah
getal: resd 1
inleiding
openuit
call leeg
inv [getal]
push dword [getal]
push dword 9
call omzetascii
schrijf
slot
leeg:
cld
mov ecx, 70
mov al, ' '
mov edi, outarea
rep stosb
ret
omzetascii:
push ebp
mov ebp, esp
push eax
push ebx
push edx
push edi
mov eax, [ebp + 12]
std
mov edi, outarea
add edi, [ebp + 8]
mov ebx, 10
lus:
mov edx, 0
idiv dword ebx
add dl, 30h
xchg al, dl
stosb
xchg al, dl
cmp eax, 0
jne lus
pop edi
pop edx
pop ebx
pop eax
pop ebp
ret 8
Grootste gemene deler
---------------------
Schrijf een programma dat aan de gebruiker twee getallen vraagt, de grootste gemene deler ervan berekent, en het resultaat aan de gebruiker toont. Zorg er voor dat het stukje code dat gebruikt wordt om de grootste gemene deler te berekenen als een subroutine geschreven is. Je kan hiervoor je code van de oefeningen van hoofdstuk 2 hergebruiken. Zorg er voor dat de twee getallen via registers EAX en EBX aan de subroutine doorgegeven worden. Het resultaat van de subroutine komt in register EDX. Na uitvoering van de subroutine mag enkel de waarde van register EDX aangepast zijn.
%include "gt.asm"
covar
getaleen: resd 1
getaltwee: resd 1
ggd: resd 1
inleiding
inv [getaleen]
inv [getaltwee]
mov eax, [getaleen]
mov ebx, [getaltwee]
push dword edx
push dword eax
push dword ebx
call grootstegemenedeler
pop dword edx
mov [ggd], edx
uit [ggd]
slot
grootstegemenedeler:
push ebp
mov ebp, esp
push eax
push ebx
push edx
mov eax, [ebp + 12]
mov ebx, [ebp + 8]
mov [ebp + 16], ebx
terug:
cmp ebx, 0
je verder
mov edx, 0
mov [ebp + 16], ebx
idiv dword [ebp + 16]
mov eax, ebx
mov ebx, edx
jmp terug
verder:
pop edx
pop ebx
pop eax
pop ebp
ret 8
Kleinste gemene veelvoud
------------------------
Schrijf een programma dat aan de gebruiker twee getallen vraagt, het kleinste gemene veelvoud ervan berekent, en het resultaat aan de gebruiker toont. Zorg er voor dat het stukje code dat gebruikt wordt om het kleinste gemene veelvoud te berekenen als een subroutine geschreven is. Je kan hiervoor je code van de oefeningen van hoofdstuk 2 en van de vorige oefening hergebruiken. Zorg er voor dat de twee getallen via registers EAX en EBX aan de subroutine doorgegeven worden. Het resultaat van de subroutine komt in register ECX. Na uitvoering van de subroutine mag enkel de waarde van register ECX aangepast zijn.
%include "gt.asm"
covar
getaleen: resd 1
getaltwee: resd 1
ggd: resd 1
kgv: resd 1
inleiding
inv [getaleen]
inv [getaltwee]
mov eax, [getaleen]
mov ebx, [getaltwee]
push dword ecx
push dword edx
push dword eax
push dword ebx
call kleinstegemeneveelvoud
pop dword ecx
mov [kgv], ecx
uit [kgv]
slot
kleinstegemeneveelvoud:
push ebp
mov ebp, esp
push eax
push ebx
push edx
mov eax, [ebp + 12]
mov ebx, [ebp + 8]
mov [ebp + 16], ebx
terug:
cmp ebx, 0
je verder
mov edx, 0
mov [ebp + 16], ebx
idiv dword [ebp + 16]
mov eax, ebx
mov ebx, edx
jmp terug
verder:
mov ebx, 1
mov eax, [ebp + 12]
imul dword [ebp + 8]
imul dword ebx
idiv dword [ebp + 16]
mov [ebp + 20], eax
pop edx
pop ebx
pop eax
pop ebp
ret 12
Faculteit
---------
Schrijf een programma dat aan de gebruiker een waarde, n, vraagt, n! berekent, en het resultaat toont.
n! = n * (n-1) * (n-2) * ... * 3 * 2 * 1
Zorg er voor dat het stukje code dat gebruikt wordt om n! te berekenen als een subroutine geschreven is.
%include "gt.asm"
covar
n: resd 1
nuitroepteken: resd 1
inleiding
inv [n]
push dword [nuitroepteken]
push dword [n]
call nfaculteit
pop dword [nuitroepteken]
uit [nuitroepteken]
slot
nfaculteit:
push ebp
mov ebp, esp
push eax
push ebx
mov ebx, [ebp + 8]
mov eax, 1
lus:
cmp ebx, 1
jg rekenen
jmp einde
rekenen:
imul dword ebx
sub ebx, 1
jmp lus
einde:
mov [ebp + 12], eax
pop ebx
pop eax
pop ebp
ret 4