Einen Assembler programmieren



  • Hallo,

    ein Assembler soll ja angeblich einfach nur die Mnemonics durch Opcodes des Prozessors ersetzen. Jedoch finde ich weder zur Programmierung eines Assemblers noch zu Opcodes viel im Internet. Ich wollte daher mal Fragen ob ihr irgendwo mal irgendwelche Tutorials, Papers oder so zur Programmierung eines Assemblers für x86 habt.

    Vielen Dank im Voraus



  • Assembler schrieb:

    Jedoch finde ich weder zur Programmierung eines Assemblers noch zu Opcodes viel im Internet.

    Vielleicht solltest du mal googeln üben?



  • Außer einem abgebrochenen Tutorial, wie man Crypter schreibt und dem seit Jahren nicht vervollständigtem Tutorial "The Art of Disassembling" habe ich nichts finden können und auch der Quellcode von FASM hilft mir leider nicht viel weiter. Ich wäre also sehr dankbar, wenn jemand mir auch nur ein gutes Stichwort ("Assembler programmieren" führt logischerweise nicht zu dem gewünschten Ergebnis :)) gibt.

    Vielen Dank im Voraus



  • http://ref.x86asm.net/

    Du musst eine Instruktion parsen, die Typen der Parameter bestimmen (Also Register, Memory, Immediate), den passenden OP-Code rausschreiben + die Parameter.
    Nicht schwierig aber viel Fleissarbeit.

    Tipp: Ein Disassembler ist einfacher, also Opcodes interpretieren.


  • Mod

    Sprichst du überhaupt selber eine Assemblersprache?

    Falls nein: Könnte vielleicht ganz hilfreich sein 😃
    Falls ja: Womit genau hast du Probleme? Erkenne die Mnemonics, erkenne die Operanden*, guck in einer Tabelle nach dem zu beidem passenden Opcode, fertig. Zumindest für ganz triviale Programme. Labels, Makros, Kommentare und ähnliches brauchen ein bisschen mehr. Aber ich habe den Eindruck, du scheiterst schon viel früher, daher hole ich gar nicht weiter aus. Daher: Stell mal konkrete Fragen, was du wissen möchtest. Jammern, dass du keine Tutorials findest, ist keine Frage. Denn eigentlich solltest du überhaupt kein Tutorial benötigen, wenn du ein Projekt wie dieses planst. Falls doch, dann bist du mit dem Vorhaben überfordert und müsstest erst einmal darüber nachdenken, was du nicht weißt, dann können wir dir Hinweise heben, was du lernen musst und wo du so etwas findest. Falls du selber nicht weißt, was du nicht weißt, dann bist du so sehr überfordert, dass keine Hoffnung besteht. Dann programmier viele einfachere Programme und versuch es in ein paar Monaten noch einmal.

    *: Nicht ganz so trivial, wie es sich anhört. Ist dies die Schwierigkeit?



  • @Assembler: schau dir einfach mal die beiden Artikel Compilerbau und Interpreterbau - Ein Anfang an (ein Assembler ist nichts anderes als ein Parser).



  • Ja, ich beherrsche eine Assemblersprache (FASM), mein Problem liegt darin, dass (zumindest steht es so in "The Art of Disassembling") Opcodes nicht nur vom eigentlichen Befehl abhängen (mov, mul, jmp, jne, ...) sonder auch vom (bzw. von den) Operand(en) und weiterem (z.B. irgendwelchen Previex Bytes, die nicht weiter erläutert werden).

    Vielen Dank


  • Mod

    Assembler schrieb:

    Ja, ich beherrsche eine Assemblersprache (FASM), mein Problem liegt darin, dass (zumindest steht es so in "The Art of Disassembling") Opcodes nicht nur vom eigentlichen Befehl abhängen (mov, mul, jmp, jne, ...) sonder auch vom (bzw. von den) Operand(en)

    Genau. Also musst du gucken, was du für Operanden hast. Oder eigentlich ist das schon der zweite Schritt. Der nullte Schritt ist erst einmal, dass du dir eine bestimmte Notation ausdenkst (oder besser: eine der Standardnotationen nimmst). Dann guckst du dir eine Zeile an (eine Operation pro Zeile, denk an Kommentare!) und dann kannst du dir die Operanden angucken. Du kannst erst einmal zählen, wie viele Operanden das sind (falls das bei dem Mnemonik eine Rolle spielt) und danach musst du gucken, was für ein Typ das ist. Kann der Operand als Zahl geparst werden? Ist es eines der bekannten Register? Von welcher Breite ist das Register? Ist es eine Speicherstelle?
    Die so gewonnene Information lässt du dann in die Wahl des Opcodes einfließen.

    und weiterem (z.B. irgendwelchen Previex Bytes, die nicht weiter erläutert werden).

    Ok, ich kann, zugegeben, nur höchst gebrochen Assembler 🙂 . Nie davon gehört und Google spuckt auch nix aus. Klingt so, als bräuchtest du noch einen internen Status für deinen Assemblerübersetzer, wenn die späteren Opcodes von etwas abhängen, was vorher einmal war. Je nach Komplexität deiner Assemblersprache benötigst du das ohnehin früher oder später, zum Beispiel für Sprunglabels. Das sollte in den erwähnten Compilerbaubüchern (viel zu ausführlich) beschreiben werden.



  • Womit wir im Prinzip wieder am Anfang sind: ich habe keine Referenz, wann wie wo welcher Opcode rauskommt (streng genommen, weiß ich nichtmal, ob ich überhaupt alles kenne, das Einfluss nimmt) und finde keine Erläuterung...

    Danke


  • Mod

    Hat dir doch Ethon schon verlinkt. Und Google findet die gleiche Seite auch ziemlich schnell. Das ist ja sogar eine XML-Datei dabei, so dass du alles ganz einfach in dein Programm übertragen kannst.

    Was brauchst du denn mehr? Suchst du kein x86?



  • Assembler schrieb:

    Womit wir im Prinzip wieder am Anfang sind: ich habe keine Referenz, wann wie wo welcher Opcode rauskommt (streng genommen, weiß ich nichtmal, ob ich überhaupt alles kenne, das Einfluss nimmt) und finde keine Erläuterung...

    Danke

    Erster Anlaufpunkt sind immer die Dokumentationen des Herstellers:

    http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

    Da steht alles, aber wirklich auch alles drin ;). Du wirst schnell merken, warum es keine "Tutorials" gibt.

    Aber einen Assembler für einen 8086 (16 Bit, Realmodus, "reduced" CISC, Ausgabe in .com-Datei) kann man relativ einfach basteln. Als ich das damals gemacht habe, habe ich jedoch bei den 32-Bit-80386-Befehlen aufgegeben. Irgendwann denkt man sich: Warum tu ich mir das an, wo es doch so viele, so gute, so billige und so fehlerfreie Assembler gibt :D.

    Hier ist eine Tabelle für die 8086-Befehle:

    http://ref.x86asm.net/coder.html

    viele grüße
    ralph



  • Ich glaube er sucht was Hübsches wie das hier, nur halt für x86: http://www.coranac.com/files/gba/re-ejected-armref.pdf



  • Nein, ich suche eine Erklärung, wie ich die Werte, die in der Tabelle stehn zu einem Opcode zusammensetzte... Einfach hintereinander schreiben funktioniert nämlich nicht und XORen auch nicht...

    Danke



  • Sorry für den Doppelpost, aber ich muss noch was anhängen:

    Und wie ich den Operanden mit einbaue, und inwiefern die hundert verschiedenen ADDs sich (außer dem Opcode) unterscheiden....


  • Mod

    Assembler schrieb:

    Nein, ich suche eine Erklärung, wie ich die Werte, die in der Tabelle stehn zu einem Opcode zusammensetzte... Einfach hintereinander schreiben funktioniert nämlich nicht

    Doch, genau so geht das. Dann wirst du wohl was falsch gemacht haben. Guck doch mal das Beispiel auf Wikipedia:
    http://en.wikipedia.org/wiki/Assembly_language#Example_listing_of_assembly_language_source_code

    und XORen auch nicht...

    😮 😕 Was hast du vor?



  • Ich meinte nicht die generierten Opcodes, klar gehören die hintereinander. Ich meinte, wie ich mit den Daten aus der Tabelle den Opcode erstelle...

    Heißt:

    Wie komme ich an

    03C3
    

    Wenn ich

    add eax, ebx
    

    habe?

    Dabei weiß ich aus der Tabelle:

    1. Dass der PO einer von 00 bis 05 ist (ich werde wohl über die Operanden entscheiden müssen)
    2. Dass das Opcode Field "r" ist (was auch immer das heißt...)

    Bei anderen Opcodes ist das ganze noch schlimmer:

    So sind die PO von

    neg
    

    und

    mul
    

    dieselben, aber bei

    neg eax
    

    und

    mul eax
    

    kommen (logischerweise andere Opcodes raus:

    neg eax ; = F7D8
    mul eax ; = F7E0
    

    ). Der Unterschied zwischen den beiden ist nur das Opcode Field, dass ist beim ersten 3 und beim zweiten 4, wie diese zwei Zahlen aber im Opcode "verarbeitet" sind weiß ich nicht...

    Danke



  • Moin.

    Welche Operanden verwendet werden wird im "Mod R/M"-Byte oder "Post"-Byte spezifiziert.

    Format of Postbyte(Mod R/M aus Intel-Doku)
    ------------------------------------------
    MM RRR MMM
    
    MM  - Memeory addressing mode
    RRR - Register operand address
    MMM - Memoy operand address
    
    RRR Register Names
    Filds  8bit  16bit  32bit
    000    AL     AX     EAX
    001    CL     CX     ECX
    010    DL     DX     EDX
    011    Bl     BX     EBX
    100    AH     SP     ESP
    101    CH     BP     EBP
    110    DH     SI     ESI
    111    BH     DI     EDI
    
    ---
    
    16bit memory (No 32 bit memory address prefix)
    MMM   Default MM Field
    Field Sreg     00        01          10             11=MMM is reg
    000   DS       [BX+SI]   [BX+SI+o8]  [BX+SI+o16]
    001   DS       [BX+DI]   [BX+DI+o8]  [BX+DI+o16]
    010   SS       [BP+SI]   [BP+SI+o8]  [BP+SI+o16]
    011   SS       [BP+DI]   [BP+DI+o8]  [BP+DI+o16]
    100   DS       [SI]      [SI+o8]     [SI+o16]
    101   DS       [DI]      [DI+o8]     [SI+o16]
    110   SS       [o16]     [BP+o8]     [BP+o16]
    111   DS       [BX]      [BX+o8]     [BX+o16]
    Note: MMM=110,MM=0 Default Sreg is DS !!!!
    
    32bit memory (Has 67h 32 bit memory address prefix)
    MMM   Default MM Field
    Field Sreg     00        01          10             11=MMM is reg
    000   DS       [EAX]     [EAX+o8]    [EAX+o32]
    001   DS       [ECX]     [ECX+o8]    [ECX+o32]
    010   DS       [EDX]     [EDX+o8]    [EDX+o32]
    011   DS       [EBX]     [EBX+o8]    [EBX+o32]
    100   SIB      [SIB]     [SIB+o8]    [SIB+o32]
    101   SS       [o32]     [EBP+o8]    [EBP+o32]
    110   DS       [ESI]     [ESI+o8]    [ESI+o32]
    111   DS       [EDI]     [EDI+o8]    [EDI+o32]
    Note: MMM=110,MM=0 Default Sreg is DS !!!!
    
    ---
    
    SIB is (Scale/Base/Index)
    SS BBB III
    Note: SIB address calculated as:
    <sib address>=<Base>+<Index>*(2^(Scale))
    
    Fild   Default Base
    BBB    Sreg    Register   Note
    000    DS      EAX
    001    DS      ECX
    010    DS      EDX
    011    DS      EBX
    100    SS      ESP
    101    DS      o32        if MM=00 (Postbyte)
    SS      EBP        if MM<>00 (Postbyte)
    110    SS      ESI
    111    DS      EDI
    
    Fild  Index
    III   register   Note
    000   EAX
    001   ECX
    010   EDX
    011   EBX
    100              never Index SS can be 00
    101   EBP
    110   ESI
    111   EDI
    
    Fild Scale coefficient
    SS   =2^(SS)
    00   1
    01   2
    10   4
    11   8
    

    Dirk



  • Anmerkung: In Bezug auf mit und ohne "memory address prefixe(67h)", werden diese Postbyte-Tabellen aus der Sicht des 16 Bit-Adressmodes(D-Flag nicht gesetz) betrachtet.

    Dirk



  • SeppJ, wenn das Wort richtig geschrieben gewesen wäre, hättest du vielleicht auch was gefunden 😉 Hier: https://webcache.googleusercontent.com/search?q=cache:16-iNtIgbicJ:http://www.c-jump.com/CIS77/CPU/x86/X77_0240_prefix.htm (Die Seite ließ sich nicht direkt öffnen, ohne Skripte zu erlauben), bzw. hier: http://brokenthorn.com/Resources/OSDevX86.html (weiter unten, bei IA32 and IA64 Instruction encoding (in grün), Unterabschnitt Instruction encoding)


  • Mod

    Sonnenbleichung schrieb:

    SeppJ, wenn das Wort richtig geschrieben gewesen wäre, hättest du vielleicht auch was gefunden 😉 Hier: https://webcache.googleusercontent.com/search?q=cache:16-iNtIgbicJ:http://www.c-jump.com/CIS77/CPU/x86/X77_0240_prefix.htm (Die Seite ließ sich nicht direkt öffnen, ohne Skripte zu erlauben), bzw. hier: http://brokenthorn.com/Resources/OSDevX86.html (weiter unten, bei IA32 and IA64 Instruction encoding (in grün), Unterabschnitt Instruction encoding)

    Ok, das sind aber Teile der Opcodes selber, nicht wie vom TE dargestellt ein "State" der Assemblersprache. Das heißt, ein einfacher 1:1 Übersetzer ist nach wie vor ausreichend.


Log in to reply