Erstellen Sie einen Bootloader, der ein bestimmtes Brainfuck-Programm ausführt. Das ist Code-Golf , also gewinnt das Programm mit den wenigsten Bytes. Als Bootloader wird die Größe des Programms im kompilierten Code in Bytes ungleich Null gezählt.
Brainfuck
30000 überlaufende 8-Bit-Zellen. Zeiger springt über.
Einige Anmerkungen zu Operationen:
- Die Eingabe muss so gelesen werden, dass alle druckbaren ASCII-Zeichen korrekt unterstützt werden. Andere Tastenanschläge können entweder ein beliebiges Zeichen einfügen oder gar nichts bewirken.
- Das Lesen von Benutzereingaben muss zeichen- und nicht zeilenweise erfolgen.
- Das Lesen von Benutzereingaben muss das eingegebene Zeichen wiedergeben.
- Die Ausgabe muss entweder der Codepage 437 oder der Standard-Codepage Ihres integrierten VGA-Adapters folgen .
Bootloader
Dies ist ein x86-Bootloader. Ein Bootloader endet mit der traditionellen 55 AA
Reihenfolge. Ihr Code muss entweder auf VirtualBox, Qemu oder einem anderen bekannten x86-Emulator ausgeführt werden.
Platte
Die ausführbare Datei "Brainfuck" befindet sich im zweiten Festplattensektor direkt nach Ihrem Bootloader. Dieser befindet sich wie gewöhnlich im MBR-Abschnitt, dem ersten Sektor auf der Festplatte. Zusätzlicher Code (jeder Code über 510 Byte) kann sich in anderen Plattensektoren befinden. Ihr Speichergerät muss entweder eine Festplatte oder eine Diskette sein.
STDIO
Natürlich kann ein Bootloader nicht auf die IO-Funktionen des Betriebssystems zugreifen. Daher werden stattdessen BIOS-Funktionen zum Drucken von Text und Lesen von Benutzereingaben verwendet.
Vorlage
Hier ist eine einfache Vorlage, die in der Nasm-Assembly (Intel-Syntax) geschrieben wurde:
[BITS 16]
[ORG 0x7c00]
; first sector:
boot:
; initialize segment registers
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
; initialize stack
mov sp, 0x7bfe
; load brainfuck code into 0x8000
; no error checking is used
mov ah, 2 ; read
mov al, 1 ; one sector
mov ch, 0 ; cylinder & 0xff
mov cl, 2 ; sector | ((cylinder >> 2) & 0xc0)
mov dh, 0 ; head
; dl is already the drive number
mov bx, 0x8000 ; read buffer (es:bx)
int 0x13 ; read sectors
; fill sector
times (0x200 - 2)-($-$$) db 0
; boot signature
db 0x55, 0xaa
; second sector:
db 'brainfuck code here'
times 0x400-($-$$) db 0
Dies zu kompilieren ist ziemlich einfach:
nasm file.asm -f bin -o boot.raw
Und die laufen davon. Zum Beispiel mit Qemu:
qemu-system-i386 -fda boot.raw
Weitere Informationen: OsDev-Wiki , Wikipedia
quelle
Input must be red
Ich bin mir ziemlich sicher, dass die meisten Bootloader von Haus aus keine Farben unterstützen.Antworten:
171 Bytes 1
Wooohoooo! Es hat den halben Tag gedauert, aber es hat Spaß gemacht ...
Hier ist es also. Ich denke, es entspricht den Spezifikationen (Umlauf des Zellenzeigers, Echo der Zeichen bei der Eingabe, Lesen von Zeichen für Zeichen, Echo der Eingabezeichen, ...), und es scheint tatsächlich zu funktionieren (naja, ich habe nicht viele Programme ausprobiert Aber angesichts der Einfachheit der Sprache ist die Berichterstattung meiner Meinung nach nicht so schlecht.
Einschränkungen
Eine wichtige Sache: Wenn Ihr Brainfuck-Programm andere Zeichen als die 8 Brainfuck-Anweisungen enthält oder wenn die
[]
nicht ausgewogen sind, stürzt es auf Sie ab, mouhahahaha!Außerdem darf das Brainfuck-Programm 512 Byte (einen Sektor) nicht überschreiten. Dies scheint jedoch konform zu sein, da Sie sagen, "ausführbares Brainfuck befindet sich im zweiten Plattensektor" .
Letztes Detail: Ich habe die Zellen nicht explizit auf Null initialisiert. Qemu scheint es für mich zu tun, und ich verlasse mich darauf, aber ich weiß nicht, ob es ein echtes BIOS auf einem echten Computer tun würde (die Initialisierung würde sowieso nur ein paar Bytes länger dauern).
Der Code
(basierend auf Ihrer Vorlage und übrigens, danke dafür, ich hätte es nie ohne versucht):
Tricks verwendet
Ok, ich habe ein bisschen geschummelt. Da Sie sagten, "ein Bootloader zu sein, wird die Größe des Programms im kompilierten Code in Bytes ungleich Null gezählt" , habe ich den Code verkleinert, indem ich "Löcher" zwischen der Implementierung der acht Brainfuck-Opcodes zugelassen habe. Auf diese Weise brauche ich keine große Sequenz von Tests, keine Sprungtabelle oder irgendetwas anderes: Ich springe einfach zu der Brainfuck-Opcode-ID (von 0 bis 8) multipliziert mit 32, um den Brainfuck-Befehl auszuführen (das ist es wert, darauf hingewiesen zu werden Dies bedeutet, dass die Implementierung der Anweisungen nicht mehr als 32 Byte dauern kann.
Um diese "Opcode-ID" aus dem Brainfuck-Programm-Zeichen zu erhalten, bemerkte ich außerdem, dass nur ein bisschen Mischen notwendig war. Betrachten wir nur die Bits 0, 1 und 4 des Opcode-Zeichens, ergeben sich die 8 eindeutigen Kombinationen:
Und zum Glück gibt es tatsächlich einen Opcode, für dessen Implementierung mehr als 32 Bytes erforderlich sind, aber es ist der letzte (Sprung nach vorne
[
). Da nachher mehr Platz ist, ist alles in Ordnung.Anderer Trick: Ich weiß nicht , wie ein typischer Gehirnfick Interpreter funktioniert, aber, um die Dinge viel kleiner, habe ich nicht tatsächlich umsetzen
]
als „nach dem entsprechenden Sprung zurück ,[
wenn Daten auf Zeiger nicht Null sind“ . Stattdessen gehe ich immer auf die entsprechende zurück[
und wende von hier aus die typische[
Implementierung erneut an (die dann]
gegebenenfalls nach der erneuten erneuten Implementierung fortgesetzt wird). Aus diesem Grund[
setze ich jedes Mal , wenn ich auf a stoße , den aktuellen "Brainfuck-Anweisungszeiger" auf den Stapel, bevor ich die inneren Anweisungen ausführe, und wenn ich auf a stoße]
Ich stelle den Befehlszeiger zurück. Ziemlich so, als wäre es ein Aufruf einer Funktion. Sie könnten daher theoretisch den Stapel überlaufen lassen, indem Sie viele unregelmäßige Schleifen bilden, aber nicht mit der aktuellen 512-Byte-Beschränkung des Brainfuck-Codes.1. Einschließlich der Null-Bytes, die Teil des Codes selbst waren, aber nicht derjenigen, die Teil einer Auffüllung waren
quelle