Assemblersprache Quine


20

Schreiben Sie die kürzest mögliche Assemblersprachen- quine .

Verwenden Sie einen von Ihnen gewünschten ISA, es sei denn, er verfügt über eine print-quineAnweisung oder eine Entsprechung. Beispiele sind x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM usw.

Sie können eine Verknüpfung mit der _printfFunktion der C-Standardbibliothek (oder der Java-Entsprechung für JVM-Bytecode) für E / A herstellen.

Die Länge wird sowohl nach der Befehlsanzahl als auch nach der Größe des Datensegments beurteilt. Die Lösungen müssen mindestens zwei Anweisungen enthalten.

Das Quine sollte den Assembler- Code und nicht den Assembler-Maschinencode drucken .


3
Oh wow, das klingt wie ein toughy
Anonymous Coward

Antworten:


20

x86 Linux, AT & T-Syntax: 244

push $10
push $34
push $s
push $34
push $37
push $37
push $s
call printf
mov $0,%ebx
mov $1,%eax
int $128
s:.ascii "push $10
push $34
push $s
push $34
push $37
push $37
push $s
call printf
mov $0,%cebx
mov $1,%ceax
int $128
s:.ascii %c%s%c%c"

(Ich es mit diesem zusammengestellt: gcc -nostartfiles -lc quine.S -o quine)


Das ist jetzt deprimierend :-(
Joey

1
Normalerweise würde ich sagen "das richtige Werkzeug für den Job", aber hier fühlt es sich nicht richtig an: D
JB

Scheint aber besser zu sein als meins ;-)
Joey

5

JVM-Bytecode-Assembly (über Jasmin ) - 952 960 990

.class public Q
.super java/io/File
.method public static main([Ljava/lang/String;)V
.limit stack 9
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc ".class public Q%n.super java/io/File%n.method public static main([Ljava/lang/String;)V%n.limit stack 9%ngetstatic java/lang/System/out Ljava/io/PrintStream;%nldc %c%s%c%nldc 3%nanewarray java/lang/Object%ndup%ndup%nldc 0%nldc 34%ninvokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;%ndup_x2%naastore%nldc 2%nswap%naastore%ndup2%nswap%nldc 1%nswap%naastore%ninvokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;%npop%nreturn%n.end method"
ldc 3
anewarray java/lang/Object
dup
dup
ldc 0
ldc 34
invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
dup_x2
aastore
ldc 2
swap
aastore
dup2
swap
ldc 1
swap
aastore
invokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
pop
return
.end method

Leider erlaubt Jasmin nicht so viele nette Tricks, wie es Microsoft ilasmerlaubt. Aber die JVM hat insgesamt sechs verschiedene dupAnweisungen, die alle Arten von lustigen Dingen ausführen. Das Umordnen von Elementen auf dem Stapel wird von .NET anscheinend nicht unterstützt.

Auf jeden Fall denke ich, dass keiner meiner beiden Einträge ernsthafte Kandidaten für den kürzesten Code sind, aber ich denke, es ist schwierig, sie viel kürzer zu machen. Deshalb nur der Vollständigkeit halber :-)

Kommentierte Version mit Informationen darüber, was sich auf dem Stapel befindet:

