Merge pull request #119 from xexyl/2001-anonymous
This commit is contained in:
5 files changed
+161
-103
No files matched your search
@@ -190,12 +190,12 @@ all: data ${TARGET}
|
||||
supernova deep_magic magic charon pluto
|
||||
|
||||
${PROG}: ${PROG}.c
|
||||
@echo "NOTE: this entry seems to no longer work."
|
||||
magic='${CC} ${CFLAGS}'; \
|
||||
X='-DA(X)=#X'; \
|
||||
warning='-Dprocessor'; \
|
||||
$$magic $$warning -Dmagic= $$X "-DX=A($$magic \"$$X\")" \
|
||||
$< -o $@ ${LIBS}
|
||||
anonymous.c
|
||||
|
||||
# alternative executable
|
||||
#
|
||||
|
||||
+111
-96
@@ -9,136 +9,151 @@
|
||||
make
|
||||
```
|
||||
|
||||
### To run:
|
||||
## To run:
|
||||
|
||||
```sh
|
||||
./anonymous file
|
||||
./anonymous program
|
||||
```
|
||||
|
||||
### Try:
|
||||
NOTE: this entry seems to no longer work. [Cody Boone
|
||||
Ferguson](/winners.html#Cody_Boone_Ferguson) has offered some tips in the
|
||||
[bugs.md](/bugs.md) file for anyone who mights want to try and fix this but it
|
||||
seems to require a lot of parsing, debugging, an x86 system and possibly knowing
|
||||
the internals of the ELF format (x86 specific). You need to run the program on a
|
||||
binary to test. See the try section below for a program that, if you get the
|
||||
entry to work, would be okay to test it on. Thank you and we will happily credit
|
||||
you if you fix this.
|
||||
|
||||
WARNING: if you do get this to work it will destroy files that it is used on.
|
||||
See the author's warning on this.
|
||||
|
||||
|
||||
## Try:
|
||||
|
||||
```sh
|
||||
./anonymous anonymous.ten.c
|
||||
make anonymous.ten
|
||||
./anonymous anonymous.ten
|
||||
```
|
||||
|
||||
|
||||
## Judges' comments:
|
||||
|
||||
Is emulation the sincerest form of flattery? This small program does
|
||||
quite a lot of bit twiddling.
|
||||
Is emulation the sincerest form of flattery? This small program does
|
||||
quite a lot of bit twiddling.
|
||||
|
||||
## Author's comments:
|
||||
|
||||
This program is an optimizing dynamic binary translator, allowing you to
|
||||
run x86 programs on any machine (x86 or otherwise).
|
||||
This program is an optimizing dynamic binary translator, allowing you to
|
||||
run x86 programs on any machine (x86 or otherwise).
|
||||
|
||||
I have included a simple "10 green bottles" program, already compiled
|
||||
for the x86. The program 'ten', and its source (dull) are given as info
|
||||
files. Warning: note that the translator screws around with the binary
|
||||
you run on it, *will* corrupt the binary to some extent, and may leave
|
||||
any program you run on it unusable.
|
||||
I have included a simple "10 green bottles" program, already compiled
|
||||
for the x86. The program 'ten', and its source (dull) are given as info
|
||||
files. Warning: note that the translator screws around with the binary
|
||||
you run on it, *will* corrupt the binary to some extent, and may leave
|
||||
any program you run on it unusable.
|
||||
|
||||
The build script should give an example command to run.
|
||||
The build script should give an example command to run.
|
||||
|
||||
Features
|
||||
### Features
|
||||
|
||||
Basic Block Cache: Rather than translating each instruction individually
|
||||
the dynamic binary translator generates a translation for an entire
|
||||
basic block of subject code. Having translated a block once, the target
|
||||
code generated will be stored for the duration that the program is
|
||||
running, so as a program runs its performance will improve, as it hits
|
||||
cached blocks. This can be clearly observed in the example program,
|
||||
'ten'.
|
||||
Basic Block Cache: Rather than translating each instruction individually
|
||||
the dynamic binary translator generates a translation for an entire
|
||||
basic block of subject code. Having translated a block once, the target
|
||||
code generated will be stored for the duration that the program is
|
||||
running, so as a program runs its performance will improve, as it hits
|
||||
cached blocks. This can be clearly observed in the example program,
|
||||
'ten'.
|
||||
|
||||
Target Library Linking:
|
||||
### Target Library Linking:
|
||||
|
||||
The program runs dynamically linked elf binaries, and when the subject
|
||||
program attempts to make a call to a standard library, the translator
|
||||
attempts to make an appropriate call to the native system libraries on
|
||||
the target machine. This involves mangling between different calling
|
||||
conventions, etc.
|
||||
The program runs dynamically linked elf binaries, and when the subject
|
||||
program attempts to make a call to a standard library, the translator
|
||||
attempts to make an appropriate call to the native system libraries on
|
||||
the target machine. This involves mangling between different calling
|
||||
conventions, etc.
|
||||
|
||||
Automatic Endian Detection/Reversal:
|
||||
### Automatic Endian Detection/Reversal:
|
||||
|
||||
There are various problems raised when attempting to run little endian
|
||||
x86 code on a big endian chip, such as a PPC. These problems are dealt
|
||||
with in a manner that is entirely transparent to the user.
|
||||
There are various problems raised when attempting to run little endian
|
||||
x86 code on a big endian chip, such as a PPC. These problems are dealt
|
||||
with in a manner that is entirely transparent to the user.
|
||||
|
||||
Configuration
|
||||
### Configuration:
|
||||
|
||||
Warnings:
|
||||
#### Warnings:
|
||||
|
||||
By default the build script should compile the program with a set of
|
||||
switches such that while compiling the program it generates one error
|
||||
(which I feel is useful advice). The program should generate no further
|
||||
compiler errors while it is running (yes, the program can generate
|
||||
compiler errors while it is running). If you do not wish to see this
|
||||
error, or if the program generates any further error when compiled using
|
||||
your C compiler please remove the "warning=..." line from the build
|
||||
script.
|
||||
By default the build script should compile the program with a set of
|
||||
switches such that while compiling the program it generates one error
|
||||
(which I feel is useful advice). The program should generate no further
|
||||
compiler errors while it is running (yes, the program can generate
|
||||
compiler errors while it is running). If you do not wish to see this
|
||||
error, or if the program generates any further error when compiled using
|
||||
your C compiler please remove the "warning=..." line from the build
|
||||
script.
|
||||
|
||||
Optimization:
|
||||
### Optimization:
|
||||
|
||||
The build script contains a "-O1" switch for the compiler. Increasing
|
||||
the optimization level will make the program run *slower*, while
|
||||
compiling the program without any optimization will allow it to run
|
||||
*faster*.
|
||||
The build script contains a "-O1" switch for the compiler. Increasing
|
||||
the optimization level will make the program run *slower*, while
|
||||
compiling the program without any optimization will allow it to run
|
||||
*faster*.
|
||||
|
||||
Obfuscation
|
||||
### Obfuscation:
|
||||
|
||||
The most obvious part of the obfuscation is probably the mess of defines
|
||||
at the top. This may seem a somewhat tired old obfuscation - however
|
||||
since many of these macros are (sometimes only) used by the program once
|
||||
it has dynamically recompiled itself, they are only referenced within
|
||||
the source code from within strings - and therefore the macros cannot be
|
||||
expanded. Furthermore, some of these strings of code are not given as
|
||||
strings, but instead are wrapped up in macros that use the "#"
|
||||
preprocessor operator to turn them into strings. In the hope throwing a
|
||||
few C beautifiers the macro to generate the strings is not contained
|
||||
within the source code but instead is passed in on the command line.
|
||||
The most obvious part of the obfuscation is probably the mess of defines
|
||||
at the top. This may seem a somewhat tired old obfuscation - however
|
||||
since many of these macros are (sometimes only) used by the program once
|
||||
it has dynamically recompiled itself, they are only referenced within
|
||||
the source code from within strings - and therefore the macros cannot be
|
||||
expanded. Furthermore, some of these strings of code are not given as
|
||||
strings, but instead are wrapped up in macros that use the "#"
|
||||
preprocessor operator to turn them into strings. In the hope throwing a
|
||||
few C beautifiers the macro to generate the strings is not contained
|
||||
within the source code but instead is passed in on the command line.
|
||||
|
||||
Buried under all this, and the fact that the entire program is just a
|
||||
call to exit, there are some nice subtle little obfuscations. For
|
||||
example, you may notice that there are a couple of macros that use the
|
||||
"##" preprocessor operator to build pairs of functions. One of these
|
||||
macros is used to build to pairs of functions of which only one has
|
||||
local variables which shadow global variables; so one modifies the
|
||||
global state, and the other doesn't.
|
||||
Buried under all this, and the fact that the entire program is just a
|
||||
call to exit, there are some nice subtle little obfuscations. For
|
||||
example, you may notice that there are a couple of macros that use the
|
||||
"##" preprocessor operator to build pairs of functions. One of these
|
||||
macros is used to build to pairs of functions of which only one has
|
||||
local variables which shadow global variables; so one modifies the
|
||||
global state, and the other doesn't.
|
||||
|
||||
There is also quite a nice trick where I wave a magic wand, and a chunk
|
||||
of code which should only be run when the program is run for the first
|
||||
time (setting the PC to point at main, etc) gets turned into a
|
||||
frog^M^M^M^Mstring. The C compiler sees a string by itself in the code,
|
||||
thinks "yup, thats a valid C expression", and quietly moves on to the
|
||||
next line of code.
|
||||
There is also quite a nice trick where I wave a magic wand, and a chunk
|
||||
of code which should only be run when the program is run for the first
|
||||
time (setting the PC to point at main, etc) gets turned into a
|
||||
frog^M^M^M^Mstring. The C compiler sees a string by itself in the code,
|
||||
thinks "yup, that's a valid C expression", and quietly moves on to the
|
||||
next line of code.
|
||||
|
||||
Limitations
|
||||
### Limitations:
|
||||
|
||||
Due to space limitations only a handful of instructions are supported,
|
||||
those instructions which are supported may supported in somewhat
|
||||
non-conventional ways, chunks of the architecture (e.g. flags) are just
|
||||
ignored, the elf loader does not really load the elf binary, the target
|
||||
library linking can only pass up to 3 parameters to the target library
|
||||
function, etc, etc, etc.
|
||||
Due to space limitations only a handful of instructions are supported,
|
||||
those instructions which are supported may supported in somewhat
|
||||
non-conventional ways, chunks of the architecture (e.g. flags) are just
|
||||
ignored, the elf loader does not really load the elf binary, the target
|
||||
library linking can only pass up to 3 parameters to the target library
|
||||
function, etc, etc, etc.
|
||||
|
||||
In short, please consider this a full disclaimer for any bug that may
|
||||
turn up - yes the program is unsafe, but it's pretty cool anyway.
|
||||
In short, please consider this a full disclaimer for any bug that may
|
||||
turn up - yes the program is unsafe, but it's pretty cool anyway.
|
||||
|
||||
Despite all this, the translator is not exclusively limited to running
|
||||
the 'ten' program. Other trivial x86 programs may run on the translator
|
||||
- and I have successfully run a wide range of HelloWorld programs,
|
||||
including one of last years IOCCC winners, 'tomx'.
|
||||
Despite all this, the translator is not exclusively limited to running
|
||||
the 'ten' program. Other trivial x86 programs may run on the translator
|
||||
\- and I have successfully run a wide range of HelloWorld programs,
|
||||
including one of last years IOCCC winners, 'tomx'.
|
||||
|
||||
Complete Program
|
||||
### Complete Program:
|
||||
|
||||
The fact that the program makes calls to system and execv may imply that
|
||||
it is not a complete program in its own right, as it relies on other
|
||||
programs. The call to system is a call to ask gcc to recompile the
|
||||
translator with a new set of switches, and the call to execv asks for
|
||||
the newly compiled program to be executed. I would point out that
|
||||
almost every other entry to this competition also require a C compiler
|
||||
(well, the published winners at any rate, and I recognize that a few
|
||||
don't). There is little real difference between this program and one
|
||||
like last years entry 'dhyang'; both are just C programs that generate C
|
||||
code as their output.
|
||||
The fact that the program makes calls to system and execv may imply that
|
||||
it is not a complete program in its own right, as it relies on other
|
||||
programs. The call to system is a call to ask gcc to recompile the
|
||||
translator with a new set of switches, and the call to execv asks for
|
||||
the newly compiled program to be executed. I would point out that
|
||||
almost every other entry to this competition also require a C compiler
|
||||
(well, the published winners at any rate, and I recognize that a few
|
||||
don't). There is little real difference between this program and one
|
||||
like last years entry 'dhyang'; both are just C programs that generate C
|
||||
code as their output.
|
||||
|
||||
Enjoy, thanks!
|
||||
Enjoy, thanks!
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define l int*
|
||||
#define F char
|
||||
|
||||
@@ -10,7 +10,7 @@ int main() {
|
||||
while(bottles) {
|
||||
sing(bottles);
|
||||
sing(bottles);
|
||||
printf("And if one green bottle should accidently fall,\nThere'd be ");
|
||||
printf("And if one green bottle should accidentally fall,\nThere'd be ");
|
||||
sing(--bottles);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -33,6 +33,46 @@ related to making it work under macOS as all that did was removing some invalid
|
||||
prototypes and use `printf()` instead of the invalid pointer to it (incompatible
|
||||
type).
|
||||
|
||||
### [2001/anonymous](2001/anonymous/anonymous.c) ([README.md](2001/anonymous/README.md))
|
||||
|
||||
This entry seems to no longer work and we would appreciate any help from anyone
|
||||
who can fix this. [Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) has
|
||||
the following hints that might help but he has no system where he could test
|
||||
it. [Yusuke Endoh](/winners.html#Yusuke_Endoh) [wrote a little bit about
|
||||
it](https://mame-github-io.translate.goog/ioccc-ja-spoilers/2001/anonymous.html?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en-US&_x_tr_pto=wapp) that
|
||||
might or might not help but he too could not get it to work.
|
||||
|
||||
Tips from Cody:
|
||||
|
||||
- Try a beautifier on the original C code.
|
||||
- Use cpp to make the functions easier to parse. For instance if you're in the
|
||||
directory try `cpp -E anonymous.cp > anonymous.cpp` and look at that file to see
|
||||
the functions. It might or might not be helpful to use cpp on the beautified
|
||||
source.
|
||||
- After beautifying it try changing references of the macros (where not too
|
||||
complicated) to their definitions. For instance in vim you might do:
|
||||
`:%s/\<l\>/int */g` and then delete the line that was changed to `#define int *
|
||||
int*` (or else do a range substitute so it's not changed). You might not need
|
||||
this if you use the cpp. This might be useful anyway to more easily test things.
|
||||
- If your system has a `setarch` tool that might or might not be of help (I'm
|
||||
not too familiar with its internals).
|
||||
- The code appears to do everything from one call to `exit(3)` but it makes use
|
||||
of the ternary operator and possibly the comma operator.
|
||||
- Check the Makefile for the defines but also observe that those are in the
|
||||
source file. It appears that the entry might try compiling as well but that's
|
||||
from a quick glance.
|
||||
- The original main() started like: `main (char *ck, char **k)` but we made it
|
||||
compilable for clang by changing it to be: `main (int cka, char **k) { char *ck
|
||||
= (char *)cka;` which might or might not be good.
|
||||
- The author warns that only simple source (once compiled) would work so make
|
||||
use of the provided source file
|
||||
[2001/anonymous/anonymous.ten.c](2001/anonymous/anonymous.ten.c). To compile try
|
||||
`make anonymous.ten` from the entry directory which you can then run the entry
|
||||
on. Note that it needs to be compiled as a x86 program.
|
||||
- The program will to an extent destroy files it is used on. See the author's
|
||||
warning in their comments on that.
|
||||
|
||||
|
||||
### [2004/burley](2004/burley/burley.c) ([README.md](2004/burley/README.md))
|
||||
|
||||
This entry did not compile with clang but [Cody Boone
|
||||
@@ -52,11 +92,12 @@ experience with `longjmp`). In particular:
|
||||
> The longjmp() routines may not be called after the routine which called the
|
||||
> setjmp() routines returns.
|
||||
3. The main() originally returned a call to main() which appeared to be an
|
||||
infinite recursion at least as it was; now it returns a call to poke() which has the same number
|
||||
and type of args (1, `char *`) that main() had. This appears to not be an
|
||||
infinite recursion but I might be reading it wrong. Perhaps that is the problem?
|
||||
4. As well main() had only one arg, a `char *`, and there were (seemingly)
|
||||
needless casts to `char *` from gets().
|
||||
infinite recursion at least as it was; now it returns a call to poke() which has
|
||||
the same number and type of args (1, `char *`) that main() had. This appears to
|
||||
not be an infinite recursion but I might be reading it wrong. Changing it to not
|
||||
return itself and the same problem occurs so perhaps this is not the problem.
|
||||
4. As well main() had only one arg, a `char *`, and there was a (seemingly)
|
||||
needless cast to `char *` from gets(). This cast remains in the code however.
|
||||
5. The code no longer uses `gets()` but `fgets()`; this is not the problem
|
||||
however.
|
||||
|
||||
|
||||
Reference in new issue
Block a user