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