9
\$\begingroup\$

Thinking about various quine puzzles here, I got an idea for another one:

Compose a program that outputs its own compiled code to a file (or multiple files, if the compiled code is). (This means that only compiled languages are eligible.)

Rules

Standard quine rules - no cheating allowed. In particular:

  1. The program cannot read the compiled code from disk, cannot store it somewhere etc. It must compute it somehow without external help.
  2. If the program is compiled to several files (i.e. several Java .class files), it must output them all.
  3. You can use any existing libraries available for your language. However:
    • The libraries you use cannot be something created just for this task. (For example in order to keep some information away from what's considered to be the program.)
    • Any libraries you use must be older than your program. You cannot just create a program that loads a piece of data from an external library, compile the program, and copy the compiled code into the library - that'd be cheating.
    • You cannot embed a compiler of your language in any form. In particular, you cannot just take a standard quine and hook it up with a compiler to produce the compiled output.
  4. As mentioned, only compiled languages are eligible. You can use a scripting language as long as it can be compiled to a bytecode that's reasonably different from the source form (if you're not sure, better ask).

Notes

Most likely, this puzzle can be solved reasonably only in languages that compile to some sort of bytecode that can be manipulated. For example, Java and compiled bytecode seems good for the task. (But if you find a genuine solution in some other compiled language, that's fine too, as long as it isn't some sort of cheating.)

Submission

Don't submit the compiled program (as this could be potentially dangerous). Instead post your sources and a description what to do to create the final program.

Evaluation

Let voters decide the best solution. Personally I'd appreciate solution that are elegant, short (in their source form) and didactic - that explain what's going on.

Bonuses

Bonus points for

  • Let the program output a compressed file containing its compiled code. This has the additional benefit that if the program is compiled into more files, the output will be a single packed file. For example, in Java try to create an executable JAR file that outputs the JAR itself.
  • Outputting the MD5 sum of the compiled file(s) - so the program would write its compiled code and its MD5 sum.
\$\endgroup\$
4
  • 3
    \$\begingroup\$ Is assembly language considered eligible for this challenge? \$\endgroup\$ Nov 10, 2012 at 12:50
  • \$\begingroup\$ @IlmariKaronen Good question. I'd say yes, because compiled output is very different from what you type in source code. \$\endgroup\$
    – Petr
    Nov 10, 2012 at 13:52
  • \$\begingroup\$ Can you read the compiled code from memory? Something like main(){write(1, main, SIZE);}? \$\endgroup\$
    – ugoren
    Nov 10, 2012 at 19:13
  • \$\begingroup\$ @ugoren No, that'd be similar to reading the code from a file. \$\endgroup\$
    – Petr
    Nov 10, 2012 at 20:02

4 Answers 4

8
\$\begingroup\$

Assembly (DOS .com file)

start:

%rep 2
    call $+3

    mov ah, 9
    mov dx, 100h + (end - start) / 2
    int 21h

    mov ah, 2
    mov dl, "$" - 1
    inc dx
    int 21h

    ret
    db "$"

%endrep

end:

Assemble with nasm quine.asm -o quine.com. Try with dosbox quine.com.

Proof of correctness (you can also verify by the smilies here):

dosbox quine screenshot

\$\endgroup\$
6
  • 3
    \$\begingroup\$ If I understand correctly, it reads compiled code from memory. \$\endgroup\$
    – ugoren
    Nov 11, 2012 at 5:12
  • 1
    \$\begingroup\$ I have to agree with @ugoren. The point of a quine is to construct its own code, not to read it from somewhere (whether it is a file or memory). For example, it could happen that the OS forbids reading the program's code (not under DOS probably, but in general). \$\endgroup\$
    – Petr
    Nov 11, 2012 at 7:03
  • 2
    \$\begingroup\$ @PetrPudlák The program actually consists of a code and a data section, which cannot really be separated in a .com executable. In my understanding this is a valid quine, because no byte is both interpreted as an instruction and written to output. \$\endgroup\$
    – copy
    Nov 11, 2012 at 12:34
  • \$\begingroup\$ OK I think I understand now how it works. But I cannot compile it, nasm tells me: quine.asm:16: error: division operator may only be applied to scalar value. Any ideas? \$\endgroup\$
    – Petr
    Nov 11, 2012 at 14:51
  • \$\begingroup\$ @PetrPudlák fixed. \$\endgroup\$
    – copy
    Nov 11, 2012 at 15:32
3
\$\begingroup\$

Python 2.7.3

#!/usr/bin/env python
import sys
import time
import struct
import compiledquine

