Live data from Hacker News

An 8086 PC emulator in 4043 bytes

ioccc.org

31–39 of 39 posts

Re: An 8086 PC emulator in 4043 bytes

#31
post #16

This is interesting, though it might be a bit of a cheat. He's put some data in the BIOS image to assist in decoding instructions (not to take away from how amazing this is!): "CPU supports the full 8086/186 instruction set. Due to the complexities of the 8086’s arbitrary-length instruction decoding and flags, 8086 instructions are first converted to a simpler intermediate format before being executed. This conversio…

Abuse of the rules, if done well, is a time-honored IOCCC tradition.

It's not the only abuse of the rules. Looking at the hint, I think there's some flaw in the size-testing tool which they've exploited.

Re: An 8086 PC emulator in 4043 bytes

#32
post #16

Earlier quoted context omitted.

Abuse of the rules, if done well, is a time-honored IOCCC tradition.

It's not the only abuse of the rules. Looking at the hint, I think there's some flaw in the size-testing tool which they've exploited.

The hint mentions "the importance of comments". The only comment I can spot in the actual code is here (with a couple of characters of context):

    I/**/n
The code up to that point (2100 bytes total) is roughly as long as the listed output of the size tool (1979). The difference is probably due to the fact that I just counted raw bytes rather than accounting for whitespace and such. My guess, then, is that /* */ without a space hits a bug in the size tool where it probably counts that as the beginning of a comment but misses the end, causing it to count the entire remainder of the program as a comment. The compiler, meanwhile, will see that as an empty comment and continue reading code.

This was a fairly predictable consequence of providing an official size tool. Used to be, they just laid out the rules for figuring out sizes, and you had to either count manually, or build your own tool to count. Now, bugs in the size tool end up being bugs in the rules, and fun like this ensues. Whether this is good or bad is a matter of opinion. I would say it certainly makes things interesting!

Edit: HN formatting makes the inline form of that comment look like a C++/C99-style // comment. Fun!

Re: An 8086 PC emulator in 4043 bytes

#33
post #32

Earlier quoted context omitted.

It's not the only abuse of the rules. Looking at the hint, I think there's some flaw in the size-testing tool which they've exploited.

The hint mentions "the importance of comments". The only comment I can spot in the actual code is here (with a couple of characters of context): I/**/n The code up to that point (2100 bytes total) is roughly as long as the listed output of the size tool (1979). The difference is probably due to the fact that I just counted raw bytes rather than accounting for whitespace and such. My guess, then, is that /* */ without…

Clearly the official tool runs the C source code through a markdown interpreter first!

Re: An 8086 PC emulator in 4043 bytes

#34
> Instruction codings are complex and irregular in size and structure, with multiple addressing modes and no consistent memory placement for operands, very often multiple possible encodings for the same instruction

It's only complex and irregular if you look at it wrong. ;)

The x86 (like the 808{5,6} and the Z80) instructions look organised in an octal format: ftp://mipt.cc/Opcode.txt

I haven't inspected the code in any detail to see if it takes advantage of this.

Re: An 8086 PC emulator in 4043 bytes

#35
post #22

Here's a link to a fully functional Windows binary (built with Visual Studio 2013): http://sdrv.ms/1hodqjP Just add the bios and image files elsewhere.

Missing MSVCR120D.dll. Can you compile in release mode or include that DLL too? Installing the Visual C++ Redistributable Packages for Visual Studio 2013 didn't help.

Note that you can link with MSVCRT.DLL to get an even smaller binary. Now you have a tiny emulator binary built from a tiny emulator source.

Re: An 8086 PC emulator in 4043 bytes

#36

Earlier quoted context omitted.

Did you do this by hand? Line 38 looks weird: main(BX,nE)char nE; {

No, just passed through gcc -E which essentially preprocesses the file only (in this case in order to unpack all the defines) without fully compiling.

For those that don't know C, basically preprocessing (cpp, gcc -E, clang -E) is one of the first steps to occurs before the C compiler is invoked. It's easiest to think of the preprocessor as a templating language that can be used (or abused) to DRY up code and make it easier to maintain and customize. So the only thing that ever really gets compiled is the amalgamated processed .c files altered and configured by .h files and preprocessor options.

Re: An 8086 PC emulator in 4043 bytes

#38

Has someone already unobfuscated the source code?

I did. Do you know the software license of the original code?

edit: P.S. working deobfuscation, i.e. you can build the executable. Including some minor corrections to the orgininal (e.g. 1MB of RAM allocation instead 2MB, BIOS file size limited to 65536-256 bytes, etc.). It a nice code, minimalistic, e.g. the "rep" prefixed instructions are actually repeated, not unrolled. Really optimized for code size. Even deobfuscated it takes 12-13KB and 22KB of executable (x86-64 Linux, stripped binary). Very cool.

Re: An 8086 PC emulator in 4043 bytes

#39

Earlier quoted context omitted.

No, just passed through gcc -E which essentially preprocesses the file only (in this case in order to unpack all the defines) without fully compiling.

For those that don't know C, basically preprocessing (cpp, gcc -E, clang -E) is one of the first steps to occurs before the C compiler is invoked. It's easiest to think of the preprocessor as a templating language that can be used (or abused) to DRY up code and make it easier to maintain and customize. So the only thing that ever really gets compiled is the amalgamated processed .c files altered and configured by .h…

In this case, even with the preprocessor and using "indent", the code is non-understandable. It requires a huge effort of deobfuscation (operator precedence mess, re-"macrofy" the code -as after expansion is very redundant, etc.). From the 4KB it goes to 30KB. After re-"macrofying" the code it drops to 15KB of somehow understandable code. It is a beautiful piece of code, no doubt.
Post reply on HN