I saw a Modern Vintage Gamer video yesterday where he talked about a project that was able to reverse engineer the machine code for Zelda Ocarina of Time. They are able to produce a 1 for 1 identical ROM from source code written in C.
I wanted to be able to build this and potentially play around with the game code. Being on NixOS I had to patch some pre-compiled binaries that were in the repository. It looks like they have a precompiled assembler and possibly a C compiler, likely to be able to produce the same binary output each time.
I was able to get into a “pure” nix shell and build the project with the following:
# NOTE: you'll need to enter the shell with this
# environment variable set:
# NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
#
let
nixpkgs = builtins.fetchTarball {
# nixpkgs-unstable (2021-10-28)
url = "https://github.com/NixOS/nixpkgs/archive/22a500a3f87bbce73bd8d777ef920b43a636f018.tar.gz";
sha256 = "1rqp9nf45m03mfh4x972whw2gsaz5x44l3dy6p639ib565g24rmh";
};
in
{
pkgsNative ? import nixpkgs { }
,pkgsCross ? import nixpkgs {
crossSystem = {
config = "mips-linux-gnu";
};
}
}:
pkgsCross.mkShell {
buildInputs = [
pkgsCross.gcc
pkgsNative.libpng
];
nativeBuildInputs = [
pkgsNative.git
pkgsNative.gcc
pkgsNative.python3
];
}
The combination of packages inside buildInputs an nativeBuidlInputs is odd, but it’s the result of trying different permuations until I was able to find something that works. For example, the project expects “gcc” to be the native compiler and “mips-linux-gnu-gcc” to be the cross-compiler, but if you put pkgsCross.gcc in nativeBuildInputs, then “gcc” points to the cross compiler. If anyone is able to simplify or make this code better let me know.
I also don’t like that I need to specify NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM. Is there a way to avoid the need for this in the nix expression?
For those interested in building this themselves, you’ll also need to patch the interpreter on the pre-compiled binaries, which you can do that with this script:
#!/usr/bin/env sh
set -ex
interp=$(patchelf --print-interpreter $(which env))
for version in 5.3 7.1; do
for tool in cc cfe uopt ugen as1; do
patchelf --set-interpreter $interp ./tools/ido_recomp/linux/$version/$tool
done
done
I can build the project in about 40 seconds with this:
NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-shell --pure ~/nix-shells/zelda.nix
time make setup -j24
time make -j24
Also note that to build the project, you’ll need to get ahold of a base rom image that the build can extract the assets from. I believe it needs to be a debug, USA, Master Quest version of the ROM. You’ll know your build worked if you produced a rom that is binary identical to the base rom file (with the baserom headers stripped, the build will do this for you).
I would love to be able to add a derivation for this in nixpkgs, but I’m not sure that’s possible with the need for assets that Nintendo would not make publicly available outside of purchasing them with a physical game cartridge.