Lenguaje de ensamblaje quine


21

Escriba la quine más breve posible en lenguaje ensamblador .

Use cualquier ISA que desee, a menos que tenga una print-quineinstrucción o equivalente. Los ejemplos incluyen x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM, etc.

Puede vincular contra la _printffunción de la biblioteca estándar de C (o el equivalente de Java para el código de bytes JVM) para E / S.

La longitud se juzgará tanto por el recuento de instrucciones como por el tamaño del segmento de datos. Las soluciones deben contener al menos dos instrucciones.

La quine debe imprimir el código de ensamblaje , no el código de máquina ensamblado.


3
Oh, wow, esto suena como una Toughy
Anonymous Coward

Respuestas:


20

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

(He compilado con esto: gcc -nostartfiles -lc quine.S -o quine)


Eso es deprimente, ahora :-(
Joey

1
Por lo general, diría "la herramienta adecuada para el trabajo", pero de nuevo, aquí no se siente bien: D
JB

Parece ser más correcto que el mío, sin embargo ;-)
Joey

5

JVM Asamblea Bytecode (a través de 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

Lamentablemente, Jasmin no permite tantos trucos agradables como los de Microsoft ilasm. Pero la JVM tiene un total de seisdup instrucciones diferentes que hacen todo tipo de cosas divertidas. Reordenar elementos en la pila es algo que .NET no parece admitir.

En cualquier caso, creo que ninguna de mis dos entradas son contendientes serios para el código más corto, pero creo que es difícil hacerlos mucho más cortos. Por lo tanto, solo para completar :-)

Versión comentada con información sobre lo que está en la pila:

.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

Historia:

  • 2011-02-07 02:09 (990) - Primera versión de trabajo.
  • 2011-02-07 02:11 (960) - ldces más corto que bipusho iconst_*.
  • 2011-02-07 02:30 (952) - ¿Quién dice que necesito heredar de java.lang.Object? Otros nombres de clase son mucho más cortos :-)

4

gas para x86 Linux (89 bytes, siete instrucciones)

Técnicamente, esto es trampa.

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

Guardar en un archivo llamado ay ensamblar con los siguientes comandos para crear el ejecutable llamado a.out.

as -o a.o ; ld a.o

La directiva .incbinincluye un archivo literalmente en la ubicación actual. Si usa esto para incluir el código fuente en sí, obtendrá un buen quine.


3

Formato .COM de Windows: 307 caracteres

Ensambla, usando A86, a 51 bytes. No requiere bibliotecas externas que no sean la función Int21 AH = 9 de DOS (escribir cadena en 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

Me temo que cuento 357 bytes. (y su programa realmente genera 408) Sin embargo, es una buena implementación. Es posible que desee incluir una fuente de ensamblaje sin db'd para que otros espectadores puedan ver directamente.
JB

@JB: no incluí CR \ NL. Mirándolo ahora, realmente debería haber puesto los datos en una sola línea de base de datos. Eso lo haría más pequeño.
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

Batir la respuesta aceptada!


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 línea, sin salto de línea al final.

Primera versión formateada y comentada (aunque ya no es una quine): es poco probable que me desvíe mucho del concepto general:

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

Historia :

  • 2011-02-06 16:48 (727) - Primera versión de trabajo.
  • 2011-02-06 17:14 (723) - No necesito un espacio después de un literal de cadena.
  • 2011-02-06 17:21 (691) - dupes más corto que escribir ldloc.1cada vez.
  • 2011-02-06 17:24 (669) - No necesito espacios después de ningún literal y ldloc.1se pueden escribir cosas como ldloc 1para hacer que el último token sea literal. El bytecode resultante es probablemente más grande, pero se trata del código ensamblador, por lo que no podría importarme menos :-)
  • 2011-02-06 17:34 (623) - No necesito el object[]como variable local; Puedo hacer todo eso en la pila directamente. Agradable.

Parece que ha eliminado el objeto [] de la versión sin formato, pero no la formateada ...
Aurel Bílý

@Aurel: De hecho, como se señaló, el formato es la primera versión. La idea sigue siendo la misma, así que no la volveré a actualizar.
Joey

2

gas para 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"

Construir con gcc -m32 -o a.out quine.S. (El -m32es opcional si su sistema operativo ya es de 32 bits).

Editado para agregar: si modificamos las reglas para permitir putsque se invoque en lugar de printfeso, se puede hacer en 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"

(Tenga en cuenta que este, a diferencia del anterior, tiene una nueva línea de finalización).


Agradezco la brevedad. Pero me siento engañado por el hecho de que, además de printf / put, realmente depende del prólogo / epílogo C estándar, que no está explícitamente permitido. Y en mi humilde opinión no estaba destinado a ser; pero tengo la respuesta principal: obviamente soy parcial :-)
JB

Bueno, uno podría argumentar que usar el prólogo / epílogo C está implícitamente permitido, debido a la mención de usar printf (). Las funciones de libc no siempre se comportan de manera confiable si omite el prólogo / epílogo de C. De hecho, en mi sistema, su versión no funciona si canalizo la salida a un archivo, porque stdout solo se vacía en el código del epílogo C. (Si hubiéramos utilizado en lugar de escritura (), que es sólo un envoltorio alrededor de una llamada al sistema, habría trabajado en ambos sentidos.)
panera

Ha pasado bastante tiempo, pero recuerdo que las funciones de C permitidas fueron una sorpresa para mí en ese momento: hizo que el problema pareciera impuro. OP no ha existido en mucho tiempo tampoco; Va a ser difícil solicitar una aclaración ahora.
JB

Tenga en cuenta que el ABI permite printfgolpear sus argumentos en la pila. No es técnicamente seguro callvolver a usarlo y esperar los mismos args, pero funciona en la práctica porque gcc / clang nunca usa ranuras de args como espacio para rascar, AFAIK.
Peter Cordes

Además, en general no es seguro llamar printfdesde _start(por ejemplo, en un binario estático), por lo que es un buen argumento para escribir un en mainlugar de un _start. Esta respuesta explica las diversas formas de vincular libc desde binarios estáticos o dinámicos. (En un binario dinámico de Linux, el enlazador dinámico ejecutará las funciones de inicializador de glibc, por lo que puede usarlo printfdesde el _startpunto de entrada, pero ese no es el caso en cygwin IIRC.)
Peter Cordes

1

ASM de arranque, 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 , jugado por el tuyo de verdad.


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"

1
No necesita un espacio después de la coma entre operandos. Y no necesita xor eax,eaxnada si no le importa el estado de salida de su programa. Todavía se imprime, incluso si sale con un estado distinto de cero. También puede usar en pushlugar de pushq. En realidad, ¿por qué estás haciendo un marco de pila? Suelta el push rbp/ mov rsp, rbpy leave. También podría usar nombres de etiqueta más cortos. .Csson 3 caracteres cuando 1 estaría bien.
Peter Cordes

Después de eso, .att_syntax noprefixprobablemente ya no se pague solo. .intel_syntax noprefixtambién te permitiría eliminar esos seis $prefijos. pero probablemente aún no valga la pena. (Podría usar en lea ecx,.Cslugar de la sintaxis de inteligencia 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 ejecutarlo, llame ::tcl::unsuppoted::assemblecon el código como argumento.
Tcl 8.6 solamente.


3
Debe incluir el recuento de bytes.
MD XF

0

80x86 TASM, 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.