.class public Q
.super java/io/File
.method public static main([Ljava/lang/String;)V
.limit stack 9
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc ".class public Q%n.super java/io/File%n.method public static main([Ljava/lang/String;)V%n.limit stack 9%ngetstatic java/lang/System/out Ljava/io/PrintStream;%nldc %c%s%c%nldc 3%nanewarray java/lang/Object%ndup%ndup%nldc 0%nldc 34%ninvokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;%ndup_x2%naastore%nldc 2%nswap%naastore%ndup2%nswap%nldc 1%nswap%naastore%ninvokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;%npop%nreturn%n.end method"
ldc 3       ; stack; System.out, string, 3
anewarray java/lang/Object    ; stack: System.out, string, Object[3]
dup
dup    ; stack: System.out, string, array, array, array
ldc 0  ; stack: System.out, string, array, array, array, 0
ldc 34   ; stack: System.out, string, array, array, array, 0, 34
invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer;
dup_x2   ; stack: System.out, string, array, array, 34, array, 0, 34
aastore  ; stack: System.out, string, array, array, 34
ldc 2    ; stack: System.out, string, array, array, 34, 2
swap     ; stack: System.out, string, array, array, 2, 34
aastore  ; stack: System.out, string, array
dup2     ; stack: System.out, string, array, string, array
swap     ; stack: System.out, string, array, array, string
ldc 1    ; stack: System.out, string, array, array, string, 1
swap     ; stack: System.out, string, array, array, 1, string
aastore  ; stack: System.out, string, array
invokevirtual java/io/PrintStream/printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
pop
return
.end method

Geschichte:

  • 2011-02-07 02:09 (990) - Erste Arbeitsversion.
  • 2011-02-07 02:11 (960) - ldcist kürzer als bipushoder iconst_*.
  • 2011-02-07 02:30 (952) - Wer sagt, dass ich von java.lang.Object erben muss? Andere Klassennamen sind so viel kürzer :-)

4

Gas für x86 Linux (89 Bytes, sieben Anweisungen)

Technisch gesehen ist das Betrug.

mov $4,%al
mov $1,%bl
mov $b,%ecx
mov $89,%dl
int $128
mov %bl,%al
int $128
b:.incbin"a"

Speichern Sie in einer Datei mit dem Namen aund fügen Sie sie mit den folgenden Befehlen zusammen, um die ausführbare Datei mit dem Namen zu erstellen a.out.

as -o a.o ; ld a.o

Die Direktive .incbinenthält eine Datei wörtlich am aktuellen Speicherort. Wenn Sie dies verwenden, um den Quellcode selbst einzuschließen, erhalten Sie eine nette Quine.


3

Windows .COM Format: 307 Zeichen

Assembliert mit A86 auf 51 Byte. Benötigt keine anderen externen Bibliotheken als die Funktion DOS Int21 AH = 9 (String in stdout schreiben).

db 185
db  51
db   0
db 190
db   0
db   1
db 191
db  47
db   1
db 172
db 178
db  10
db 199
db   6
db  45
db   1
db  32
db  32
db 180
db   0
db 246
db 242
db 128
db 196
db  48
db 136
db  37
db  79
db  10
db 192
db 117
db 242
db 180
db   9
db 186
db  42
db   1
db 205
db  33
db 226
db 221
db 195
db 100
db  98
db  32
db  32
db  51
db  49
db  10
db  13
db  36

Ich fürchte, ich zähle 357 Bytes. (und Ihr Programm gibt tatsächlich 408 aus). Möglicherweise möchten Sie nicht als Datenbank gespeicherte Assembly-Quelle einschließen, damit andere Betrachter einen direkten Blick darauf werfen können.
JB

@JB: Ich habe CR \ NL nicht berücksichtigt. Wenn ich es mir jetzt ansehe, hätte ich die Daten wirklich in eine einzige db-Zeile schreiben sollen. Das würde es kleiner machen.
Skizz

3

NASM, 223 Bytes

%define a "%define "
%define b "db "
%define c "%deftok "
%define d "a, 97, 32, 34, a, 34, 10, a, 98, 32, 34, b, 34, 10, a, 99, 32, 34, c, 34, 10, a, 100, 32, 34, d, 34, 10, c, 101, 32, 100, 10, b, 101, 10"
%deftok e d
db e

Die akzeptierte Antwort schlagen!


2

.NET CIL - 623 669 691 723 727

