Γλώσσα μηχανής

Στον προγραμματισμό υπολογιστών, ως κώδικας μηχανής θεωρούμε οποιαδήποτε γλώσσα προγραμματισμού χαμηλού επιπέδου, που αποτελείται από οδηγίες γλώσσας μηχανής, οι οποίες χρησιμοποιούνται για τον έλεγχο της κεντρικής μονάδας επεξεργασίας ενός υπολογιστή (CPU). Κάθε εντολή αναγκάζει τη CPU να εκτελέσει μια πολύ συγκεκριμένη εργασία, όπως μια λειτουργία φόρτωσης, αποθήκευσης, άλματος ή μία λειτουργία αριθμητικής λογικής μονάδας (ALU) σε μία ή περισσότερες μονάδες δεδομένων στους καταχωρητές ή στη μνήμη της CPU.

Ο κώδικας μηχανής είναι μια αυστηρά αριθμητική γλώσσα που έχει σχεδιαστεί για να εκτελείται όσο το δυνατόν γρηγορότερα και μπορεί να θεωρηθεί ως η αναπαράσταση του χαμηλότερου επιπέδου ενός μεταγλωττισμένου ή συναρμολογημένου προγράμματος υπολογιστή ή ως μια πρωτόγονη και εξαρτώμενη από το υλικό, γλώσσα προγραμματισμού. Ενώ είναι δυνατό να γραφτούν προγράμματα απευθείας σε κώδικα μηχανής, η διαχείριση μεμονωμένων bit και ο  υπολογισμός αριθμητικών διευθύνσεων και σταθερών χειροκίνητα είναι κουραστικά και επιρρεπή σε σφάλματα. Για αυτόν τον λόγο, τα προγράμματα πολύ σπάνια γράφονται απευθείας σε κώδικα μηχανής σε σύγχρονες συνθήκες, αλλά μπορεί να χρησιμοποιηθούν για τον εντοπισμό σφαλμάτων χαμηλού επιπέδου, την επιδιόρθωση προγραμμάτων (ειδικά όταν η πηγή συναρμολογητή δεν είναι διαθέσιμη) και την αποσυναρμολόγηση γλώσσας συναρμολόγησης .

Η πλειονότητα των πρακτικών προγραμμάτων σήμερα είναι γραμμένα σε γλώσσες υψηλότερου επιπέδου ή σε γλώσσα συναρμολόγησης. Στην συνέχεια, ο πηγαίος κώδικας μεταφράζεται  σε εκτελέσιμο κώδικα μηχανής από βοηθητικά προγράμματα όπως μεταγλωττιστές, συναρμολογητές και συνδέτες, με σημαντική εξαίρεση τα ερμηνευμένα προγράμματα,  που δεν μεταφράζονται σε κώδικα μηχανής. Ωστόσο, ο ίδιος ο διερμηνέας, που μπορεί να θεωρηθεί και ως εκτελεστής ή επεξεργαστής των οδηγιών του πηγαίου κώδικα, συνήθως αποτελείται από απευθείας εκτελέσιμο κώδικα μηχανής (που δημιουργείται από τη συναρμολόγηση ή τον πηγαίο κώδικα γλώσσας υψηλού επιπέδου).

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

Σύνολο οδηγιών 
Κάθε επεξεργαστής ή οικογένεια επεξεργαστών έχει το δικό του σύνολο εντολών . Οι οδηγίες είναι μοτίβα από bits, ψηφίων ή χαρακτήρων που αντιστοιχούν σε εντολές μηχανής. Έτσι, το σύνολο εντολών είναι συγκεκριμένο για μια κατηγορία επεξεργαστών που χρησιμοποιούν (κυρίως) την ίδια αρχιτεκτονική. Τα σχέδια διαδοχικών ή παραγώγων επεξεργαστών συχνά περιλαμβάνουν οδηγίες ενός προκατόχου και μπορεί να προσθέσουν νέες πρόσθετες οδηγίες. Περιστασιακά, ένας διάδοχος σχεδιασμός θα διακόψει ή θα αλλάξει τη σημασία κάποιου κώδικα εντολών (συνήθως επειδή απαιτείται για νέους σκοπούς), επηρεάζοντας σε κάποιο βαθμό τη συμβατότητα του κώδικα. Ακόμη και οι συμβατοί επεξεργαστές ενδέχεται να παρουσιάσουν ελαφρώς διαφορετική συμπεριφορά για ορισμένες οδηγίες, αλλά αυτό είναι σπάνια πρόβλημα. Τα συστήματα μπορεί επίσης να διαφέρουν σε άλλες λεπτομέρειες, όπως διάταξη μνήμης, λειτουργικά συστήματα ή περιφερειακές συσκευές . Επειδή ένα πρόγραμμα βασίζεται συνήθως σε τέτοιους παράγοντες, διαφορετικά συστήματα συνήθως δεν εκτελούν τον ίδιο κώδικα μηχανής, ακόμη και όταν χρησιμοποιείται ο ίδιος τύπος επεξεργαστή.

