4.12 Τύποι Εκτελέσιμων

Για να καταλάβετε γιατί το FreeBSD χρησιμοποιεί τον τύπο elf(5) θα πρέπει πρώτα να γνωρίζετε μερικά πράγματα για τους τρεις «κυρίαρχους» τύπους εκτελέσιμων για το UNIX®

Το FreeBSD προέρχεται από τον «κλασσικό» χώρο και μέχρι την αρχή της σειράς 3.X, χρησιμοποιούσε τον τύπο a.out(5), μια τεχνολογία δοκιμασμένη και αποδεδειγμένη σε πολλές γενιές εκδόσεων του BSD. Αν και η μεταγλώττιση και εκτέλεση εγγενών εκτελέσιμων (και πυρήνων) τύπου ELF ήταν δυνατή στα FreeBSD συστήματα ήδη από πολύ καιρό πριν, το FreeBSD αρχικά αντιστάθηκε στην «ώθηση» για καθιέρωση του ELF ως προκαθορισμένου τύπου. Γιατί; Όταν ο κόσμος του Λίνουξ έκανε την οδυνηρή μετάβαση προς το ELF, δεν ήταν τόσο για να ξεφύγει από τον τύπο εκτελέσιμων a.out όσο για να αντιμετωπίσει το δύσκαμπτο δικό τους μηχανισμό κοινόχρηστων βιβλιοθηκών, ο οποίος βασίζονταν σε jump-tables και προκαλούσε μεγάλη δυσχέρεια στην κατασκευή τους, τόσο στους προγραμματιστές όσο και στους μεταπωλητές. Από τη στιγμή που τα διαθέσιμα εργαλεία του ELF προσέφεραν λύση στο πρόβλημα των κοινών βιβλιοθηκών και έγινε γενικώς αποδεκτό πως ήταν «ο δρόμος προς τα εμπρός», έγινε αποδεκτό το αναγκαίο κόστος της μεταφοράς και επιτεύχθηκε η μετακίνηση. Ο μηχανισμός κοινόχρηστων βιβλιοθηκών του FreeBSD βασίζεται σε μεγάλο βαθμό στον αντίστοιχο μηχανισμό του SunOS™ της Sun και είναι πολύ εύκολος στη χρήση.

Τότε, γιατί υπάρχουν τόσοι διαφορετικοί τύποι;

Πίσω στο σκοτεινό παρελθόν, υπήρχε απλό hardware. Αυτό το απλό hardware υποστήριζε ένα απλό, μικρό σύστημα. Το a.out ήταν απόλυτα κατάλληλο για την αναπαράσταση εκτελέσιμων σε αυτό το απλό σύστημα (ένα PDP-11). Όταν ο κόσμος άρχισε να μεταφέρει το UNIX από αυτό το απλό σύστημα, διατηρήθηκε ο τύπος a.out γιατί ήταν ικανοποιητικός για τα πρώτα ports του UNIX σε αρχιτεκτονικές όπως η Motorola 68k, VAXen, κτλ.

Μετέπειτα κάποιος λαμπρός μηχανικός hardware αποφάσισε πως αφού μπορούσε να εξαναγκάζει το λογισμικό να κάνει τόσα πρόχειρα κόλπα, θα μπορούσε επίσης να παραλείψει μερικές πύλες από το σχεδιασμό ώστε να επιτρέψει στον πυρήνα της CPU να τρέχει γρηγορότερα. Αν και διασκευάσθηκε ώστε να δουλεύει με αυτό το νέο είδος hardware (γνωστό σήμερα ως RISC), ο τύπος a.out ήταν τελικά ακατάλληλος για αυτό, και έτσι σχεδιάστηκαν πολλοί νέοι τύποι για να επιτευχθεί καλύτερη απόδοση από το hardware από ότι ήταν δυνατόν με τον απλό και περιοριστικό τύπο a.out. Εφευρέθηκαν διάφοροι τύποι όπως οι COFF, ECOFF, και μερικοί άλλοι λιγότερο γνωστοί, και ερευνήθηκαν οι περιορισμοί τους ώσπου τα πράγματα σταθεροποιήθηκαν στο ELF.

