Προς το περιεχόμενο

White_Cat

Members
  • ΜΗΝΥΜΑΤΑ

    374
  • ΜΕΛΟΣ

  • ΤΕΛ. ΕΠΙΣΚΕΨΗ

  • ΑΞΙΟΛΟΓΗΣΕΙΣ

    0%

ΑΝΤΙΔΡΑΣΕΙΣ

363 Excellent

3 ΑΚΟΛΟΥΘΟΙ

ΣΧΕΤΙΚΑ ΜΕ White_Cat

  • Κατάταξη
    Senior Member
  • Ημερομηνία γέννησης 10/01/1975

ΠΛΗΡΟΦΟΡΙΕΣ ΠΡΟΦΙΛ

  • Φύλο
    Άνδρας
  • Τοποθεσία
    Αθήνα
  • Ενδιαφέροντα
    Η τροφή, το νερό, το αμμοδοχείο μου και κάτι λιγοστά παιχνίδια με σκοινάκι.

ΠΡΟΣΦΑΤΟΙ ΕΠΙΣΚΕΠΤΕΣ ΠΡΟΦΙΛ

2.856 προβολές προφίλ
  1. White_Cat

    Αεππ

    Θα υπάρξουν ορισμένα μαθήματα που θα είναι καθαρώς θεωρητικά, αλλά κυρίως θα έχεις μαθήματα που θα είναι άκρως πρακτικά, όπου θα σου ζητάνε να γράψεις κώδικα που να είναι λειτουργικός, δηλαδή να τρέχει σωστά.
  2. White_Cat

    Αεππ

    Δεν υπάρχει εύκολη απάντηση σ' αυτό. Είναι θέμα προσωπικής προτίμησης. Αν θέλεις, μπορείς να ξεκινήσεις δοκιμάζοντας και τη C και την Python και μόνο η καρδιά σου θα σου πει ποια από τις δύο είναι καλύτερη. Πάντως στα πανεπιστήμια (1ο έτος), απ' όσο ξέρω η C έχει μεγαλύτερη πέραση από την Python.
  3. White_Cat

    Αεππ

    Καλημέρα, φίλε ! Πριν πω ό,τιδήποτε άλλο, εύχομαι καλή επιτυχία στις εξετάσεις. Ας έρθουμε όμως τώρα στο ερώτημά σου. Η ψευδογλώσσα που μαθαίνεις στο λύκειο είναι βέβαιο ότι θα σου δώσει μια πρώτη ώθηση στο πώς να σκέπτεσαι προγραμματιστικά. Πώς δηλαδή να παίρνεις ένα πρόβλημα και να το "σπάζεις", να το αναλύεις δηλ. σε λογικά βήματα, ώστε ξεκινώντας από τα δεδομένα να φτάνεις σιγά-σιγά ως τη λύση του. Αυτός είναι ο στόχος του μαθήματος κι άμα θέλεις τη γνώμη μου, αυτή είναι όλη η ουσία του προγραμματισμού. Από εκεί και πέρα, προσωπικά αντιπαθώ την ψευδογλώσσα, γιατί εδώ που τα λέμε είναι μόνο για το χαρτί. Άμα θέλεις να προχωρήσεις λίγο περισσότερο και να μάθεις να φτιάχνεις τα πρώτα σου πραγματικά προγράμματα που θα τρέχουν στον Η/Υ, τότε προτείνω να παρακολουθήσεις λίγα μαθήματα στη γλώσσα C που σχεδόν σίγουρα θα κάνετε στο πρώτο έτος του πανεπιστημίου. Τα μαθήματα παρέχονται από το πανεπιστήμιο Μακεδονίας και είναι σε μορφή video. Δες εδώ : http://opencourses.uom.gr/courses/efarmosmenhs-plhroforikhs/187-diadikastikos-programmatismos/enothtes Παράλληλα, αν θέλεις, μπορείς ας πούμε να διαβάσεις και το βιβλίο "C για αρχάριους" του Βασίλη Σεφερίδη από τις εκδόσεις Κλειδάριθμος. Αν και γράφτηκε στα μέσα της δεκαετίας του 90, ακόμα και σήμερα το θεωρώ Ευαγγέλιο. Ελπίζω να είσαι πάντα καλά, και πάλι να έχεις καλή επιτυχία στις εξετάσεις και για όποια βοήθεια θα είμαστε όλοι πάντα εδώ!!! Φιλικά, Ο Άσπρος Γάτος
  4. Καλησπέρα ! Θα ήθελα να μας γράψεις σε γενικές γραμμές τι ζητάει η εργασία για να δούμε αν μπορούμε να ανταποκριθούμε. Να είσαι καλά, Ο Άσπρος Γάτος
  5. Σήμερα θα συνεχίσουμε την εξερεύνηση της γλώσσας Assembly από εκεί που είχαμε σταματήσει την προηγούμενη φορά. Πριν απ' ό,τιδήποτε άλλο όμως, θα ήθελα να ευχαριστήσω θερμά όλους τους φίλους για τη θετική ανταπόκρισή τους, η οποία και με ενθαρρύνει να εξακολουθήσω να γράφω. Όπως είναι ήδη προφανές από όσα έχουμε πει ως τώρα, η Assembly είναι μια πρωτόλεια γλώσσα, όπου δεν συναντούμε τις ευκολίες εκείνες στις οποίες είναι συνηθισμένοι οι σημερινοί προγραμματιστές. Παρ' όλ' αυτά όμως, ακόμα κι εδώ υπάρχουν κάποιες λίγες διευκολύνσεις που μπορούμε να χρησιμοποιήσουμε ώστε να μας λύσουν κάπως τα χέρια. Η βασικότερη από αυτές είναι οι λεγόμενες μακροεντολές, οι οποίες είναι συμπαγή τμήματα κώδικα που εκτελούν τετριμμένες και επαναλαμβανόμενες διαδικασίες και μπορούν να επαναχρησιμοποιούνται, ώστε ο προγραμματιστής να μην απαιτείται να γράφει παρόμοιο κώδικα ξανά και ξανά. Μια μακροεντολή δηλαδή δέχεται έναν αριθμό παραμέτρων και θυμίζει εν πολλοίς για παράδειγμα τις συναρτήσεις της γλώσσας C, ή τα υποπρογράμματα (procedures) της PASCAL. Αξίζει να θυμόμαστε ότι οι μακροεντολές συντάσσονται πριν από το κυρίως πρόγραμμα και σε γενικές γραμμές ορίζονται ως εξής : %macro όνομα μακροεντολής αριθμός παραμέτρων κώδικας μακροεντολής %endmacro Επί παραδείγματι, την προηγούμενη φορά μιλήσαμε για το system call με αριθμό 60, το οποίο χρησιμοποιείται στο τέλος κάθε προγράμματος, ώστε το λειτουργικό σύστημα να ανακτήσει τον έλεγχο του υπολογιστή. (Αν δεν θυμάστε πώς ακριβώς καλείται, ανατρέξτε στο προηγούμενό μας κείμενο.) Είναι σκόπιμο λοιπόν για τη δική μας ευκολία να ορίσουμε μία μακροεντολή που θα ονομάζεται exit και θα κάνει ακριβώς αυτή τη δουλειά, χωρίς να χρειάζεται να δέχεται κάποια παράμετρο. %macro exit 0 mov rax,60 xor rdi,rdi syscall %endmacro Την προηγούμενη φορά είχαμε αναφερθεί και στο system call με αριθμό 1 που το χρησιμοποιούμε για να τυπώνουμε μηνύματα στην οθόνη. Για να φτιάξουμε μια μακροεντολή γι' αυτό πρέπει πρώτα να σκεφτούμε το πλήθος των παραμέτρων που αλλάζουν κάθε φορά που το καλούμε. Οι παράμετροι αυτές είναι κατ' αρχήν η διεύθυνση μέσα στη RAM όπου βρίσκεται αυτό που πρέπει να τυπώσουμε και δεύτερον το μήκος αυτού σε bytes. Άρα οι παράμετροι που θα δέχεται η συγκεκριμένη μακροεντολή θα είναι δύο. Όπως ίσως θα θυμάστε, πριν από τη χρήση της εντολής syscall, φορτώνουμε τη διεύθυνση μνήμης όπου βρίσκεται το μήνυμά μας στον καταχωρητή RSI, ενώ το μήκος του σε bytes φορτώνεται στον καταχωρητή RDX. Άρα η μακροεντολή μπορεί να οριστεί ως εξής : %macro print 2 mov rax,1 mov rdi,1 mov rsi,%1 mov rdx,%2 syscall %endmacro Στο παραπάνω τμήμα κώδικα αξίζει να προσεχθούν οι γραμμές 4 και 5, ώστε να γίνει κατανοητή η χρήση του συμβόλου % κατά τον ορισμό μακροεντολών. Η γραμμή 4 λέει «φόρτωσε στον RSI την πρώτη παράμετρο που δέχτηκε η εν λόγω μακροεντολή», ενώ η 5 λέει «φόρτωσε στον RDX τη δεύτερη παράμετρο». Έτσι λοιπόν για να τυπώσω ένα μήνυμα αρκεί μέσα στο κυρίως πρόγραμμα να γράψω μια γραμμή που θα μοιάζει κάπως έτσι : print message message_length Ένα ακόμα πολύ βασικό ζήτημα για το οποίο θα ήθελα να μιλήσω είναι ο ορισμός μεταβλητών μέσα σε ένα πρόγραμμα. Την περασμένη φορά αναφερθήκαμε μόνο στον ορισμό σταθερών τιμών και είπαμε ότι αυτές ορίζονται μέσα στο τμήμα του προγράμματος που ονομάζεται data section. Για τον ορισμό μεταβλητών υπάρχει το ανάλογο τμήμα προγράμματος που ονομάζεται bss section, όπου ορίζουμε το όνομα κάθε μεταβλητής και το πόσα bytes θα δεσμευτούν γι' αυτήν μέσα στη μνήμη. section .bss name resb 40 Εδώ ορίζουμε μια μεταβλητή που ονομάζεται name και δεσμεύει 40 bytes. Η λέξη-κλειδί RESB σημαίνει «reserve bytes». Στο σημείο αυτό θα πρέπει να αναφερθώ σ' ένα ακόμα πολύ σημαντικό system call που χρησιμοποιείται όταν θέλουμε να διαβάσουμε δεδομένα από το πληκτρολόγιο. Για να το χρησιμοποιήσουμε πρέπει κατ' αρχήν να έχουμε ορίσει μια μεταβλητή (όπως παραπάνω) στην οποία θα αποθηκευτούν τα δεδομένα. Έπειτα φορτώνουμε στον RAX την τιμή μηδέν (αριθμός system call), ενώ στον RDI φορτώνουμε επίσης την τιμή μηδέν (που αντιστοιχεί στην standard input). Στον RSI φορτώνουμε τη διεύθυνση της RAM όπου βρίσκεται ο δεσμευμένος μας χώρος για τη μεταβλητή που ορίσαμε πριν, ενώ στον RDX φορτώνουμε τον αριθμό των bytes που ζητήσαμε να δεσμευτούν. Τέλος χρησιμοποιούμε την εντολή syscall ώστε να κληθεί ο πυρήνας του λειτουργικού συστήματος. Θεωρώ σκόπιμο να ορίσω κατ' ευθείαν μία μακροεντολή για το συγκεκριμένο system call που θα την ονομάσω read και θα δέχεται δύο παραμέτρους. Η πρώτη θα είναι το όνομα της μεταβλητής όπου αποθηκεύονται τα δεδομένα που θα διαβάσουμε και η δεύτερη το μέγιστο μήκος των δεδομένων σε bytes. %macro read 2 mov rax,0 mov rdi,0 mov rsi,%1 mov rdx,%2 syscall %endmacro Κλείνοντας ας επιχειρήσουμε να φτιάξουμε ένα ολοκληρωμένο πρόγραμμα με όσα είπαμε σήμερα. Το πρόγραμμά μας απλά θα ζητάει το όνομα του χρήστη και μετά θα τυπώνει ένα μήνυμα χαιρετισμού, το οποίο θα περιέχει το όνομα που δόθηκε. Με τα όσα έχουμε πει ως εδώ, πιστεύω ότι πλέον ο κώδικας είναι απολύτως κατανοητός. Το πρόγραμμα μπορεί να μεταγλωττιστεί και να εκτελεστεί σύμφωνα με τα όσα είπαμε την προηγούμενη φορά. %macro print 2 mov rax,1 mov rdi,1 mov rsi,%1 mov rdx,%2 syscall %endmacro %macro read 2 mov rax,0 mov rdi,0 mov rsi,%1 mov rdx,%2 syscall %endmacro %macro exit 0 mov rax,60 xor rdi,rdi syscall %endmacro section .data input_msg: db "Πώς σε λένε ; ", 10 input_msglen equ $-input_msg output_msg: db " Τα πας πολύ καλά με την Assembly, φίλε " output_msglen equ $-output_msg section .bss name resb 40 section .text global _start _start: print input_msg, input_msglen read name,40 print output_msg,output_msglen print name,40 exit Στο σημείο αυτό θα ήθελα να ευχαριστήσω για ακόμα μια φορά όλους όσοι διάβασαν ένα ακόμα κείμενό μου ως το τέλος. Βασικός στόχος μου με τα κείμενα αυτά είναι να κάνω τα μέλη του forum να αγαπήσουν ξανά την Assembly. Πώς να το κάνουμε, αυτό το έχω πάρει «πατριωτικά» και με ευχαριστεί πάρα πολύ, ειδικά όταν ο βαθμός ανταπόκρισής σας είναι μεγάλος, όπως συνέβη την πρώτη φορά. Πολλές ευχές σε όλους, Ο Άσπρος Γάτος
  6. Κατά τα τελευταία 30 χρόνια η εξέλιξη των Η/Υ υπήρξε αλματώδης, τόσο σε ταχύτητα όσο και σε επεξεργαστική ισχύ. Παρ' όλ' αυτά υπάρχουν ακόμα και σήμερα ορισμένες βασικές αρχές της λειτουργίας τους οι οποίες παραμένουν αναλλοίωτες, με αποτέλεσμα να συνεχίζουν να διδάσκονται στα πανεπιστήμια μαθήματα όπως η ψηφιακή σχεδίαση, η αρχιτεκτονική υπολογιστών, αλλά και κάποια εκδοχή της γλώσσας προγραμματισμού Assembly. Για τη διδασκαλία της Assembly συνήθως χρησιμοποιείται λογισμικό εξομοίωσης το οποίο προσομοιώνει μόνο ένα μέρος των λειτουργιών του επεξεργαστή που κατά περίπτωση εξετάζεται. Η πρακτική αυτή σίγουρα παρέχει κάποιες ευκολίες, αλλά έχει ως αποτέλεσμα πολλοί φοιτητές να πιστεύουν λανθασμένα ότι δήθεν η Assembly είναι πλέον κάτι εντελώς νεκρό, ένα κατάλοιπο του παρελθόντος της επιστήμης της πληροφορικής που δεν έχει καμία χρησιμότητα σήμερα. Αυτός ακριβώς ο μύθος θα επιχειρηθεί να καταρριφθεί με αυτό το άρθρο. Προφανώς και δεν θεωρώ ότι οι προγραμματιστές είναι γενικώς παραγωγικότεροι όταν προγραμματίζουν σε Assembly αντί κάποιας άλλης γλώσσας υψηλού επιπέδου, ούτε εξασφαλίζεται η φορητότητα του λογισμικού. Υπάρχουν όμως καταστάσεις που η απ' ευθείας επικοινωνία με το υλικό του υπολογιστή παράγει ταχύτατη απόκριση, με αποτέλεσμα η Assembly σήμερα να χρησιμοποιείται σε περιπτώσεις όπως είναι ο προγραμματισμός μικρο-ελεγκτών, όπου ο χρόνος αποτελεί κρίσιμο παράγοντα. Σ' αυτό λοιπόν το άρθρο θα επιχειρήσουμε να δείξουμε ότι η Assembly είναι δυνατόν να χρησιμοποιηθεί ακόμα και σε σύγχρονα συστήματα και κυρίως θα δούμε ότι μπορούμε να τρέξουμε ρουτίνες της γλώσσας, απ' ευθείας επάνω στο τρέχον υλικό του υπολογιστή, χωρίς να χρειάζεται λογισμικό προσομοίωσης. Στην εποχή μας οι επεξεργαστές που κυριαρχούν στο εμπόριο για επιτραπέζιους υπολογιστές είναι αυτοί της Intel με αρχιτεκτονική 64 bits. Υποθέτοντας βάσιμα ότι ο αναγνώστης διαθέτει έναν τέτοιο επεξεργαστή, επιλέγουμε να μιλήσουμε μόνο για την αρχιτεκτονική αυτή. Επιπλέον, αντί των Windows, επιλέγουμε να χρησιμοποιήσουμε το Linux γιατί η δομή του και η συνολική φιλοσοφία του ως λειτουργικό σύστημα διευκολύνει την ενασχόληση του χρήστη απ' ευθείας με το υλικό του υπολογιστή. Ξεκινώντας την περιήγησή μας στη γλώσσα, είναι σκόπιμο πριν απ' ο,τιδήποτε άλλο να μιλήσουμε για τους καταχωρητές των επεξεργαστών της Intel. Οι καταχωρητές οιουδήποτε επεξεργαστή είναι στην ουσία πολύ γρήγορες μνήμες που βρίσκονται πολύ κοντά στη CPU και κατά τον προγραμματισμό σε Assembly χρησιμοποιούνται κατά κόρον για την αποθήκευση και ανάκληση μικρών ποσοτήτων δεδομένων. Οι επεξεργαστές της Intel με αρχιτεκτονική 64 bits διαθέτουν 16 καταχωρητές συνολικά που όπως αναμένεται ο καθένας τους χωράει δεδομένα 64 bits ή αλλιώς 8 bytes. Οι 14 εξ αυτών μπορούν να χρησιμοποιηθούν για οποιοδήποτε σκοπό ενώ οι υπόλοιποι δύο αποτελούν καταχωρητές ειδικής χρήσης. Οι καταχωρητές γενικού σκοπού είναι : RAX, RBX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15 Να θυμάστε πάντα ότι αυτά τα 14 ονόματα καταχωρητών μπορούν να χρησιμοποιηθούν μόνο όταν θέλουμε να παράγουμε αποκλειστικά 64μπιτο εκτελέσιμο κώδικα. Όσοι αναγνώστες τυχόν νοσταλγούν την Assembly 8086/88 της δεκαετίας του 80 ή 90 ασφαλώς και αναγνωρίζουν τα πρώτα 6 ονόματα καταχωρητών με μόνη διαφορά την προσθήκη του R στην αρχή τους. Αυτό συμβαίνει επειδή οι σχεδιαστές των επεξεργαστών αυτών έχουν φροντίσει ώστε να υπάρχει συμβατότητα με παλαιότερα μοντέλα. Για παράδειγμα, εάν θέλουμε να προσπελάσουμε τα 4 πρώτα bytes του καταχωρητή RAX τότε το όνομά του πρέπει να αλλάξει σε EAX και μπορούμε να τον χειριστούμε άφοβα σαν να ήταν καταχωρητής 32 bit σε παλαιότερο επεξεργαστή. Επίσης στην περίπτωση που θέλουμε να προσπελάσουμε τα bytes 0-1 του RAX, μπορούμε να χρησιμοποιήσουμε άφοβα τα ονόματα AH και AL όπως ακριβώς θα έκανε ένας προγραμματιστής σε επεξεργαστή 8086/88. Το ίδιο ακριβώς συμβαίνει και με τους υπόλοιπους καταχωρητές και για να μη μακρηγορώ προτείνω σε όσους θέλουν να ανατρέξουν σε εγχειρίδια σχετικά με τον 8086/88. Καταχωρητής 64 bit Καταχωρητής 32 bit Καταχωρητής 16 bit Καταχωρητής 8 bit RAX EAX AX AL RCX ECX CX CL RDX EDX DX DL RBX EBX BX BL RSI ESI SI SIL RDI EDI DI DIL RSP (ειδ. χρήση) ESP (ειδ. χρήση) SP (ειδ. χρήση) SPL (ειδ. χρήση) RBP (ειδ. χρήση) EBP (ειδ. χρήση) BP (ειδ. χρήση) BPL (ειδ. χρήση) R8 R8D R8W R8B R9 R9D R9W R9B R10 R10D R10W R10B R11 R11D R11W R11B R12 R12D R12W R12B R13 R13D R13W R13B R14 R14D R14W R14B R15 R15D R15W R15B Είναι προφανές ότι σε σχέση με την αρχιτεκτονική του 8086/88 οι σχεδιαστές της Intel φρόντισαν να αυξήσουν κατά πολύ τους καταχωρητές γενικού σκοπού -τόσο σε πλήθος, όσο και σε χωρητικότητα- αλλά παράλληλα κατέβαλαν μεγάλη προσπάθεια ώστε ακόμα και κώδικας που συντάχτηκε πριν από 20 χρόνια να μπορεί να λειτουργήσει με ελάχιστες αλλαγές. Δεν κρίνω σκόπιμο να μιλήσουμε σήμερα για τους καταχωρητές ειδικής χρήσης, γιατί αυτοί αφορούν τη δομή δεδομένων του σωρού που θα μας χρειαστεί αργότερα. Σήμερα θα προσπαθήσουμε να συντάξουμε και να τρέξουμε ένα απλό πρόγραμμα που θα τυπώνει ένα μήνυμα στην οθόνη. Το πρόγραμμα που θα χρειαστούμε είναι ένας assembler που λέγεται yasm και είναι διαθέσιμος στα αποθετήρια λογισμικού όλων των γνωστών διανομών Linux. Πριν προχωρήσουμε, απλά εγκαταστήστε τον όπως ακριβώς θα εγκαθιστούσατε οποιοδήποτε άλλο λογισμικό στη διανομή σας. Όπως είναι γνωστό ο assembler θα παράγει αποκλειστικά object code, οπότε θα χρειαστούμε κι έναν linker για να μας δώσει το τελικό εκτελέσιμο αρχείο. Αυτός ονομάζεται ld, αλλά συνήθως είναι προ-εγκατεστημένος στις πιο πολλές διανομές. Αν τυχαίνει να μην τον έχει ήδη εγκαταστήσει η δική σας διανομή, ακολουθείστε τα συνήθη βήματα για να τον εγκαταστήσετε. Επόμενο βήμα είναι να ανοίξετε έναν οποιοδήποτε απλό κειμενογράφο και να πληκτρολογήσετε προσεκτικά τα παρακάτω : global _start _start: mov rax, 1 ; Κλήση της υπηρεσίας 1 σημαίνει εκτύπωση μηνύματος mov rdi, 1 ; Εδώ ορίζουμε το που θα εκτυπωθεί το μήνυμα. 1 = Standard συσκ. εξόδου mov rsi, message ; Διεύθυνση RAM που αποθηκεύτηκε το μήνυμα mov rdx, messagelen ; Μήκος μηνύματος σε bytes syscall ; Κλήση του πυρήνα του Linux mov rax, 60 ; Κλήση της υπηρεσίας 60 για επιστροφή στο λειτουργικό σύστημα xor rdi, rdi ; Στον καταχωρητή RDI φορτώνουμε τον κωδικό εξόδου syscall ; Κλήση του πυρήνα του Linux section .data message: db "Άσπρος Γάτος", 10 messagelen equ $-message Είναι πολλά αυτά που πρέπει να ειπωθούν εδώ και θα ξεκινήσω καλύτερα από την data section. Θα μπορούσα να την έχω γράψει στην αρχή του κώδικα αντί για το τέλος, αλλά αυτό δεν έχει σημασία. Μέσα σ’ αυτό το τμήμα προγράμματος ορίζουμε τις σταθερές τιμές που θέλουμε να χρησιμοποιήσουμε στο πρόγραμμά μας. Είναι σαν τη δήλωση CONST ας πούμε στην Pascal. Με την εντολή message db ορίζεται ότι θα έχουμε μία σταθερά που ονομάζεται message και θα είναι αλφαριθμητική. Ο αριθμός 10 στο τέλος είναι ο χαρακτήρας αλλαγής γραμμής. Με την εντολή messagelen equ $-message ορίζεται ότι θα έχουμε μία αριθμητική σταθερά με όνομα messagelen που θα ισούται με το μήκος του αλφαριθμητικού της σταθεράς message. Προσέξτε ότι οι αλφαριθμητικές σταθερές ορίζονται με τον τελεστή db και διπλά εισαγωγικά, ενώ οι αριθμητικές σταθερές ορίζονται με τον τελεστή equ. Επιπλέον η έκφραση “$-τάδε” σημαίνει “μήκος της σταθεράς τάδε σε bytes”. Ας πάμε τώρα στον κυρίως κώδικα. Ξεκινάμε δηλώνοντας ότι θα αποτελείται από μία ρουτίνα με καθολική ορατότητα που ονομάζεται start. Αυτή η ρουτίνα είναι σαν την main() της C. Αυτήν απαιτεί να βρει ο linker για να ξέρει από που θα ξεκινήσει. Όλοι όσοι έχουν ασχοληθεί έστω λίγο με Assembly στους επεξεργαστές Intel γνωρίζουν την εντολή MOV. H σύνταξή της είναι MOV καταχωρητής, τιμή και σημαίνει ότι απαιτούμε να φορτωθεί σε συγκεκριμένο καταχωρητή συγκεκριμένη τιμή. Φυσικά έχει κι άλλες μορφές, αλλά αυτή είναι η συνηθέστερη. Γενικά στον προγραμματισμό σε Assembly λειτουργούμε ως εξής. Για ό,τι κι αν θελήσουμε να κάνουμε, ανοίγουμε τον εγχειρίδιο και βρίσκουμε ποια είναι η κατάλληλη υπηρεσία του λειτουργικού συστήματος που πρέπει να κληθεί για να κάνει τη δουλειά που θέλουμε. Έπειτα βρίσκουμε ποιες είναι οι κατάλληλες παράμετροι και τις φορτώνουμε στους σωστούς καταχωρητές, πάλι σύμφωνα με το εγχειρίδιο γιατί αυτά κανείς δεν τα μαθαίνει απ’ έξω. Τέλος χρησιμοποιούμε συνήθως την εντολή syscall για να καλέσουμε τον πυρήνα του λειτουργικού συστήματος να διαβάσει τις τιμές στους καταχωρητές και να ενεργήσει κατάλληλα. Για να τυπώσουμε ένα μήνυμα θα χρειαστούμε την υπηρεσία υπ’ αριθμόν 1. Φορτώνουμε λοιπόν στον πρώτο καταχωρητή γενικού σκοπού τον αύξοντα αριθμό υπηρεσίας. Έπειτα στον καταχωρητή RDI φορτώνουμε το πού ακριβώς θα εκτυπωθεί το μήνυμά μας. Η τιμή 1 σημαίνει την οθόνη. Στον καταχωρητή RSI φορτώνουμε τη διεύθυνση της RAM που έχει αποθηκευτεί το μήνυμα που θέλουμε να τυπώσουμε. Στον καταχωρητή RDX φορτώνουμε μια τιμή που αντιστοιχεί στο μήκος του μηνύματος σε bytes. Στο τέλος καλούμε το λειτουργικό σύστημα να ενεργήσει μέσω της εντολής syscall. Φαινομενικά έχουμε τελειώσει, αλλά δεν είναι καθόλου έτσι. Τώρα πρέπει να δηλώσουμε ότι θέλουμε το λειτουργικό σύστημα να εγκαταλείψει το τρέχον πρόγραμμα και να ξαναπάρει τον έλεγχο. Να μας γυρίσει δηλαδή πίσω στο προτρεπτικό σήμα του Linux. Αν αυτό δεν το κάνουμε, το πρόγραμμα θα κολλήσει. Η αντίστοιχη υπηρεσία του λειτουργικού συστήματος είναι η υπ' αριθμόν 60 και δέχεται μόνο μία παράμετρο στον καταχωρητή RDI. Η παράμετρος αυτή είναι ο κωδικός σφάλματος που θέλουμε να επιστρέφει το πρόγραμμά μας προς το ίδιο το Linux. Αν η εκτέλεση έχει φτάσει μέχρι αυτό το σημείο, σημαίνει ότι όλα έχουν πάει καλά και ο κωδικός σφάλματος που θα επιστραφεί πρέπει να ισούται με 0. Κάνοντας αποκλειστική διάζευξη της τιμής του RDI με τον εαυτό της, προφανώς διασφαλίζουμε ότι όλα τα bits μηδενίστηκαν και στο τέλος καλούμε πάλι τον πυρήνα του Linux. Τώρα που τελειώσαμε απλά σώστε τη ρουτίνα σε απλό αρχείο κειμένου (έστω firstprog.asm) και μεταγλωττίστε το με τις εξής εντολές προς το Linux yasm -f elf64 firstprog.asm && ld firstprog.o Η παράμετρος -f elf64 ορίζει ότι θα παράγουμε αποκλειστικά 64μπιτο κώδικα. Όταν εκτελεστεί ο yasm παράγει ένα αρχείο object code που λέγεται firstprog.o ενώ η εντολή μετά το διπλό & καλεί τον linker για να δώσει το τελικό εκτελέσιμο. Παρατηρώ ότι το μέγεθος του τελικού εκτελέσιμου αρχείου είναι μόλις 928 bytes, πράγμα που δεν συμβαίνει με άλλες γλώσσες υψηλού επιπέδου. Αν θέλετε να παράγετε κώδικα στα 32 bits θα πρέπει να αλλάξετε το elf64 σε elf32 αλλά και να αλλάξετε τον κώδικα της ρουτίνας μας, ώστε να χρησιμοποιεί αποκλειστικά ονόματα 32μπιτων καταχωρητών, δηλ. πχ EAX αντί RAX κλπ. Ελπίζω με το κείμενο αυτό να έχω καταφέρει να δώσω μία ιδέα περί του πώς λειτουργεί η γλώσσα Assembly σε σύγχρονους επεξεργαστές. Αν επίσης έχω καταφέρει να αναζωπυρώσω το ενδιαφέρον για τη γλώσσα αυτή και για την απ' ευθείας επικοινωνία με το υλικό του Η/Υ θα έχω πετύχει το στόχο μου. Σε περίπτωση που υπάρξει αρκετό ενδιαφέρον και ανταπόκριση στο κείμενό μου αυτό, υπόσχομαι να επανέλθω. Σας ευχαριστώ πολύ, Ο Άσπρος Γάτος
  7. Καλημέρα ! Η εύρεση της ν-οστής ρίζας μιγαδικού απ' όσο θυμάμαι έχει δύο σκέλη. Συνήθως τον μιγαδικό μας τον δίνουνε στη μορφή z=α+βi. Οπότε το πρώτο στάδιο είναι να τον μετατρέψουμε σε πολική (τριγωνομετρική) μορφή με τους εξής τύπους : ρ=τετραγ.ριζα(α*α+β*β) Αυτό λέγεται μέτρο του μιγαδικού. Μετά υπολογίζουμε τη γωνία θ ως εξής : συνθ=α/ρ και ημθ=β/ρ. Οπότε ο αρχικός μιγαδικός z=α+βi γράφεται ως εξής : z=ρ(συνθ+iημθ) Αφού το ξεπεράσαμε αυτό το στάδιο, στόχος είναι να υψώσουμε τον z στη δύναμη 1/n. Αυτό σημαίνει ουσιαστικά n-οστή ρίζα. Έτσι ακριβώς γίνεται και με τους πραγματικούς. Η εύρεση π.χ. της κυβικής ρίζας του οκτώ ισούται με "οκτώ εις την 1/3". Για να το κάνεις αυτό υπάρχει ένας μαθηματικός τύπος που ονομάζεται "τύπος του De Moivre". Ορίζει έναν απλό τρόπο για να υψώνουμε οποιονδήποτε μιγαδικό (πολικής μορφής) σε οποιαδήποτε δύναμη. Σ' ένα παλιό βιβλίο για τη C++ από τα χρόνια στο πανεπιστήμιο έτυχε να βρω ένα σύνολο από ρουτίνες για να κάνεις ό,τι θέλεις με μιγαδικούς. Βλέπω ότι έχει μέσα και ύψωση μιγαδικού σε δύναμη και μετατροπές από και προς την πολική μορφή. Δεν θελω να κάνω τον έξυπνο, τον κώδικα αυτό φυσικά και δεν τον έγραψα μόνος μου, απλά δοκίμασα τις περισσότερες ρουτίνες και δουλεύουνε. Άρα τον αντιγράφω εδώ γιατί πιστεύω ότι θα βοηθήσει. #include<iostream> #include<cmath> #include<cstdlib> #include<iomanip> #define Pi 3.141592653589793 #define Eu 2.718281828459045 typedef long double ld; typedef long long int l; using namespace std; int signum(ld x) { return (0<x)-(x<0); } ld degtorad(ld deg) { cout.setf(ios::fixed); cout.precision(8); ld cnst=Pi/180.0; return deg*cnst; } ld radtodeg(ld rad) { cout.setf(ios::fixed); cout.precision(8); ld cnst=180.0/Pi; return rad*cnst; } class Complex { private: ld real; ld imag; public: Complex(ld re=0,ld im=0):real(re),imag(im){} ///Complex Constructor -- Assigns Real and Imaginary values... ///Complex(Complex& a){} ///Complex Copy Constructor -- @CurrentlyUnderConstruction... void Get() ///Gets the Real and Imaginary Parts of the Complex Number { cout<<"Enter Real Value = ";cin>>real; cout<<"Enter Imaginary Value = ";cin>>imag; cout<<endl; } void Print() ///Prints the Complex Number { if(imag>0) { cout<<"The Number is = "<<real<<" + "<<imag<<" i "<<endl; } else if(imag==0) { cout<<"The Number is = "<<real<<endl; } else if(imag<0) { cout<<"The Number is = "<<real<<" - "<<abs(imag)<<" i "<<endl; } else { cout<<"The Number is = "<<imag<<" i "<<endl; } } void Re(ld re) ///Sets the Real Part to 're' { real=re; } void Im(ld im) ///Sets the Imaginary Part to 'im' { imag=im; } ld Re() ///Returns the Real Part of the Complex Number { return real; } ld Im() ///Returns the Imaginary Part of the Complex Number { return imag; } ld Modulus() ///Returns |z| for Complex z { ld term=pow(real,2)+pow(imag,2); return sqrt(term); } ld Normal() ///Returns |z|^2 for Complex z { ld term=pow(real,2)+pow(imag,2); return term; } Complex Conjugate() ///Returns Conj(z) of Complex z { Complex res; res.real=real; res.imag=-imag; return res; } ld Argument() ///Returns The Slope's Angle of Complex in Argand Plane { ld term; term=atan2(imag,real); return radtodeg(term); } void Inverse() ///Returns Inverse of the Complex Number { imag=-imag; ld a=Normal(); real/=a; imag/=a; } void GetPolar() ///Gets the Complex z in Polar Form { ld arg,mod; cout<<"Enter the Argument - ";cin>>arg; cout<<"Enter the Modulus - ";cin>>mod; cout<<endl; ld newarg=degtorad(arg); real=mod*cos(newarg); imag=mod*sin(newarg); } void Polar1Print() ///Prints Polar form of z - r(cos(x)+isin(x)) { cout<<"The Polar Form is = "; cout<<Modulus()<<"( cos("<<Argument()<<")+sin("<<Argument()<<") )"<<endl; } void Polar2Print() ///Prints Polar form of z - re^ix { Complex term,t1(0,1),t2; term.real=t1.real*degtorad(Argument()); term.imag=t1.imag*degtorad(Argument()); t2.RaiseToComplex(Eu,term); cout<<"The Polar Form is = "; cout<<Modulus()<<"( e ^ "<<degtorad(Argument())<<"i )"<<endl; cout<<" OR "<<endl; cout<<"The Polar Form is = "; cout<<Modulus()<<"( "<<Eu<<" ^ "<<degtorad(Argument())<<"i )"<<endl; cout<<" OR "<<endl; cout<<"The Polar Form is = "; if(imag>0) cout<<Modulus()<<"( "<<t2.real<<" + "<<t2.imag<<" i )"<<endl; else if(imag<0) cout<<Modulus()<<"( "<<t2.real<<" - "<<abs(t2.imag)<<" i )"<<endl; } Complex Polar(ld mod,ld arg) ///Converts Polar Form of the Complex Number to Original Form { Complex res; ld newarg=degtorad(arg); res.real=mod*cos(newarg); res.imag=mod*sin(newarg); return res; } void Root(Complex& x1, Complex& x2) ///Returns Square Roots of Complex z in x1 and x2 { ld a=Modulus(); x1.real=sqrt((a+real)/2); x1.imag=signum(imag)*sqrt((-real+a)/2); x2.real=-(sqrt((a+real)/2)); x2.imag=-(signum(imag)*sqrt((-real+a)/2)); } Complex* Root(int m) ///Returns nth Roots of Complex z in Complex array { int n=abs(m); Complex *z=new Complex[n]; ld rn=pow(Modulus(),1.0/n); ld narg=(degtorad(Argument()))/n; ld npi=(2.0*Pi)/n; for(int i=0;i<n;i++) { z[i]=Complex(0,0); } for(int k=0;k<n;k++) { if(n>0) z[k]=Complex(rn*cos(narg+k*npi),rn*sin(narg+k*npi)); else z[k]=Complex(rn*cos(narg+(-k)*npi),rn*sin(narg+(-k)*npi)); } return z; } void Rotate(ld angle) ///Rotates the Complex Number by 'angle' Degrees { ld a=Modulus(),b=Argument(); b+=angle; ld bx=degtorad(b); real=a*cos(bx); imag=a*sin(bx); } void RaiseToComplex(ld a,Complex& z) ///Returns a raised to Complex z { cout.precision(8); cout.setf(ios::fixed); ld t1,t2,t3; t1=pow(a,z.real); t2=cos(z.imag*log(a)); t3=sin(z.imag*log(a)); real=t1*t2; imag=t1*t3; } Complex Cos() ///Returns Cosine of Complex z { Complex res,t1(0,1),t2(0,-1),t3,t4,t5,t6,t7; t3.real=(real*t1.real)-(imag*t1.imag); t3.imag=(real*t1.imag)+(imag*t1.real); t4.real=(real*t2.real)-(imag*t2.imag); t4.imag=(real*t2.imag)+(imag*t2.real); t5.RaiseToComplex(2.718281828459045,t3); t6.RaiseToComplex(2.718281828459045,t4); t7=t5+t6; res.real=t7.real/2; res.imag=t7.imag/2; return res; } Complex Cosh() ///Returns Hyperbolic Cosine of Complex z { Complex res,t1(real,imag),t2(-real,-imag),t3,t4,t5; t3.RaiseToComplex(2.718281828459045,t1); t4.RaiseToComplex(2.718281828459045,t2); t5=t4+t3; res.real=t5.real/2; res.imag=t5.imag/2; return res; } Complex Sin() ///Returns Sine of Complex z { Complex res,t(0,1),t1(0,1),t2(0,-1),t3,t4,t5,t6,t7,t8; t3.real=(real*t1.real)-(imag*t1.imag); t3.imag=(real*t1.imag)+(imag*t1.real); t4.real=(real*t2.real)-(imag*t2.imag); t4.imag=(real*t2.imag)+(imag*t2.real); t5.RaiseToComplex(2.718281828459045,t3); t6.RaiseToComplex(2.718281828459045,t4); t7=t6-t5; t8=t7*t; res.real=t8.real/2; res.imag=t8.imag/2; return res; } Complex Sinh() ///Returns Hyperbolic Sine of Complex z { Complex res,t1(real,imag),t2(-real,-imag),t3,t4,t5; t3.RaiseToComplex(2.718281828459045,t1); t4.RaiseToComplex(2.718281828459045,t2); t5=t3-t4; res.real=t5.real/2; res.imag=t5.imag/2; return res; } Complex Tan() ///Returns Tangent of Complex z { Complex res,t1,t2; t1=Sin(); t2=Cos(); res=t1/t2; return res; } Complex Tanh() ///Returns Hyperbolic Tangent of Complex z { Complex res,t1,t2; t1=Sinh(); t2=Cosh(); res=t1/t2; return res; } Complex Exp() { Complex res; res.RaiseToComplex(Eu,*this); return res; } Complex Log(ld base) ///Returns Log of the Complex No. to the base { Complex res; res.real=log(Modulus())/((log(base))); res.imag=degtorad(Argument())/((log(base))); return res; } bool operator==(const Complex& rhs) ///Checks if the Complex Numbers are Equal { return(real==rhs.real&&imag==rhs.imag); } bool operator!=(const Complex& rhs) //Checks if the Complex Numbers are Unequal { return(real!=rhs.real&&imag!=rhs.imag); } Complex operator~() ///Returns Conjugate of the Complex Number { *this=Conjugate(); return *this; } Complex operator+(Complex rhs) ///Adds Two Complex Numbers { Complex res; res.real=real+rhs.real; res.imag=imag+rhs.imag; return res; } Complex operator+(ld rhs) ///Adds Constant to Complex Number { Complex res; res.real=real+rhs; res.imag=imag; return res; } Complex operator-(Complex rhs) ///Subtracts Two Complex Numbers { Complex res; res.real=real-rhs.real; res.imag=imag-rhs.imag; return res; } Complex operator-(ld rhs) ///Subtracts Constant from Complex Number { Complex res; res.real=real-rhs; res.imag=imag; return res; } Complex operator*(Complex rhs) ///Multiplies Two Complex Numbers { Complex res; res.real=(real*rhs.real)-(imag*rhs.imag); res.imag=(real*rhs.imag)+(imag*rhs.real); return res; } Complex operator*(ld rhs) ///Multiplies Complex z by a Constant { Complex res; res.real=real*rhs; res.imag=imag*rhs; return res; } Complex operator/(Complex rhs) ///Divides Two Complex Numbers { rhs.Inverse(); Complex res; res.real=(real*rhs.real)-(imag*rhs.imag); res.imag=(real*rhs.imag)+(imag*rhs.real); return res; } Complex operator/(ld rhs) ///Divides Complex z by a Constant { Complex res; res.real=real/rhs; res.imag=imag/rhs; return res; } void operator+=(Complex rhs) ///Adds z2 to z1 { real+=rhs.real; imag+=rhs.imag; } void operator-=(Complex rhs) ///Subtracts z2 from z1 { real-=rhs.real; imag-=rhs.imag; } void operator*=(Complex rhs) ///Multiplies z2 and z1 and returns to z1 { real=(real*rhs.real)-(imag*rhs.imag); imag=(real*rhs.imag)+(imag*rhs.real); } void operator/=(Complex rhs) ///Divides z2 and z1 and returns to z1 { rhs.Inverse(); real=(real*rhs.real)-(imag*rhs.imag); imag=(real*rhs.imag)+(imag*rhs.real); } void operator+=(ld rhs) ///Adds Constant to z1 { real+=rhs; imag=imag; } void operator-=(ld rhs) ///Subtracts Constant from z1 { real-=rhs; imag=imag; } void operator*=(ld rhs) ///Multiplies z1 with a Constant and returns to z1 { real*=rhs; imag*=rhs; } void operator/=(ld rhs) ///Divides z1 with a Constant and returns to z1 { real/=rhs; imag/=rhs; } Complex operator^(ld power) ///Returns Complex z Raised to 'power' { ld a,b; a=Modulus(); b=pow(a,power); ld c,d; d=Argument(); c=degtorad(d); Complex res; res.real=b*cos(power*c); res.imag=b*sin(power*c); return res; } Complex operator^(Complex b) ///Returns Complex z1 raised to Complex z2 { Complex res,t1(0,1),t2(b.real/2,b.imag/2),t3,t4,t5,t6; ld a1,a2; a1=Normal();a2=degtorad(Argument()); t3.RaiseToComplex(a1,t2); t4=t1*b; t5.real=t4.real*a2; t5.imag=t4.imag*a2; t6.RaiseToComplex(Eu,t5); res=t6*t3; return res; } ~Complex(){} ///Complex Destructor -- Does Nothing till now... ///Non - Member friend Overloads... friend Complex operator+(ld rhs,Complex c) { return(Complex(c.real+rhs,c.imag)); } friend Complex operator-(ld rhs,Complex c) { return(Complex(c.real-rhs,c.imag)); } friend Complex operator*(ld rhs,Complex c) { return(Complex(c.real*rhs,c.imag*rhs)); } friend Complex operator/(ld rhs,Complex c) { return(Complex(c.real/rhs,c.imag/rhs)); } friend Complex operator^(ld rhs,Complex c) { Complex res; ld t1,t2,t3; t1=pow(rhs,c.real); t2=cos(c.imag*log(rhs)); t3=sin(c.imag*log(rhs)); res.real=t1*t2; res.imag=t1*t3; return res; } }; Να είστε όλοι καλά, Ο Άσπρος Γάτος
  8. White_Cat

    προγραμματισμός c++

    Καλησπέρα ! Αν θέλεις μπορείς να μας γράψεις ή να επισυνάψεις τις εκφωνήσεις και θα προσπαθήσουμε να βοηθήσουμε. Φιλικά, Ο Άσπρος Γάτος
  9. Καλησπέρα ! Συμφωνώ κι εγώ ότι θα πρέπει να γίνεις λίγο πιο συγκεκριμένος. Τι ακριβώς είναι αυτό που θέλεις να φτιάξεις και σε ποια γλώσσα προγραμματισμού ; Ο Άσπρος Γάτος
  10. Καλησπέρα ! Αν το laptop εκτός του δίσκου του, είναι γενικά σε καλή κατάσταση, τότε δεν μπορώ να συμφωνήσω με την άποψη ότι είναι καιρός να "ξεκουραστεί". Στο e-Bay βρήκα αυτόν εδώ το δίσκο (https://www.ebay.co.uk/itm/Fujitsu-MHV2080AT-IDE-80-GB-2-5-Hard-disk/324027410342?_trkparms=ispr%3D1&hash=item4b7189e7a6:g:EK8AAOSw64ZeCfxE&enc=AQAEAAACYIQvEcHUrT7nmUC3yY5qbPyaBN1nJEDYW8MyypsJPgXKtMiVu7s8Kj2Ur48i56ldd3v6YYSZYHEvxcrtnVs9gWGyWT2rdVCOxyKoBQEH88eTDQPpRwUg25VGJd0hqakJe3yR3wW51RDULKNtxa0VUDZqnYcSawJLm7KqAaFmohjzWcviMUpo1F%2F2UfrVPczE%2BqPpuNPFcmOiA%2FQoLondU%2FZDdzLi0DeH33S%2FIHZhpUXzupN%2BoXsIbSRKZTEEB2gUvV91nfTdJMw9qSkXVxclva%2BlnxCmD1tyCa7z%2FPMHfry5AHIT%2F%2FFvrddqnbOnSLYUZjgKk9I9ji3nALayikkeCmzWe41tOixnVGJ6hIr1AXpeQOHMNQyptAcNEBcUCbQquE1bopF%2BFetTvrmbUGW4XXO38wjvsnQ7lb90WeFIL%2FA%2FFere0r7cRBDuTzFogPRlC4JCDMXuyuw3RuJlb2zEubQPZWlxGv9OHRZrcp5GBQhbbrT1Md9elBvjoilKR1aepRRBsr5HGFbGi5lmjHG1LPSzQnVwfqN4Ha0jN20fPqJpJu4BpVbPTsX9KxXkwq8SomD4atkRLMLKKRjjBCA22IZ%2BPO6RtLnaHFZyaCTdIkn0u%2Fp8H5XechUqBG%2Bb%2FvtJTaIWohTkczmS338Kor2Mqi5B0eZHd9MXyY5qTh9eueaubcpCMrF3ZCZE0EN3CqsX10hmEjwNu8Ue5ObxZ8KnnkLfEgW7mta0E6%2FMa%2BTbHiVwZJZoIoGImd%2B6aep13NWl%2F7OCTJcdkyZ%2FFsXUDz9dCU%2B3MzQraVXrLwUVpljpoQyN&checksum=324027410342991d2ed9b2c34c7bacc886956e3dcff0) Μπορείς να τον αντικαταστήσεις αν θέλεις και μετά να εγκαταστήσεις ένα κατάλληλο λειτουργικό σύστημα (ας πούμε Linux), ώστε να έχεις τη δυνατότητα να εκτελείς απλές εργασίες γραφείου. Αν δε θέλεις να μπεις σ' αυτή τη διαδικασία, προτείνω να βάλεις αγγελία στο Insomnia και να το πουλήσεις, μιας και εδώ έχουμε αρκετά άτομα που αγαπούν το Retro Computing. Ευχαριστώ, Ο Άσπρος Γάτος
  11. White_Cat

    MIPS ASSEMBLY

    Καλησπέρα ! Κατ' αρχήν συγνώμη που άργησα ν' απαντήσω, το μήνυμά σου το είδα μόλις τώρα. Το τμήμα κώδικα C που δίνεις ουσιαστικά αυτό που κάνει είναι να φορτώνει σ' ένα μονοδιάστατο πίνακα 10 ακεραίους και μετά να βρίσκει το άθροισμά τους διατρέχοντας τον πίνακα. Έγραψα λοιπόν ένα προγραμματάκι που κάνει ακριβώς αυτή τη δουλειά σε MIPS Assembly και το δίνω παρακάτω. Το άθροισμα των στοιχείων του πίνακα είναι ίσο με 169 και στο τέλος της ρουτίνας φορτώνεται στον καταχωρητή t0. Έχω βάλει αγγλικά σχόλια στον κώδικα, γιατί ο emulator που έχω δεν υποστηρίζει ελληνικά. Ελπίζω να βοηθήσει και για οποιαδήποτε απορία εδώ είμαστε. Φιλικά, Ο Άσπρος Γάτος .data array: .word 1,15,0,-3,99,48,-17,-9,20,15 arrend: sumMessage: .asciiz "The SUM is equal to " newLine: .asciiz "\n" .text main: li $t0,0 # sum = 0 la $t3,array # load base addr. of array la $t2,arrend # load address of array end j test loop: lw $t4,0($t3) # load array[i] addi $t3,$t3,4 # increment array pointer add $t0,$t0,$t4 # update sum test: blt $t3,$t2,loop # more to do? if yes, loop # print sum message li $v0,4 la $a0,sumMessage syscall # print value of sum li $v0,1 addi $a0,$t0,0 syscall # print new line li $v0,4 la $a0,newLine syscall li $v0,10 syscall
  12. Καλησπέρα ! Αν θέλεις ρίξε μια ματιά στο βιβλίο 'C για αρχαρίους' του Β. Σεφερίδη. Γράφτηκε πριν από 25 χρόνια περίπου αλλά είναι πάρα πολύ καλό και ξεκινάει απ' τα απολύτως βασικά. https://www.public.gr/product/books/greek-books/computer-science/programming/c-gia-arharioys/prod253709/ Να είσαι καλά, Ο Άσπρος Γάτος
  13. Καλή σας ημέρα ! Είμαι βέβαιος ότι αυτή η ιδέα της ενοποίησης και κυρίως της "προς τα πίσω" συμβατότητας θα δώσει μεγάλο πλεονέκτημα στη Microsoft. Επιπλέον πιστεύω ότι αυτός είναι κι ένας από τους λόγους που η συγκεκριμένη εταιρεία κατέχει τη μερίδα του λέοντος στον τομέα του λογισμικού εδώ και πολλά χρόνια. Αρκεί να θυμηθούμε τα γνωστά Compatibility layers που έχει ενσωματώσει η εταιρεία στις περισσότερες εκδόσεις των Windows, με αποτέλεσμα μεγάλο ποσοστό παλιών εφαρμογών να μπορούν να λειτουργήσουν απρόσκοπτα ακόμα και σήμερα. Για να εχουμε ένα μέτρο σύγκρισης, ας μην ξεχνάμε ότι όταν π.χ. βγήκε το Mac OS System 7 (το λεγόμενο Big Bang) στα μέσα Μαϊου του 1991 -ενώ εγώ ήμουν μόλις 11 χρόνων-, οι μισές εφαρμογές του System 6 δεν δουλεύανε στο νέο λειτουργικό. Αυτό κι αν αποτελεί ασέβεια για την επένδυση του χρήστη ! Ναι μεν μπορεί λοιπόν η Microsoft να κατηγορείται για διάφορα πράγματα, αλλά στον τομέα της συμβατότητας τα έχει πάει καλά και οφείλουμε σ' αυτό να είμαστε δίκαιοι στην κριτική μας. Ευχαριστώ, Ο Άσπρος Γάτος
  14. White_Cat

    Assembly sos

    Καλημέρα ! Όταν ήμουν κι εγώ στο πανεπιστήμιο είχα παιδευτεί πολύ με την assembly γι' αυτό καταλαβαίνω την κατάσταση απόλυτα. Εκείνο όμως που πρέπει να γνωρίζεις είναι ότι, λόγω του ότι η γλώσσα αυτή είναι χαμηλού επιπέδου γλώσσα, ο κάθε επεξεργαστής έχει την εντελώς δική του εκδοχή assembly. Άρα λοιπόν όταν ζητάς βοήθεια σε τέτοια γλώσσα, θα πρέπει να προσδιορίζεις ακριβώς για ποιο είδος assembly πρόκειται. Αλλιώς η εκφώνηση είναι ημιτελής. Αυθαίρετα θα υποθέσω λοιπόν ότι πρόκειται για την assembly του επεξεργαστή 8086, μόνο και μόνο για να μπορέσω να προχωρήσω. Αυτή την εκδοχή της γλώσσας τη διαλέγω επειδή είναι γενικά δημοφιλής για διδακτικούς σκοπούς και επιπλέον επειδή παλιά είχα τον Amstrad 1640 με επεξεργαστή 8086 κι επομένως πάνω-κάτω γνωρίζω την αρχιτεκτονική του. Η αρχιτεκτονική του 8086 ορίζει ότι η κάθε θέση μνήμης μπορεί ν' αποθηκεύσει αριθμούς των οκτώ bit. Εδώ τα δεδομένα εισόδου είναι 16 bit συνολικά και επομένως θα πρέπει να είναι αποθηκευμένα σε δύο διαφορετικές θέσεις μνήμης. Αν είχαμε το πλήρες κείμενο της εκφώνησης θα μας όριζε σε ποιες θέσεις ακριβώς έχουν αποθηκευτεί, ή τέλος πάντων από πού θα τα διαβάσουμε. Θ' αναγκαστώ και πάλι αυθαίρετα να υποθέσω ότι το πρώτο byte βρίσκεται στη θέση 1000 και το άλλο στη θέση 1001. Αφού λοιπόν κατασκευάσαμε όσα δεδομένα λείπουν απ' την εκφώνηση, ας ξεκινήσουμε να σκεπτόμαστε τον κώδικα. Η πρώτη εντολή πρέπει απλά να λέει «φόρτωσε τα περιεχόμενα της θέσης 1000 σ' έναν καταχωρητή γενικού σκοπού». Ποιος είναι ο πιο γνωστός καταχωρητής γενικού σκοπού του 8086 ; Είναι ο AX και έχει χωρητικότητα 16 bit συνολικά. Αποτελείται από τους καταχωρητές AH & AL (υψηλής τάξης byte και χαμηλής τάξης byte αντιστοίχως). Η εντολή για να φορτώσουμε τα περιεχόμενα μιας θέσης μνήμης σε κάποιον καταχωρητή είναι η MOV και πάντα πρέπει να θυμόμαστε ότι ο αύξων αριθμός θέσης μνήμης μπαίνει σε αγκύλη. MOV AL,[1000] MOV AH,[1001] Η αντιστροφή μπορεί να γίνει με την χρήση της εντολής ROL ας πούμε ανά 4 bit ως εξής : ROL AL,4 ROL AH,4 Τελικά η αποθήκευση μπορεί να γίνει στις ίδιες θέσεις μνήμης ως εξής : MOV [1000],AH MOV [1001], AL Υπάρχει κάτι τελευταίο που πρέπει οπωσδήποτε να πω. Η τελευταία εντολή κάθε προγράμματος assembly πρέπει πάντα να διασφαλίζει ότι το πρόγραμμα θα παραδώσει τα ηνία στο «μητρικό» πρόγραμμα και δεν θα κολλήσει. Συνήθως πρόκειται για το λειτουργικό σύστημα. Αυτή η εντολή στην Assembly του 8086 λέγεται RET. Ο Άσπρος Γάτος
  15. Καλημέρα ! Όπως έχω πει και παλιότερα, έχω τελειώσει πληροφορική και απ' όσα έχω δει γενικά συμφωνώ με αυτό που λες ότι δεν υπάρχει κάπου που να διδάσκεται εντελώς καθαρός προγραμματισμός. Αυτό πιστεύω ότι δικαιολογείται με βάση το ότι για να γίνει κανείς καλός προγραμματιστής, δεν αρκεί να απομνημονεύσει τις εντολές κάποιας γλώσσας προγραμματισμού. Πριν απ' όλα πρέπει να διδαχθεί τις βασικές αρχές της αλγοριθμικής και φυσικά των μαθηματικών, ώστε να μπορεί να σκέφτεται προγραμματιστικά. Άρα λοιπόν θεωρώ ότι σε όποιο πανεπιστήμιο κι αν φοιτήσεις, θα διδαχθείς κατ' αρχήν βασικές αρχές αλγοριθμικής και μαθηματικών και μετά μ' αυτά τα εφόδια μπορείς να προχωρήσεις μόνος σου σε ό,τι θέλεις. Εμείς στη σχολή από καθαρές γλώσσες προγραμματισμού κάναμε στο πρώτο έτος C και Pascal, στο δεύτερο έτος Assembly, κώδικα μηχανής και ψηφιακή σχεδίαση, στο τρίτο έτος Java και Prolog και στο τέταρτο έτος άλλα μαθήματα που δεν είχαν άμεση σχέση με κάποια γλώσσα (διδακτική του προγραμματισμού, ασφάλεια δικτύων/κρυπτογραφία). Αφήστε που είμαι και 40++ χρονών ήδη και δεν μπορώ να θυμάμαι τα πάντα. Θυμάμαι ότι και τότε αγαπούσα πολύ την Prolog που δεν άρεσε σε κανέναν άλλο. Εγώ είμαι παράξενος τελικά ή όλοι οι άλλοι ; :-) Αυτά τα ολίγα, Ο Άσπρος Γάτος
×
×
  • Δημιουργία νέου...

Χρήσιμες πληροφορίες

Με την περιήγησή σας στο insomnia.gr, αποδέχεστε τη χρήση cookies που ενισχύουν σημαντικά την εμπειρία χρήσης.