Το σύνολο εντολών ενός επεξεργαστή μπορεί να έχει όλες τις εντολές του ίδιου μήκους ή μπορεί να έχει εντολές μεταβλητού μήκους. Ο τρόπος οργάνωσης των μοτίβων ποικίλλει ανάλογα με τη συγκεκριμένη αρχιτεκτονική και τον τύπο της οδηγίας. Οι περισσότερες εντολές έχουν ένα ή περισσότερα πεδία opcode που καθορίζουν τον βασικό τύπο οδηγίας (όπως αριθμητική, λογική, άλμα κ.λπ.), τη λειτουργία (όπως προσθήκη ή σύγκριση) και άλλα πεδία που μπορεί να δίνουν τον τύπο του τελεστή (ων), ο τρόπος διευθυνσιοδότησης (οι), η μετατόπιση (εων) ή ο δείκτης διευθυνσιοδότησης ή η ίδια η τιμή του τελεστή (τέτοιοι σταθεροί τελεστές που περιέχονται σε μια οδηγία ονομάζονται άμεσοι ).   

Σαφείς τελεστές δεν υπάρχουν σε όλα τα μηχανήματα και σε όλες τις μεμονωμένες οδηγίες. Ένα μηχάνημα συσσωρευτή έχει συνδυασμένα ένα αριστερό τελεστή και ένα αποτέλεσμα σε έναν εγγενής συσσωρευτή για τις περισσότερες αριθμητικές εντολές. Άλλες αρχιτεκτονικές (όπως το 8086 και το x86-family) έχουν εκδόσεις συσσωρευτή με κοινές εντολές, όπου ως συσσωρευτής  θεωρείται ένας από τους γενικούς καταχωρητές από μεγαλύτερες εντολές. Μια μηχανή στοίβας έχει τους περισσότερους ή ακόμα και όλους τους τελεστές της σε μια άρρητη στοίβα. Οι οδηγίες ειδικού σκοπού επίσης συχνά στερούνται ρητούς τελεστές (για παράδειγμα, το CPUID στην αρχιτεκτονική x86 εγγράφει τιμές σε τέσσερις άρρητους καταχωρητές προορισμού). Αυτή η διάκριση μεταξύ ρητών και άρρητων τελεστών είναι σημαντική στις γεννήτριες κώδικα, ειδικά όσον αφορά την κατανομή καταχωρητών. Ένας καλός βελτιστοποιητής κώδικα μπορεί να παρακολουθεί ρητούς και άρρητους τελεστές που μπορεί να επιτρέπουν συχνότερη συνεχή διάδοση, συνεχές δίπλωμα καταχωρητών και άλλες βελτιώσεις κώδικα.

Προγράμματα 
Ένα πρόγραμμα υπολογιστή είναι μια λίστη απο οδηγίες που εκτελούνται από μια Κεντρική Μονάδα Επεξεργασίας (CPU). Η εκτέλεση ενός προγράμματος γίνεται με τον σκοπό η CPU που το εκτελεί να λύσει ένα πρόβλημα και να επιτύχει ένα αποτέλεσμα. Οι απλοι επεξεργαστές είναι ικανοί να εκτελέσουν οδηγίες τη μία μετά την άλλη, σε αντίθεση με τους υπερβαθμωτούς επεξεργαστές που είναι ικανοί να εκτελέσουν πολλές οδηγίες ταυτόχρονα.

