Η διαδρομή x86-64 στο Exercism χρησιμοποιεί το NASM (The Netwide Assembler) ως assembler.
Στο NASM, τα σχόλια ξεκινούν με ένα ερωτηματικό (;).
Τα σχόλια μπορούν να τοποθετηθούν οπουδήποτε στο πρόγραμμα και ό,τι ακολουθεί μετά από ένα ; αγνοείται από τον assembler.
Μια σταθερά χρόνου συμβολομετάφρασης μπορεί να οριστεί στο NASM με το equ.
Για παράδειγμα, αυτό ορίζει μια σταθερά με το όνομα UNIVERSE και την τιμή 42:
UNIVERSE equ 42
Οι σταθερές αξιολογούνται μία φορά, όταν ορίζονται, και δεν μπορούν να επαναοριστούν αργότερα.
Στην assembly, αντί για μεταβλητές, συνήθως χρησιμοποιούμε καταχωρητές για να αποθηκεύουμε τιμές. Ένας καταχωρητής CPU είναι ένα κομμάτι γρήγορης μνήμης μέσα στον επεξεργαστή ενός υπολογιστή. Οι περισσότεροι υπολογισμοί εκτελούνται στους καταχωρητές της CPU.
Κάποιοι από τους καταχωρητές χρησιμοποιούνται για διάφορους διαφορετικούς υπολογισμούς και ονομάζονται Γενικοί Καταχωρητές (GPRs). Άλλοι έχουν ειδικούς ή αποκλειστικούς σκοπούς.
Στο x86-64, υπάρχουν 16 Γενικοί Καταχωρητές (GPRs) των 64-bit, στους οποίους μπορεί επίσης να γίνει προσπέλαση ως 32-bit, 16-bit ή 8-bit.
Οι GPRs περιγράφονται παρακάτω, όπου το n στο rn κυμαίνεται από το 8 έως το 15: r8, r9, r10, r11, r12, r13, r14 και r15.
| 64-bit | 32-bit | 16-bit | 8-bit |
|---|---|---|---|
| rax | eax | ax | ah/al |
| rbx | ebx | bx | bh/bl |
| rcx | ecx | cx | ch/cl |
| rdx | edx | dx | dh/dl |
| rsi | esi | si | sil |
| rdi | edi | di | dil |
| rbp | ebp | bp | bpl |
| rsp | esp | sp | spl |
| rn | rnd | rnw | rnb |
Όταν χρησιμοποιούνται λιγότερα από 64-bit, τα bit στα οποία γίνεται προσπέλαση προέρχονται συνήθως από το χαμηλότερο τμήμα του καταχωρητή.
Η εξαίρεση σε αυτόν τον κανόνα είναι τα ah, bh, ch και dh, τα οποία προσπελαύνουν τα ανώτερα 8-bit από το τμήμα των 16-bit του καταχωρητή.
Απεικόνιση του τρόπου με τον οποίο γίνεται προσπέλαση στα bit για τον καταχωρητή rax:
+--------+---------------------------------------+
| 64-bit | rax |
+--------+-------------------+-------------------+
| 32-bit | | eax |
+--------+-------------------+---------+---------+
| 16-bit | | ax |
+--------+-----------------------------+----+----+
| 8-bit | | ah | al |
+--------+-----------------------------+----+----+
Κάποιοι από αυτούς τους καταχωρητές πρέπει να διατηρούνται ανάμεσα σε κλήσεις συναρτήσεων: rbp, rsp, rbx, r12, r13, r14 και r15.
Η αποτυχία διατήρησής τους μπορεί να οδηγήσει σε σφάλμα ή σε απροσδιόριστη συμπεριφορά.
Οι υπόλοιποι δεν διατηρούνται και μπορούν να χρησιμοποιηθούν ελεύθερα: rax, rcx, rdx, rdi, rsi, r8, r9, r10 και r11.
Οι καταχωρητές συνήθως διατηρούνται στη στοίβα χρησιμοποιώντας μια εντολή push.
Στη συνέχεια επαναφέρονται πριν από το τέλος της συνάρτησης χρησιμοποιώντας μια εντολή pop.
Οι εντολές είναι κομμάτια υπολογισμών που μπορεί να εκτελέσει μια CPU. Συνήθως έχουν την ακόλουθη μορφή:
name destination, source
Έτσι, το όνομα της εντολής τοποθετείται πρώτο, μετά τουλάχιστον ένα κενό διάστημα, ακολουθούμενο από τον τελεστέο προορισμού, ένα κόμμα (,) και τέλος έναν τελεστέο πηγής.
Ο τελεστέος πηγής συνήθως δεν τροποποιείται από μια εντολή, μόνο ο τελεστέος προορισμού.
Και οι δύο τελεστέοι πρέπει να έχουν το ίδιο μέγεθος, εκτός αν αναφέρεται διαφορετικά. Για παράδειγμα, ο τελεστέος προορισμού πρέπει επίσης να έχει 16 bit αν ο τελεστέος πηγής έχει 16 bit.
Για παράδειγμα, για να αποθηκεύσουμε μια τιμή σε έναν καταχωρητή, μπορούμε να χρησιμοποιήσουμε την εντολή mov:
mov rax, rdx ; rax = rdx
; mov is the name, rax is the destination operand and rdx is the source operand
Το παραπάνω απόσπασμα αντιγράφει τα περιεχόμενα και των 64 bit του rdx, του τελεστέου πηγής, σε όλα τα 64 bit του rax, που είναι ο τελεστέος προορισμού για την εντολή.
Είναι δυνατό να χρησιμοποιηθούν σταθεροί ακέραιοι αριθμοί ως τελεστέοι πηγής (αλλά όχι ως τελεστέοι προορισμού) στις περισσότερες εντολές:
mov rcx, 42 ; rcx = 42
; rcx is the destination operand and 42 is the source operand
Σημείωσε ότι η εγγραφή σε έναν καταχωρητή 32-bit καθαρίζει επίσης τα ανώτερα bit, οπότε το mov eax, 42 είναι το ίδιο με το mov rax, 42.
Αυτό δεν ισχύει για καταχωρητές 16-bit και 8-bit.
Για τις αριθμητικές πράξεις της πρόσθεσης, της αφαίρεσης και του πολλαπλασιασμού, μπορούμε να χρησιμοποιήσουμε τις εντολές add, sub και imul:
add rax, rsi ; rax = rax + rsi
imul rax, rdi ; rax = rax * rdi
sub rax, r8 ; rax = rax - r8
Οι εντολές οργανώνονται σε συναρτήσεις. Όλες οι συναρτήσεις τοποθετούνται στην ενότητα .text του αρχείου πηγής.
Μια δήλωση συνάρτησης αποτελείται από:
:.Υπάρχουν συγκεκριμένες συμβάσεις για το πώς περνούν και επιστρέφονται τα ορίσματα από μια συνάρτηση. Οι δύο κύριες συμβάσεις κλήσης είναι η System V AMD64 ABI και η Microsoft x64.
Αυτή η διαδρομή χρησιμοποιεί τη σύμβαση κλήσης System V AMD64 ABI και τα έξι πρώτα ακέραια ορίσματα περνούν σε μια συνάρτηση μέσω καταχωρητών.
Περνούν με την ακόλουθη σειρά: rdi, rsi, rdx, rcx, r8 και r9.
Μια ακέραια τιμή επιστρέφεται από τη συνάρτηση στον καταχωρητή rax.
Για να καλέσουμε μια συνάρτηση, χρησιμοποιούμε την εντολή call.
Μια συνάρτηση μπορεί να κληθεί οπουδήποτε στο ίδιο αρχείο πηγής.
Για να γίνει μια συνάρτηση ορατή σε άλλα αρχεία πηγής, πρέπει να χρησιμοποιηθεί η οδηγία global.
Για παράδειγμα, αυτό δηλώνει μια συνάρτηση sum:
section .text ; functions are placed here
global sum ; sum is visible to other source files
sum:
; first argument is passed in rdi
; second argument is passed in rsi
; return value is placed in rax
mov rax, rdi ; rax is now equal to rdi
add rax, rsi ; rax = rax + rsi
ret ; function return
Και αυτό καλεί τη συνάρτηση sum με ορίσματα 3 και 5:
mov rdi, 3 ; First argument in rdi
mov rsi, 5 ; Second argument in rsi
call sum
; The rax register now contains the value 8 (3 + 5), after sum returns