Διαδρομές
/
Lean
Lean
/
Ασκήσεις
/
Συναρμολόγηση
Συναρμολόγηση

Συναρμολόγηση

Δύσκολο

Οδηγίες

Σε αυτή την άσκηση, θα ορίσεις τη σύνταξη και το μοντέλο εκτέλεσης μιας μικρής γλώσσας εμπνευσμένης από τη γλώσσα assembly x86-64.

Στόχος είναι να επισημοποιήσεις τον τρόπο με τον οποίο ο κώδικας γράφεται, αναλύεται και εκτελείται μέσα σε ένα περιορισμένο περιβάλλον.

Μοντέλο εκτέλεσης

Ο κώδικας assembly σου θα γράφεται μέσα σε ένα ειδικό κατασκεύασμα:

let program := assemble!(
    -- assembly code here
)

Αυτό το κατασκεύασμα πρέπει να παράγει ένα πρόγραμμα, το οποίο προσομοιώνει μια συνάρτηση που εκτελεί τον κώδικα assembly και επιστρέφει μια τιμή. Στη συνέχεια, αυτό το πρόγραμμα καλείται με την ακόλουθη σύνταξη, όπου τα a, b, c, κ.λπ. είναι ορίσματα:

let result := program(a, b, c, ...)

Όλα τα ορίσματα και η τιμή επιστροφής είναι 64-bit προσημασμένοι ακέραιοι. Επιτρέπονται το πολύ 6 ορίσματα.

Καταχωρητές

Η τιμή επιστροφής και όλα τα ορίσματα περνούν μέσα από καταχωρητές. Η γλώσσα σου πρέπει να υποστηρίζει τους ακόλουθους καταχωρητές:

καταχωρητής ρόλος
rdi 1ο όρισμα
rsi 2ο όρισμα
rdx 3ο όρισμα
rcx 4ο όρισμα
r8 5ο όρισμα
r9 6ο όρισμα
rax τιμή επιστροφής

Οι καταχωρητές ξεκινούν με προεπιλεγμένη τιμή 0, εκτός αν χρησιμοποιούνται για να περάσουν ορίσματα στη συνάρτηση.

Για παράδειγμα, στο παρακάτω πρόγραμμα, όλοι οι καταχωρητές έχουν τιμή 0 με εξαίρεση τον rdi, ο οποίος αρχικοποιείται με 10, και τον rsi, ο οποίος αρχικοποιείται με -20:

program(10, -20)

Η τιμή επιστροφής του προγράμματος αποθηκεύεται πάντα στον rax.

Note

Τα ονόματα των καταχωρητών δεν έχουν διάκριση πεζών-κεφαλαίων. Αυτό σημαίνει ότι τα rax, RAX και rAx αναφέρονται όλα στον ίδιο καταχωρητή.

Κώδικας assembly

Κάθε γραμμή στον κώδικα assembly μπορεί να έχει μία από δύο μορφές:

  • Ετικέτες σημαδεύουν συγκεκριμένα σημεία του προγράμματος που θα χρησιμοποιηθούν από κάποιες εντολές.
  • Εντολές αντιπροσωπεύουν πράξεις που εκτελεί το πρόγραμμα.

Εκτός αν τροποποιηθεί από κάποια εντολή, η ροή εκτέλεσης του προγράμματος προχωρά γραμμικά. Αυτό σημαίνει ότι μια προηγούμενη γραμμή εκτελείται πλήρως πριν εκτελεστεί η επόμενη.

Ετικέτες

Οι ετικέτες έχουν την ακόλουθη σύνταξη:

<label>:

Δεν αλλάζουν την τιμή κανενός καταχωρητή ούτε έχουν καμία άλλη επίδραση στο πρόγραμμα πέρα από το να σημαδεύουν συγκεκριμένα σημεία του κώδικα, ώστε να μπορούν να χρησιμοποιηθούν από εντολές.

Note