Η ροή ενός προγράμματος μπορεί να επηρεαστεί από μία ιδιαίτερη οδηγία άλμα που μεταφέρει την εκτέλεση σε μια διεύθυνση (και συνεπώς σε μια οδηγία) σε μια που δεν είναι αριθμητικά η επόμενη.

Συμβολικές γλώσσες (Assembly) 
Μια πολύ πιο φιλική προς τον άνθρωπο εκδοχή της γλώσσας μηχανής, λεγόμενη ως γλώσσα συναρμολόγησης, χρησιμοποιεί μνημονικούς κώδικες για να αναφέρεται σε οδηγίες κώδικα μηχανής, αντί να χρησιμοποιεί απευθείας τις αριθμητικές τιμές των εντολών και χρησιμοποιεί συμβολικά ονόματα για να αναφερθεί σε τοποθεσίες αποθήκευσης και μερικές φορές σε καταχωρητές . Για παράδειγμα, στον επεξεργαστή Zilog Z80, ο κωδικός μηχανής 00000101, ο οποίος προκαλεί τη μείωση του καταχωρητή επεξεργαστή B από την CPU, θα είχε αντιπροσωπευτεί στη γλώσσα συναρμολόγησης ως DEC B

Παράδειγμα 
Η αρχιτεκτονική MIPS παρέχει ένα συγκεκριμένο παράδειγμα για έναν κώδικα μηχανής του οποίου οι οδηγίες έχουν πάντα μήκος 32 bit. Ο γενικός τύπος εντολής δίνεται από το πεδίο op (λειτουργία/operation), τα υψηλότερα 6 bit. Οι οδηγίες τύπου J (άλμα/jump) και τύπου Ι (άμεσες/immediate) καθορίζονται πλήρως από το op . Οι οδηγίες τύπου R (καταχώριση/register) περιλαμβάνουν μια πρόσθετη funct (συναρτηση) πεδίου για τον προσδιορισμό της ακριβούς λειτουργίας. Τα πεδία που χρησιμοποιούνται σε αυτούς τους τύπους είναι:
    6      5     5     5     5      6 bits
 [  op  |  rs |  rt |  rd |shamt| funct]  R-type
 [  op  |  rs |  rt | address/immediate]  I-type
 [  op  |        target address        ]  J-type
Τα rs, rt και rd υποδεικνύουν τελεστές καταχωρητή. Το shamt δίνει ένα ποσό μετατόπισης ενώ η διεύθυνση ή άμεσα πεδια περιέχουν έναν τελεστή ευθέως.

Για παράδειγμα, η προσθήκη των καταχωρητών 1 και 2 και η τοποθέτηση του αποτελέσματος στον καταχωρητή 6 κωδικοποιείται ως:
 [  op  |  rs |  rt |  rd |shamt| funct]
     0     1     2     6     0     32     decimal
  000000 00001 00010 00110 00000 100000   binary
Φορτώνοντας μια τιμή στον καταχωρητή 8, που λαμβάνεται από το κελί μνήμης που βρίσκεται 68 κελία μετά την θέση που αναγράφεται στον καταχωρήτη 3:
 [  op  |  rs |  rt | address/immediate]
    35     3     8           68           decimal
  100011 00011 01000 00000 00001 000100   binary
Μετάβαση στη διεύθυνση 1024:
 [  op  |        target address        ]
     2                 1024               decimal
  000010 00000 00000 00000 10000 000000   binary

Επικαλυπτόμενες οδηγίες 
Σε αρχιτεκτονικές επεξεργαστών με σύνολα εντολών μεταβλητού μήκους  (όπως η οικογένεια επεξεργαστών x86 της Intel ) είναι μερικές φορές δυνατό μέσω προγραμματισμού σε επίπεδο opcode (κώδικας λειτουργίας) να διευθετηθεί σκόπιμα ο συνεπαγόμενος κώδικας έτσι ώστε δύο διαδρομές κώδικα να μοιράζονται ένα κοινό θραύσμα αλληλουχιών opcode. Αυτά ονομάζονται επικαλυπτόμενες εντολές, επικαλυπτόμενοι κωδικοί επιλογής, επικαλυπτόμενος κώδικας, επικαλυπτόμενος κώδικας, κοπή εντολών ή άλμα στη μέση μιας εντολής και αντιπροσωπεύουν μια μορφή υπέρθεσης. Σημειώνεται ότι αυτά ισχύουν εντός των ορίων του φαινομένου επανασυγχρονισμού ροής ελέγχου, γνωστό ως Κρουσκάλ Count.     

