Κάθε bit ενός ακέραιου μπορεί να χρησιμοποιηθεί για να αποθηκεύσει μια δυαδική τιμή. Επειδή πολλές καταστάσεις περιλαμβάνουν δυαδική πληροφορία, όπως αληθής ή ψευδής, συμπερίληψη ή αποκλεισμό, ενεργό ή ανενεργό, η δυαδική αναπαράσταση ενός ακέραιου N bit παρέχει έναν συμπαγή τρόπο κωδικοποίησης της δυαδικής κατάστασης N στοιχείων. Αυτό κάνει την ικανότητα χειρισμού bit και byte απαραίτητη στη γλώσσα assembly. Το σύνολο εντολών x86-64 προσφέρει μεγάλη ποικιλία εντολών χειρισμού bit.
Αυτές οι εντολές λειτουργούν σε μεμονωμένα bit ενός τελεστέου.
Όλες δέχονται δύο τελεστέους, ο δεύτερος υποδεικνύει τη θέση του bit στο οποίο γίνεται η πράξη στον πρώτο τελεστέο. Όλες αντιγράφουν το επιλεγμένο bit στη σημαία μεταφοράς (CF).
| Όνομα | Περιγραφή |
|---|---|
bt |
αντιγράφει το bit στο CF χωρίς να τροποποιεί κανέναν τελεστέο |
bts |
αντιγράφει το bit στο CF και το θέτει στον τελεστέο προορισμού |
btr |
αντιγράφει το bit στο CF και το καθαρίζει στον τελεστέο προορισμού |
btc |
αντιγράφει το bit στο CF και το συμπληρώνει (το αντιστρέφει) στον τελεστέο προορισμού |
Οι πράξεις bit εκτελούνται σε όλα τα bit ενός τελεστέου.
Όλες έχουν μια εντολή με το ίδιο όνομα με την πράξη bit που εκτελείται:
| Όνομα | Περιγραφή |
|---|---|
and |
1 αν και τα δύο bit είναι 1 |
or |
1 αν τουλάχιστον ένα από τα bit είναι 1 |
xor |
1 αν τα bit διαφέρουν |
not |
1 αν το bit ήταν 0, 0 αν το bit ήταν 1 |
Οι περισσότερες δέχονται δύο τελεστέους, εκτελούν μια πράξη bit και στους δύο και αποθηκεύουν το αποτέλεσμα στον τελεστέο προορισμού.
Η εξαίρεση είναι η not, η οποία δέχεται μόνο έναν τελεστέο προορισμού.
Όταν ερμηνεύουμε το ένα και το μηδέν ως συμπερίληψη και αποκλεισμό αντίστοιχα, ένας ακέραιος ονομάζεται μάσκα bit (ή απλώς μάσκα).
Μια μάσκα bit "αποκλείει" στοιχεία, επειδή ένα μηδέν στο i-οστό bit αποκλείει το i-οστό στοιχείο, ενώ ένα ένα το συμπεριλαμβάνει.
Χρησιμοποιούμε επίσης συνήθως μια μάσκα bit για να συμπεριλάβουμε ορισμένα bit ενός ακέραιου και να αποκλείσουμε άλλα.
Για παράδειγμα, έστω A ένας ακέραιος του οποίου η δυαδική αναπαράσταση είναι:
| θέση | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| bit | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
Επίσης, έστω M ένας ακέραιος του οποίου η δυαδική αναπαράσταση είναι:
| θέση | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| bit | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
Και οι δύο είναι ακέραιοι 8 bit.
Σε αυτή την περίπτωση, μπορούμε να πούμε ότι ο M επιλέγει τα bit 0, 2 και 3 του A και αποκλείει τα υπόλοιπα.
Οι εντολές bit που συζητήσαμε νωρίτερα είναι χρήσιμες για τον χειρισμό ακεραίων με μάσκες. Για παράδειγμα:
A που δεν επιλέγονται από τον M, κάνε το bitwise AND: A AND M.A που επιλέγονται από τον M, κάνε το bitwise OR: A OR M.Η εντολή test κάνει ένα bitwise AND μεταξύ των δύο τελεστέων και θέτει τις σημαίες ανάλογα με το αποτέλεσμα.
Αν ο A είναι ο πρώτος τελεστέος και ο B ο δεύτερος:
| σημαία | τίθεται όταν |
|---|---|
CF |
καθαρίζεται πάντα |
ZF |
A AND B == 0 |
SF |
το bit προσήμου του A AND B είναι ορισμένο |
OF |
καθαρίζεται πάντα |
Αυτή η εντολή δέχεται δύο τελεστέους και ενημερώνει τις σημαίες, αλλά δεν τροποποιεί τους τελεστέους της.
Αυτές οι εντολές μετακινούν τα bit του τελεστέου προορισμού κατά έναν αριθμό θέσεων που καθορίζεται από τον δεύτερο τελεστέο.
Ο δεύτερος τελεστέος πρέπει να είναι ένας σταθερός αριθμός (ένα immediate) ή ο καταχωρητής cl (τα χαμηλότερα 8 bit του rcx).
| Όνομα | Περιγραφή |
|---|---|
shl/sal
|
Μετατοπίζει τα bit προς τα αριστερά |
shr/sar
|
Μετατοπίζει τα bit προς τα δεξιά |
Σημείωσε ότι ο μετρητής στον δεύτερο τελεστέο περιορίζεται με μάσκα στα 5 bit, ή στα 6 bit όταν ο τελεστέος προορισμού είναι 64 bit.
Κάθε bit μετά από αυτά αγνοείται ουσιαστικά.
Αυτό σημαίνει ότι η μέγιστη ολίσθηση είναι 31, ή 63 με έναν τελεστέο 64 bit.
Οι shl και sal εκτελούν την ίδια ακριβώς πράξη, η μία είναι ψευδώνυμο της άλλης.
Κάθε φορά που γίνεται ολίσθηση προς τα αριστερά, τα bit που βρίσκονται πιο κοντά στο τέλος της ακολουθίας από όσο το μήκος της ολίσθησης μετακινούνται πρώτα στο CF και μετά απορρίπτονται.
Από την άλλη, ένας αριθμός νέων μηδενισμένων bit ίσος με το μήκος της ολίσθησης προστίθεται στην αρχή.
Επειδή κάθε bit ενός ακέραιου αντιπροσωπεύει μια δύναμη του 2, μια ολίσθηση προς τα αριστερά κατά n θέσεις έχει το αποτέλεσμα του πολλαπλασιασμού του ακέραιου επί 2ⁿ.
Υπάρχουν δύο εντολές για μετακίνηση bit προς τα δεξιά: οι shr και sar.
Κάθε φορά που χρησιμοποιείται οποιαδήποτε από τις δύο εντολές, τα bit που βρίσκονται πιο κοντά στην αρχή της ακολουθίας από όσο το μήκος της ολίσθησης μετακινούνται πρώτα στο CF και μετά απορρίπτονται.
Από την άλλη, ένας αριθμός νέων bit ίσος με το μήκος της ολίσθησης προστίθεται στο τέλος.
Η διαφορά μεταξύ τους είναι ότι η shr μετακινεί 0 bit στο αριστερό άκρο, ενώ η sar μετακινεί 1 αν το πιο σημαντικό bit ήταν ορισμένο και 0 διαφορετικά.
Αυτό σημαίνει ότι η sar διατηρεί το πρόσημο στην ολίσθηση ενός προσημασμένου ακέραιου.
Επειδή κάθε bit ενός ακέραιου αντιπροσωπεύει μια δύναμη του 2, μια ολίσθηση προς τα δεξιά κατά n θέσεις με τη χρήση της shr έχει το αποτέλεσμα μιας χωρίς πρόσημο διαίρεσης με το 2ⁿ.
Παρομοίως, μια ολίσθηση προς τα δεξιά κατά n θέσεις με τη χρήση της sar έχει το αποτέλεσμα μιας προσημασμένης διαίρεσης με το 2ⁿ.
Αυτές οι εντολές μετακινούν τα bit του τελεστέου προορισμού κατά έναν αριθμό θέσεων που καθορίζεται από τον δεύτερο τελεστέο.
Ο δεύτερος τελεστέος πρέπει να είναι ένας σταθερός αριθμός (ένα immediate) ή ο καταχωρητής cl (τα χαμηλότερα 8 bit του rcx).
Η διαφορά μεταξύ μιας περιστροφής και μιας ολίσθησης είναι ότι η περιστροφή δεν απορρίπτει ούτε προσθέτει bit. Τα bit που θα απορρίπτονταν από μια ολίσθηση μετακινούνται αντ' αυτού στο αντίθετο άκρο. Έτσι, όλα τα bit παραμένουν, απλώς αλλάζουν όλα θέση.
| Όνομα | Περιγραφή |
|---|---|
rol |
Περιστρέφει τα bit προς τα αριστερά |
ror |
Περιστρέφει τα bit προς τα δεξιά |
Σημείωσε ότι ο μετρητής στον δεύτερο τελεστέο περιορίζεται με μάσκα στα 5 bit, ή στα 6 bit όταν ο τελεστέος προορισμού είναι 64 bit.
Κάθε bit μετά από αυτά αγνοείται ουσιαστικά.
Αυτό σημαίνει ότι η μέγιστη περιστροφή είναι 31, ή 63 με έναν τελεστέο 64 bit.
Υπάρχουν και άλλες χρήσιμες εντολές χειρισμού bit:
| Όνομα | Περιγραφή |
|---|---|
popcnt |
Μετράει τον αριθμό των bit που είναι ορισμένα |
bsr |
Παίρνει τη θέση του πιο σημαντικού ορισμένου bit. Αν δεν είναι ορισμένο κανένα bit, το αποτέλεσμα είναι απροσδιόριστο |
bsf |
Παίρνει τη θέση του λιγότερο σημαντικού ορισμένου bit. Αν δεν είναι ορισμένο κανένα bit, το αποτέλεσμα είναι απροσδιόριστο |
Αυτές οι εντολές λειτουργούν όλες με δύο τελεστέους των 16, 32 ή 64 bit.
Δεν μπορούν να χρησιμοποιηθούν με τελεστέους των 8 bit.
Ο φίλος σου μόλις σου έστειλε ένα μήνυμα με ένα σημαντικό μυστικό. Επειδή δεν ήθελε να είναι εύκολο για τους άλλους να το διαβάσουν, το μήνυμα κρυπτογραφήθηκε με μια σειρά από χειρισμούς bit. Θα χρειαστεί να γράψεις τις μεθόδους που θα βοηθήσουν στην αποκρυπτογράφηση του μηνύματος.
Αυτές είναι οι εντολές μεμονωμένου bit που αναφέρονται σε αυτή την έννοια:
| Όνομα | Περιγραφή |
|---|---|
| bt | αντιγράφει το bit στο CF χωρίς να τροποποιεί κανέναν τελεστέο |
| bts | αντιγράφει το bit στο CF και το θέτει σε 1 στον τελεστέο προορισμού |
| btr | αντιγράφει το bit στο CF και το μηδενίζει στον τελεστέο προορισμού |
| btc | αντιγράφει το bit στο CF και το συμπληρώνει (το αντιστρέφει) στον τελεστέο προορισμού |
Αυτές είναι οι εντολές bitwise που αναφέρονται σε αυτή την έννοια:
| Όνομα | Περιγραφή |
|---|---|
| and | 1 αν και τα δύο bit είναι 1 |
| or | 1 αν τουλάχιστον ένα από τα bit είναι 1 |
| xor | 1 αν τα bit διαφέρουν |
| not | 1 αν το bit ήταν 0, 0 αν το bit ήταν 1 |
Αυτές είναι οι εντολές μετατόπισης που αναφέρονται σε αυτή την έννοια:
| Όνομα | Περιγραφή |
|---|---|
| shl/sal | Μετατοπίζει τα bit προς τα αριστερά |
| shr/sar | Μετατοπίζει τα bit προς τα δεξιά |
Αυτές είναι οι εντολές περιστροφής που αναφέρονται σε αυτή την έννοια:
| Όνομα | Περιγραφή |
|---|---|
| rol | Περιστρέφει τα bit προς τα αριστερά |
| ror | Περιστρέφει τα bit προς τα δεξιά |
Αυτές είναι οι λοιπές εντολές που αναφέρονται σε αυτή την έννοια:
| Όνομα | Περιγραφή |
|---|---|
| popcnt | Μετράει τον αριθμό των ορισμένων bit |
| bsr | Δίνει τη θέση του πιο σημαντικού ορισμένου bit. Αν δεν έχει οριστεί κανένα bit, το αποτέλεσμα είναι απροσδιόριστο |
| bsf | Δίνει τη θέση του λιγότερο σημαντικού ορισμένου bit. Αν δεν έχει οριστεί κανένα bit, το αποτέλεσμα είναι απροσδιόριστο |
Το μήνυμα είναι κωδικοποιημένο σε έναν ακέραιο 16 bit. Ωστόσο, από αυτά, τα 8 υψηλότερα bit δεν είναι στην πραγματικότητα μέρος του μηνύματος, αλλά μια μάσκα που πρέπει να χρησιμοποιηθεί στην αποκρυπτογράφηση.
Υλοποίησε τη συνάρτηση extract_higher_bits, η οποία δέχεται έναν ακέραιο 16 bit και επιστρέφει τα 8 υψηλότερα bit του.
extract_higher_bits(0b1010010011000101)
// => 0b10100100
Το να μπορείς να εξάγεις τη μάσκα δεν αρκεί, θα πρέπει επίσης να απομονώσεις το μήνυμα.
Υλοποίησε τη συνάρτηση extract_lower_bits, η οποία δέχεται έναν ακέραιο 16 bit και επιστρέφει τα 8 χαμηλότερα bit του.
extract_lower_bits(0b1010010011000101);
// => 0b11000101
Μερικά bit είναι ορισμένα τόσο στο μήνυμα όσο και στη μάσκα. Αυτή είναι μια πολύ σημαντική πληροφορία που θα χρησιμοποιηθεί αργότερα.
Υλοποίησε τη συνάρτηση extract_redundant_bits, η οποία δέχεται έναν ακέραιο 16 bit, που κωδικοποιεί τόσο το μήνυμα όσο και μια μάσκα, και επιστρέφει έναν ακέραιο 8 bit με ορισμένα μόνο τα πλεονάζοντα bit.
Ένα bit στον αριθμό που επιστρέφεται θα πρέπει να ορίζεται σε 1 όπου είναι επίσης 1 τόσο στο μήνυμα όσο και στη μάσκα.
Όλα τα άλλα bit θα πρέπει να μηδενίζονται.
extract_redundant_bits(0b1010010011000101);
// => 0b10000100
Στη συνέχεια, υπάρχουν κάποια bit που πρέπει να οριστούν σε 1 στο μήνυμα, σύμφωνα με τη μάσκα.
Υλοποίησε τη συνάρτηση set_message_bits, η οποία δέχεται έναν ακέραιο 16 bit, που κωδικοποιεί τόσο το μήνυμα όσο και μια μάσκα, και επιστρέφει το αποτέλεσμα του ορισμού των bit του μηνύματος σε 1.
Ένα bit του μηνύματος θα πρέπει να ορίζεται σε 1 όπου το bit στη μάσκα είναι 1.
Όλα τα άλλα bit θα πρέπει να παραμένουν αμετάβλητα, ώστε να παραμένουν ορισμένα αν ήταν ήδη ορισμένα, και μηδενισμένα αν ήταν ήδη μηδενισμένα.
set_message_bits(0b1010010011000101);
// => 0b11100101
Υπάρχει ένα κομμάτι του παζλ που δεν είναι ρητά στο μήνυμα: ο αριθμός 16 bit 0b1011001100111100.
Αυτός ο αριθμός είναι το κοινόχρηστο ιδιωτικό κλειδί σου και θα πρέπει να το χρησιμοποιήσεις για να βοηθήσεις στην αποκρυπτογράφηση του μηνύματος.
Για να το κάνεις αυτό, πρέπει πρώτα να περιστρέψεις τα bit του ιδιωτικού κλειδιού σου προς τα αριστερά κατά έναν ορισμένο αριθμό θέσεων. Ο αριθμός των θέσεων είναι ίσος με τον αριθμό των πλεοναζόντων bit που είναι ορισμένα τόσο στο μήνυμα όσο και στη μάσκα.
Υλοποίησε τη συνάρτηση rotate_private_key, η οποία δέχεται έναν ακέραιο 16 bit, που κωδικοποιεί τόσο το μήνυμα όσο και μια μάσκα, και επιστρέφει το αποτέλεσμα της περιστροφής του ιδιωτικού κλειδιού σου.
Αυτό το αποτέλεσμα είναι ένας ακέραιος 16 bit.
rotate_private_key(0b1010010011000101);
// => 0b1100110011110010
Ο NASM (The Netwide Assembler, ο assembler που χρησιμοποιεί αυτό το track) υποστηρίζει σταθερές σε δυαδική μορφή με πρόθεμα 0b.
Υποστηρίζει επίσης τη χρήση κάτω παύλας (_) ως διαχωριστικού σε μια σταθερά, για ευκολία ανάγνωσης:
PRIVATE_KEY equ 0b1011_0011_0011_1100
Για να χρησιμοποιηθεί στην αποκρυπτογράφηση, το ιδιωτικό κλειδί σου πρέπει να μορφοποιηθεί ώστε να απομονώσει τα σχετικά bit.
Για να μορφοποιήσεις πλήρως ένα ιδιωτικό κλειδί, πρέπει:
Ένα αντεστραμμένο bit είναι 1 αν ήταν 0 και 0 αν ήταν 1.
Υλοποίησε τη συνάρτηση format_private_key, η οποία δέχεται έναν ακέραιο 16 bit, που κωδικοποιεί τόσο το μήνυμα όσο και μια μάσκα, και επιστρέφει ένα πλήρως μορφοποιημένο ιδιωτικό κλειδί 8 bit.
format_private_key(0b1010010011000101);
// => 0b11000001
Μόλις έχεις το μήνυμα με όλα τα σχετικά bit ορισμένα και το μορφοποιημένο ιδιωτικό κλειδί, ήρθε η ώρα να τα ενώσεις για να πάρεις το τελικό μήνυμα.
Το μήνυμα που προκύπτει είναι ένας ακέραιος 16 bit, του οποίου:
Υλοποίησε τη συνάρτηση decrypt_message, η οποία δέχεται έναν ακέραιο 16 bit που κωδικοποιεί τόσο το μήνυμα όσο και μια μάσκα, και επιστρέφει έναν ακέραιο 16 bit με το μήνυμα πλήρως αποκρυπτογραφημένο.
Αυτή η συνάρτηση θα πρέπει να χρησιμοποιεί το μορφοποιημένο ιδιωτικό κλειδί που παράγεις με τη format_private_key και επίσης το μήνυμα με όλα τα σχετικά bit ορισμένα με τη set_message_bits.
decrypt_message(0b1010010011000101);
// => 0b1100000111100101
Γράψου στο Exercism για να μάθεις και να κατακτήσεις x86-64 Assembly με 22 έννοιες130 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.