Bahasa assembly diubah menjadi bahasa mesin oleh assembler. Mengapa kompiler akan mengkonversi bahasa tingkat tinggi ke perakitan? Tidak bisakah itu secara langsung mengkonversi dari bahasa tingkat tinggi ke kode mesin?
compilers
code-generation
assembly
CODERSAM
sumber
sumber
add eax,2
dapat diterjemahkan ke83 c0 02
atau ke66 83 c0 02
, tergantung pada arahan terbaru yang terjadi sepertiuse16
.Compiler biasanya mengkonversi kode tingkat tinggi langsung ke bahasa mesin, tetapi dapat dibangun dengan cara modular sehingga satu back-end memancarkan kode mesin dan kode assembly lainnya (seperti GCC). Fase pembuatan kode menghasilkan "kode" yang merupakan representasi internal dari kode mesin, yang kemudian harus dikonversi ke format yang dapat digunakan seperti bahasa mesin atau kode rakitan.
sumber
Secara historis sejumlah kompiler terkenal melakukan kode mesin output secara langsung. Namun, ada beberapa kesulitan dengan melakukannya. Secara umum seseorang yang mencoba mengonfirmasi bahwa sebuah kompiler bekerja dengan benar akan lebih mudah untuk memeriksa output kode assembly daripada kode mesin. Lebih lanjut, adalah mungkin (dan secara historis umum) untuk menggunakan one-pass C atau kompilator Pascal untuk menghasilkan file bahasa assembly yang kemudian dapat diproses menggunakan assembler dua-pass. Membuat kode secara langsung akan membutuhkan menggunakan dua-pass C atau kompilator Pascal atau menggunakan kompilator satu-pass diikuti oleh beberapa cara back-patching alamat forward-jump [jika lingkungan runtime membuat ukuran program yang diluncurkan tersedia dalam sebuah tempat tetap, kompiler dapat menulis daftar tambalan di akhir kode dan meminta kode startup menerapkan tambalan tersebut pada saat runtime; pendekatan semacam itu akan meningkatkan ukuran yang dapat dieksekusi sekitar empat byte per patch-point, tetapi akan meningkatkan kecepatan pembuatan program].
Jika tujuannya adalah untuk memiliki kompiler yang berjalan cepat, pembuatan kode langsung dapat bekerja dengan baik. Namun, untuk sebagian besar proyek, biaya untuk menghasilkan kode bahasa rakitan dan merakitnya sebenarnya bukan masalah besar saat ini. Memiliki kompiler menghasilkan kode dalam bentuk yang dapat berinteraksi dengan baik dengan kode yang dihasilkan oleh kompiler lain umumnya manfaat yang cukup besar untuk membenarkan peningkatan waktu kompilasi.
sumber
Bahkan platform yang menggunakan set instruksi yang sama mungkin memiliki format file objek yang dapat dipindahkan. Saya bisa memikirkan "a.out" (UNIX awal), OMF, MZ (MS-DOS EXE), NE (Windows 16-bit), COFF (Sistem UNIX V), Mach-O (OS X dan iOS), dan ELF (Linux dan lainnya), serta varian dari mereka, seperti XCOFF (AIX), ECOFF (SGI), dan Portable Executable (PE) berbasis COFF pada Windows 32-bit. Kompiler yang menghasilkan bahasa assembly tidak perlu tahu banyak tentang format file objek, memungkinkan assembler dan linker untuk merangkum pengetahuan itu dalam proses terpisah.
Lihat juga Perbedaan antara OMF dan COFF pada Stack Overflow.
sumber
Biasanya kompiler bekerja secara internal dengan urutan instruksi. Setiap instruksi akan diwakili oleh struktur data yang mewakili nama operasi, operan, dan sebagainya. Ketika operan adalah alamat, alamat itu biasanya akan menjadi referensi simbolik, bukan nilai konkret.
Menghasilkan assembler relatif sederhana. Cukup banyak masalah dengan mengambil struktur data internal kompiler dan membuangnya ke file teks dalam format tertentu. Output Assembler juga relatif mudah dibaca yang berguna ketika Anda perlu memeriksa apa yang dilakukan kompiler.
Mengeluarkan file objek biner secara signifikan lebih banyak pekerjaan. Penulis kompiler perlu mengetahui bagaimana semua instruksi dikodekan (yang mungkin jauh dari sepele pada beberapa CPUS), mereka perlu mengonversi beberapa referensi simbolis ke program counter alamat relatif dan lainnya ke beberapa bentuk data meta dalam file objek biner . Mereka perlu menuliskan semuanya dalam format yang sangat spesifik untuk sistem.
Ya, Anda benar-benar dapat membuat kompiler yang dapat menampilkan objek biner secara langsung tanpa menuliskan assembler sebagai langkah perantara. Pertanyaan seperti banyak hal dalam pengembangan perangkat lunak adalah apakah pengurangan waktu kompilasi sepadan dengan pengembangan tambahan dan pekerjaan pemeliharaan.
Compiler yang paling saya kenal (freepascal) dapat menampilkan assembler pada semua platform tetapi hanya bisa menampilkan objek biner langsung pada subset platform.
sumber
Seorang kompiler harus dapat menghasilkan output assembler selain kode relocatable normal adalah untuk kepentingan programmer.
Suatu kali saya tidak menemukan bug dalam program C yang berjalan pada Unix System V pada mesin LSI-11. Tampaknya tidak ada yang berhasil. Akhirnya dalam keputus-asaan saya memiliki kompiler C protable mengeluarkan versi assembler dari terjemahannya. Saya akhirnya menemukan bug! Kompiler mengalokasikan register lebih banyak daripada yang ada di mesin! (Kompilator mengalokasikan register R0 hingga R8 pada mesin dengan register hanya R0 hingga R7.) Saya berhasil mengatasi bug di kompiler dan program saya berhasil.
Manfaat lain dari memiliki keluaran assembler adalah mencoba menggunakan pustaka "standar" yang menggunakan protokol passing parameter yang berbeda. Kemudian kompiler C memungkinkan saya untuk mengatur protokol dengan parameter ("pascal" akan membuat kompiler menambahkan parameter dalam urutan yang diberikan sebagai lawan dari standar C untuk membalikkan urutan).
Namun manfaat lain adalah memungkinkan pemrogram untuk melihat apa pekerjaan yang mengerikan kompilernya lakukan. Pernyataan C sederhana membutuhkan sekitar 44 instruksi mesin. Nilai dimuat dari memori dan kemudian dibuang dengan cepat. dll, dll, dll ...
Saya pribadi percaya bahwa memiliki kompiler alih-alih modul objek yang dapat dipindahkan benar-benar bodoh. Saat mengkompilasi program Anda, kompiler mengumpulkan banyak informasi tentang program Anda. Biasanya menyimpan semua informasi ini dalam sesuatu yang disebut Tabel Simbol. Setelah mengeluarkan kode assembler, ia membuang semua tabel informasi ini. Assembler kemudian memeriksa kode yang diekskresikan dan mengumpulkan kembali beberapa informasi yang telah dimiliki oleh kompiler. Namun assembler tidak tahu apa-apa tentang pernyataan If untuk pernyataan While atau pernyataan While. Jadi semua informasi ini hilang. Kemudian assembler menghasilkan modul objek yang dapat dipindahkan yang tidak dikompilasi oleh kompiler.
Mengapa???
sumber