Jawaban singkatnya : Anda tidak dapat menerjemahkan executable yang dikompilasi dan dikompilasi. Meskipun secara teknis memungkinkan, sangat tidak mungkin untuk dicapai (lihat di bawah). Namun , jika Anda memiliki file sumber rakitan (berisi instruksi dan label), sangat mungkin dilakukan (walaupun jika Anda mendapatkan sumber rakitan, kecuali jika program tersebut ditulis dalam rakitan, Anda harus memiliki kode sumber program asli sebagai baik, jadi Anda sebaiknya mengkompilasinya untuk arsitektur yang berbeda untuk memulai).
Jawaban panjangnya :
QEMU dan emulator lain dapat menerjemahkan instruksi dengan cepat, dan karenanya menjalankan executable di komputer yang tidak dikompilasi untuknya. Mengapa tidak melakukan terjemahan ini sebelumnya, alih-alih dengan cepat untuk mempercepat proses?
Saya tahu prinsipnya mungkin tampak mudah, tetapi dalam praktiknya, hampir tidak mungkin karena beberapa alasan utama. Untuk memulai, set instruksi yang berbeda menggunakan mode pengalamatan yang sangat berbeda, struktur opcode yang berbeda, ukuran kata yang berbeda, dan beberapa bahkan tidak memiliki instruksi yang Anda butuhkan.
Katakanlah Anda perlu mengganti instruksi XYZ
dengan dua instruksi lagi, ABC
dan DEF
. Sekarang Anda telah secara efektif menggeser semua alamat relatif / offset di seluruh program sejak saat itu, jadi Anda perlu menganalisis dan menelusuri seluruh program dan memperbarui offset (baik sebelum dan sesudah perubahan). Sekarang, katakanlah salah satu dari perubahan offset secara signifikan - sekarang Anda perlu mengubah mode pengalamatan, yang mungkin mengubah ukuran alamat. Ini lagi akan memaksa Anda untuk memindai ulang seluruh file dan menghitung kembali semua alamat, dan seterusnya dan keempat.
Saat Anda menulis program perakitan, Anda mungkin menggunakan label, tetapi CPU tidak - ketika file dirakit, semua label dihitung sebagai lokasi relatif, absolut, atau offset. Anda dapat melihat mengapa ini dengan cepat menjadi tugas yang tidak sepele, dan hampir tidak mungkin. Mengganti instruksi tunggal mungkin mengharuskan Anda melewati seluruh program ratusan kali sebelum melanjutkan.
Dari pengetahuan perakitan yang agak terbatas, sebagian besar instruksi seperti MOV, ADD, dan lainnya harus portabel di seluruh arsitektur.
Ya, tetapi lihat masalah yang saya uraikan di atas. Bagaimana dengan ukuran kata mesin? Panjang alamat? Apakah ia bahkan memiliki mode pengalamatan yang sama? Sekali lagi, Anda tidak bisa hanya "menemukan dan mengganti" instruksi. Setiap segmen program memiliki alamat yang ditentukan secara khusus. Melompat ke label lain diganti dengan alamat memori literal atau offset ketika suatu program dirakit.
Apa pun yang tidak memiliki pemetaan langsung dapat dipetakan ke beberapa set instruksi lain, karena semua mesin Turing Lengkap. Apakah melakukan ini terlalu rumit? Apakah itu tidak bekerja sama sekali untuk beberapa alasan yang saya tidak kenal? Apakah ini akan berhasil, tetapi tidak menghasilkan hasil yang lebih baik daripada menggunakan emulator?
Anda 100% benar bahwa keduanya mungkin , dan akan jauh lebih cepat . Namun, menulis sebuah program untuk mencapai ini sangat sulit dan sangat tidak mungkin, jika tidak untuk apa pun kecuali masalah yang saya uraikan di atas.
Jika Anda memiliki kode sumber rakitan yang sebenarnya, akan mudah untuk menerjemahkan kode mesin ke arsitektur kumpulan instruksi lain. Namun, kode mesin sendiri dirakit , jadi tanpa sumber perakitan (yang berisi berbagai label yang digunakan untuk menghitung alamat memori), itu menjadi sangat sulit. Sekali lagi, mengubah satu instruksi dapat mengubah offset memori di seluruh program, dan membutuhkan ratusan lintasan untuk menghitung ulang alamat.
Melakukan ini untuk program dengan beberapa ribu instruksi akan membutuhkan puluhan bahkan ratusan ribu lintasan. Untuk program yang relatif kecil, ini dimungkinkan, tetapi ingat bahwa jumlah lintasan akan meningkat secara eksponensial dengan jumlah instruksi mesin dalam program. Untuk setiap program dengan ukuran yang cukup layak, hampir tidak mungkin.