Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Write the shortest possible assembly-language quine.

Use any ISA you want, unless it has a print-quine instruction or equivalent. Examples include x86, MIPS, SPARC, MMIX, IBM BAL, MIX, VAX, JVM, ARM, etc.

You may link against the C standard library's _printf function (or the Java equivalent for JVM bytecode) for I/O.

Length will be judged both on instruction count and size of the data segment. Solutions must contain at least two instructions.

The quine should print the assembly code, not the assembled machine code.

share|improve this question
2  
Oh wow, this sounds like a toughy – Charlie Somerville Feb 6 '11 at 0:47

8 Answers

up vote 11 down vote accepted

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"

(I compiled it with this: gcc -nostartfiles -lc quine.S -o quine)

share|improve this answer
That's depressing, now :-( – Joey Feb 6 '11 at 17:14
I'd usually say "the right tool for the job", but then again, here it doesn't feel right :D – J B Feb 6 '11 at 17:44
Seems to be more right than mine, though ;-) – Joey Feb 6 '11 at 22:37

gas for x86 Linux (89 bytes, seven instructions)

Technically, this is cheating.

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

Save in a file named a and assemble with the following commands to create the executable named a.out.

as -o a.o ; ld a.o

The directive .incbin includes a file verbatim at the current location. If you use this to include the source code itself, you get a nice quine.

share|improve this answer

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

A single line, no line break at the end.

Formatted and commented first version (even though it isn't a quine anymore) – it's unlikely that I deviate much from the general concept:

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

History:

  • 2011-02-06 16:48 (727) – First working version.
  • 2011-02-06 17:14 (723) – I don't need a space after a string literal.
  • 2011-02-06 17:21 (691) – dup is shorter than writing ldloc.1 every time.
  • 2011-02-06 17:24 (669) – I don't need spaces after any literal and things like ldloc.1 can be written as ldloc 1 to make the last token a literal. The resulting bytecode is likely larger, but it's about the assembler code so I couldn't care less :-)
  • 2011-02-06 17:34 (623) – I don't need the object[] as a local variable; I can do all that on the stack directly. Nice.
share|improve this answer
Seems like you've removed the object[] from the unformatted version, but not the formatted one... – Aurel300 Feb 6 '11 at 18:34
@Aurel: Indeed, as noted, the formatted is the very first version. The idea is still the same so I won't update it again. – Joey Feb 6 '11 at 18:41

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

Sadly, Jasmin doesn't allow as many nice tricks as Microsoft's ilasm allows. But the JVM has a total of six different dup instructions that do all kinds of fun things. Reordering items on the stack is something .NET doesn't seem to support.

In any case, I guess none of my two entries are serious contenders for shortest code but I guess it's hard to make them much shorter. Therefore just for completeness :-)

Commented version with info about what's on the 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

History:

  • 2011-02-07 02:09 (990) – First working version.
  • 2011-02-07 02:11 (960) – ldc is shorter than bipush or iconst_*.
  • 2011-02-07 02:30 (952) – Who says I need to inherit from java.lang.Object? Other class names are so much shorter :-)
share|improve this answer

gas for x86 Linux, 184 bytes:

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

Build with gcc -m32 -o a.out quine.S. (The -m32 is optional if your OS is already 32-bit.)

Edited to add: If we modify the rules to allow puts to be called instead of printf then it can be done in 182 bytes:

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

(Note that this one, unlike the previous one, has a terminating newline.)

share|improve this answer
I appreciate the shortness. But I do feel cheated by the fact that in addition to printf/puts, you actually depend on the standard C prolog/epilog, which isn't explicitely allowed. And IMHO wasn't meant to be; but I've got the top answer: obviously I'm biased :-) – J B May 6 '12 at 20:14
Well, one could argue that using the C prolog/epilog is implicitly allowed, due to the mention of using printf(). libc functions don't always behave reliably if you bypass the C prolog/epilog. In fact on my system, your version doesn't work if I pipe the output to a file, because stdout only gets flushed in the C epilog code. (Had we instead used write(), which is just a wrapper around a syscall, it would have worked either way.) – breadbox May 7 '12 at 8:55
It's a been pretty long time now, but I seem to recall the C functions' being allowed was a surprise to me back then: it did make the problem sound kind of impure. OP hasn't been around in a long time either; it's going to be hard to request clarification now. – J B May 7 '12 at 12:23

Windows .COM Format: 307 characters

Assembles, using A86, to 51 bytes. Requires no external libraries other than the DOS Int21 AH=9 function (write string to 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
share|improve this answer
I'm afraid I count 357 bytes. (and your program actually outputs 408) Nice implementation, though. You might want to include un-db'd assembly source so other viewers get a direct look. – J B Mar 7 '11 at 13:34
@J B: I didn't include CR\NL. Looking at it now, I really should have put the data into a single db line. That would make it smaller. – Skizz Mar 7 '11 at 18:35

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"
share|improve this answer

TAL

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

To execute it, call ::tcl::unsuppoted::assemble with the code as argument.
Tcl 8.6 only.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.