- Elevator menerjemahkan seluruh executable x86-64 ke AArch64 secara statis tanpa informasi debug, kode sumber, atau asumsi tata letak biner
- Alih-alih memakai heuristik untuk membedakan kode dan data, ia membangun superset CFG yang memuat semua interpretasi yang mungkin untuk setiap byte lalu hanya menghapus jalur yang berakhir pada terminasi program
- Elevator memetakan status x64 satu-banding-satu ke register AArch64 dan menangani percabangan tidak langsung dengan tabel lookup dari alamat asli ke kode hasil terjemahan
- Bank tile offline menuliskan semantik instruksi x64 sebagai template C lalu mengompilasikannya menjadi urutan byte AArch64 dengan LLVM 20
- Hasilnya adalah biner AArch64 mandiri tanpa translasi saat runtime, dan pada SPECint 2006 menunjukkan kinerja setara atau lebih baik daripada mode pengguna QEMU JIT
Tujuan Elevator
- Elevator adalah penerjemah biner statis penuh yang memindahkan seluruh executable x86-64 ke AArch64
- Tidak menggunakan informasi debug, kode sumber, pola kode biner asli, atau asumsi tentang tata letak biner
- Penerjemah statis konvensional bergantung pada heuristik atau fallback runtime untuk membedakan kode dan data, tetapi Elevator menerjemahkan lebih dulu semua byte executable asli menurut setiap interpretasi yang mungkin
- Karena byte apa pun bisa menjadi data, bagian dari opcode, atau bagian dari argumen opcode, Elevator membangun superset CFG yang mencakup semua aliran kontrol yang mungkin, lalu hanya membuang jalur yang mengarah ke penghentian program yang eksepsional
- Keluarannya terdiri dari biner AArch64 mandiri yang memuat kode hasil terjemahan, biner x64 asli, tabel lookup alamat, dan driver runtime
- Setelah translasi selesai, hasilnya dapat dijalankan tanpa JIT atau dukungan translasi runtime
- Jika biner input yang sama diterjemahkan dua kali, hasil bit output akan sama, sehingga objek yang diuji, diverifikasi, disertifikasi, atau ditandatangani secara kriptografis identik dengan kode yang benar-benar didistribusikan
- Biaya utamanya adalah pembengkakan ukuran kode, tetapi sebagai gantinya verifikasi sebelum distribusi menjadi lebih memungkinkan dibanding emulator atau kompiler JIT
- Evaluasi mencakup seluruh benchmark SPECint 2006 dan biner buatan tangan, dengan performa setara atau lebih baik daripada emulasi mode pengguna QEMU yang dipercepat JIT
- Tim peneliti menyatakan akan merilis seluruh proyek sebagai open source saat proyek selesai
Mengapa translasi statis dibutuhkan dan keterbatasan yang ada
- Ketika perangkat keras berpindah dari satu ISA ke ISA lain, perangkat lunak lama perlu dibawa ke platform baru, dan sekadar mengompilasi ulang source code yang tersisa mungkin tidak cukup
- Pada kode legacy yang telah diverifikasi atau disertifikasi, objek sertifikasi sering kali bukan source code, melainkan binary executable otoritatif tertentu yang sudah teruji dengan baik
- Untuk mereproduksi biner yang sama persis per bit dari source code di kemudian hari, mungkin dibutuhkan versi compiler, linker, dan build system pada masa itu, yang secara praktis sulit dilakukan
- Jika vendor pernah menerapkan patch langsung ke biner tanpa melalui source code, build ulang dari source yang diarsipkan bisa menghidupkan kembali bug yang sudah diperbaiki
- Pendekatan yang langsung menangani biner yang ada biasanya menggabungkan emulasi, translasi statis, dan translasi dinamis, tetapi komponen sistem tambahan yang berjalan bersama program hasil terjemahan menjadi bagian dari trusted code base
- Perilaku dinamis dapat berbeda tergantung urutan pengujian atau input, sehingga sulit memastikan keandalan keseluruhan
- Horspool dan Marovac menunjukkan pada 1980 bahwa untuk membalik executable perlu membedakan kode dan data secara pasti, dan pada sebagian besar arsitektur hal ini ekuivalen dengan halting problem, sehingga secara umum tidak dapat diselesaikan
- Pengangkat biner statis yang ada mendekati pembedaan kode dan data dengan heuristik, dan masalahnya makin besar terutama saat memprediksi target transfer aliran kontrol tidak langsung
- LLBT mengangkat instruksi ARM ke LLVM IR lalu mengompilasi ulang ke arsitektur target, tetapi memakai heuristik untuk mendeteksi target percabangan tidak langsung dan membuat berbagai asumsi tentang biner input
- Bahkan heuristik yang bagus pun gagal pada sebagian input, dan karena pengangkatan seluruh biner secara benar mengharuskan semua pembedaan kode-data akurat, peluang gagal meningkat seiring membesarnya biner
- Pendekatan dinamis dapat mengikuti aliran instruksi yang benar-benar dieksekusi sehingga bisa menangani pemulihan instruksi dan aliran kontrol tidak langsung, tetapi tidak bisa mengangkat instruksi yang tidak tercapai dalam eksekusi konkret
- Pada ISA seperti x64 yang memiliki instruksi panjang variabel, satu rangkaian instruksi bisa menumpang di dalam rangkaian instruksi lain, dan cabang ke tengah instruksi multibyte dapat membuat operand lama didekode sebagai instruksi terpisah
- Serangan ROP dan obfuscation kode dapat memanfaatkan sifat ini
- Rosetta II dari Apple dan Prism dari Microsoft menggabungkan komponen translasi awal dan translasi dinamis
- WYTIWYG dan Polynima mengangkat secara statis jalur aliran kontrol yang diidentifikasi lewat profiling dinamis, lalu memakai fallback dinamis untuk mengumpulkan informasi aliran kontrol saat mencapai alamat target yang belum pernah terlihat
- Elevator tidak memutuskan apakah sebuah byte adalah kode atau data, atau apakah ia adalah word instruksi atau argumen; sebaliknya, setiap byte executable dimasukkan ke jalur aliran kontrol terpisah menurut semua interpretasi yang mungkin
- Pendekatan ini menerapkan superset disassembly pada rekompilasi statis dan kompilasi lintas ISA, dengan menukar presisi decoding dengan pertambahan ukuran kode
Pelestarian aliran kontrol dan status
- Elevator bekerja berdasarkan prinsip mempertahankan seluruh status x64 di dalam kode AArch64 hasil terjemahan
- Register x64 dan register AArch64 dipetakan satu-banding-satu, sehingga setiap status register x64 diemulasikan pada register AArch64 yang bersesuaian
- Stack x64 diemulasikan langsung di atas stack AArch64, dan ekspansi stack normal saat eksekusi ditangani oleh sistem operasi
- Elevator tidak menganalisis ABI biner x64 input; translasi ABI hanya dilakukan pada titik saat eksekusi keluar ke kode eksternal atau kembali darinya, mengikuti aturan x64 System V ABI dan AArch64 Procedure Call Standard
- Berkat pelestarian status penuh dan korespondensi register satu-banding-satu, setiap instruksi x64 dapat diterjemahkan secara independen tanpa perlu mengetahui instruksi sebelum atau sesudahnya
- Setiap byte offset yang dapat dieksekusi pada biner asli ditafsirkan sekaligus sebagai data dan sebagai titik awal potensial dari rangkaian instruksi
- Untuk semua target potensial yang tidak dapat dianalisis secara statis, seperti indirect jump, callback, atau dispatch runtime, biner yang ditulis ulang akan memiliki titik pendaratan yang sesuai
- Saat runtime, target diuraikan dengan tabel lookup yang tertanam di biner akhir untuk memetakan alamat instruksi asli ke alamat kode hasil terjemahan
-
Contoh instruksi bertumpuk
Listing 1 menunjukkan bahwa jika decoding dimulai dari .byte 0xB0, hasilnya MOV AL, 0xC3 diikuti RET, sedangkan jika dimulai satu byte kemudian di ReturnC2, hasilnya hanya RET
- Kedua decode itu dapat dicapai dari
jz sebelumnya, dan jika penerjemah hanya memilih satu interpretasi untuk dua byte tersebut, satu jalur akan terlewat
-
Contoh percabangan tidak langsung terhitung
Listing 2 menunjukkan call Label membuat alamat basis tabel, pop rsi mengambilnya kembali, lalu offset yang bergantung pada input ditambahkan untuk membentuk target jmp rsi
- Cabang dapat mendarat pada salah satu dari empat instruksi
inc eax yang ditempatkan dengan jarak 2 byte dalam stream encoding
- Penerjemah yang hanya menulis ulang target lompatan yang bisa ditafsirkan secara statis tidak akan punya tempat untuk mendaratkan cabang seperti ini
-
Call, return, dan branch
- Instruksi
call, return, dan branch tidak dapat dinyatakan sebagai tile C karena lokasi alamat kembali, program counter, dan layout flag kondisi berbeda antara x64 dan AArch64
- Direct call mendorong alamat kembali x64 asli ke stack emulasi lalu melakukan branch ke tile hasil terjemahan milik callee
- Indirect call memeriksa apakah target berada di dalam biner hasil terjemahan atau di library eksternal; target internal diterjemahkan melalui tabel offset-x64-ke-tile lalu dilakukan branch ke tile terkait
- Untuk target eksternal, alamat gadget translasi ABI balik ditempatkan di
X30, translasi ABI keluar dilakukan, lalu dieksekusi branch ke target eksternal
- Return mengambil alamat kembali 8 byte dari stack emulasi, membandingkannya dengan rentang biner x64 tertanam, dan jika itu return internal, alamat tersebut diterjemahkan lewat tabel lookup lalu dilakukan branch ke tile terkait
- Direct branch memiliki target yang diketahui saat translasi, sedangkan branch kondisional diterjemahkan menjadi branch kondisional AArch64 yang memeriksa bit flag x64 yang disimpan di
X14
- Indirect branch mengeluarkan bounds check seperti pada indirect call dan return, dan jika targetnya eksternal maka translasi ABI keluar dijalankan
Pipeline translasi berbasis tile
- Translasi Elevator dibagi menjadi tiga tahap: pembuatan bank tile offline, penulisan ulang per biner input, dan packaging akhir
- Tahap offline menyatakan semantik instruksi x64 sebagai fungsi C, menspesialisasikannya untuk setiap kombinasi operand di bawah pemetaan register x64-ke-AArch64 yang tetap, lalu mengompilasinya dengan LLVM 20 yang dimodifikasi untuk menghasilkan urutan byte AArch64 yang dapat dipakai ulang
- Tahap per biner input menjalankan superset disassembly, lalu untuk tiap instruksi kandidat yang ditemukan, mencari tile berdasarkan nama dan menyambungkan urutan byte AArch64
- Kategori instruksi yang sulit dinyatakan sebagai tile C, seperti transfer aliran kontrol dan batas ABI, ditangani dengan template kecil buatan tangan
- Tahap packaging menggabungkan kode hasil terjemahan, biner x64 asli, tabel lookup alamat, dan driver runtime untuk menghasilkan biner AArch64 yang dapat dieksekusi secara mandiri
-
Bank tile offline
- Menulis secara manual rangkaian instruksi AArch64 yang ekuivalen untuk tiap instruksi x64 tidak praktis
- Satu template seperti
ADD Reg8, Reg8 saja berkembang menjadi 256 kombinasi register konkret, dan keseluruhan instruction set x64 memiliki banyak variasi pengalamatan untuk register, operand memori, dan immediate
- Elevator menulis semantik tiap instruksi x64 sebagai fungsi C kecil, lalu menspesialisasikannya menurut kombinasi operand konkret dan membiarkan LLVM mengompilasikannya ke AArch64
- Pada contoh
ADD Reg8, Reg8, template memperbarui 8 bit bawah register tujuan dengan hasil penjumlahan 8 bit sambil mempertahankan 56 bit atas agar sesuai dengan semantik penulisan partial register x64
- x64
ADD Reg8, Reg8 juga mengubah flag RFLAGS seperti Carry, Parity, Auxiliary Carry, Zero, Sign, dan Overflow, sehingga karena keterbatasan fungsi C yang hanya punya satu nilai kembali, pembaruan flag ditangkap sebagai tile flag terpisah
- Satu instruksi x64 dapat berkorespondensi dengan satu atau beberapa tile, dan saat emisi tile-tile itu kembali disambung berurutan untuk memulihkan semantik penuhnya
- Atribut
aarch64_custom_reg menyatakan register AArch64 mana yang harus dipakai LLVM untuk menempatkan nilai kembali dan tiap argumen
- Pemetaan tetap dipilih agar sifat callee-saved dan caller-saved antara x64 System V dan AAPCS64 selaras, mengurangi penataan ulang posisi register argumen integer, dan menyisakan register callee-saved AArch64 yang tidak terpakai untuk status bayangan di masa depan
- Bit
RFLAGS x64 dan berkas register XMM juga disimpan pada register AArch64 khusus dengan prinsip satu-banding-satu yang sama
- LLVM 20 yang dimodifikasi menangani atribut
aarch64_custom_reg per fungsi dan mengklasifikasikan ulang register AArch64 yang menyimpan status x64 emulasi sebagai callee-saved di dalam allocator register
TileGen menelusuri template C untuk membuat salinan terspesialisasi bagi setiap kombinasi operand yang diizinkan, lalu menyintesis atribut secara mekanis dari posisi parameter template dan pemetaan register
-
Penulisan ulang per biner input
- Saat diberi biner x64 input, tahap per-binary menjalankan superset disassembly dan menelusuri CFG hasilnya
- Pada tiap node, formatter membangun nama tile dari opcode dan operand instruksi yang telah didekode; untuk instruksi yang membutuhkan beberapa tile, beberapa nama digabungkan
- x64 tidak memiliki pembatasan alignment stack pointer, tetapi AArch64 mengharuskan alignment 16 byte saat stack pointer digunakan sebagai operand memori
- Jika
RSP dipetakan langsung ke SP, pola kode x64 umum seperti PUSH beruntun di function prologue dapat memicu exception alignment di AArch64
- Elevator membuat tile mengakses stack melalui register terpisah
X25, dan hanya mengonkretkan SP di dalamnya saat tile benar-benar membutuhkannya
- Tile yang dikompilasi dengan LLVM mengasumsikan alignment
SP 16 byte saat masuk, sehingga sebelum menjalankan tile yang terdeteksi mengalokasikan spill space, SP disejajarkan ke bawah dan dipulihkan setelah eksekusi
- Karena tile perhitungan flag relatif mahal, Elevator menghapus perhitungan flag pada node saat ini jika flag itu akan ditimpa sebelum dibaca oleh instruksi post-dominating berikutnya
- Instruksi yang saat ini belum didukung terutama adalah AVX2 x64 dan ekstensi vektor lebar yang lebih baru, dan pada lokasi tersebut disisipkan instruksi interrupt sebagai pengganti tile
- Dalam evaluasi penuh SPECint 2006, keseluruhan ISA integer x86-64 dan subset SSE yang dipakai SPECint sudah cukup untuk menjalankan semua benchmark
- Dukungan instruksi tambahan dapat diperluas dengan menambahkan tile baru, tetapi para peneliti menilai rekayasa tambahan semacam itu kecil kemungkinan memberi wawasan ilmiah baru
Penanganan batas ABI
- Elevator hanya mendukung biner dynamic linking
- Biner static linking dapat langsung memuat instruksi spesifik arsitektur seperti
CPUID, tetapi biner dynamic linking mendelegasikan hal itu ke libc, sehingga kebutuhan translasi berkurang
- Saat berinteraksi dengan library dynamic linking, Elevator mendukung perpindahan antara ABI Linux x64 dan ABI Linux AArch64 untuk berpindah antara lingkungan x64 emulasi dan kode library AArch64 native
- Elemen utama yang memerlukan translasi ABI adalah penempatan argumen dan lokasi alamat kembali
- ABI System V x64 memakai enam register
RDI, RSI, RDX, RCX, R8, R9 sebagai register argumen, dan argumen tambahan dikirim lewat stack mulai dari [RSP+8]
CALL x64 menyimpan alamat kembali di [RSP]
- AArch64 Procedure Call Standard memakai delapan register argumen
X0-X7, menaruh argumen sisanya di stack pada [SP], dan menyimpan alamat kembali di X30
-
Memanggil library eksternal
- Jika call x64 hasil terjemahan menargetkan library eksternal, layout argumen harus diubah agar sesuai dengan calling convention AArch64
- Pertama,
SP dikurangi 8 agar kembali sejajar pada batas 16 byte, dan alamat kembali x64 yang sudah ada di stack ditempatkan di [SP+0x8]
- Nilai pada
[SP+0x10] dan [SP+0x18] dimuat ke X6 dan X7 agar argumen ke-7 dan ke-8 potensial yang diletakkan kode x64 di stack dapat dilihat oleh library AArch64
- Argumen stack potensial yang tersisa tetap berada mulai dari
[SP+0x20], sehingga tidak cocok dengan posisi yang diharapkan AArch64
- Menghapus alamat kembali x64 dan nilai yang dipindahkan ke
X6 dan X7 dari stack tidak aman karena nilai-nilai itu mungkin bukan argumen nyata, melainkan caller spill space atau sebagian struktur yang dialokasikan di stack caller
- Elevator tidak mengutak-atik layout stack caller, melainkan mengalokasikan ruang stack tambahan sebesar
n×8 byte lalu menyalin n argumen potensial 8 byte dari posisi saat ini
- Nilai baku
n adalah 10, dan jika biner input mengirim lebih dari total 16 argumen ke fungsi library eksternal, nilainya bisa dinaikkan lewat konfigurasi
- Terakhir, alamat gadget tempat library eksternal akan kembali disimpan di
X30
-
Kembali dari library eksternal
- Ketika kontrol kembali ke gadget yang sebelumnya disimpan di
X30 sebelum pemanggilan library eksternal, stack pointer ditambah n×8 untuk membersihkan argumen stack yang tadi disalin
- Nilai kembali library eksternal dipindahkan dari
X0 ke X9, yakni lokasi RAX yang diharapkan kode x64 emulasi
- Alamat kembali x64 asli beserta padding terkait diambil dari stack, alamat itu diterjemahkan, lalu dilakukan branch ke sana untuk melanjutkan eksekusi setelah
CALL asli
-
Callback yang masuk ke kode hasil terjemahan
- Jika kode AArch64 native memanggil biner hasil terjemahan, calling convention AArch64 harus diubah ke calling convention x64
- Kode x64 emulasi mengharapkan argumen ke-7 dan ke-8 berada di stack, bukan di
X6 dan X7, sehingga X7 didorong lebih dulu lalu X6 agar ditempatkan pada posisi stack yang diharapkan x64
- Jika callee sebenarnya tidak mengharapkan argumen ke-7 dan ke-8, nilai yang didorong ini tidak akan berdampak
- Alamat kembali yang dimasukkan instruksi AArch64 branch-and-link ke
X30 oleh library eksternal didorong ke lokasi stack yang diharapkan instruksi return x64
-
Kembali dari callback ke library eksternal
- Saat kode hasil terjemahan kembali dari callback ke library eksternal, proses masuk tadi dibalik
- Alamat kembali diambil dari stack,
X6 dan X7 didorong, dan ruang stack yang dialokasikan dibersihkan dengan menambahkan 0x10 ke stack pointer
1 komentar
Komentar Hacker News
Saya tidak tahu persis apa yang dilakukan user-mode JIT milik QEMU, tetapi tampaknya masih ada banyak ruang untuk perbaikan
Pada 2013 saya membuat mesin JIT yang menerjemahkan dari x86-64 ke aarch64, dan saat itu saya bisa menjalankan biner Fedora beta aarch64 serta membangun ulang sebagian besar port Fedora untuk aarch64 di Linux x86_64
Saya juga membuat JIT untuk arah sebaliknya, aarch64 → x86-64, dan untuk iseng saya bahkan sempat menunjukkan kedua JIT itu saling menjalankan dalam bentuk loopback di proses yang sama, seperti x86-64 → aarch64 → x86_64
JIT yang saya buat memetakan instruksi dan status CPU dalam rasio satu-ke-banyak, dan kinerjanya kira-kira 2~5 kali lebih lambat dibanding kode yang dikompilasi ulang secara native
Belakangan saat saya membandingkannya dengan QEMU JIT, QEMU tampak berada di kisaran 10~50 kali lebih lambat
Sayangnya lisensinya tidak disiapkan sebagai open source, jadi saya tidak bisa merilis kode untuk membuktikannya
Terutama jika desainnya bisa dikhususkan hanya untuk “x86 ke aarch64” dan “user mode saja”, ada banyak keuntungan performa yang bisa didapat
Dukungan user mode di QEMU lebih mirip lampiran “kebetulan juga berfungsi” dari dukungan emulasi sistem, dan keseluruhan struktur JIT-nya juga memakai pendekatan “guest → representasi menengah → host”, sehingga bagus untuk mendukung banyak arsitektur guest dan banyak arsitektur host, tetapi sulit memanfaatkan sifat khusus dari kombinasi guest/host tertentu seperti “x86 punya sedikit register integer jadi bisa dialokasikan secara hard” atau “kalau CPU aarch64 dibiarkan pada mode yang tepat, semantik floating-point yang rumit akan selalu cocok”
Selain itu, dalam pengembangan QEMU, lebih banyak waktu dihabiskan untuk “mengemulasikan fitur arsitektur baru X” daripada mencari peluang optimasi performa, karena pihak yang membiayai pengembangan memang lebih mementingkan hal itu
Membesarnya section
.texthingga 50 kali memang sangat besar, tetapi sebagai harga untuk mendapatkan translasi yang sepenuhnya deterministik, tampaknya masih bisa diterimaDalam banyak kasus, perbedaan performa dibanding emulasi akan lebih besar daripada ketidaknyamanan akibat ukuran yang membengkak
Menarik juga bahwa multithreading dan exception handling bukan tidak mungkin, melainkan memang berada di luar cakupan proyek ini
Saya penasaran apakah langkah berikutnya adalah memangkas ruang kemungkinan dengan heuristik untuk mengurangi ukuran biner
Itu memang akan merusak jaminan translasi, tetapi bisa membuat portabilitas biner lebih realistis dalam praktik
Translator ini jauh lebih lambat daripada Box64 atau FEX, dan kecuali Anda berada dalam situasi di mana JIT tidak bisa dipakai karena alasan apa pun, ini tetap pilihan yang lebih buruk
Saya selalu penasaran bagaimana translator menangani indirect jump
Saat menganalisis biner, Anda hanya bisa menemukan potongan kode yang terhubung oleh direct jump dengan alamat tujuan yang diketahui
Jadi apakah itu berarti setiap kali indirect jump terjadi, target fungsinya harus dicari, lalu diterjemahkan bila perlu, kemudian kembali ke kode hasil terjemahan? Bukankah itu lambat?
Saya penasaran apakah ada cara yang lebih cepat, apakah alamat fungsi hasil terjemahan bisa dicocokkan dengan alamat fungsi asli, atau apakah dimasukkan jump pada alamat asli yang menuju kode hasil terjemahan
jmpke alamat X, blok yang sesuai ada di lokasi Y”Cara ini memang lebih lambat daripada direct
jmpyang tidak memakai tabel, tetapi indirect jump di program asli memang sejak awal lebih lambat, dan biasanya tidak sering muncul di dalam loop yang penting bagi performaSaya sangat suka ide superset control flow graph ini, tetapi bagi orang yang hendak membaca artikelnya, hal-hal berikut layak diketahui
Waktu jalan menjadi sekitar 4,75 kali lebih cepat (lebih cepat dari QEMU tetapi masih cukup jauh lebih lambat dari Box64), jumlah instruksi yang dieksekusi meningkat 7 kali, dan ukuran biner meningkat 50 kali
x86 ABI diemulasikan sampai sebelum pemanggilan eksternal
Sebagian besar status CPU x86 seperti EFLAGS harus diemulasikan, dan
movyang kompleks juga harus dihitung satu per satuHanya mendukung biner single-thread
Tidak ada exception handling maupun stack unwinding
Tidak mendukung seluruh instruction set
Pekerjaan yang menarik
Saya belum melihatnya secara rinci, tetapi relative offset sepertinya masih bisa menjadi masalah
Karena ukuran hasil pembangkitan kode pasti akan berbeda, rasanya tetap perlu semacam lapisan translasi atau MMU, dan ini kemungkinan besar terutama akan memengaruhi jump table dan branch internal
Saya kebanyakan menangani barang-barang era 90-an, dan disassembler membuat banyak asumsi tentang awal dan akhir kode
Namun kadang ada kasus di mana tanpa pengetahuan awal seperti pointer entry point di lokasi tetap, Anda bahkan tidak bisa menemukan bongkahan biner itu
Setelah beberapa kali pass, sepertinya biner bisa dimurnikan menjadi “wilayah yang pasti kode”
Jika “Elevator mempertimbangkan semua interpretasi yang mungkin untuk setiap byte, menghasilkan terjemahan terpisah untuk masing-masing yang mungkin sebelumnya, dan [...] hanya memangkas yang berujung crash”, apakah berarti semua program nyata yang punya kemungkinan collision akan terpangkas semuanya?
Jadi tetap akan terjadi collision, tetapi tidak akan sama dengan crash akibat kode salah yang dieksekusi secara langsung
Bagi saya, bagian yang paling menarik adalah dari sudut pandang sertifikasi
Di industri yang teregulasi seperti penerbangan atau perangkat medis, kode yang dijalankan harus berupa kode yang tersertifikasi, sehingga sering kali JIT tidak bisa dipakai justru karena alasan seperti ini
Translasi statis yang menghasilkan biner yang bisa ditandatangani dapat menjadi terobosan nyata meskipun harus menerima pembengkakan kode
Mungkin di area ini juga tidak ada cara untuk menerapkan LLM dalam skala besar, tetapi dalam wacana besar tentang “AI di tempat kerja”, bagian seperti ini hampir tidak pernah dibahas
50 kali itu tidak masuk akal, benar-benar bencana cache
Keuntungan performa yang didapat dengan menghindari JIT bisa habis termakan semuanya
Jika kode panas dikumpulkan di satu tempat, kode yang tidak dipakai bisa dibuat tidak pernah dimuat sama sekali
Instruksi toh tidak sebesar itu, dan CPU juga melakukan optimasi saat berjalan
Apakah ini bisa menangani self-modifying code?
Saya juga penasaran kenapa hanya x86_64
Terasa lebih bermakna kalau yang diterjemahkan justru program 32-bit seperti game lama
“Self-modifying dan kode hasil kompilasi JIT. Elevator, seperti semua penulis ulang biner yang sepenuhnya statis, tidak mendukung self-modifying code maupun kode hasil kompilasi JIT”
Section
.textmodern umumnya read-only, dan tuntutan keamanan tidak akan berkurangSecara mendasar itu kontradiktif
Karena itu merusak performa cache line dan prediksi cabang pipeline
Selain itu, hal itu melanggar W^X sehingga biasanya hanya boleh dilakukan pada halaman memori yang kompatibel dengan JIT
Karena itu hampir selalu harus dihindari
Pada era 486 atau P5, ini sempat dipakai sampai batas tertentu, misalnya dengan memakai immediate value sebagai variabel loop internal, tetapi sekarang sudah tidak terlalu begitu
Untuk mencapai emulasi atau translasi x86 yang nyaris sempurna, ada banyak kasus pengecualian kotor yang harus ditangani
Di mana source code-nya?