Compiled quine variant

5

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.

Petr Pudlák

Posted 2012-11-10T11:06:53.070

Reputation: 4 272

3Is assembly language considered eligible for this challenge? – Ilmari Karonen – 2012-11-10T12:50:12.233

@IlmariKaronen Good question. I'd say yes, because compiled output is very different from what you type in source code. – Petr Pudlák – 2012-11-10T13:52:40.063

Can you read the compiled code from memory? Something like main(){write(1, main, SIZE);}? – ugoren – 2012-11-10T19:13:15.357

@ugoren No, that'd be similar to reading the code from a file. – Petr Pudlák – 2012-11-10T20:02:02.037

Answers

4

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

copy

Posted 2012-11-10T11:06:53.070

Reputation: 6 466

2If I understand correctly, it reads compiled code from memory. – ugoren – 2012-11-11T05:12:58.280

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). – Petr Pudlák – 2012-11-11T07:03:25.577

1@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. – copy – 2012-11-11T12:34:43.980

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? – Petr Pudlák – 2012-11-11T14:51:52.920

@PetrPudlák fixed. – copy – 2012-11-11T15:32:59.700

Just to clarify, the assembler's being asked to assemble two copies of the code (see the %rep … %endrep); one set of assembler output is treated as code by the program, the other as data (and obviously they're identical because the assembler is deterministic in this case; all the references to other addresses in the code are relative). The DOS .com format doesn't provide any way of specifying what is code and what is data, thus that distinction doesn't need to appear in the source. – None – 2017-04-06T14:02:57.330

1

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.

Fraxtil

Posted 2012-11-10T11:06:53.070

Reputation: 2 495

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). – Petr Pudlák – 2012-11-12T05:22:31.650

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. – Fraxtil – 2012-11-12T19:11:28.890

0

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  :........(w@..s="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  :..@...A.A@......$.......
000000d8:  0680 4000 0cc0 4100 8600 4200 8740 4201 c680 4200 0601 4000  :..@...A...B..@B...B...@.
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

ATaco

Posted 2012-11-10T11:06:53.070

Reputation: 7 898