Assembly Language Quine


21

Scrivi il quine di linguaggio assembly più breve possibile .

Utilizzare qualsiasi ISA desiderato, a meno che non abbia print-quineun'istruzione o equivalente. Gli esempi includono x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM, ecc.

È possibile eseguire il collegamento con la _printffunzione della libreria standard C (o l'equivalente Java per il bytecode JVM) per l'I / O.

La lunghezza verrà valutata in base al conteggio delle istruzioni e alla dimensione del segmento di dati. Le soluzioni devono contenere almeno due istruzioni.

Il quine dovrebbe stampare il codice assembly , non il codice macchina assemblato.


3
Oh wow, sembra un duro
codardo anonimo il

Risposte:


20

x86 Linux, sintassi AT&T: 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"

(L'ho compilato con questo gcc -nostartfiles -lc quine.S -o quine:)


È deprimente, ora :-(
Joey

1
Di solito direi "lo strumento giusto per il lavoro", ma poi di nuovo, qui non sembra giusto: D
JB

Sembra essere più giusto del mio, però ;-)
Joey,

5

JVM Bytecode Assembly (via 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

Purtroppo, Jasmin non consente tutti i trucchi piacevoli di quelli consentiti da Microsoft ilasm. Ma JVM ha un totale di sei diverse dupistruzioni che fanno tutti i tipi di cose divertenti. Riordinare gli elementi nello stack è qualcosa che .NET non sembra supportare.

In ogni caso, immagino che nessuna delle mie due voci contesti seriamente per il codice più breve, ma credo sia difficile renderle molto più brevi. Pertanto solo per completezza :-)

Versione commentata con informazioni su cosa c'è nello stack:

.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

Storia:

  • 2011-02-07 02:09 (990) - Prima versione funzionante.
  • 2011-02-07 02:11 (960) - ldcè più corto di bipusho iconst_*.
  • 2011-02-07 02:30 (952) - Chi dice che devo ereditare da java.lang.Object? I nomi di altre classi sono molto più brevi :-)

4

gas per x86 Linux (89 byte, sette istruzioni)

Tecnicamente, questo è barare.

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

Salvare in un file denominato ae assemblare con i seguenti comandi per creare l'eseguibile denominato a.out.

as -o a.o ; ld a.o

La direttiva .incbininclude un file testualmente nella posizione corrente. Se lo usi per includere il codice sorgente stesso, otterrai un bel quine.


3

Formato Windows .COM: 307 caratteri

Assembla, usando A86, a 51 byte. Non richiede librerie esterne diverse dalla funzione DOS Int21 AH = 9 (scrivere la stringa su stdout).

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

Temo di contare 357 byte. (e il tuo programma effettivamente genera 408) Buona implementazione, comunque. Potresti voler includere una sorgente assembly non-db in modo che altri spettatori possano dare un'occhiata diretta.
JB

@JB: non ho incluso CR \ NL. Guardandolo ora, avrei davvero dovuto mettere i dati in una singola linea db. Ciò lo renderebbe più piccolo.
Skizz

3

NASM, 223 byte

%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

Battere la risposta accettata!


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}

Una sola riga, nessuna interruzione di riga alla fine.

Prima versione formattata e commentata (anche se non è più una quine) - è improbabile che mi discosti molto dal concetto generale:

.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
}

Storia :

  • 06/02/2011 16:48 (727) - Prima versione funzionante.
  • 2011-02-06 17:14 (723) - Non ho bisogno di uno spazio dopo una stringa letterale.
  • 06/02/2011 17:21 (691) - dupè più breve della scrittura ldloc.1ogni volta.
  • 2011-02-06 17:24 (669) - Non ho bisogno di spazi dopo alcun valore letterale e cose del genere ldloc.1possono essere scritte ldloc 1per rendere l'ultimo token letterale. Il codice byte risultante è probabilmente più grande, ma riguarda il codice dell'assemblatore, quindi non me ne può fregare di meno :-)
  • 2011-02-06 17:34 (623) - Non ho bisogno di object[]come variabile locale; Posso fare tutto direttamente in pila. Bello.

