Mengapa kompiler menghasilkan kode rakitan?

19

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?

CODERSAM
sumber

Jawaban:

22

Alasan lain bagi kompiler untuk menghasilkan perakitan daripada kode mesin yang tepat adalah:

  • Alamat simbolik yang digunakan oleh assembler alih-alih alamat mesin pengkodean keras membuat pemindahan kode menjadi lebih mudah.
  • Menghubungkan kode mungkin melibatkan pemeriksaan keamanan seperti pengecekan tipe, dan itu lebih mudah dilakukan dengan nama simbolis.
  • Perubahan kecil pada kode mesin lebih mudah diakomodasi dengan mengganti assembler daripada generator kode.
Martin Berger
sumber
mengapa bahasa assembly sangat efisien, meskipun juga ditulis dalam bahasa Inggris dan bagaimana prosesor memahaminya?
CODERSAM
3
Majelis @CODERSAM adalah bahasa formal, bukan bahasa alami. Sangat dekat dengan bahasa mesin. Jadi tranlasi tidak menimbulkan inefisiensi.
Martin Berger
ketika Anda berkata, "sangat dekat dengan bahasa mesin", apa artinya itu? Saya benar-benar bingung dengan ini!
CODERSAM
2
@ CODERSAM Arti yang tepat rumit, tetapi sesuatu seperti homomorfisme dalam aljabar. Saat Anda menerjemahkan, ucapkan "add eax, # 2" yang merupakan rakitan x86, Anda dapat menerjemahkannya ke d7f5 (atau apa pun kode opnya), langsung, tanpa melihat konteksnya, tanpa menambahkan lebih banyak barang. Majelis tidak memiliki abstraksi.
Martin Berger
1
"Majelis tidak memiliki abstraksi" - Saya akan mengatakan nama label sudah merupakan abstraksi (dari offset). Juga, konteksnya memainkan peran: misalnya add eax,2dapat diterjemahkan ke 83 c0 02atau ke 66 83 c0 02, tergantung pada arahan terbaru yang terjadi seperti use16.
Ruslan
15

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.

Yuval Filmus
sumber
Selain itu, jika sumber dapat menyertakan beberapa kode rakitan, maka suatu mekanisme harus tersedia untuk menerjemahkan rakitan inline itu.
Paul A. Clayton
mengapa bahasa assembly sangat efisien, meskipun juga ditulis dalam bahasa Inggris dan bagaimana prosesor memahaminya?
CODERSAM
1
Bahasa assembly adalah deskripsi "bahasa Inggris" dari kode mesin.
Yuval Filmus
11

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.

supercat
sumber
1

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.

Damian Yerrick
sumber
1

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.

Peter Green
sumber
1

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???

Robert Pearson
sumber