Οι ετικέτες έχουν διάκριση πεζών-κεφαλαίων. Αυτό σημαίνει ότι τα Start, start και sTart είναι όλα διαφορετικές ετικέτες.

Εντολές δύο τελεστέων

Οι περισσότερες εντολές έχουν την ακόλουθη σύνταξη:

<opcode> <destination>, <source>

Το opcode δηλώνει την πράξη που εκτελείται, χρησιμοποιώντας τις τιμές των τελεστέων destination και source. Το αποτέλεσμα της πράξης αποθηκεύεται στον τελεστέο destination.

Για παράδειγμα, η εντολή add αθροίζει τις τιμές των τελεστέων destination και source και αποθηκεύει αυτό το αποτέλεσμα στον τελεστέο destination.

Ο τελεστέος destination είναι πάντα ένας καταχωρητής, ενώ ο τελεστέος source μπορεί να είναι ένας καταχωρητής ή ένας αριθμητικός λεκτικός.

Αυτή είναι μια λίστα με τις εντολές που πρέπει να υποστηρίζει το πρόγραμμά σου:

opcode πράξη που εκτελείται
mov destination := source
add destination := destination + source
sub destination := destination - source
mul destination := destination * source
div destination := destination / source
xor destination := destination ^^^ source
and destination := destination &&& source
or destination := destination ||| source
shl destination := destination <<< source
shr destination := destination >>> source

Εκτός από αυτές, το πρόγραμμά σου πρέπει να υποστηρίζει την εντολή cmp με δύο τελεστέους.

Αυτή η εντολή δεν τροποποιεί κανέναν καταχωρητή, αλλά αντ' αυτού συγκρίνει τους τελεστέους destination και source και θέτει μια εσωτερική κατάσταση του προγράμματος σε μία από τρεις επιλογές:

  • μεγαλύτερο από, αν destination > source
  • ίσο, αν destination == source
  • μικρότερο από, αν destination < source

Το πώς παρακολουθείς εσωτερικά αυτή την κατάσταση είναι δική σου επιλογή.

Εντολές ενός τελεστέου

Υπάρχουν κάποιες εντολές που αλλάζουν τη ροή του προγράμματος, μεταφέροντας την εκτέλεση σε άλλο σημείο του κώδικα. Ονομάζονται εντολές άλματος.

Όλες δέχονται μόνο έναν τελεστέο, ο οποίος είναι μια ετικέτα που δηλώνει τον προορισμό του άλματος, δηλαδή το σημείο του κώδικα από όπου θα συνεχιστεί η εκτέλεση:

<opcode> <label>

Η εντολή jmp κάνει πάντα το άλμα στην ετικέτα-στόχο.

Οι υπόλοιπες εντολές άλματος κάνουν το άλμα μόνο αν η εσωτερική κατάσταση του προγράμματος έχει μια συγκεκριμένη τιμή. Αυτό σημαίνει ότι συνήθως προηγείται μια εντολή cmp.

Αυτές είναι οι εντολές άλματος που πρέπει να υποστηρίζει το πρόγραμμά σου:

εντολή πράξη που εκτελείται
jmp άλμα χωρίς συνθήκη. Το άλμα γίνεται πάντα
je κάνει άλμα αν η εσωτερική κατάσταση είναι ίση
jl κάνει άλμα αν η εσωτερική κατάσταση είναι μικρότερη από
jg κάνει άλμα αν η εσωτερική κατάσταση είναι μεγαλύτερη από
Note

Οι κωδικοί των εντολών, είτε είναι δύο τελεστέων είτε ενός τελεστέου, δεν έχουν διάκριση πεζών-κεφαλαίων. Αυτό σημαίνει ότι τα add, ADD και aDd αναφέρονται όλα στην ίδια εντολή.

Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Lean Exercism

Έτοιμος να ξεκινήσεις την άσκηση Συναρμολόγηση;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Lean με 100 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.