Sembra che tu abbia rimosso l'oggetto [] dalla versione non formattata, ma non quella formattata ...
Aurel Bílý

@Aurel: In effetti, come notato, il formattato è la primissima versione. L'idea è sempre la stessa, quindi non la aggiornerò più.
Joey,

2

gas per x86 Linux, 184 176 byte

.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"

Costruisci con gcc -m32 -o a.out quine.S. ( -m32È facoltativo se il tuo sistema operativo è già a 32 bit.)

Modificato per aggiungere: Se modifichiamo le regole per consentire putsdi essere chiamate anziché, printfciò può essere fatto in 182 174 byte:

.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"

(Nota che questo, a differenza del precedente, ha una nuova riga finale.)


Apprezzo la mancanza. Ma mi sento ingannato dal fatto che oltre a printf / put, in realtà dipendi dallo standard C prolog / epilog, che non è esplicitamente consentito. E IMHO non doveva essere; ma ho la risposta migliore: ovviamente sono di parte :-)
JB

Bene, si potrebbe sostenere che l'uso del C prolog / epilog è implicitamente consentito, a causa della menzione dell'uso di printf (). Le funzioni libc non si comportano sempre in modo affidabile se si ignora C prolog / epilog. In effetti sul mio sistema, la tua versione non funziona se installo l'output in un file, perché stdout viene scaricato solo nel codice C epilog. (Se avessimo invece usato write (), che è solo un wrapper attorno a un syscall, avrebbe funzionato in entrambi i modi.)
breadbox

È passato un bel po 'di tempo ormai, ma mi sembra di ricordare che la concessione delle funzioni C sia stata una sorpresa per me allora: ha reso il problema un po' impuro. OP non esiste da molto tempo; sarà difficile richiedere chiarimenti ora.
JB

Si noti che l'ABI consente printfdi bloccare i suoi argomenti nello stack. Non è tecnicamente sicuro semplicemente callripeterlo e aspettarsi gli stessi argomenti, ma funziona in pratica perché gcc / clang non usa mai gli slot arg come spazio di lavoro, AFAIK.
Peter Cordes,

Inoltre, in generale non è sicuro chiamare printfda _start(ad esempio in un binario statico), quindi questo è un buon argomento per scrivere un maininvece di un _start. Questa risposta spiega i vari modi di collegare libc da binari statici o dinamici. (In un binario dinamico Linux, il linker dinamico eseguirà le funzioni di inizializzazione di glibc, quindi è possibile utilizzarlo printfdal _startpunto di ingresso, ma non è il caso su Cygwin IIRC.)
Peter Cordes,

1

ASM avviabile, 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

Originariamente di jdiez17 , giocato davvero dal tuo.


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
Non è necessario uno spazio dopo la virgola tra gli operandi. E non ti serve xor eax,eaxaffatto se non ti interessa lo stato di uscita del tuo programma. Stampa ancora se stesso, anche se esce con uno stato diverso da zero. Puoi anche usare al pushposto di pushq. In realtà, perché stai addirittura creando un frame stack? Rilascia il push rbp/ mov rsp, rbpe leave. È inoltre possibile utilizzare nomi di etichette più brevi. .Csè di 3 caratteri quando 1 andrebbe bene.
Peter Cordes,

Dopodiché, .att_syntax noprefixprobabilmente non si ripaga più. .intel_syntax noprefixti lascerebbe cadere anche quei sei $prefissi. ma probabilmente non ne vale ancora la pena. (È possibile utilizzare al lea ecx,.Csposto della sintassi Intel 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

Per eseguirlo, chiama ::tcl::unsuppoted::assemblecon il codice come argomento.
Solo Tcl 8.6.


3
È necessario includere il conteggio dei byte.
MD XF,

0

80x86 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.