Ein Assembler, viele Ziele: Windows auf Intel und ARM, DOS, ARM-Linux und der Raspberry Pi Pico.
Drei Zeilen am Anfang einer Quelldatei legen fest, wofür ein Programm ist: .format (die Art der Datei), .arch (der Befehlssatz) und bei einem Board .target. Danach richtet sich auch, wo der Debugger das Programm startet: auf diesem Rechner, in einem Hilfsprozess, auf einem zweiten Rechner, in QEMU oder auf dem Board an einer Debug-Probe. Unter Debug > Debug targets stellst du das für jedes Ziel einmal ein.
| Ziel | Quelltext | Ergebnis | Läuft und wird debuggt | Dismonite |
|---|---|---|---|---|
| Windows, Intel 32 Bit | .format pe.arch i386 | PE32 (.exe) | auf diesem Rechner | zerlegen, debuggen |
| Windows, Intel 64 Bit | .format pe.arch x64 | PE32+ (.exe) | auf diesem Rechner über den Hilfsprozess asmodbgx64 | zerlegen, debuggen |
| Windows on ARM, 32 Bit | .format pe.arch thumb | PE32, Thumb-2 | auf einem Windows-on-ARM-Rechner (Debug-Server asmodbg) | zerlegen, debuggen |
| Windows on ARM, 64 Bit | .format pe.arch arm64 | PE32+, AArch64 | auf einem Windows-on-ARM-Rechner (Debug-Server asmodbg64) | zerlegen, debuggen |
| DOS | .format binary.arch x86_real | .COM oder .EXE (MZ) | in QEMU mit FreeDOS | zerlegen (MZ), debuggen |
| ARM-Linux | – | ELF (von anderen Werkzeugen) | in QEMU (Raspberry Pi OS) | zerlegen, debuggen |
| Raspberry Pi Pico | .target pico.arch thumb | Binärdatei, UF2 | auf dem Board über eine Debug-Probe | – |
| Raspberry Pi Pico 2 | .target pico2.arch thumb oder riscv32 | Binärdatei, UF2 | auf dem Board über eine Debug-Probe | – |
Mit .format pe schreibt der Assembler eine fertige Windows-Datei: DOS-Stub, PE-Kopf, Abschnitte und Import-Tabelle. Der Quelltext enthält nur Code (.code), Daten (.data) und die Funktionen, die er aus DLLs braucht (.import). Ein Linker ist nicht nötig.
| 32 Bit | 64 Bit | |
|---|---|---|
| Intel | .arch i386: PE32, Maschine 0x014C; Argumente auf dem Stack (stdcall, cdecl) | .arch x64: PE32+, Maschine 0x8664; Argumente in rcx, rdx, r8, r9 |
| ARM | .arch thumb: PE32, Maschine 0x01C4 (ARMNT, Thumb-2); Argumente in r0…r3 | .arch arm64: PE32+, Maschine 0xAA64; Argumente in x0…x7 |
examples\windows_intel\hello_i386.asm).format pe console .arch i386 .import msvcrt.dll printf, exit .code start: push dword msg ; the argument on the stack call [printf] ; through the import table add esp, 4 ; printf does not clean up push 0 call [exit] .data msg db 'Hello, World!', 10, 0
examples\windows_intel\hello_x64.asm).format pe console .arch x64 .import msvcrt.dll printf, exit .code start: sub rsp, 40 ; shadow space, stack aligned lea rcx, [msg] ; first argument in rcx call [printf] xor ecx, ecx call [exit] .data msg db 'Hello, World!', 10, 0
Dasselbe für ARM steht mit Erklärung auf der Seite Windows on ARM. .format pe gui macht ein Fensterprogramm statt eines Konsolenprogramms (messagebox_*.asm, window_*.asm).
Debuggen. Ein 32-Bit-Programm für Intel debuggt Asmonite selbst, auf diesem Rechner. Ein x64-Programm läuft unter dem Hilfsprozess asmodbgx64, weil Asmonite selbst ein 32-Bit-Programm ist; auch das geschieht auf diesem Rechner (oder auf einem anderen mit demselben Debug-Server). ARM-Programme laufen auf einem Windows-on-ARM-Rechner mit dem Debug-Server asmodbg oder asmodbg64, verbunden über ssh oder direkt im Netz; auf dem ARM-Rechner selbst auch lokal. Vor jedem Start prüft Asmonite die erzeugte Datei: Kopf, Abschnitte, Einsprung und ob es die importierten DLLs und Funktionen wirklich gibt.
Mit .format binary und .arch x86_real schreibt Asmonite 16-Bit-Code für den Real Mode, Byte für Byte so, wie er im Quelltext steht.
.COM | Kein Kopf, nur Code. DOS lädt die Datei an Offset 0x100 eines Segments; section 0x100 zählt die Labels von dort. Code, Daten und Stack teilen sich 64 KB. Beispiel examples\dos\hello_com.asm. |
.EXE (MZ) | Der MZ-Kopf steht mit dw im Quelltext: Größe, Speicherbedarf, Start (CS:IP) und Stack (SS:SP); mehrere Segmente mit segment. Beispiel examples\dos\hello_exe.asm, mit Erklärung jedes Feldes. |
Debuggen. F9 legt das Programm auf ein Festplatten-Abbild und startet QEMU mit FreeDOS; das Hilfsprogramm dbgload.com lädt es dort, und der Debugger hält an der ersten Zeile. Breakpoints, Schritte, Register und Speicher funktionieren wie bei Windows-Programmen; ein zweiter Lauf braucht kein neues Booten. qemu\run_freedos.bat holt einmal die FreeDOS-Diskette, QEMU selbst wird mit qemu\install_qemu.bat eingerichtet. Dismonite öffnet fertige DOS-Programme (MZ), findet Code, Daten, Sprungtabellen und das Programmende und lässt dich Bereiche von Hand markieren.
Dieses Ziel ist eines von Dismonite: Es liest ELF-Dateien für 32-Bit-ARM, wie sie GCC oder ein anderer Compiler unter Linux erzeugt, und debuggt sie in einem Raspberry Pi OS, das in QEMU läuft.
qemu\run_buster.bat startet das Gastsystem; der Debugger erreicht es über ssh und gdbserver, kopiert das Programm hinein und hält am Einsprung. Läuft der Gast nicht, fragt Dismonite, ob es ihn starten soll.Mit .target pico (RP2040, Cortex-M0+) oder .target pico2 (RP2350, Cortex-M33 oder RISC-V Hazard3) schreibt Asmonite die Bytes für das Board und prüft sie: die erlaubten Befehle, RAM und Flash, beim Pico den boot2-Block, beim Pico 2 den IMAGE_DEF-Block. F7 bringt das Programm über eine CMSIS-DAP-Debug-Probe ins RAM oder in den Flash und hält bei _start, ohne OpenOCD und ohne SDK. Ohne Probe geht es als UF2-Datei auf das BOOTSEL-Laufwerk.