ΠΑΝΕΠΙΣΤΗΜΙΟ ΙΩΑΝΝΙΝΩΝ ΑΝΟΙΚΤΑ ΑΚΑΔΗΜΑΪΚΑ ΜΑΘΗΜΑΤΑ Αρχιτεκτονική Υπολογιστών Αρχιτεκτονικό σύνολο εντολών Διδάσκων: Επίκουρος Καθηγητής Αριστείδης Ευθυμίου
Άδειες Χρήσης Το παρόν εκπαιδευτικό υλικό υπόκειται σε άδειες χρήσης Creative Commons. Για εκπαιδευτικό υλικό, όπως εικόνες, που υπόκειται σε άλλου τύπου άδειας χρήσης, η άδεια χρήσης αναφέρεται ρητώς.
ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών Υπορουτίνες στον MIPS Αρης Ευθυμίου
Το σημερινό μάθημα!!!!! Υπορουτίνες σε γλώσσα assembly Εντολές jal, jr Σύμβαση για χρήση καταχωρητών Στοίβα προγράμματος/μηχανής Χάρτης μνήμης 2
Υπορουτίνες! Αφαίρεση στον προγραμματισμό: διαίρεση της δουλειάς σε διαχειρίσιμα κομμάτια! Διαφορετικά ονόματα ανάλογα με τη γλώσσα προγραμματισμού συναρτήση, μέθοδος, υπορουτίνα, διαδικασία,...! Κοινά χαρακτηριστικά: τιμές εισόδου (παράμετροι) τιμές εξόδου τοπικός (local) χώρος αποθήκευσης δεδομένων! «εξαφανίζεται» μετά το τέλος της υπορουτίνας 3
6 βήματα κλήσης υπορουτίνας 1. Βάλε εισόδους κάπου ώστε να τις βρεί η υπορουτίνα 2. Μεταφορά ελέγχου στην υπορουτίνα για εκτέλεση 3. Πάρε τους αποθηκευτικούς πόρους που χρειάζεται η υπορουτίνα 4. Κάνε τη δουλειά! 5. Βάλε το αποτέλεσμα κάπου ώστε αυτός που κάλεσε την υπορουτίνα να το βρεί 6. Επέστρεψε τον έλεγχο σε αυτόν που κάλεσε την υπορουτίνα 4
Καταχωρητές για υπορουτίνες! Επειδή η πιο γρήγορη «μνήμη» είναι οι καταχωρητές, χρησιμοποιούνται για κληση υπορουτίνων! $a0 $a3: τέσσερεις καταχωρητές εισόδου πέρασμα παραμέτρων εισόδου! $v0 $v1: δύο καταχωρητές αποτελεσμάτων επιστροφή τιμών (εξόδου)! $ra: ένας καταχωρητής επιστροφής διεύθυνση επιστροφής! και βέβαια διάφοροι καταχωρητές για τοπική αποθήκευση θα χρειαστεί και μνήμη... 5
Παράδειγμα κλήσης υπορουτ. Εστω subroulne(x, y): return x+y add $a0, $s0, $zero # x = a add $a1, $s1, $zero # y = b li $ra, return j subroutine #goto to subroutine return: # next instruction subroutine: add $v0, $a0, $a1 jr $ra # new instruction 6
Νέα εντολή jal! Αντί για 2-3 εντολές: li $ra, return j subroutine #goto to subroutine! Νέα εντολή: jump and link jal subroutine Αποθηκεύει την διεύθυνση της επόμενης εντολής στον ra! PC+4 Εκτελεί άλμα στην υπορουτίνα! PC = διεύθυνση της subroulne! Πλεονεκτήμα: εύκολη μεταφορά jal σε άλλη διεύθυνση 7
Ορολογία! Η υπορουτίνα που καλεί μια άλλη υπορουτίνα ονομάζεται καλούσα (caller) σε αυτή θα επιστρέψει ο έλεγχος με την εντολή jr $ra! Η υπορουτίνα που καλείται ονομάζεται καλούμενη (callee) αυτή είναι που καλείται με την jal 8
Αποθήκευση για υπορουτίνες! Πολλαπλά επίπεδα κλήσεων υπορουτινών υπορουτίνα Α καλεί υπορουτίνα Β, καλεί υπορουτίνα Γ,...! Η τιμή του $ra χάνεται με τη 2η κλήση! πρέπει να αποθηκευτεί κάπου! Παρόμοια οι καταχωρητές επαναχρησιμοποιούνται π.χ. οι $a0 $a3! Πρέπει οι τιμές καταχωρητών να αποθηκευτούν στη μνήμη αν πρόκειται να επαναγραφούν ονομαζεται register spilling 9
Στοίβα (stack)! Ονομάζεται και ουρά: «τελευταίος μέσα, πρώτος έξω» last- in, first- out (LIFO queue)! Ιδανική δομή δεδομένων για register spilling χρειάζεται μόνο ένας δείκτης στην τελευταία δεσμευμένη θέση στην επόμενη θα γραφτεί η τιμή του επόμενου καταχωρητή που γίνεται spill! Η συνάρτηση που κλήθηκε τελευταία, επιστρέφει πρώτα άρα μπορεί εύκολα να ξαναδιαβάσει από τη στοίβα τα δεδομένα που μόλις έγραψε! Τοποθέτηση/Εγγραφή ονομάζεται push αλλάζει το δείκτη να δείχνει στην επόμενη θέση, γράφει μία λέξη! Απομάκρυνση/Ανάγνωση ονομάζεται pop 10
Στοίβα! Στον MIPS ο καταχωρητής 29 είναι ο δείκτης στοίβας stack pointer, $sp! Η στοίβα «μεγαλώνει» από μεγάλες προς μικρές διευθύνσεις! push: (πολύπλοκο για να γίνει σε 1 εντολή) addi $sp, $sp, - 4 sw reg, 0($sp)! pop: lw reg, 0($sp) # δεν είναι πάντα απαραίτητο addi $sp, $sp, 4 11
Παράδειγμα:! Τερματική (?) υπορουτίνα δεν καλεί άλλες υπορουτίνες leaf subroulne! Απλοϊκή υλοποίηση μπορεί να γίνει πολύ καλύτερα int leaf_example (int g, int h, int i, int j) { int f; f = (g + h) (i + j); return f; } 12
f = (g + h) (i + j);! Είσοδοι στους καταχωρητές $a0 - $a3! Προσωρινοί καταχωρητές: $t0, $t1! Μεταβλητή f στον $s0 add $t0,$a0,$a1 # t0 = g + h add $t1,$a2,$a3 # t1 = i + j sub $s0,$t0,$t1 # s0 = (g + h) (i + j) add $v0,$s0,$zero # return value in v0 Χρησιμοποιήσαμε 3 καταχωρητές: t0, t1, s0 Πρέπει να αποθηκεύσουμε τις προηγούμενες τιμές και να τις επαναφέρουμε όταν τελειώσουμε 13
Leaf subroulne addi $sp, $sp, 12 # make room for 3 in stack sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) add $t0,$a0,$a1 # t0 = g + h add $t1,$a2,$a3 # t1 = i + j sub $s0,$t0,$t1 # s0 = (g + h) (i + j) add $v0,$s0,$zero # return value in v0 lw $s0, 0($sp) # restore register $s0 lw $t0, 4($sp) lw $t1, 8($sp) addi $sp,$sp,12 # adjust stack to delete 3 items jr $ra 14
Leaf subroulne addi $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) add $t0,$a0,$a1 add $t1,$a2,$a3 sub $s0,$t0,$t1 add $v0,$s0,$zero lw $s0, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) addi $sp,$sp,12 jr $ra high address $sp Contents of $t1 Contents of $t0 $sp Contents of $s0 Low address 15
Leaf subroulne addi $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) add $t0,$a0,$a1 add $t1,$a2,$a3 sub $s0,$t0,$t1 add $v0,$s0,$zero lw $s0, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) addi $sp,$sp,12 jr $ra high address $sp Contents of $t1 Contents of $t0 $sp Contents of $s0 Low address 16
Μείωση register spilling! Χρειάζονται αρκετές εντολές για αποθήκευση και μετά επανάκτηση τιμών καταχωρητών! Για να μειώθει, το λογισμικό στον MIPS ακολουθεί τη σύμβαση: οι καταχωρητές $t0- $t9 δεν χρειάζεται να «προστατευθούν»! η καλούμενη υπορουτίνα (callee) μπορεί να τους χρησιμοποιήσει/ αλλάξει! αν η καλούσα υπορουτίνα (caller) χρειάζεται τις τιμές τους θα πρέπει να τους αποθηκεύσει στη στοίβα, πριν την κλήση και να τις ανακτήσει μετά την επιστροφή οι καταχωρητές $s0- $s7 πρέπει να «προστατευθούν»! αν η καλούμενη τους χρειάζεται, πρέπει να τους «σώσει» (save) και ανακτήσει (restore) 17
non- leaf υπορουτίνες! Οι περισσότερες υπορουτίνες δεν είναι leaf καλούν άλλες μπορούν να καλέσουν και τον εαυτό τους!! αναδρομικές (recursive) υπορουτίνες! Επιπλέον από ότι κάνουν οι leaf «προστασία» των $s0- $s7, s saved! Πρέπει να αποθηκεύσουν στη στοίβα τον $ra και εκτός από τους $s0- $s7, όλους τους καταχωρητές που χρειάζονται (π.χ. $a0- $a3) 18
Παράδειγμα: παραγοντικό int fact (int n) if (n < 1) return (1); else return (n * fact(n 1))! Δεν είναι leaf γιατί καλεί άλλη υπορουτίνα τον εαυτό της αναδρομική! Αγγλικά: factorial! Θα χρησιμοποιήσω απαγορευμένη εντολή mul για να κάνω πιο απλό τον κώδικα μην την χρησιμοποιείτε στις ασκήσεις! 19
Factorial code fact: addi $sp, $sp, 8 # adjust stack for 2 items sw $ra, 4($sp) # save the return address sw $a0, 0($sp) # save the argument n slti $t0, $a0, 1 # test for n < 1 beq $t0, $zero,l1 # if n >= 1, go to L1 addi $v0, $zero, 1 # return 1 addi $sp, $sp, 8 # pop 2 items off stack jr $ra # return to caller L1: addi $a0, $a0, 1 # n >= 1: argument gets (n 1) jal fact # call fact with (n 1) lw $a0, 0($sp) # restore argument n lw $ra, 4($sp) # restore the return address addi $sp, $sp, 8 # adjust $sp to pop 2 items mul $v0,$a0, $v0 # return n * fact (n 1) jr $ra # return to the caller 20
Συμβάσεις για καταχωρητές! Ποιός από τους caller, callee είναι υπεύθυνος για κάθε είδος καταχωρητή;! Ποιών καταχωρητών οι τιμές διατηρούνται (preserved) μετά από κληση υπορουτίνας; Υπεύθυνος: caller Υπεύθυνος: callee 21
Hack: stack buffer overflow! Η στοίβα έχει μια τρύπα ασφάλειας η διεύθυνση επιστροφής της προηγούμενης υπορουτίνας είναι αποθηκευμένη στη στοίβα. Αν βρώ που είναι και γράψω στη θέση της μια «δική μου» διεύθυνση, μπορώ να τρέξω «δικό μου» κώδικα! Το μεγάλο κόλπο είναι να το κάνω αυτό μόνο δίνοντας κατάλληλα δεδομένα στο πρόγραμμα σαν προγραμματιστής είναι εύκολο... 22
Πόροι αποθήκευσης! Με τα προηγούμενα μια υπορουτίνα μπορεί να χρησιμοποιήσει αρκετούς καταχωρητές για αποθήκευση! Αν όμως χρειάζεται χώρο για περισσότερα δεδομένα; ή πίνακες, strings, κλπ.! Χρησιμοποιούμε τη στοίβα για επιπλέον αποθήκευση για λεγόμενες τοπικές μεταβλητές (locals) για την ακρίβεια για automalc locals! Ολος ο χώρος της στοίβας που χρησιμοποιείται για μία κλήση συνάρτησης ονομάζεται procedure frame ή aclvalon record 23
Procedure frame Συχνά ο frame pointer ($fp, $30) δείχνει στην αρχή 24
Πρόλογος, επίλογος υπορουτίνας! Πρόλογος (εξασφάλιση χώρου στη στοιβα, «σώσιμο» καταχωρητών) entry_label: addi $sp, $sp, - framesize # reserve stack space sw $ra, framesize- 4($sp) # save $ra # save other preserved regs, if used! Επίλογος («διαγραφή» χώρου στη στοιβα, αποκατάσταση καταχωρητών) # restore preserved regs, if used lw $ra, framesize- 4($sp) # restore $ra addi $sp, $sp, framesize jr $ra 25
Καθολικές (global) μεταβλητές! Σε πολλά προγράμματα υπάρχουν μεταβλητές «ορατές» από όλες τις υπορουτίνες Σχετικά λίγες. Δεν είναι καλή πρακτική! Πώς υλοποιείται αυτό; Αντιστοιχούν σε διευθύνσεις μνήμης γνωστές σε όλους που δεν αλλάζουν (stakc) Χρησιμοποιείται και για (μεγάλες) σταθερές προγραμμάτων! O MIPS ως τρόπο υπολογισμού διευθύνσεων έχει το καταχωρητής (base) + σταθερά (offset)! Καταχωρητής global pointer ($gp, $28) δείχνει στο μέσο του τμήματος stalc 26
Χάρτης μνήμης του MIPS Mars $sp: 7fff effc Mars Data Segment (.data) 1001 0000 Το αποθηκευμένο πρόγραμμα 27
Σωρός (heap) μνήμης! Εκτός από τοπικές (automalc locals) και καθολικές μεταβλητές (globals, stalc locals) τα προγράμματα μπορούν να «παίρνουν» τμήματα μνήμης δυναμικά dynamic memory allocalon! Στη java με το new! Αυτή η μνήμη διατίθεται από τον σωρό (heap): το τμήμα κάτω απο τη στοίβα και πάνω από το stalc data! Οι λεπτομέρειες διαχείρισης του σωρού εξαρτώνται από τη γλώσσα προγραμματισμού και γενικά χρειάζεται υποστήριξη από το Λειτουργικό Σύστημα 28
Ανακοινώσεις! 2η εργαστηριακή άσκηση Μόνο μία μέρα μένει! Δεν θα μπορώ να απαντάω σε όλες τις ερωτήσεις τις Παρασκευές! Στο piazza έχετε ελπίδες να απαντήσουν συμφοιτητές σας...! Η 3η εργαστηριακή άσκηση διαθέσιμη (βλ ecourse) παράδοση μέχρι την Παρασκευή 13/3 ώρα 23.00 29
Επόμενο μάθημα Πώς συνδέονται οι γλώσσες προγραμματισμού που ξέρουμε με την γλώσσα του υπολογιστή: Compiler Assembler Linker Loader 30
Τέλος Ενότητας
Χρηματοδότηση Το παρόν εκπαιδευτικό υλικό έχει αναπτυχθεί στα πλαίσια του εκπαιδευτικού έργου του διδάσκοντα. Το έργο «Ανοικτά Ακαδημαϊκά Μαθήματα στο Πανεπιστήμιο Ιωαννίνων» έχει χρηματοδοτήσει μόνο τη αναδιαμόρφωση του εκπαιδευτικού υλικού. Το έργο υλοποιείται στο πλαίσιο του Επιχειρησιακού Προγράμματος «Εκπαίδευση και Δια Βίου Μάθηση» και συγχρηματοδοτείται από την Ευρωπαϊκή Ένωση (Ευρωπαϊκό Κοινωνικό Ταμείο) και από εθνικούς πόρους.
Σημειώματα
Σημείωμα Ιστορικού Εκδόσεων Έργου Το παρόν έργο αποτελεί την έκδοση 1.0. Έχουν προηγηθεί οι κάτωθι εκδόσεις: Έκδοση 1.0 διαθέσιμη εδώ. http://ecourse.uoi.gr/course/view.php?id=1307.
Σημείωμα Αναφοράς Copyright Πανεπιστήμιο Ιωαννίνων, Διδάσκων: Επίκουρος Καθηγητής Αριστείδης Ευθυμίου. «Αρχιτεκτονική Υπολογιστών. Αρχιτεκτονικό σύνολο εντολών». Έκδοση: 1.0. Ιωάννινα 2014. Διαθέσιμο από τη δικτυακή διεύθυνση: http://ecourse.uoi.gr/course/view.php?id=1307.
Σημείωμα Αδειοδότησης Το παρόν υλικό διατίθεται με τους όρους της άδειας χρήσης Creative Commons Αναφορά Δημιουργού - Παρόμοια Διανομή, Διεθνής Έκδοση 4.0 [1] ή μεταγενέστερη. [1] https://creativecommons.org/licenses/by-sa/4.0/.