_ = '\x63\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x40\x00\x00\x00\x73\x6e\x00\x00\x00\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x00\x00\x64\x00\x00\x64\x01\x00\x6c\x01\x00\x5a\x01\x00\x64\x00\x00\x64\x01\x00\x6c\x02\x00\x5a\x02\x00\x64\x00\x00\x64\x01\x00\x6c\x03\x00\x5a\x03\x00\x64\x02\x00\x5a\x04\x00\x65\x00\x00\x6a\x05\x00\x6a\x06\x00\x64\x03\x00\x65\x02\x00\x6a\x07\x00\x64\x04\x00\x65\x08\x00\x65\x01\x00\x6a\x01\x00\x83\x00\x00\x83\x01\x00\x83\x02\x00\x17\x65\x04\x00\x65\x04\x00\x16\x17\x83\x01\x00\x01\x64\x01\x00\x53\x28\x05\x00\x00\x00\x69\xff\xff\xff\xff\x4e\x73\x08\x00\x00\x00%s\x73\x04\x00\x00\x00\x03\xf3\x0d\x0a\x74\x01\x00\x00\x00\x49\x28\x09\x00\x00\x00\x74\x03\x00\x00\x00\x73\x79\x73\x74\x04\x00\x00\x00\x74\x69\x6d\x65\x74\x06\x00\x00\x00\x73\x74\x72\x75\x63\x74\x74\x0d\x00\x00\x00\x63\x6f\x6d\x70\x69\x6c\x65\x64\x71\x75\x69\x6e\x65\x74\x01\x00\x00\x00\x5f\x74\x06\x00\x00\x00\x73\x74\x64\x6f\x75\x74\x74\x05\x00\x00\x00\x77\x72\x69\x74\x65\x74\x04\x00\x00\x00\x70\x61\x63\x6b\x74\x03\x00\x00\x00\x69\x6e\x74\x28\x00\x00\x00\x00\x28\x00\x00\x00\x00\x28\x00\x00\x00\x00\x73\x1c\x00\x00\x00\x2f\x68\x6f\x6d\x65\x2f\x67\x72\x61\x6e\x74\x2f\x63\x6f\x6d\x70\x69\x6c\x65\x64\x71\x75\x69\x6e\x65\x2e\x70\x79\x74\x08\x00\x00\x00\x3c\x6d\x6f\x64\x75\x6c\x65\x3e\x02\x00\x00\x00\x73\x0a\x00\x00\x00\x0c\x01\x0c\x01\x0c\x01\x0c\x02\x06\x01'
sys.stdout.write('\x03\xf3\x0d\x0a' + struct.pack('I', int(time.time())) + _ % _)

Note that this must be saved as compiledquine.py. These are the results I get:

$ ./compiledquine.py > compiledquine.py.out
$ md5sum compiledquine.pyc compiledquine.py.out
4b82e7d94d0d59e3d647d775fffc1948  compiledquine.pyc
4b82e7d94d0d59e3d647d775fffc1948  compiledquine.py.out

I won't guarantee that it'll work for you, but it does consistently work for me. Here's what happens:

  • At the bottom of the import statements, the script itself is imported. This compiles it to a .pyc file.
  • The variable _ is filled with the program's bytecode starting at byte 0x08, except %s is put in place of the variable itself.
  • The script fills in the first 4 'magic' bytes, which are specific to Python 2.7.3, followed by the timestamp in the next 4 bytes, which is generated by struct.pack and time.time, and then adds _ % _ to complete the output. (That last bit is borrowed from some other Python quines.)
  • Because of the timestamp at the beginning, this script technically isn't always accurate. If the self-import and the last line execute in different seconds, the output will be a byte off.
\$\endgroup\$
2
  • \$\begingroup\$ It seems to me there is a typo - shouldn't it be md5sum compiledquine.pyc compiledquine.py.out? However I tried and .pyc (679 bytes) is very different from .out (1372 bytes). \$\endgroup\$
    – Petr
    Nov 12, 2012 at 5:22
  • \$\begingroup\$ That was indeed a typo, my bad. And I'm not sure what to tell you regarding the outputs of .pyc and .out. For what it's worth, I'm using CPython 2.7.3 on 32-bit Linux. \$\endgroup\$
    – ashastral
    Nov 12, 2012 at 19:11
0
\$\begingroup\$

Lua

s="s=%qf=io.open('dump.txt','w')f:write(string.dump(load(s:format(s))))"f=io.open('dump.txt','w')f:write(string.dump(load(s:format(s))))

Now, one's first concern may be that Lua is 'An Interpreted Language, not a compiled one' However, Lua actually interprets by compiling at runtime. string.dump returns the compiled byte code of the function supplied, and load returns the function defined by the string supplied.

Very simply, makes a function out of itself through the usual Lua quine method, then writes its compiled output.

Output