.assembly H{}.method void M(){.entrypoint.locals init(string)ldstr".assembly H{0}{1}.method void M(){0}.entrypoint.locals init(string)ldstr{2}{3}{2}stloc 0ldloc 0ldc.i4 4newarr object dup dup dup dup ldc.i4 0ldstr{2}{0}{2}stelem.ref ldc.i4 1ldstr{2}{1}{2}stelem.ref ldc.i4 2ldc.i4 34box char stelem.ref ldc.i4 3ldloc 0stelem.ref call void[mscorlib]System.Console::Write(string,object[])ret{1}"stloc 0ldloc 0ldc.i4 4newarr object dup dup dup dup ldc.i4 0ldstr"{"stelem.ref ldc.i4 1ldstr"}"stelem.ref ldc.i4 2ldc.i4 34box char stelem.ref ldc.i4 3ldloc 0stelem.ref call void[mscorlib]System.Console::Write(string,object[])ret}

Eine einzelne Zeile, kein Zeilenumbruch am Ende.

Erste Version formatiert und kommentiert (auch wenn es keine Quine mehr ist) - es ist unwahrscheinlich, dass ich stark vom allgemeinen Konzept abweiche:

.assembly H{}
.method void M() {
  .entrypoint
  .locals init (
    string,
    object[]
  )
  // the string
  ldstr".assembly H{0}{1}.method void M(){0}.entrypoint.locals init(string,object[])ldstr{2}{3}{2}stloc.0 ldloc.0 ldc.i4.4 newarr object stloc.1 ldloc.1 ldc.i4.0 ldstr{2}{0}{2} stelem.ref ldloc.1 ldc.i4.1 ldstr{2}{1}{2} stelem.ref ldloc.1 ldc.i4.2 ldc.i4 34 box char stelem.ref ldloc.1 ldc.i4.3 ldloc.0 stelem.ref ldloc.1 call void[mscorlib]System.Console::Write(string,object[])ret{1}"
  stloc.0   // store in first local var
  ldloc.0   // load again. Going to be the first argument to Console::Write
  ldc.i4.4 newarr object stloc.1   // create new array and store in local var
  ldloc.1 ldc.i4.0 ldstr"{" stelem.ref   // we need a literal brace
  ldloc.1 ldc.i4.1 ldstr"}" stelem.ref   // closing, too
  ldloc.1 ldc.i4.2 ldc.i4 34 box char stelem.ref   // double quote
  ldloc.1 ldc.i4.3 ldloc.0 stelem.ref   // our format string from before
  ldloc.1 // load array
  call void[mscorlib]System.Console::Write(string,object[]) // output
  ret
}

Geschichte :

  • 2011-02-06 16:48 (727) - Erste Arbeitsversion.
  • 2011-02-06 17:14 (723) - Nach einem String-Literal muss kein Leerzeichen eingefügt werden.
  • 2011-02-06 17:21 (691) - dupist ldloc.1jedes Mal kürzer als das Schreiben .
  • 2011-02-06 17:24 (669) - Ich benötige nachher keine Leerzeichen einem Literal und Dinge wie ldloc.1können geschrieben werden ldloc 1, um das letzte Token zu einem Literal zu machen. Der resultierende Bytecode ist wahrscheinlich größer, aber es geht um den Assembler-Code, also ist mir das egal :-)
  • 2011-02-06 17:34 (623) - Ich benötige die object[]als lokale Variable nicht. Ich kann das alles direkt auf dem Stapel machen. Nett.

Scheint, als hättest du das Objekt [] aus der unformatierten Version entfernt, aber nicht die formatierte ...
Aurel Bílý

@ Aurel: Tatsächlich ist das Formatierte, wie bereits erwähnt, die allererste Version. Die Idee ist immer noch dieselbe, daher werde ich sie nicht noch einmal aktualisieren.
Joey

2

Gas für x86 Linux, 184 176 Bytes

.globl main
main:movw $34,B+87
push $B
call printf
call printf
pop B
ret
.data
B:.ascii".globl main
main:movw $34,B+87
push $B
call printf
call printf
pop B
ret
.data
B:.ascii"

