Präsenz¨ubung 1 - Universität Paderborn
Transcrição
Präsenz¨ubung 1 - Universität Paderborn
SoSe 2014 Konzepte und Methoden der Systemsoftware Universität Paderborn Fachgebiet Rechnernetze Präsenzübung 1 2014-04-21 bis 2014-04-27 Aufgabe 1: Assembler Wiederholung 0P Eine Kurzübersicht zu x86-Assembler befindet sich im Anhang. (a) (0 Punkte) Geben Sie einen groben Überblick, wie eine CPU aufgebaut ist. Lösung: Eine CPU besteht aus Rechenwerk und Steuerwerk. Das Steuerwerk setzt Instruktionen um und ist für die Ablaufsteuerung zuständig. Das Rechenwerk führt arithmetische Operationen durch. (Folie 1.15) (b) (0 Punkte) Nennen Sie die am häufigsten verwendeten Register eines x86-Prozessors. Welche Größe besitzen sie? Nennen Sie zwei Möglichkeiten, auf das zweite (least-significant) Byte in Register EAX zuzugreifen. Hinweis: Diese Informationen finden Sie nicht in den Vorlesungsfolien. Lösung: Die am häufigsten verwendeten Register sind die Allzweckregister EAX, EBX, ECX, EDX, ESI, EDI, das Stackpointer-Register ESP, das Basepointer-Register EBP. Diese Register sind alle 32 Bit groß. Innerhalb der ersten vier gibt es jeweils noch Unterregister. Für EAX sind das AX, AH und AL, wobei AX die least significant 16 bit von EAX enthält und selbst in AH und AL zu je 8 bit aufgeteilt ist. Damit ergibt sich auch gleiche eine Möglichkeit auf das zweite Byte in Register EAX zuzugreifen: Das Register AH enthält dieses. Eine zweite Möglichkeit ist, den Inhalt in EAX durch Maskieren (and eax, 0xff00) und Verschieben (shr eax, 8) zu verändern. Musterlösung KMS SoSe 2014 Präsenzübung 1 1/5 (c) (0 Punkte) Übersetzen Sie den folgenden (defekten) Assemblercode in Pseudocode! Welche Argumente werden ihm in den Registern ECX und EDX übergeben? Welcher bekannte Algorithmus wurde hier versucht zu implementieren? ; ; ; P a r a m e t e r : ecx , e d x function : l1 : cmp edx , 1 jle el1 mov e s i , 1 l2 : cmp e s i , edx jge el2 mov a l , b y t e [ e c x + e s i −1] mov bl , b y t e [ e c x + e s i ] cmp a l , b l j l e ns mov [ e c x + e s i −1] , b l mov [ e c x + e s i ] , a l ns : inc e s i jmp l 2 el2 : jmp l 1 el1 : ret Lösung: Der Algorithmus ist ein Bubblesort, der sein Suchfenster nie verkleinert und somit nicht terminiert. Register ECX enthält einen Zeiger auf das Array mit den zu sortierenden Bytes, Register EDX enthält die Anzahl der zu sortierenden Bytes. w h i l e ( l e n >1) { i = 1; while ( i < len ) { i f ( a r r [ i −1] > a r r [ i ] ) { swap ( a r r [ i −1] , a r r [ i ] ) ; i += 1 ; } / / l e n −= 1 ; h i e r i s t d e r bug −> A u f g a b e 1 d } } return ; (d) (0 Punkte) Finden und korrigieren Sie den Fehler in Teilaufgabe (c). Lösung: Die äußere Schleife ist eine Endlosschleife, es fehlt ein dec edx vor jmp l1: ns : el2 : el1 : inc jmp dec jmp ret esi l2 edx l1 Musterlösung KMS SoSe 2014 Präsenzübung 1 2/5 Aufgabe 2: Unterprogrammaufrufe 0P Eine Kurzübersicht zu x86-Assembler befindet sich im Anhang. (a) (0 Punkte) Was ist der (Laufzeit-) Stack? Wozu wird er benötigt und wie wird er verwendet? Lösung: Der Stack ist per se ein Speicherbereich. Er dient zur Verwaltung von Unterprogrammen, in ihm werden Aufrufparameter, lokale Variablen und Rücksprungadressen gespeichert. Er wird benötigt um rekursive Aufrufe von Unterprogrammen zu ermöglichen. (b) (0 Punkte) Was versteht man unter einer Aufrufkonvention und wozu dient sie? Hinweis: Diese Informationen finden Sie nicht in den Vorlesungsfolien. Lösung: Eine Aufrufkonvention ist eine Vereinbarung, wie ein Unterprogramm aufgerufen wird. Sie gibt an, wie Parameter an das Unterprogramm übergeben werden, bspw. in Registern oder auf dem Stack und in welcher Reihenfolge. Sie gibt weiterhin an, wie das Unterprogramm seine Rückgabewerte zurück gibt, wie die Rücksprungadresse zu finden ist und Welche Register nach Rückkehr aus dem Unterprogramm verändert sein dürfen. Sie beschreibt auch, wer die Funktionsparameter wieder vom Stack entfernt. (c) (0 Punkte) Die Anweisungen push, call und ret vereinfachen das Schreiben von Unterprogrammen, sie sind jedoch nicht notwendig: Ihre Funktion kann auch durch andere Anweisungen ausgedrückt werden. Schreiben Sie jeweils Assemblercode, der sie ersetzen kann. Lösung: 1. push arg1 sub esp , 4 ; 4 B y t e P l a t z a u f dem S t a c k s c h a f f e n mov [ e s p ] , a r g 1 2. call arg1 sub esp , 4 mov [ e s p ] , r e t jmp a r g 1 ret : 3. ret pop eax jmp eax (d) (0 Punkte) Was berechnet der folgende Assemblercode? Beschreiben Sie die verwendete Aufrufkonvention. Wie ruft man ihn auf? Zeichnen Sie das Stacklayout eines Aufrufes! func : rec : done : sub esp , 4 cmp [ e s p +0 x8 ] , dword 0 x1 jg rec mov eax , 1 jmp done mov eax , [ e s p +0 x8 ] dec eax push eax c a l l func add esp , 0 x4 mov [ e s p ] , eax imul eax , dword [ e s p +0 x8 ] mov [ e s p ] , eax add esp , 4 ret Musterlösung KMS SoSe 2014 Präsenzübung 1 3/5 Lösung: Der Code berechnet rekursiv die Fakultät. Äquivalent: int fak ( int n ) { i f ( n <= 1 ) r e t u r n 1 ; return n∗ f a k ( n −1); } Aufrufkonvention: Der Aufrufer legt das Argument auf den Stack, dann die Rücksprungadresse. Der Aufrufer entfernt nach Rückkehr der Funktion den Parameter wieder vom Stack (add esp,0x4). Der Rückgabewert steht in Register EAX. Stacklayout: ... Argument Rücksprungadresse lokale Variable esp Aufruf fak(17): push 17 c a l l func Hinweis: Die lokale Variable [esp] ist überflüssig (sie wird offensichtlich nicht gelesen und die Rückgabe steht auch in Register EAX). Sie dient nur zur Vorbereitung auf die nächste Teilaufgabe. (e) (0 Punkte) Implementieren Sie eine Funktion zur rekursiven Berechnung von Elementen der Fibonacci-Folge in Assembler. Überläufe ab dem 47. Element können Sie dabei ignorieren. ( f (n − 1) + f (n − 2) n > 2 f (n) = 1 sonst Lösung: fib : rec : done : sub esp , 0 x4 cmp [ e s p +0 x8 ] , dword 0 x2 jg rec mov eax , 1 jmp done mov eax , [ e s p +0 x8 ] dec eax push eax call fib add esp , 0 x4 mov [ e s p ] , eax mov eax , [ e s p +0 x8 ] sub eax , 2 push eax call fib add esp , 0 x4 add eax , dword [ e s p ] add esp , 0 x4 ret Musterlösung KMS SoSe 2014 Präsenzübung 1 4/5 x86 Kurzübersicht (Intel-Syntax) Registergrößen EAX AX AL AH Speicherzugriff mov eax,[17] mov eax,[esp] mov eax,[ebx] mov eax,[ebx+3] mov [ecx],dword 5 mov [ecx],byte 5 Anweisungen add r1,arg2 sub r1,arg2 xor r1,arg2 imul r1,arg2 shr r1,arg2 mov r1,arg2 inc r1 dec r1 nop jmp arg1 cmp r1,arg2 jg/jl arg1 je/jne arg1 jge arg1 jle arg1 call arg1 ret push arg1 pop r1 int arg1 32 bit 16 bit, AX=EAX[1:16] je 8 bit, AL=AX[1:8], AH=AX[9:16] Schreibt in eax das dword, das an Adresse 17 im Speicher steht Schreibt in eax das dword, das oben auf dem Stack liegt Schreibt in eax das dword, das an der Speicheradresse aus ebx steht Schreibt in eax das dword, das an der Speicheradresse ebx+3“ steht ” Schreibt eine 5 (als 4 byte-dword) an die Speicheradresse, die in ecx steht Schreibt eine 5 (als 1 byte) an die Speicheradresse, die in ecx steht r1 = r1 + arg2 r1 = r1 - arg2 r1 = r1 ˆ arg2 r1 = r1 · arg2 r1 = r1 arg2 r1 = arg2 r1 = r1+1 r1 = r1-1 no op springe zu Adresse arg1 r1 mit arg2 vergleichen und das Ergebnis in den Prozessorflags speichern springe zu Adresse arg1, falls der letzte Vergleich größer“ / kleiner“ ergeben hat ” ” springe zu Adresse arg1, falls der letzte Vergleich gleich“ / ungleich“ ergeben hat ” ” springe zu Adresse arg1, falls der letzte Vergleich größer oder gleich“ ergeben hat ” springe zu Adresse arg1, falls der letzte Vergleich kleiner oder gleich“ ergeben hat ” pusht die nächste Adresse (als Rücksprungadresse) auf den Stack und springt zu arg1 springt an die Adresse (Rücksprungadresse), die ganz oben auf dem Stack liegt aktualisiert den Stackpointer und schreibt arg1 auf den Stack läd das oberste Element vom Stack in r1 und aktualisiert den Stackpointer löst den Interrupt arg1 aus - üblicherweise benutzt als int 0x80 für syscalls Die Argumente r1 müssen schreibbar sein, also Register oder Speicherreferenzen. Arg1/2 können auch immediates sein. Bspw. add eax,7 Beispiel bedingter Sprung cmp eax , 70 jle label1 Siehe auch: http://www.cs.virginia.edu/ evans/cs216/guides/x86.html Musterlösung KMS SoSe 2014 Präsenzübung 1 5/5