DedSec Project

llvm_ir — συγκεντρωτικός οδηγός — DedSec Project

llvm_ir — συγκεντρωτικός οδηγός LLVM IR Τι προσφέρει η γλώσσα Το LLVM IR είναι ενδιάμεση αναπαράσταση με τύπους που χρησιμοποιείται σε toolchains, όχι assembly που εκτελείται απευθείας σε…

LLVM IR

Τι προσφέρει η γλώσσα

Το LLVM IR είναι ενδιάμεση αναπαράσταση με τύπους που χρησιμοποιείται σε toolchains, όχι assembly που εκτελείται απευθείας σε CPU.

Μικρό παράδειγμα προς μελέτη

define i32 @add(i32 %a, i32 %b) {
entry:
  %sum = add i32 %a, %b
  ret i32 %sum
}

Εντόπισε υπογραφή, βασικό block και SSA value. Σύγκρινε σωστό τύπο επιστροφής με σκόπιμα λανθασμένο μέσα στον verifier.

Τι να επαληθεύσεις

Κατάγραψε την πραγματική έκδοση εργαλείου, τις απαιτούμενες εξαρτήσεις και την έξοδο σε δοκιμαστικά δεδομένα για τη LLVM_IR. Πρόβλεψε το αποτέλεσμα πριν το ελέγξεις και διατήρησε την αρχική και τη διορθωμένη εκδοχή ώστε να φαίνεται η αιτιώδης διαφορά. Μην αποκαλείς ένα απόσπασμα εκτελεσμένο αν δεν έχεις το κατάλληλο περιβάλλον.

Παγίδα ειδική για το θέμα

Η σύνταξη και τα attributes αλλάζουν μεταξύ εκδόσεων LLVM· έλεγξε τα IR με εργαλεία ίδιας έκδοσης.

Εργαστήριο εξάσκησης: LLVM IR

Εκτέλεση του αρχικού module

Το 00_starter.ll έχει define i32 @main() και τερματίζει με ret i32 0. Αντέγραψέ το σε exercise.ll ώστε να μη χαλάσεις το αρχικό. Με συμβατά εργαλεία LLVM εκτέλεσε:

llvm-as exercise.ll -o exercise.bc
lli exercise.bc
printf 'exit status: %s\n' "$?"

Η επιτυχής εκτέλεση αναμένεται να επιστρέψει κωδικό μηδέν. Η lli δεν εκτυπώνει την ακέραια επιστροφή στην οθόνη: ο κωδικός εξόδου είναι άλλο κανάλι παρατήρησης. Κράτησε τις εκδόσεις llvm-as --version και lli --version, επειδή διαφορές μεταξύ τους επηρεάζουν την ανάγνωση του IR. Οι εντολές δεν έχουν εκτελεστεί στο παρόν περιβάλλον.

Μία ελεγχόμενη αλλαγή

Άλλαξε μόνο το ret i32 0 σε ret i32 7. Πρόβλεψε κωδικό εξόδου 7 για συστήματα που χρησιμοποιούν τη main ως σημείο εισόδου και επανέλαβε τη μεταγλώττιση. Μη συμπεράνεις ότι ο κωδικός εξόδου διατηρεί οποιονδήποτε 32-bit αριθμό: πολλά λειτουργικά εκθέτουν περιορισμένο εύρος. Για πλήρη ακέραια τιμή χρησιμοποίησε κατάλληλο πρόγραμμα κλήσης.

Σκόπιμο σφάλμα τύπων

Σε προσωρινό αντίγραφο βάλε ret i64 7 χωρίς αλλαγή του define i32 @main(). Οι τύποι της εντολής επιστροφής και της συνάρτησης δεν συμφωνούν. Εκτέλεσε llvm-as, αποθήκευσε την πραγματική διαγνωστική έξοδο και μετά διόρθωσε σε ret i32 7. Η διόρθωση πρέπει να εξηγεί την ασυμφωνία, όχι να βασίζεται σε τυχαίες δοκιμές.

Άσκηση με έλεγχο ροής

Δημιούργησε δεύτερη υλοποίηση με blocks entry, positive και nonpositive. Σύγκρινε μια παράμετρο με μηδέν με icmp sgt i32, διακλάδωσε με br i1 και τερμάτισε κάθε προσπελάσιμο block. Όλες οι επιστροφές πρέπει να είναι i32. Αν ενώσεις τις δύο διαδρομές με phi, δώσε μία είσοδο ανά προκάτοχο block.

Κριτήρια ελέγχου

Εξήγησε γιατί το i32 είναι συμβόλαιο και γιατί δεν υπάρχει αυτόματη πτώση στο επόμενο block. Σύγκρινε το llvm-dis με το αρχικό κείμενο, κράτησε ένα θετικό και ένα αρνητικό τεστ και σημείωσε την αρχιτεκτονική στόχο. Αναφορά: https://llvm.org/docs/LangRef.html

LLVM_IR — Διαδρομή ουσιαστικής εξάσκησης

Μια ελάχιστη συνάρτηση

Η LLVM Intermediate Representation περιγράφει typed operations μέσα σε basic blocks. Κάθε SSA temporary έχει έναν ορισμό, αλλά η μνήμη είναι διαφορετική περίπτωση και απαιτεί load/store ή κατάλληλες μετατροπές. Αποθήκευσε το παράδειγμα σε add.ll.

define i32 @add(i32 %a, i32 %b) {
entry:
  %sum = add i32 %a, %b
  ret i32 %sum
}

Η συνάρτηση επιστρέφει το άθροισμα των δύο i32. Έλεγξε τη σύνταξη με llvm-as add.ll και εξέτασε το module με εργαλεία της ίδιας LLVM έκδοσης. Μη συγχέεις το LLVM IR με φορητό assembly συγκεκριμένου επεξεργαστή: το IR μπορεί να μετασχηματιστεί και να μεταγλωττιστεί για διαφορετικά targets με target-specific επιλογές.

Πότε δεν ισχύει μια υποτιθέμενη ιδιότητα

Η πρόσθεση i32 χωρίς επισημάνσεις διαχειρίζεται υπερχείλιση με modular συμπεριφορά στο πλάτος i32. Αν χρησιμοποιήσεις add nsw, δηλώνεις ότι δεν υπάρχει signed overflow· όταν αυτή η υπόθεση παραβιάζεται μπορεί να προκύψει poison value, κάτι διαφορετικό από «έγκυρο αριθμητικό αποτέλεσμα με wrap». Μην προσθέτεις τέτοιες σημαίες απλώς για να κάνει ο optimizer πιο πολλά.

Φ-κόμβοι και control flow

Γράψε δεύτερη συνάρτηση με δύο predecessors που επιστρέφουν διαφορετική τιμή. Στο join block χρησιμοποίησε phi ώστε το SSA αποτέλεσμα να αντιστοιχεί στο εκάστοτε προηγούμενο block. Η phi είναι επιλογή βάσει CFG predecessor, όχι ένας αυθαίρετος imperative assignment.

Κριτήρια αποδοχής

Εξέτασε έγκυρο και σκόπιμα μη έγκυρο type mismatch, διάβασε το diagnostic του llvm-as και χρησιμοποίησε opt -verify με συμβατή LLVM έκδοση. Σύγκρινε i32 με i64 χωρίς να υποθέτεις ότι ο ίδιος bitpattern έχει πάντα την ίδια αριθμητική ερμηνεία. Κατάγραψε toolchain version, target assumptions και πραγματικά αποτελέσματα. Τα παραδείγματα είναι για δοκιμή, όχι πιστοποιημένες εκτελέσεις.