Στις δεκαετίες του 1970 και του 1980, οι αλληλοκαλυπτόμενες οδηγίες μερικές φορές χρησιμοποιούνταν για να διατηρηθεί χώρος στη μνήμη. Ένα παράδειγμα ήταν η υλοποίηση πινάκων σφαλμάτων στο Altair BASIC της Microsoft, όπου οι παρεμβαλλόμενες εντολές μοιράζονταν αμοιβαία τα byte εντολών τους.   Η τεχνική χρησιμοποιείται σπάνια σήμερα, αλλά εξακολουθεί να είναι απαραίτητη σε περιπτώσεις όπου απαιτείται ακραία βελτιστοποίηση  μεγέθους σε επίπεδο byte, όπως στην εφαρμογή φορτωτών εκκίνησης που πρέπει να ταιριάζουν σε τομείς εκκίνησης .

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

Η αρχή χρησιμοποιείται επίσης σε κοινές ακολουθίες κώδικα δυαδικών πολυαρχιτεκτονικών προγραμμάτων (fat binary), οι οποίες πρέπει να εκτελούνται σε πολλαπλές πλατφόρμες επεξεργαστών που δεν είναι συμβατές με σύνολο εντολών.

Αυτή η ιδιότητα χρησιμοποιείται επίσης για την εύρεση ακούσιων οδηγιών που ονομάζονται gadget σε υπάρχοντα αποθετήρια κώδικα και χρησιμοποιείται σε προγραμματισμό προσανατολισμένο στην επιστροφή (return-oriented programming) ως εναλλακτική λύση στην ένεση κώδικα για εκμεταλλεύσεις ευπάθειας όπως επιθέσεις return-to-libc .

Σχέση με μικροκώδικα 
Σε ορισμένες αρχιτεκτονικές υπολογιστών, ο κώδικας μηχανής υλοποιείται από ένα ακόμη πιο θεμελιώδες υποκείμενο στρώμα, λεγόμενος μικροκώδικας. Με τον χρήση του μικροκωδικα παρέχεται μια κοινή διεπαφή γλώσσας μηχανής σε μια γραμμή ή σε μια οικογένεια διαφορετικών μοντέλων ενός υπολογιστή με πολύ διαφορετικές υποκείμενες ροές δεδομένων . Αυτό γίνεται για την διευκόλυνση της μεταφοράς (porting) προγραμμάτων γλώσσας μηχανής μεταξύ διαφορετικών μοντέλων. Ένα παράδειγμα αυτής της χρήσης είναι η οικογένεια υπολογιστών IBM System/360 και οι διάδοχοί τους. Με διαδρομή ροής δεδομένων πλάτους 8 bits μέχρι 64 bits και πέρα, παρουσιάζουν μια κοινή αρχιτεκτονική σε επίπεδο γλώσσας μηχανής κατά μήκος μιας ολόκληρης γραμμή.

Η χρήση μικροκώδικα για την υλοποίηση ενός εξομοιωτή επιτρέπει στον υπολογιστή να παρουσιάσει την αρχιτεκτονική ενός εντελώς διαφορετικού υπολογιστή. Η γραμμή System/360 το χρησιμοποιούσε για να επιτρέπει τη μεταφορά προγραμμάτων από προηγούμενες μηχανές IBM στη νέα οικογένεια υπολογιστών, π.χ. έναν εξομοιωτή IBM 1401/1440/1460 στο IBM S/360 μοντέλο 40.

Σχέση με bytecode 
Ο κώδικας μηχανής είναι γενικά διαφορετικός από τον κώδικα μπάιτ (bycode ή και p-code), ο οποίος είτε εκτελείται από έναν διερμηνέα είτε ο ίδιος μεταγλωττίζεται σε κώδικα μηχανής για ταχύτερη εκτέλεση. Μια εξαίρεση είναι όταν ένας επεξεργαστής έχει σχεδιαστεί για να χρησιμοποιεί έναν συγκεκριμένο bytecode απευθείας ως κώδικα μηχανής του, όπως συμβαίνει με τους επεξεργαστές Java .

