N64: RECORMILE adalah alat untuk secara statis mengkompilasi ulang binari N64 ke dalam kode C yang dapat dikompilasi untuk platform apa pun. Ini dapat digunakan untuk port atau alat serta untuk mensimulasikan perilaku secara signifikan lebih cepat daripada penerjemah atau kompilasi ulang dinamis. Lebih luas, dapat digunakan dalam konteks apa pun di mana Anda ingin menjalankan beberapa bagian dari biner N64 di lingkungan mandiri.
Ini bukan proyek pertama yang menggunakan kompilasi kembali statis pada biner konsol game. Contoh yang terkenal adalah Jamulator, yang menargetkan binari NES. Selain itu, ini bahkan bukan proyek pertama yang menerapkan kembali statis untuk proyek-proyek terkait N64: Kompilasi IDO statis mengkompilasi ulang kompiler SGI IRIX IDO pada sistem modern untuk memfasilitasi dekompilasi pencocokan game N64. Proyek ini bekerja serupa dengan proyek IDO Static Recomp dalam beberapa hal, dan proyek itu adalah inspirasi utama saya untuk membuat ini.
Recompiler bekerja dengan menerima daftar simbol dan metadata di samping biner dengan tujuan membagi biner input menjadi fungsi yang masing -masing secara individual dikompilasi kembali ke dalam fungsi C, dinamai sesuai dengan metadata.
Instruksi diproses satu per satu dan kode C yang sesuai dipancarkan saat masing-masing diproses. Terjemahan ini sangat literal untuk menjaga kompleksitas tetap rendah. Misalnya, instruksi addiu $r4, $r4, 0x20
, yang menambahkan 0x20
ke nilai 32-bit dalam byte rendah register $r4
dan menyimpan tanda yang diperpanjang hasil 64-bit di $r4
, akan dikompilasi ulang ke dalam ctx->r4 = ADD32(ctx->r4, 0X20);
Instruksi jal
(lompatan-dan-link) dikompilasi ulang secara langsung ke dalam panggilan fungsi, dan instruksi j
atau b
(lompatan dan cabang tanpa syarat) yang dapat diidentifikasi sebagai optimasi panggilan-ekor juga dikompilasi kembali ke dalam panggilan fungsi juga. Slot penundaan cabang ditangani dengan menduplikasi instruksi seperlunya. Ada perilaku spesifik lainnya untuk instruksi tertentu, seperti kompilasi yang mencoba mengubah instruksi jr
menjadi pernyataan sakelar-kasus jika dapat mengatakan bahwa itu digunakan dengan tabel lompat. Rekompiler sebagian besar telah diuji pada biner yang dibangun dengan kompiler MIPS lama (misalnya MIPS GCC 2.7.2 dan IDO) serta MIP yang menargetkan dentang modern. MIPS MIPS Modern dapat membuat kompiler menumpuk karena optimasi tertentu yang dapat dilakukannya, tetapi kasus -kasus tersebut mungkin dapat dihindari dengan menetapkan bendera kompilasi tertentu.
Setiap fungsi output yang dibuat oleh recompiler saat ini dipancarkan ke dalam file sendiri. Opsi dapat disediakan di masa mendatang untuk mengelompokkan fungsi bersama menjadi file output, yang seharusnya membantu meningkatkan waktu pembangunan output recompiler dengan mengurangi file I/O dalam proses pembuatan.
Output recompiler dapat dikompilasi dengan kompiler C apa pun (diuji dengan MSVC, GCC dan Clang). Output diharapkan digunakan dengan runtime yang dapat memberikan fungsionalitas yang diperlukan dan implementasi makro untuk menjalankannya. Runtime disediakan di N64Modernruntime yang dapat dilihat beraksi di Zelda 64: proyek yang dikompilasi ulang.
Hamparan yang terkait secara statis dan dipindahkan dapat ditangani oleh alat ini. Dalam kedua kasus, alat ini memancarkan pencarian fungsi untuk lompatan-dan-tautan (yaitu pointer fungsi atau fungsi virtual) yang dapat diimplementasikan runtime yang disediakan menggunakan segala jenis tabel pencarian. Misalnya, instruksi jalr $25
akan dikompilasi ulang sebagai LOOKUP_FUNC(ctx->r25)(rdram, ctx);
Runtime kemudian dapat mempertahankan daftar bagian program mana yang dimuat dan pada alamat apa mereka untuk menentukan fungsi mana yang akan dijalankan kapan pun pencarian dipicu selama runtime.
Untuk overlay yang dapat dipindahkan, alat ini akan memodifikasi instruksi yang didukung yang memiliki data relokasi ( lui
, addiu
, memuat dan menyimpan instruksi) dengan memancarkan makro ekstra yang memungkinkan runtime untuk memindahkan bidang nilai langsung instruksi. Misalnya, instruksi lui $24, 0x80C0
di bagian yang dimulai pada alamat 0x80BFA100
dengan relokasi terhadap simbol dengan alamat 0x80BFA730
akan dikompilasi ulang sebagai ctx->r24 = S32(RELOC_HI16(1754, 0X630) << 16);
, di mana 1754 adalah indeks bagian ini. Runtime kemudian dapat mengimplementasikan makro Reloc_HI16 dan Reloc_LO16 untuk menangani memodifikasi langsung berdasarkan alamat yang dimuat saat ini dari bagian tersebut.
Dukungan untuk relokasi untuk pemetaan TLB akan datang di masa depan, yang akan menambah kemampuan untuk memberikan daftar relokasi MIPS32 sehingga runtime dapat memindahkannya saat beban. Menggabungkan ini dengan fungsionalitas yang digunakan untuk overlay yang dapat dipindahkan harus memungkinkan menjalankan sebagian besar kode yang dipetakan TLB tanpa menimbulkan penalti kinerja pada setiap akses RAM.
Recompiler dikonfigurasi dengan menyediakan file TOML untuk mengonfigurasi perilaku kompiler, yang merupakan satu -satunya argumen yang diberikan kepada kompiler. TOML adalah tempat Anda menentukan jalur file input dan output, serta secara opsional mengeluarkan fungsi tertentu, melewatkan kompilasi ulang fungsi tertentu, dan menambal instruksi tunggal dalam biner target. Ada juga fungsionalitas yang direncanakan untuk dapat memancarkan kait dalam output recompiler dengan menambahkannya ke TOML ( [[patches.func]]
dan [[patches.hook]]
bagian dari TOML tertaut di bawah), tetapi ini saat ini tidak diterapkan. Dokumentasi pada setiap opsi yang disediakan oleh Recompiler saat ini tidak tersedia, tetapi contoh TOML dapat ditemukan di proyek Zelda 64: yang dikompilasi ulang di sini.
Saat ini, satu -satunya cara untuk menyediakan metadata yang diperlukan adalah dengan meneruskan file ELF ke alat ini. Cara termudah untuk mendapatkan peri seperti itu adalah dengan mengatur pembongkaran atau dekompilasi biner target, tetapi akan ada dukungan untuk menyediakan metadata melalui format khusus untuk mem -bypass kebutuhan untuk melakukannya di masa depan.
Alat ini juga dapat dikonfigurasi untuk mengkompilasi ulang mode "Output File Tunggal" melalui opsi dalam TOML konfigurasi. Ini akan memancarkan semua fungsi dalam ELF yang disediakan menjadi satu file output. Tujuan dari mode ini adalah untuk dapat mengkompilasi versi fungsi yang ditambal dari biner target.
Mode ini dapat dikombinasikan dengan fungsionalitas yang disediakan oleh hampir semua penghubung (LD, LLD, MSVC's Link.exe, dll.) Untuk mengganti fungsi dari output recompiler asli dengan versi yang dimodifikasi. Penghubung itu hanya mencari simbol di perpustakaan statis jika belum ditemukan dalam file input sebelumnya, jadi memberikan tambalan yang dikompilasi ulang ke tautan sebelum memberikan output recompiler asli akan menghasilkan tambalan yang diprioritaskan daripada fungsi dengan nama yang sama dari output recompiler asli.
Ini menghemat banyak waktu saat iterasi pada tambalan untuk biner target, karena Anda dapat mem -bypass menjalankan kembali kompiler pada biner target serta menyusun output kompiler asli. Contoh menggunakan mode output file tunggal ini untuk tujuan itu dapat ditemukan di Zelda 64: proyek yang dikompilasi ulang di sini, dengan makefile yang sesuai yang digunakan untuk membangun peri untuk tambalan tersebut di sini.
Mikrokode RSP juga dapat dikompilasi ulang dengan alat ini. Saat ini tidak ada dukungan untuk mengkompilasi ulang overlay RSP, tetapi dapat ditambahkan di masa depan jika diinginkan. Dokumentasi tentang cara menggunakan fungsi ini akan segera hadir.
Proyek ini dapat dibangun dengan CMake 3.20 atau di atas dan kompiler C ++ yang mendukung C ++ 20. Repo ini menggunakan submodul GIT, jadi pastikan untuk mengkloning secara rekursif ( git clone --recurse-submodules
) atau menginisialisasi submodula secara rekursif setelah kloning ( git submodule update --init --recursive
). Dari sana, bangunan identik dengan proyek CMake lainnya, misalnya menjalankan cmake
di folder Target Build dan arahkan pada akar repo ini, lalu jalankan cmake --build .
dari folder target itu.