Bauen mit gcc -m32 -o a.out quine.S. (Das -m32ist optional, wenn Ihr Betriebssystem bereits 32-Bit ist.)

Bearbeitet, um hinzuzufügen: Wenn wir die Regeln so ändern, dass putssie aufgerufen werden printfkönnen, kann dies in 182 bis 174 Bytes erfolgen:

.globl main
main:movw $34,B+86
push $B+1
call puts
call puts
pop B
ret
.data
B:.ascii"
.globl main
main:movw $34,B+86
push $B+1
call puts
call puts
pop B
ret
.data
B:.ascii"

(Beachten Sie, dass dieses im Gegensatz zum vorherigen eine abschließende Newline hat.)


Ich schätze die Kürze. Aber ich fühle mich betrogen von der Tatsache, dass Sie zusätzlich zu printf / puts tatsächlich auf den Standard-C-Prolog / -Epilog angewiesen sind, der nicht ausdrücklich erlaubt ist. Und IMHO sollte es nicht sein. Aber ich habe die beste Antwort: Offensichtlich bin ich voreingenommen :-)
JB

Nun, man könnte argumentieren, dass die Verwendung des C-Prologs / Epilogs aufgrund der Erwähnung der Verwendung von printf () implizit erlaubt ist. libc-Funktionen verhalten sich nicht immer zuverlässig, wenn Sie den C-Prolog / Epilog umgehen. Tatsächlich funktioniert Ihre Version auf meinem System nicht, wenn ich die Ausgabe an eine Datei weitergebe, da stdout nur im C-Epilog-Code gelöscht wird. (Hätten wir stattdessen write () verwendet, was nur ein Wrapper um einen Syscall ist, hätte es in beide Richtungen funktioniert.)
breadbox

Es ist schon ziemlich lange her, aber ich scheine mich daran zu erinnern, dass das Zulassen von C-Funktionen damals eine Überraschung für mich war: Das Problem klang dadurch irgendwie unrein. OP gibt es auch schon lange nicht mehr; Es wird jetzt schwierig sein, um Klärung zu bitten.
JB

Beachten Sie, dass der ABI erlaubt printf, seine Args auf dem Stapel zu blockieren. Es ist technisch nicht sicher, calles noch einmal zu tun und dieselben Argumente zu erwarten, aber es funktioniert in der Praxis, weil gcc / clang niemals Argumente als Scratch-Space verwenden, AFAIK.
Peter Cordes

Außerdem ist es im Allgemeinen nicht sicher, printfvon _start(z. B. in einer statischen Binärdatei) aufzurufen , sodass dies ein gutes Argument für das Schreiben von a mainanstelle von a ist _start. In dieser Antwort werden die verschiedenen Möglichkeiten zum Verknüpfen von libc aus statischen oder dynamischen Binärdateien erläutert. (In einer dynamischen Linux-Binärdatei führt der dynamische Linker die Initialisierungsfunktionen von glibc aus, sodass Sie diese printfvom _startEinstiegspunkt aus verwenden können. Dies ist jedoch bei cygwin IIRC nicht der Fall.)
Peter Cordes

1

Bootfähiges ASM, 660 Byte

[bits 16]
mov ax,07C0h
mov ds,ax 
mov ah,0
mov al,03h 
int 10h
mov si,code
call p 
jmp $
p:mov ah,0Eh
r:lodsb
cmp al,0
je d
cmp bx,0x42
jne s
c:int 10h
jmp r
s: cmp al,94 
je re
cmp al,63
je q
jmp c
q:mov al,34
jmp c
re:push si
mov bx,0x42
mov si,code
call p 
mov bx,0
pop si
jmp p 
d:ret
code:db "[bits 16]\mov ax,07C0h\mov ds,ax\mov ah,0\mov al,03h\int 10h\mov si,code\call p\jmp $\p:mov ah,0Eh\r:lodsb\cmp al,0\je d\cmp bx,0x42\jne s\c:int 10h\jmp r\s:cmp al,94\je re\cmp al,63\je q\jmp c\q:mov al,34\jmp c\re:push si\mov bx,0x42\mov si,code\call p\mov bx,0\pop si\jmp p\\d:ret\\code:db ?^?\times 510-($-$$) db 0\dw 0xAA55"
times 510-($-$$) db 0
dw 0xAA55

