Linguagem Assembly Quine


20

Escreva o quine mais curto possível em linguagem assembly .

Use qualquer ISA desejado, a menos que tenha uma print-quineinstrução ou equivalente. Os exemplos incluem x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM, etc.

Você pode vincular à _printffunção da biblioteca padrão C (ou o equivalente em Java para o bytecode da JVM) para E / S.

O comprimento será avaliado tanto na contagem de instruções quanto no tamanho do segmento de dados. As soluções devem conter pelo menos duas instruções.

O quine deve imprimir o código de montagem , não o código de máquina montado.


3
Oh uau, isso soa como um
covarde

Respostas:


20

x86 Linux, sintaxe 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"

(Eu compilei com isso gcc -nostartfiles -lc quine.S -o quine:)


Isso é deprimente, agora :-(
Joey

11
Eu normalmente diria "a ferramenta certa para o trabalho", mas, novamente, aqui não parece certo: D
JB

Parece ser mais certo do que a minha, embora ;-)
Joey

5

JVM Assembléia Bytecode (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

Infelizmente, o Jasmin não permite tantos truques legais quanto os da Microsoft ilasm. Mas a JVM possui um total de seisdup instruções diferentes que fazem todos os tipos de coisas divertidas. Reordenar itens na pilha é algo que o .NET parece não suportar.

De qualquer forma, acho que nenhuma das minhas duas entradas é um candidato sério ao código mais curto, mas acho que é difícil reduzi-las. Portanto, apenas para completar :-)

Versão comentada com informações sobre o que está na pilha:

.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

História:

  • 2011-02-07 02:09 (990) - Primeira versão de trabalho.
  • 2011-02-07 02:11 (960) - ldcé mais curto que bipushou iconst_*.
  • 07-02-2011 02:30 (952) - Quem disse que preciso herdar do java.lang.Object? Outros nomes de classe são muito mais curtos :-)

4

gás para x86 Linux (89 bytes, sete instruções)

Tecnicamente, isso é trapaça.

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

Salve em um arquivo nomeado ae monte com os seguintes comandos para criar o executável nomeado a.out.

as -o a.o ; ld a.o

A diretiva .incbininclui um arquivo literalmente no local atual. Se você usar isso para incluir o próprio código-fonte, obterá uma boa solução.


3

Formato Windows .COM: 307 caracteres

Monta, usando A86, em 51 bytes. Não requer bibliotecas externas além da função DOS Int21 AH = 9 (grave a string em 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

Receio contar 357 bytes. (e seu programa realmente gera 408) Boa implementação, no entanto. Convém incluir a fonte de montagem não db'd para que outros visualizadores tenham uma visão direta.
JB

@JB: Eu não incluí CR \ NL. Olhando agora, eu realmente deveria ter colocado os dados em uma única linha de banco de dados. Isso tornaria menor.
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

Superando a resposta aceita!


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}

Uma única linha, sem quebra de linha no final.

Primeira versão formatada e comentada (mesmo que não seja mais uma solução) - é improvável que eu me afaste muito do conceito geral:

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

História :

  • 06-02-2011 16:48 (727) - Primeira versão de trabalho.
  • 06-02-2011 17:14 (723) - Eu não preciso de um espaço depois de uma string literal.
  • 06-02-2011 17:21 (691) - dupé mais curto que escrever ldloc.1sempre.
  • 06-02-2011 17:24 (669) - Não preciso de espaços depois de qualquer literal e coisas do tipo ldloc.1podem ser escritas ldloc 1para tornar o último token literal. O bytecode resultante provavelmente é maior, mas é sobre o código do assembler, então eu não poderia me importar menos :-)
  • 06-02-2011 17:34 (623) - Não preciso da object[]variável local; Eu posso fazer tudo isso diretamente na pilha. Agradável.

Parece que você removeu o objeto [] da versão não formatada, mas não a formatada ...
Aurel Bílý

@Aurel: De fato, como observado, o formatado é a primeira versão. A ideia ainda é a mesma, então não a atualizarei novamente.
Joey

2

gás para Linux x86, 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"

Construa com gcc -m32 -o a.out quine.S. (Isso -m32é opcional se o seu sistema operacional já tiver 32 bits.)

Editado para adicionar: se modificarmos as regras para permitir putsa chamada em vez de printf, isso poderá ser feito em 182 174 bytes:

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

(Observe que este, diferentemente do anterior, tem uma nova linha final.)


Eu aprecio a falta. Mas sinto-me enganado pelo fato de que, além de printf / puts, você realmente depende do prólogo / epílogo C padrão, o que não é explicitamente permitido. E IMHO não era para ser; mas eu tenho a resposta superior: obviamente, eu sou preconceituoso :-)
JB

Bem, alguém poderia argumentar que o uso do prólogo / epílogo C é implicitamente permitido, devido à menção do uso de printf (). As funções libc nem sempre se comportam de maneira confiável se você ignorar o prólogo / epílogo C. De fato, no meu sistema, sua versão não funcionará se eu canalizar a saída para um arquivo, porque o stdout só é liberado no código de epilog C. (Se tivéssemos vez utilizado write (), que é apenas um wrapper em torno de um syscall, teria funcionado de qualquer maneira.)
breadbox

Já faz muito tempo, mas me lembro que as funções C permitidas eram uma surpresa para mim naquela época: isso fez o problema parecer meio impuro. O OP também não existe há muito tempo; vai ser difícil solicitar esclarecimentos agora.
JB

Observe que a ABI permite printfacumular seus argumentos na pilha. Tecnicamente, não é seguro apenas callrepetir e esperar os mesmos argumentos, mas funciona na prática porque o gcc / clang nunca usa slots de argumentos como espaço temporário, o AFAIK.
Peter Cordes

Além disso, em geral, não é seguro chamar printffrom _start(por exemplo, em um binário estático), portanto esse é um bom argumento para escrever um em mainvez de a _start. Esta resposta explica as várias maneiras de vincular libc de binários estáticos ou dinâmicos. (Em um binário dinâmico do Linux, o vinculador dinâmico será executado funções inicializador do glibc, assim você pode usar printfa partir do _startponto de entrada, mas isso não é o caso em cygwin IIRC.)
Peter Cordes

1

ASM inicializável, 660 bytes

[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

Originalmente por jdiez17 , jogado de verdade pelo seu.


0

x86-64, Sistema 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"

11
Você não precisa de um espaço após a vírgula entre operandos. E você não precisa xor eax,eaxse não se importa com o status de saída do seu programa. Ele ainda se imprime, mesmo que saia com um status diferente de zero. Você também pode usar em pushvez de pushq. Na verdade, por que você está fazendo um quadro de pilha? Solte o push rbp/ mov rsp, rbpe leave. Você também pode usar nomes mais curtos de etiqueta. .Cstem 3 caracteres quando 1 seria bom.
Peter Cordes

Depois disso, .att_syntax noprefixprovavelmente não se paga mais. .intel_syntax noprefixdeixaria você soltar esses seis $prefixos também. mas provavelmente ainda não vale a pena. (Você pode usar lea ecx,.Csem vez da intel-sintaxe 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

Para executá-lo, chame ::tcl::unsuppoted::assemblecom o código como argumento.
Apenas Tcl 8.6.


3
Você deve incluir a contagem de bytes.
MD XF

0

TASM de 80x86, 561 bytes

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.