3 poin oleh GN⁺ 2024-04-09 | Belum ada komentar. | Bagikan ke WhatsApp
  • Menjelajahi dunia abstraksi yang tersembunyi di balik program Hello World modern

    • Artikel ini membahas program Hello World yang ditulis dalam C. Di antara bahasa tingkat tinggi yang tidak mengharuskan kita memikirkan apa yang dilakukan bahasa sebelum program benar-benar berjalan melalui interpreter/kompiler/JIT, C berada pada tingkat paling rendah.
    • Awalnya tulisan ini ingin dibuat agar bisa dipahami siapa pun yang punya latar belakang pemrograman, tetapi setidaknya akan membantu jika memiliki pengetahuan tentang C atau assembly.
  • Memulai program Hello World

    • Semua orang pasti sudah akrab dengan program Hello World. Di Python, mungkin program pertama yang ditulis adalah sesuatu seperti print('Hello World!').
    • Dalam tulisan ini kita akan melihat Hello World yang ditulis dalam bahasa pemrograman C. Di C, kita tidak bisa menjalankan program dengan memanggil interpreter. Kita harus terlebih dahulu menjalankan kompiler untuk mengubahnya menjadi kode mesin yang bisa dijalankan langsung oleh prosesor komputer.
  • Menganalisis program kita

    • Jika file program yang telah dikompilasi dianalisis, kita bisa mengetahui bahwa itu adalah berkas eksekusi ELF dan ditujukan untuk arsitektur set instruksi x86-64.
    • Berkas eksekusi ELF di Linux setara dengan file .exe di Windows.
    • x86-64 adalah arsitektur CPU yang telah digunakan di PC sejak IBM PC diperkenalkan pada tahun 1981.
    • Berkas ini berisi kode mesin, satu-satunya bahasa yang dapat dipahami CPU.
  • Analisis kode assembly

    • Kita mencari entry point, yaitu alamat awal program, lalu menganalisis kode assembly-nya.
    • Bahasa assembly adalah representasi kode mesin dalam bentuk yang bisa dibaca manusia.
    • Terlihat ada kode inisialisasi yang ditambahkan secara otomatis oleh kompiler, lebih tepatnya linker, dan kita bisa melihat pemanggilan fungsi __libc_start_main.
    • Namun kode ini tidak didefinisikan di program kita, melainkan berada di tempat lain.
  • Pustaka standar C

    • Fungsi __libc_start_main didefinisikan di libc.so.6, yaitu pustaka C standar pada sistem kita.
    • Pustaka standar C adalah kumpulan rutin dan fungsi yang digunakan oleh hampir semua program di komputer kita.
    • Pustaka C melakukan pekerjaan inisialisasi lalu memanggil fungsi main() yang kita tulis. Saat main() mengembalikan nilai, program akan diakhiri dengan kode keluar yang kita berikan.
  • Analisis fungsi main()

    • Di fungsi main(), stack frame disiapkan, alamat string Hello World ditetapkan sebagai argumen pemanggilan fungsi, lalu fungsi puts() dipanggil.
    • puts() dipakai sebagai pengganti printf() karena kompiler melakukan optimisasi. printf() lebih kompleks, sedangkan puts() hanya mencetak string tanpa format.
  • String Hello World

    • String disusun sebagai "Hello World!" yang diikuti terminator NULL.
    • Di C, tidak ada informasi panjang yang terkait dengan string, sehingga akhir string ditandai dengan terminator NULL. Tanpa terminator NULL, program akan terus membaca memori yang tidak diizinkan dan mati karena Segmentation Fault.
    • Karena optimisasi kompiler, newline (\n) yang dipakai di printf() dihapus. puts() memang menambahkan newline setelah mencetak string.
  • Fungsi puts()

    • Fungsi puts() pada gilirannya akan memanggil kode di dalam pustaka standar.
    • Jika melihat kode glibc, kita bisa melihat alur pemanggilan _IO_puts -> _IO_new_file_xsputn, tetapi kodenya rumit sehingga sulit dijelaskan.
    • Pada musl libc, alurnya lebih sederhana. puts -> fputs -> fwrite -> __fwritex -> __stdio_write -> syscall.
  • System call

    • Seberapa besar pun pustaka C, ia tetap tidak bisa berkomunikasi langsung dengan perangkat keras. Hanya kernel yang bisa melakukannya.
    • Karena itu, pemanggilan puts() pada akhirnya berujung pada permintaan kepada OS untuk melakukan sesuatu. Di sini, yang diminta adalah menulis string ke stream output.
    • musl libc menggunakan system call writev, yang memungkinkan beberapa buffer ditulis sekaligus.
    • System call dilakukan dengan menyiapkan parameter di register lalu menjalankan instruksi syscall. Setelah itu kontrol berpindah ke kernel, dan kernel membaca parameter tersebut untuk menjalankan system call.
  • Kernel

    • Kernel Linux harus menjalankan aksi yang diminta melalui system call. System call write memerintahkan kernel untuk menulis ke file atau stream terbuka di file system.
    • write menerima 3 parameter, seperti file descriptor tujuan, buffer yang akan ditulis, dan jumlah byte yang akan ditulis.
    • Ke mana data benar-benar ditulis bergantung pada situasinya. Jika itu emulator terminal, ia terlihat sebagai virtual terminal (pty); jika login jarak jauh, ia diteruskan ke sshd; jika terminal fisik, ia menuju adaptor serial-USB. Jika itu konsol frame buffer, kernel merender teks lalu menampilkannya ke layar.
  • Kesimpulan

    • Sistem perangkat lunak modern bekerja dengan cara yang sangat kompleks dan canggih di atas perangkat keras, sehingga mencoba memahami sepenuhnya bagaimana komputer melakukan satu tugas kecil menjadi sesuatu yang nyaris sia-sia.
    • Untuk menjelaskan semuanya, banyak bagian terpaksa harus dihilangkan.
    • Mengirim pesan Hello World hanyalah salah satu dari sekian banyak system call dan program yang sedang berjalan di komputer saat ini.

Opini GN⁺

  • Ini adalah tulisan yang menunjukkan bagaimana setiap lapisan dalam sistem komputasi menyembunyikan kompleksitas lapisan di bawahnya melalui abstraksi, sehingga pengembang bisa membangun aplikasi dengan lebih nyaman.
  • Di sisi lain, tulisan ini juga menyadarkan kita betapa banyak hal yang terjadi di bawah permukaan agar satu baris aplikasi bisa dijalankan, sekaligus menjelaskan mengapa debugging itu sulit.
  • Saya rasa setiap programmer sebaiknya memahami setidaknya sistem di bawah bahasa yang paling sering mereka gunakan. Tidak perlu mengetahui semuanya, tetapi penting untuk memahami bagaimana bagian yang diabstraksikan itu sebenarnya bekerja.
  • Meski menggunakan bahasa tingkat tinggi, mempelajari konsep pemrograman sistem seperti struktur memori, stack dan heap, serta system call akan sangat membantu dalam debugging maupun optimisasi performa.
  • Pengembang aplikasi mungkin hampir tidak pernah menyentuh langsung kompiler atau pustaka C, tetapi memahami bagaimana program yang kita tulis pada akhirnya menggunakan sistem adalah hal yang esensial untuk menjadi programmer yang baik.

Belum ada komentar.

Belum ada komentar.