Ursprünglich von jdiez17 , aufrichtig von Ihnen gespielt.


0

x86-64, System V AMD64 ABI, GASM: 432

.att_syntax noprefix
.globl main
main:
pushq rbp
movq rsp, rbp
mov $.Cs, rdi
mov $0xa, rsi
mov $0x22, edx
mov $.Cs, ecx
mov $0x22, r8d
mov $0xa, r9d
xor eax, eax
call printf
xor eax, eax
leave
ret
.Cs: .string ".att_syntax noprefix
.globl main
main:
pushq rbp
movq rsp, rbp
mov $.Cs, rdi
mov $0xa, rsi
mov $0x22, edx
mov $.Cs, ecx
mov $0x22, r8d
mov $0xa, r9d
xor eax, eax
call printf
xor eax, eax
leave
ret%c.Cs: .string %c%s%c%c"

1
Nach dem Komma zwischen den Operanden brauchen Sie kein Leerzeichen. Und das brauchen Sie überhaupt nicht, xor eax,eaxwenn Sie sich nicht um den Exit-Status Ihres Programms kümmern. Es druckt sich selbst dann noch aus, wenn es mit einem Status ungleich Null beendet wird. Sie können auch pushanstelle von verwenden pushq. Warum machst du überhaupt einen Stapelrahmen? Lassen Sie das push rbp/ mov rsp, rbpund fallen leave. Sie können auch kürzere Bezeichnungen verwenden. .Csist 3 Zeichen, wenn 1 in Ordnung wäre.
Peter Cordes

Danach .att_syntax noprefixzahlt sich das wohl nicht mehr aus. .intel_syntax noprefixDamit können Sie auch diese sechs $Präfixe löschen. aber wahrscheinlich immer noch nicht wert. (Sie könnten lea ecx,.Csanstelle der Intel-Syntax verwenden mov ecx,offset .Cs)
Peter Cordes

0

TAL

push puts
push \100
push {push puts
push \100
push {@}
dup
strmap
invokeStk 2}
dup
strmap
invokeStk 2

Rufen Sie ::tcl::unsuppoted::assemblemit dem Code als Argument auf, um es auszuführen .
Nur Tcl 8.6.


3
Sie sollten die Anzahl der Bytes angeben.
MD XF

0

80 x 86 TASM, 561 Byte

MODEL TINY
.CODE
.STARTUP
DB 177
DB 076
DB 186
DB 044
DB 001
DB 172
DB 180
DB 036
DB 179
DB 004
DB 191
DB 080
DB 001
DB 079
DB 136
DB 037
DB 212
DB 010
DB 004
DB 048
DB 134
DB 196
DB 075
DB 117
DB 244
DB 180
DB 009
DB 205
DB 033
DB 178
DB 071
DB 226
DB 228
DB 178
DB 038
DB 205
DB 033
DB 195
DB 013
DB 010
DB 069
DB 078
DB 068
DB 036
DB 077
DB 079
DB 068
DB 069
DB 076
DB 032
DB 084
DB 073
DB 078
DB 089
DB 013
DB 010
DB 046
DB 067
DB 079
DB 068
DB 069
DB 013
DB 010
DB 046
DB 083
DB 084
DB 065
DB 082
DB 084
DB 085
DB 080
DB 013
DB 010
DB 068
DB 066
DB 032
END
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.