Επιπλέον, το μέγεθος των προγραμμάτων γινόταν όλο και μεγαλύτερο και οι δίσκοι (και η φυσική μνήμη) ήταν ακόμη σχετικά μικροί και κάπως έτσι γεννήθηκε η ιδέα της κοινής βιβλιοθήκης. Το σύστημα VM έγινε επίσης περισσότερο περίπλοκο. Κάθε μία από τις βελτιώσεις γινόταν με βάση τον τύπο a.out, που όμως γινόταν όλο και πιο δύσχρηστος με κάθε νέα προσθήκη. Επιπρόσθετα, ο κόσμος ήθελε να φορτώνει τμήματα δυναμικά ενώ το σύστημα ήταν σε φάση εκτέλεσης, ή να εξαλείφει μέρη προγραμμάτων αφού είχε εκτελεστεί ο κώδικας αρχικοποίησης (init) ώστε να εξοικονομηθεί φυσική μνήμη και χώρος swap. Οι γλώσσες προγραμματισμού γινόντουσαν ακόμα πιο περίπλοκες και ο κόσμος ήθελε αυτόματη φόρτωση και εκτέλεση κώδικα πριν την κλήση της main. Έγιναν πρόχειρες διορθώσεις (hacks) στον τύπο a.out ώστε να συμβαδίζει με όλες αυτές τις αλλαγές, και πράγματι, για μια περίοδο έδειχνε να λειτουργεί. Με τον καιρό όμως, φάνηκε ότι ο τύπος a.out δεν θα μπορούσε να αντεπεξέλθει σε όλα αυτά τα προβλήματα, αφού θα έπρεπε να αναπτύσσεται συνεχώς και με περίπλοκο τρόπο. Αν και το ELF έλυνε πολλά από αυτά τα προβλήματα, η μετάβαση σε αυτό ενός συστήματος που βασικά λειτουργούσε, θα οδηγούσε σε οδυνηρές καταστάσεις. Έτσι ο τύπος ELF έπρεπε να περιμένει μέχρι τη στιγμή όπου η παραμονή στο a.out θα δημιουργούσε περισσότερα προβλήματα από ότι η μετάβαση στο ELF.

Ωστόσο, όσο ο καιρός περνούσε, και τα εργαλεία μεταγλώττισης από τα οποία προέρχονται τα αντίστοιχα εργαλεία του FreeBSD (ειδικότερα ο assembler και ο loader), αναπτύχθηκαν παράλληλα σε δύο δέντρα. Το δέντρο του FreeBSD πρόσθεσε κοινές βιβλιοθήκες και διόρθωσε κάποια σφάλματα. Η ομάδα του GNU που είχε αρχικά γράψει αυτά τα προγράμματα, τα έγραψε ξανά και πρόσθεσε ευκολότερη υποστήριξη για κατασκευή cross compilers, την ενσωμάτωση διαφορετικών τύπων κατά βούληση, κλπ. Αν και πολλοί ζητούσαν να κατασκευαστούν cross compilers για FreeBSD, ήταν άτυχοι, αφού ο παλιός πηγαίος κώδικας του FreeBSD για τα as και ld τα έκανε ακατάλληλα. Η νέα αλυσίδα εργαλείων του GNU (binutils) υποστηρίζει cross compiling, ELF, κοινές βιβλιοθήκες, προεκτάσεις C++, κτλ. Επιπλέον, πολλοί τρίτοι κατασκευαστές προσφέρουν εκτελέσιμα ELF, και είναι πολύ καλό να μπορούν να εκτελεστούν στο FreeBSD.

Ο ELF είναι πιο εκφραστικός από τον a.out και περισσότερο επεκτάσιμος στο βασικό σύστημα. Τα εργαλεία ELF είναι ευκολότερα στην συντήρηση και προσφέρουν υποστήριξη για cross compilers, κάτι που είναι πολύ σημαντικό για μερικούς ανθρώπους. Μπορεί ο ELF να είναι λίγο πιο αργός από τον a.out, αλλά η διαφορά δεν είναι αισθητή. Υπάρχουν επίσης πολλές άλλες διαφορές μεταξύ τους, σε λεπτομέρειες όπως τον τρόπο που αντιστοιχίζουν σελίδες, που χειρίζονται τον κώδικα init, κλπ. Καμιά από αυτές δεν είναι πολύ σημαντική, αλλά ωστόσο δεν παύουν να είναι διαφορές. Με τον καιρό η υποστήριξη για το a.out θα απομακρυνθεί από τον πυρήνα GENERIC, και τελικά θα αφαιρεθεί εντελώς από τον πυρήνα όταν εκλείψει ολοκληρωτικά η ανάγκη εκτέλεσης παλαιών προγραμμάτων τύπου a.out.

Αυτό το κείμενο, και άλλα κείμενα, μπορεί να βρεθεί στο ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Για ερωτήσεις σχετικά με το FreeBSD, διαβάστε την τεκμηρίωση πριν να επικοινωνήσετε με την <questions@FreeBSD.org>.
Για ερωτήσεις σχετικά με αυτή την τεκμηρίωση, στείλτε e-mail στην <doc@FreeBSD.org>.