Kompilieren in C/C++: Zuerst in Assembler umwandeln?


  • Administrator

    Mir wäre nicht bekannt, dass es irgendwo eine Vorschrift gibt, dass ein C++ Kompiler zuerst Assembler Code erstellen muss, bevor er die Sache linkt. Das ist meiner Meinung nach völlig freigestellt, wie ein Kompiler das machen will.

    Grüssli



  • Dravere schrieb:

    Mir wäre nicht bekannt, dass es irgendwo eine Vorschrift gibt, dass ein C++ Kompiler zuerst Assembler Code erstellen muss, bevor er die Sache linkt. Das ist meiner Meinung nach völlig freigestellt, wie ein Kompiler das machen will.

    Grüssli

    Hmm. Klar, vorgeschrieben ist das im Standard nicht, aber imo kann man davon ausgehen, dass gängige Implementierungen das über die Assemblersprache lösen und man den generierten Code anschauen kann.


  • Administrator

    drakon schrieb:

    Hmm. Klar, vorgeschrieben ist das im Standard nicht, aber imo kann man davon ausgehen, dass gängige Implementierungen das über die Assemblersprache lösen und man den generierten Code anschauen kann.

    Davon würde ich nicht ausgehen. Die meisten Kompiler verwenden eine eigene Zwischensprache, da sich die Assemblersprachen von CPU zu CPU unterscheiden. Von der Zwischensprache wird dann wahrscheinlich nicht noch mühsam über die Assemblersprache zur Maschinensprache gegangen, sondern der direkte Weg genommen.
    Natürlich kann man, wenn man das möchte, Assemblercode als Ausgabe wählen. Maschinensprache und Assemblercode sind ja gründsätzlich 1:1 übersetzbar.

    Grüssli



  • drakon schrieb:

    Dravere schrieb:

    Mir wäre nicht bekannt, dass es irgendwo eine Vorschrift gibt, dass ein C++ Kompiler zuerst Assembler Code erstellen muss, bevor er die Sache linkt. Das ist meiner Meinung nach völlig freigestellt, wie ein Kompiler das machen will.

    Grüssli

    Hmm. Klar, vorgeschrieben ist das im Standard nicht, aber imo kann man davon ausgehen, dass gängige Implementierungen das über die Assemblersprache lösen und man den generierten Code anschauen kann.

    Ich kenne keinen Compiler der wirklich noch über Assembler geht. Viele *können* Assembler Code ausgeben, wenn man das verlangt, aber die meisten verwenden intern nicht den Zwischenschritt über Assembler. Wie Dravere geschrieben hat: wäre auch ziemlich sinnlos (sinngemäss).



  • Zur Referenz hier der entsprechende Ausschnitt aus dem Standard, der rein garnichts über die Art von Zwischencodes aussagt:

    INTERNATIONAL ISO/IEC STANDARD 14882 §2.1 schrieb:

    2.1 Phases of translation [lex.phases]

    1 The precedence among the syntax rules of translation is specified by the following phases.13)

    • 1. Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences (2.3) are replaced by corresponding single-character internal representations. Any source file character not in the basic source character set (2.2) is replaced by the universal-character-name that designates that character. (An implementation may use any internal encoding, so long as an actual extended character encountered in the source file, and the same extended character expressed in the source file as a universal-character-name (i.e. using the \uXXXX notation), are handled equivalently.)
    • 2. Each instance of a new-line character and an immediately preceding backslash character is deleted, splicing physical source lines to form logical source lines. If, as a result, a character sequence that matches the syntax of a universal-character-name is produced, the behavior is undefined. If a source file that is not empty does not end in a new-line character, or ends in a new-line character immediately preceded by a backslash character, the behavior is undefined.
    • 3. The source file is decomposed into preprocessing tokens (2.4) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or partial comment14). Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined. The process of dividing a source file's characters into preprocessing tokens is context-dependent. [Example: see the handling of < within a #include preprocessing directive. ]
    • 4. Preprocessing directives are executed and macro invocations are expanded. If a character sequence that matches the syntax of a universal-character-name is produced by token concatenation (16.3.3), the behavior is undefined. A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively.
    • 5. Each source character set member, escape sequence, or universal-character-name in character literals and string literals is converted to a member of the execution character set (2.13.2, 2.13.4).
    • 6. Adjacent ordinary string literal tokens are concatenated. Adjacent wide string literal tokens are concatenated.
    • 7. White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. (2.6). The resulting tokens are syntactically and semantically analyzed and translated. [Note: Source files, translation units and translated translation units need not necessarily be stored as files, nor need there be any one-to-one correspondence between these entities and any external representation. The description is conceptual only, and does not specify any particular implementation. ]
    • 8. Translated translation units and instantiation units are combined as follows: [Note: some or all of these may be supplied from a library. ] Each translated translation unit is examined to produce a list of required instantiations. [Note: this may include instantiations which have been explicitly requested (14.7.2). ] The definitions of the required templates are located. It is implementation-defined whether the source of the translation units containing these definitions is required to be available. [Note: an implementation could encode sufficient information into the translated translation unit so as to ensure the source is not required here. ] All the required instantiations are performed to produce instantiation units. [Note: these are similar to translated translation units, but contain no references to uninstantiated templates and no template definitions. ] The program is ill-formed if any instantiation fails.
    • 9. All external object and function references are resolved. Library components are linked to satisfy external references to functions and objects not defined in the current translation. All such translator output is collected into a program image which contains information needed for execution in its execution environment.

    13)Implementations must behave as if these separate phases occur, although in practice different phases might be folded together.
    14)A partial preprocessing token would arise from a source file ending in the first portion of a multi-character token that requires a terminating sequence of characters, such as a header-name that is missing the closing " or >. A partial comment would arise from a source file ending with an unclosed /* comment.



  • Hat ja auch keiner behauptet das man es so machen muss.
    Der Kompilerhersteller macht das so wie er meint das es am besten ist.
    Es wird gemacht weil es einfacher ist als direkt in Maschinensprache um zu setzen. Um so abstrakter die Sprache von der Maschinensprache ist, um so schwieriger ist es in diese direkt um zu wandeln.

    Auf der gcc-Seite habe ich mal vor längerer Zeit etwas darüber gelesen. Eventuell da mal suchen und sich das anschauen.



  • schminkköfferchen schrieb:

    Es wird gemacht weil es einfacher ist als direkt in Maschinensprache um zu setzen. Um so abstrakter die Sprache von der Maschinensprache ist, um so schwieriger ist es in diese direkt um zu wandeln.

    Das ist nicht der Grund. Es ist naemlich deutlich aufwendiger erst eine Zwischensprache zu erfinden als gleich direkt in Maschinensprache zu Uebersetzen.

    Die Idee dahinter ist einfach nur Abstraktion. Man trennt den Compiler in Backend und Frontend. Das Backend bekommt die Zwischensprache und wandelt sie in die jeweilige Maschinensprache um. Das Frontend generiert die Zwischensprache.

    Der Vorteil ist nun, ich kann unterschiedliche Frontends verwenden, zB fuer C++, Java, OCaml, Objective-C,... und alle generieren mir die passende Zwischensprache fuer das Backend. Und das Backend tausche ich je nach Plattform aus.

    Weiters kann ich die Zwischensprache auch gut optimieren und ich habe einen Optimizer der fuer jede Frontend Sprache funktioniert. Das Spart auch wieder viel Arbeit.



  • Ja ok, danke. Hatte das nicht mehr genau in Erinnerung. Aber so wie du es sagst steht es auch auf den entsprechenden Seiten.
    Die Links zu Register Transfer Language.
    http://gcc.gnu.org/onlinedocs/gccint/
    http://gcc.gnu.org/onlinedocs/gccint/RTL.html



  • Assembler ist doch Maschinensprache. Das ist wie zu fragen: "ich hab gehoert, dass du eine Zahl, bevor sie ins Englische uebersetzt wird, erst ins Hexadezimale uebersetzt wird, stimmt das?"... oder lieg ich grad daneben?



  • Wenn Assembler Maschinensprache ist, wie bezeichnest du dann das wo man "mov eax, 0" schreibt, statt der entsprechenden Bytefolge in Maschinensprache?



  • hustbaer schrieb:

    Wenn Assembler Maschinensprache ist, wie bezeichnest du dann das wo man "mov eax, 0" schreibt, statt der entsprechenden Bytefolge in Maschinensprache?

    Ich meinte damit: es gibt eine eins-zu-eins Entsprechung, "mov eax, 0" ist nur eine andere Schreibweise fuer die entsprechende Bitfolge.



  • Blue-Tiger schrieb:

    hustbaer schrieb:

    Wenn Assembler Maschinensprache ist, wie bezeichnest du dann das wo man "mov eax, 0" schreibt, statt der entsprechenden Bytefolge in Maschinensprache?

    Ich meinte damit: es gibt eine eins-zu-eins Entsprechung, "mov eax, 0" ist nur eine andere Schreibweise fuer die entsprechende Bitfolge.

    Ich kann auch "mov eax, 10 + 20" schreiben. In Maschinensprache übersetzt und wieder zurück ergibt das dann "mov eax, 30", also nichtmehr dasselbe.
    Davon abgesehen hab' ich in Assembler meist haufenweise Bezeichner (Labels), die alle die Übersetzung in Maschinensprache nicht überleben.

    Aber zurück zum eigentlichen Thema: die Frage des OP ist nicht ganz unberechtigt, denn viele Compiler haben ursprünglich so gearbeitet. D.h. die haben wirklich Textfiles ausgespuckt mit Assembler-Code drinnen, und den dann erst durch einen Assembler gejagt.


Anmelden zum Antworten