LuaS “


xV           (w@‰s="s=%qf=io.open('dump.txt','w')f:write(string.dump(load(s:format(s))))"f=io.open('dump.txt','w')f:write(string.dump(load(s:format(s))))            @@€À@  A A@ € $€€  €@ ÀA † B ‡@BÆ€B @ ÁB†@ $€ä   ¤   $@  & €    sEs=%qf=io.open('dump.txt','w')f:write(string.dump(load(s:format(s))))fioopen  dump.txtwwritestringdumploadformat                                                                              _ENV

Contains mostly unprintable characters, so here's a Hex Dump

00000000:  1b4c 7561 5300 1993 0d0d 0a1a 0d0a 0408 0408 0878 5600 0000  :.LuaS..............xV...
00000018:  0000 0000 0000 0000 2877 4001 8973 3d22 733d 2571 663d 696f  :........([email protected]="s=%qf=io
00000030:  2e6f 7065 6e28 2764 756d 702e 7478 7427 2c27 7727 2966 3a77  :.open('dump.txt','w')f:w
00000048:  7269 7465 2873 7472 696e 672e 6475 6d70 286c 6f61 6428 733a  :rite(string.dump(load(s:
00000060:  666f 726d 6174 2873 2929 2929 2266 3d69 6f2e 6f70 656e 2827  :format(s))))"f=io.open('
00000078:  6475 6d70 2e74 7874 272c 2777 2729 663a 7772 6974 6528 7374  :dump.txt','w')f:write(st
00000090:  7269 6e67 2e64 756d 7028 6c6f 6164 2873 3a66 6f72 6d61 7428  :ring.dump(load(s:format(
000000a8:  7329 2929 2900 0000 0000 0000 0000 0207 1400 0000 0840 4080  :s))))................@@.
000000c0:  06c0 4000 0700 4100 4140 0100 8180 0100 2480 8001 0800 0081  :[email protected]@......$.......
000000d8:  0680 4000 0cc0 4100 8600 4200 8740 4201 c680 4200 0601 4000  :[email protected][email protected]...@.
000000f0:  0cc1 4202 8601 4000 2401 8001 e400 0000 a400 0000 2440 0000  :..B...@.$...........$@..
00000108:  2600 8000 0c00 0000 0402 7314 4573 3d25 7166 3d69 6f2e 6f70  :&.........s.Es=%qf=io.op
00000120:  656e 2827 6475 6d70 2e74 7874 272c 2777 2729 663a 7772 6974  :en('dump.txt','w')f:writ
00000138:  6528 7374 7269 6e67 2e64 756d 7028 6c6f 6164 2873 3a66 6f72  :e(string.dump(load(s:for
00000150:  6d61 7428 7329 2929 2904 0266 0403 696f 0405 6f70 656e 0409  :mat(s))))..f..io..open..
00000168:  6475 6d70 2e74 7874 0402 7704 0677 7269 7465 0407 7374 7269  :dump.txt..w..write..stri
00000180:  6e67 0405 6475 6d70 0405 6c6f 6164 0407 666f 726d 6174 0100  :ng..dump..load..format..
00000198:  0000 0100 0000 0000 1400 0000 0100 0000 0100 0000 0100 0000  :........................
000001b0:  0100 0000 0100 0000 0100 0000 0100 0000 0100 0000 0100 0000  :........................
000001c8:  0100 0000 0100 0000 0100 0000 0100 0000 0100 0000 0100 0000  :........................
000001e0:  0100 0000 0100 0000 0100 0000 0100 0000 0100 0000 0000 0000  :........................
000001f8:  0100 0000 055f 454e 56                                       :....._ENV
\$\endgroup\$
0
\$\begingroup\$

Python 3, 161 bytes

s = 's = %s; print(compile(s %% repr(s), \'file\', \'exec\').co_code.decode(\'utf-16\'))'; print(compile(s % repr(s), '<file>', 'exec').co_code.decode('utf-16'))

Try it online!

This one outputs its EXACT bytecode (that is, the bytecode that is stored in the Python interpreter when you run the program.)

Python 3, 328 bytes (Extension)

import zipfile
with zipfile.ZipFile("output.zip", "w") as f:s = 'import zipfile\n\nwith open(\"output.zip\", \"w\") as f:\ns = %s\nf.writestr(\n\'output\',\ndata=(compile(s %% repr(s), \'file\', \'exec\').co_code.decode(\'utf-16\')))\n';f.writestr('output',data=(compile(s % repr(s), '<file>', 'exec')).co_code.decode('utf-16'))

Try it online!

This one prints its EXACT bytecode (that is, the bytecode that is stored in the Python interpreter when you run the program. It also outputs it being compressed.)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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