Ο κώδικας μηχανής και ο κώδικας συναρμολόγησης ονομάζονται μερικές φορές εγγενής κώδικας όταν αναφέρονται σε τμήματα γλωσσικών χαρακτηριστικών ή βιβλιοθηκών που εξαρτώνται από την πλατφόρμα.

Αποθήκευση στη μνήμη 
Η αρχιτεκτονική του Χάρβαρντ είναι μια αρχιτεκτονική υπολογιστή με φυσικά χωριστές διαδρομές αποθήκευσης και σήματος για τον κώδικα (οδηγίες) και τα δεδομένα . Σήμερα, οι περισσότεροι επεξεργαστές εφαρμόζουν τέτοιες ξεχωριστές διαδρομές σήματος για λόγους απόδοσης, αλλά εφαρμόζουν μια τροποποιημένη αρχιτεκτονική του Χάρβαρντ ,  ώστε να μπορούν να υποστηρίξουν εργασίες όπως η φόρτωση ενός εκτελέσιμου προγράμματος από την αποθήκευση του δίσκου ως δεδομένα και στη συνέχεια την εκτέλεσή του. Η αρχιτεκτονική του Χάρβαρντ έρχεται σε αντίθεση με την αρχιτεκτονική Von Neumann, όπου τα δεδομένα και ο κώδικας αποθηκεύονται στην ίδια μνήμη που διαβάζεται από τον επεξεργαστή επιτρέποντας στον υπολογιστή να εκτελεί εντολές.

Από την άποψη μιας διεργασίας, ο χώρος κώδικα είναι το μέρος του χώρου διευθύνσεών της όπου αποθηκεύεται ο κώδικας που εκτελείται. Στα συστήματα πολλαπλών εργασιών, αυτό περιλαμβάνει το τμήμα κώδικα του προγράμματος και συνήθως κοινόχρηστες βιβλιοθήκες . Σε περιβάλλον πολλαπλών νημάτων(multi-threading), διαφορετικά νήματα μιας διεργασίας μοιράζονται χώρο κώδικα μαζί με χώρο δεδομένων, γεγονός που μειώνει σημαντικά την επιβάρυνση της εναλλαγής περιβάλλοντος σε σύγκριση με την εναλλαγή διεργασίας.

Αναγνωσιμότητα από τον άνθρωπο 
Η Pamela Samuelson έγραψε ότι ο κώδικας μηχανής είναι τόσο δυσανάγνωστος που το Γραφείο Πνευματικών Δικαιωμάτων των Ηνωμένων Πολιτειών της Αμερικης δεν μπορεί να προσδιορίσει εάν ένα συγκεκριμένο κωδικοποιημένο πρόγραμμα είναι πρωτότυπο έργο συγγραφής.  Ωστόσο, επιτρέπει την καταχώριση πνευματικών δικαιωμάτων προγραμμάτων υπολογιστών   και ο κώδικας μηχανής ενός προγράμματος μπορεί μερικές φορές να απομεταγλωττιστεί προκειμένου να γίνει η λειτουργία του πιο κατανοητή από τον άνθρωπο.  Ωστόσο, από την έξοδο ενός απομεταγλωττιστή ή αποσυναρμολογητή θα λείπουν τα σχόλια και οι συμβολικές αναφορές, επομένως, ενώ η έξοδος μπορεί να είναι πιο ευανάγνωστη από τον κώδικα του αντικειμένου, θα εξακολουθεί να είναι πιο δύσκολη από τον αρχικό πηγαίο κώδικα. Αυτό το πρόβλημα δεν υπάρχει για μορφές αντικειμενικού κώδικα όπως το SQUOZE, όπου ο πηγαίος κώδικας περιλαμβάνεται στο αρχείο.

Ο καθηγητής γνωστικών επιστημών Douglas Hofstadter συνέκρινε τον κώδικα μηχανής με τον γενετικό κώδικα, λέγοντας ότι «η εξέταση ενός προγράμματος γραμμένου σε γλώσσα μηχανής είναι αόριστα συγκρίσιμη με την εξέταση ενός μορίου DNA, άτομο προς άτομο».

Δείτε επίσης 

 Συμβολική γλώσσα
 Ενδιανότητα
 Υπολογισμός μειωμένου συνόλου εντολών (RISC)

Bιβλιογραφικές αναφορές