Chapter 7 USING ASSEMBLY LANGUAGE WITH C/C++
Saat ini, jarang sekali sebuah sistem dikembangkan hanya dengan bahasa assembly. Umumnya, sistem dibuat dengan C/C++ yang dikombinasikan dengan assembly language.
Assembly biasanya dipakai untuk:
-
Tugas yang sulit atau tidak efisien dilakukan di C/C++ (misalnya kontrol software untuk peripheral interface, driver dengan interrupts).
-
Instruksi khusus prosesor (contoh MMX dan SSE) yang tidak sepenuhnya didukung oleh C/C++.
C++ memang menyediakan makro untuk instruksi khusus tersebut, tetapi penggunaan langsung dengan assembly lebih sederhana. Oleh karena itu, penggabungan C/C++ dengan assembly banyak dipakai dalam aplikasi nyata.
Buku/teks ini menggunakan Microsoft Visual C/C++ Express sebagai compiler utama, namun kode bisa diadaptasi ke compiler lain selama mengikuti standar ANSI C/C++.
-
Aplikasi 16-bit ditulis menggunakan Visual C/C++ v1.52 (tersedia gratis di Microsoft Windows Driver Development Kit).
-
Aplikasi 32-bit ditulis menggunakan Visual C/C++ v6 ke atas, lebih disarankan menggunakan Visual C++ .NET 2003 atau Visual C++ Express (gratis diunduh dari msdn.com).
Chapter Objectives
Setelah mempelajari bab ini, mahasiswa/pembaca diharapkan dapat:
-
Menggunakan assembly language di dalam blok
_asm
pada program C/C++. -
Memahami aturan penggunaan mixed language programming (C/C++ + assembly).
-
Mengakses dan memanipulasi data dan struktur C/C++ dengan assembly.
-
Menggunakan assembly untuk antarmuka 16-bit (DOS) dan 32-bit (Windows).
-
Mengintegrasikan object file assembly dengan program C/C++.
Menggunakan Assembly Language dengan C++ untuk Aplikasi DOS 16-Bit
Bagian ini menjelaskan bagaimana cara menggabungkan perintah assembly language ke dalam program C/C++. Hal ini penting karena kinerja suatu program sering kali bergantung pada penyisipan rangkaian perintah assembly untuk mempercepat eksekusi. Seperti yang disebutkan pada bagian pendahuluan bab ini, assembly language juga digunakan untuk operasi I/O pada sistem tertanam (embedded systems).
Teks ini mengasumsikan bahwa Anda menggunakan salah satu versi program Microsoft C/C++, tetapi program C/C++ lain seharusnya tetap dapat berfungsi seperti yang ditunjukkan, selama mendukung perintah inline assembly. Satu-satunya perbedaan mungkin adalah pada pengaturan paket C/C++ agar dapat berjalan dengan assembly language. Bagian ini mengasumsikan bahwa Anda membangun aplikasi 16-bit untuk DOS. Pastikan perangkat lunak Anda dapat membangun aplikasi 16-bit sebelum mencoba program dalam bagian ini.
Jika Anda membangun aplikasi 32-bit dan mencoba menggunakan fungsi DOS INT 21H, maka program akan mengalami crash karena pemanggilan DOS tidak diizinkan secara langsung. Bahkan, pemanggilan tersebut tidak efisien untuk digunakan dalam aplikasi 32-bit.
Untuk membangun aplikasi DOS 16-bit, Anda memerlukan compiler 16-bit lama (legacy) yang biasanya dapat ditemukan pada direktori:
dari Windows DDK (Driver Development Kit). Paket DDK ini bisa diperoleh dari Microsoft Corporation dengan biaya pengiriman yang kecil. Compiler yang digunakan adalah CL.EXE dan program linker 16-bit adalah LINK.EXE, keduanya terletak di direktori yang disebutkan.
Karena path (jalur) pada komputer Anda mungkin menunjuk ke program linker 32-bit, sebaiknya Anda bekerja langsung dari direktori ini agar linker yang tepat digunakan saat melakukan linking pada file objek yang dihasilkan oleh compiler. Proses kompilasi dan linking harus dilakukan melalui command line, karena tidak ada antarmuka visual atau editor yang disediakan dengan compiler dan linker ini. Program ditulis menggunakan Notepad atau DOS Edit.
Aturan Dasar dan Program Sederhana
Sebelum kode assembly dapat dimasukkan ke dalam program C/C++, beberapa aturan harus dipahami terlebih dahulu. Contoh 7–1 menunjukkan bagaimana menempatkan kode assembly di dalam sebuah blok assembly language pada program C/C++ sederhana.
Perhatikan bahwa seluruh kode assembly dalam contoh ini ditempatkan di dalam blok _asm
. Label juga digunakan, seperti yang ditunjukkan dengan label big:
dalam contoh tersebut. Sangat penting untuk menggunakan huruf kecil untuk setiap kode inline assembly. Jika menggunakan huruf besar, beberapa instruksi assembly dan register akan berbenturan karena sudah didefinisikan sebagai kata kunci di dalam bahasa C/C++.
Contoh 7–1 ini tidak menggunakan perintah C/C++ selain prosedur main
. Program ini (Contoh 7–1) membaca satu karakter dari keyboard console, kemudian menyaringnya melalui assembly language sehingga hanya angka 0 hingga 9 yang dikirim kembali ke tampilan layar (video display).
Meskipun contoh program ini tidak melakukan banyak hal, namun menunjukkan bagaimana cara menyiapkan dan menggunakan pemrograman sederhana dengan assembly language.
Register AX tidak disimpan dalam Contoh 7–1, tetapi digunakan oleh program. Sangat penting untuk dicatat bahwa register AX, BX, CX, DX, dan ES tidak pernah digunakan oleh Microsoft C/C++. (Fungsi register AX saat mengembalikan nilai dari sebuah prosedur akan dijelaskan lebih lanjut pada bab ini.) Register-register tersebut dapat dianggap sebagai scratchpad registers (tempat penyimpanan sementara) yang bisa digunakan bebas dengan assembly language.
Jika Anda ingin menggunakan register lain, pastikan untuk menyimpannya terlebih dahulu dengan perintah PUSH sebelum digunakan, dan mengembalikannya dengan POP setelah selesai. Jika Anda tidak menyimpan register yang digunakan oleh program, maka program mungkin tidak berjalan dengan benar dan bahkan bisa menyebabkan komputer crash.
Jika prosesor 80386 atau yang lebih baru digunakan sebagai dasar program, maka register EAX, EBX, ECX, EDX, dan ES tidak perlu disimpan. Tetapi jika ada register lain yang digunakan, maka register tersebut harus disimpan atau program akan crash.
Untuk melakukan kompilasi program:
-
Jalankan Command Prompt dari menu Start → Accessories.
-
Ubah path ke:
jika memang di situlah lokasi Windows DDK Anda.
3. Anda juga perlu masuk ke direktori:
dan menyalin file slibce.lib ke direktori:
-
Pastikan Anda menyimpan program di path yang sama, dengan ekstensi .c pada nama file. Jika menggunakan Notepad, pilih All Files pada bagian File Type saat menyimpan.
-
Untuk mengompilasi program, ketik:
Perintah ini akan menghasilkan file .exe (opsi /G3 menunjukkan target prosesor 80386). (Lihat Tabel 7–1 untuk daftar switch compiler /G).
Jika muncul error, tekan Enter saja untuk mengabaikannya. Error tersebut hanya berupa warning yang tidak akan menyebabkan masalah saat program dijalankan. Ketika dijalankan, Anda hanya akan melihat angka yang ditampilkan kembali (echo) di layar DOS.
Contoh 7–2 menunjukkan bagaimana cara menggunakan variabel dari C dalam program assembly sederhana. Pada contoh ini, tipe variabel char (1 byte dalam C) digunakan untuk menyimpan beberapa data 8-bit. Program tersebut melakukan operasi:
di mana X dan Y adalah angka satu digit, dan Z adalah hasilnya.
Seperti yang bisa Anda bayangkan, inline assembly dalam C dapat digunakan untuk belajar assembly language dan menulis banyak program dalam buku teks ini. Tanda semicolon ( ; ) digunakan untuk menambahkan komentar pada listing di dalam blok _asm, sama seperti pada assembler normal.
Apa yang Tidak Dapat Digunakan dari MASM di Dalam Blok _asm
Meskipun MASM memiliki beberapa fitur menarik, seperti perintah kondisional (.IF, .WHILE, .REPEAT, dan sebagainya), inline assembler tidak mendukung perintah kondisional dari MASM, juga tidak mendukung fitur MACRO yang ada di assembler.
Alokasi data dalam inline assembler ditangani oleh bahasa C, bukan dengan menggunakan direktif DB, DW, DD, dan sejenisnya. Hampir semua fitur lain masih didukung oleh inline assembler. Kekurangan fitur-fitur ini dapat menimbulkan sedikit masalah, yang akan dibahas pada bagian-bagian selanjutnya di bab ini.
Menggunakan String Karakter
Contoh 7–3 menunjukkan program sederhana yang menggunakan string karakter yang didefinisikan dengan bahasa C, lalu menampilkannya sehingga setiap kata ditulis pada baris terpisah.
Perhatikan perpaduan antara pernyataan C dan perintah assembly. Pernyataan WHILE mengulangi instruksi assembly sampai ditemukan null (00H) di akhir string karakter.
Jika null tidak ditemukan, instruksi assembly akan menampilkan satu karakter dari string tersebut, kecuali jika yang ditemukan adalah spasi. Untuk setiap spasi, program menampilkan kombinasi carriage return/line feed. Hal ini menyebabkan setiap kata dalam string ditampilkan pada baris yang terpisah.
Menggunakan Struktur Data
Struktur data adalah bagian penting dari sebagian besar program. Bagian ini menunjukkan bagaimana cara menghubungkan (interface) sebuah struktur data yang dibuat dalam bahasa C dengan bagian assembly language yang memanipulasi data di dalam struktur tersebut.
Contoh 7–5 menggambarkan sebuah program singkat yang menggunakan struktur data untuk menyimpan nama, umur, dan gaji. Program kemudian menampilkan setiap entri dengan menggunakan beberapa prosedur dalam assembly language.
Meskipun prosedur string menampilkan sebuah string karakter (seperti yang ditunjukkan pada Contoh 7–4), prosedur ini tidak menampilkan kombinasi carriage return/line feed—sebagai gantinya, program menampilkan sebuah spasi.
Prosedur Crlf menampilkan kombinasi carriage return/line feed, sedangkan prosedur Numb menampilkan bilangan integer.
Contoh Program Campuran Bahasa (Mixed-Language Program)
Untuk melihat bagaimana teknik ini dapat diterapkan pada program apa pun, Contoh 7–6 menunjukkan bagaimana sebuah program dapat melakukan beberapa operasi dalam assembly language dan sebagian lainnya dalam bahasa C.
Dalam contoh ini, bagian assembly language hanya terdapat pada prosedur Dispn, yang menampilkan sebuah bilangan integer, dan prosedur Readnum, yang membaca sebuah bilangan integer.
Program pada Contoh 7–6 tidak berusaha mendeteksi atau memperbaiki error. Selain itu, program hanya berfungsi dengan benar jika hasil operasi bernilai positif dan kurang dari 64K.
Perhatikan bahwa pada contoh ini, assembly language digunakan untuk melakukan I/O, sedangkan bagian C menangani semua operasi lainnya untuk membentuk kerangka utama (shell) dari program.
Menggunakan Assembly Language dengan Visual C/C++ untuk Aplikasi 32-Bit
Terdapat perbedaan besar antara aplikasi 16-bit dan 32-bit.
-
Aplikasi 32-bit ditulis menggunakan Microsoft Visual C/C++ Express untuk Windows,
-
sedangkan aplikasi 16-bit ditulis menggunakan Microsoft C++ untuk DOS.
Perbedaan utamanya adalah: Visual C/C++ Express untuk Windows lebih umum digunakan saat ini, tetapi Visual C/C++ Express tidak dapat dengan mudah memanggil fungsi DOS seperti INT 21H.
Disarankan bahwa:
-
Aplikasi embedded yang tidak membutuhkan antarmuka visual sebaiknya ditulis dalam C atau C++ 16-bit.
-
Aplikasi yang melibatkan Microsoft Windows atau Windows CE (tersedia pada ROM atau Flash untuk aplikasi embedded) sebaiknya menggunakan Visual C/C++ Express 32-bit untuk Windows.
Sebuah aplikasi 32-bit ditulis dengan menggunakan register 32-bit apa pun, dan ruang memori pada Windows pada dasarnya dibatasi hingga 2 GB. Versi gratis Visual C++ Express tidak mendukung aplikasi 64-bit yang ditulis dengan assembly language saat ini.
Perbedaan utamanya adalah Anda tidak dapat menggunakan pemanggilan fungsi DOS; sebagai gantinya gunakan fungsi bahasa C/C++ seperti getch(), getche(), dan putch dari console untuk aplikasi DOS console.
Aplikasi embedded menggunakan instruksi langsung assembly language untuk mengakses perangkat I/O dalam sistem embedded. Sedangkan dalam antarmuka Visual, semua I/O ditangani oleh kerangka kerja Windows operating system.
Aplikasi console dalam WIN32 berjalan dalam native mode, yang memungkinkan assembly language dimasukkan ke dalam program hanya dengan menambahkan kata kunci _asm.
Sebaliknya, Windows forms applications lebih menantang karena berjalan dalam managed mode, bukan dalam native mode mikroprosesor. Aplikasi managed berjalan dalam pseudo mode yang tidak menghasilkan kode native.
Contoh yang Menggunakan Console I/O untuk Mengakses Keyboard dan Display
Contoh 7–7 menunjukkan sebuah aplikasi console sederhana yang menggunakan perintah console I/O untuk membaca dan menulis data dari console.
Untuk memasukkan aplikasi ini (dengan asumsi Visual Studio .NET 2003 atau Visual C++ Express tersedia), pilih WIN32 console application pada opsi new project (lihat Gambar 7–1).
Perhatikan bahwa alih-alih menggunakan pustaka stdio.h seperti biasanya, pada aplikasi ini digunakan pustaka conio.h.
Program contoh ini menampilkan sembarang angka antara 0 hingga 1000 dalam semua basis bilangan, mulai dari basis 2 hingga basis 16.
Perhatikan bahwa program utama tidak lagi disebut main seperti pada versi C/C++ sebelumnya, tetapi disebut _tmain pada versi Visual C/C++ Express saat ini jika digunakan dengan aplikasi console.
Parameter argc adalah jumlah argumen yang dilewatkan ke prosedur tmain dari command line, sedangkan argv[] adalah array yang berisi string argumen dari command line.
Contoh ini menyajikan kombinasi perintah assembly language dan C/C++.
Prosedur disps(base, data) melakukan sebagian besar pekerjaan dalam program ini. Prosedur ini memungkinkan bilangan bulat (unsigned integer) ditampilkan dalam basis bilangan apa pun, yang dapat berupa nilai antara basis 2 hingga basis 36.
Batas atas (36) terjadi karena huruf alfabet hanya sampai huruf Z. Jika Anda ingin mengonversi ke basis bilangan yang lebih besar, maka harus dikembangkan skema baru untuk basis di atas 36—misalnya, huruf kecil a hingga z bisa digunakan untuk basis 37 hingga 52.
Namun, Contoh 7–7 hanya menampilkan bilangan yang dimasukkan dalam basis 2 hingga basis 16.
Mengakses Port I/O Secara Langsung
Jika sebuah program ditulis dan harus mengakses nomor port tertentu, kita dapat menggunakan perintah console I/O seperti:
-
_inp(port) → untuk mengambil data byte dari sebuah port (input),
-
_outp(port, byte_data) → untuk mengirim data byte ke sebuah port (output).
Saat menulis perangkat lunak untuk personal computer, sangat jarang dilakukan pengaksesan port I/O secara langsung. Namun, ketika menulis perangkat lunak untuk embedded system, kita sering kali harus mengakses port I/O secara langsung.
Alternatif lain selain menggunakan perintah _inp dan _outp adalah menggunakan assembly language, yang lebih efisien.
Dalam banyak kasus, I/O port tidak dapat diakses di lingkungan Windows jika Anda menggunakan Windows NT, Windows 2000, Windows XP, atau Windows Vista. Satu-satunya cara untuk mengakses I/O port di sistem operasi modern tersebut adalah dengan mengembangkan kernel driver. Pada tahap ini, tidaklah praktis untuk membuat driver semacam itu.
Jika Anda menggunakan Windows 98 atau bahkan Windows 95, Anda masih dapat menggunakan instruksi inp dan outp dalam C/C++ untuk mengakses I/O port secara langsung.
Mengembangkan Aplikasi Visual C++ untuk Windows
Bagian ini menjelaskan cara menggunakan Visual C++ Express untuk mengembangkan aplikasi berbasis dialog dengan pustaka Microsoft Foundation Classes (MFC).
Microsoft Foundation Classes (MFC) adalah kumpulan class yang memungkinkan kita menggunakan antarmuka Windows tanpa terlalu banyak kesulitan. Dalam Visual C++ Express, MFC telah diganti namanya menjadi Common Language Runtime (CLR).
Jenis aplikasi yang paling mudah dipelajari dan dikembangkan adalah program yang menggunakan forms application, seperti yang ditunjukkan di sini. Aplikasi dasar ini digunakan untuk memprogram dan menguji semua contoh perangkat lunak dalam buku teks ini yang ditulis di lingkungan Visual C++ Express.
Untuk membuat aplikasi berbasis form Visual C++, jalankan Visual C++ Express dan klik Create Project di dekat pojok kiri atas layar awal. (Jika Anda belum memiliki program Visual C++ Express, program ini tersedia gratis dari Microsoft di http://msdn.com). Unduh dan instal versi terbaru, meskipun itu masih versi beta.
Gambar 7–2 mengilustrasikan tampilan yang muncul.
Ketika CLR Windows Forms application type dipilih di bawah Visual C++ Express Projects, masukkan nama untuk project dan pilih jalur (path) yang sesuai untuk project, lalu klik OK.
Setelah beberapa saat, layar desain akan muncul seperti yang ditunjukkan pada Gambar 7–3. Pada bagian tengah terdapat form yang dibuat oleh aplikasi ini. Untuk menguji aplikasi sebagaimana adanya, cari tanda panah hijau yang terletak di atas form dan di bawah Windows menu bar di bagian atas layar, lalu klik tanda tersebut untuk meng-compile, meng-link, dan mengeksekusi aplikasi dialog. (Jawab Yes pada pertanyaan “Would you like to build the application?”). Klik tombol X di bilah judul untuk menutup aplikasi. Dengan begitu, Anda baru saja membuat dan menguji aplikasi Visual C++ Express pertama Anda.
Ketika melihat tangkapan layar (screenshot) pada Gambar 7–3, terdapat beberapa item yang penting untuk pembuatan dan pengembangan program. Pada margin kanan layar terdapat Properties window, yang berisi properti dari form. Pada margin kiri terdapat Solution Explorer. Tab-tab yang terletak di bagian bawah jendela Solution Explorer memungkinkan tampilan lain seperti class view dan seterusnya ditampilkan di area ini. Tab-tab di bagian bawah Properties window memungkinkan tampilan class, properties, dynamic help, atau output pada jendela ini.
Tampilan layar Anda mungkin tidak persis sama dengan ilustrasi di Gambar 7–3, karena bisa dimodifikasi dan kemungkinan besar akan berubah seiring penggunaan program.
Untuk membuat sebuah aplikasi sederhana, pilih toolbox dengan mengklik Tools di bagian atas layar atau dengan membuka menu dropdown View dan memilih Toolbox dari daftar.
Sistem ini berbasis event-driven, sehingga sebuah objek atau kontrol diperlukan pada form untuk memicu suatu event. Kontrol tersebut bisa berupa tombol (button) atau hampir semua objek kontrol yang dipilih dari toolbox. Klik kontrol button yang berada dekat bagian atas toolbox untuk memilih tombol tersebut. Setelah itu, pindahkan penunjuk mouse (jangan menyeret tombol) ke aplikasi dialog di bagian tengah layar, lalu gambar tombol dengan klik kiri dan ubah ukurannya di dekat bagian tengah (lihat Gambar 7–4).
Setelah tombol ditempatkan di layar, sebuah event handler harus ditambahkan ke aplikasi sehingga tindakan menekan atau mengklik tombol dapat ditangani. Event handler dipilih melalui Properties window dengan mengklik ikon petir kuning (lightning bolt). Pastikan bahwa item yang dipilih untuk event adalah objek button1. Untuk kembali dari event window ke Properties window, klik ikon yang berada tepat di sebelah kiri ikon petir tersebut. Cari event Click (biasanya menjadi event pertama), lalu double-click pada kotak teks di sebelah kanan untuk memasang event handler bagi Click. Tampilan kemudian akan beralih ke code view dan memperlihatkan lokasi kode program untuk penanganan klik tombol.
Kode yang saat ini terlihat adalah fungsi button1_Click, yang dipanggil saat pengguna menekan tombol. Prosedur ini digambarkan dalam Contoh 7–8. Untuk menguji tombol, ubah kode dalam Contoh 7–8 menjadi kode dalam Contoh 7–9(a). Klik panah hijau untuk compile, link, dan menjalankan aplikasi dialog, lalu klik button1 saat program berjalan. Label pada button1 akan berubah menjadi “Wow, Hello” jika tombol dibuat cukup lebar
Ini adalah aplikasi pertama yang berjalan dengan baik, tetapi belum menggunakan kode assembly. Contoh 7–9(a) menggunakan properti Text dari objek button1 untuk mengubah teks yang ditampilkan pada button1. Versi lainnya yang menggunakan objek string (String^) ditunjukkan dalam Contoh 7–9(b) untuk menampilkan teks “Wow, Hello World.”
Sekarang setelah sebuah aplikasi sederhana berhasil dibuat, kita dapat memodifikasinya untuk menggambarkan aplikasi yang lebih kompleks seperti yang ditunjukkan pada Gambar 7–5. Caption pada tombol telah diubah menjadi kata “Convert.” Untuk kembali ke layar desain, pilih tab di bagian atas jendela program yang diberi label Form1.h[design]*. Saat berada di Design window, ubah caption pada objek button1 dengan mengklik tombol tersebut, lalu cari properti Text dari button1 di Properties window. Ubah properti Text menjadi “Convert.”
Pada Gambar 7–5, terlihat bahwa ada tiga kontrol Label dan tiga kontrol Textbox yang ditempatkan di bawah dan di sebelah kiri tombol Convert. Kontrol-kontrol ini tersedia di toolbox. Gambar kontrol tersebut di layar dengan posisi kurang lebih sama seperti yang ditunjukkan pada ilustrasi.
Tempatkan kontrol seperti pada Gambar 7–5. Label diubah melalui properti masing-masing kontrol label. Ubah teks untuk setiap label sesuai dengan yang ditunjukkan.
Tujuan kita dalam contoh ini adalah menampilkan setiap bilangan desimal yang dimasukkan pada kotak Decimal Number sebagai bilangan dengan basis (radix/number base) tertentu sesuai angka yang dimasukkan pada kotak Radix. Hasilnya akan muncul di kotak Result ketika tombol Convert diklik. Untuk beralih ke tampilan program, klik tab Form1.h di bagian atas Design window.
Untuk mendapatkan nilai dari kontrol edit, gunakan properti Text untuk memperoleh versi string dari angka tersebut. Masalahnya, dalam kasus ini yang dibutuhkan adalah sebuah bilangan bulat (integer), bukan string. String tersebut harus dikonversi ke integer. Kelas Convert yang disediakan dalam C++ melakukan konversi dari berbagai tipe data ke berbagai tipe data lainnya. Dalam hal ini, fungsi anggota kelas Convert, yaitu ToInt32, digunakan untuk mengubah string menjadi integer.
Bagian yang sulit dari contoh ini adalah konversi dari basis 10 ke basis bilangan lain. Contoh 7–10 menunjukkan bagaimana kelas Convert digunakan untuk mengonversi string dari textbox menjadi integer. Hal ini hanya akan berfungsi dengan benar jika angka yang dimasukkan ke dalam textbox1 adalah integer. Jika huruf atau hal lain yang dimasukkan, program akan crash dan menampilkan pesan error.
Sisa dari aplikasi ini terdapat pada fungsi button1_Click di Contoh 7–12.
Program ini menggunakan algoritma Horner untuk melakukan konversi ke basis bilangan apa pun dari 2 hingga 36. Algoritma konversi ini membagi bilangan yang akan dikonversi dengan basis (radix) yang diinginkan sampai hasilnya nol.
Setelah setiap pembagian, sisa (remainder) disimpan sebagai digit signifikan dalam hasil, dan hasil bagi (quotient) kembali dibagi dengan basis tersebut. Perlu dicatat bahwa Windows tidak menggunakan kode ASCII, melainkan menggunakan Unicode, sehingga diperlukan Char (Unicode 16-bit) sebagai pengganti char 8-bit.
Perhatikan bagaimana urutan sisa pembagian dimasukkan ke dalam string hasil dengan cara menggabungkan (concatenate) setiap digit ke sebelah kiri string. Nilai 0x30 ditambahkan ke setiap digit untuk mengubahnya menjadi kode ASCII dalam contoh tersebut.
Algoritma Horner:
Bagi bilangan dengan basis (radix) yang diinginkan.
Simpan sisanya, lalu ganti bilangan dengan hasil bagi.
Ulangi langkah 1 dan 2 sampai hasil bagi bernilai nol.
Karena ini adalah teks tentang bahasa rakitan (assembly language), kelas Convert tidak akan digunakan dengan alasan yang jelas; fungsinya cukup besar. Untuk melihat seberapa besar ukurannya, Anda bisa meletakkan breakpoint pada perangkat lunak di sebelah kiri fungsi Convert dengan mengklik bilah abu-abu di sebelah kiri baris kode. Sebuah lingkaran cokelat (breakpoint) akan muncul. Jika Anda menjalankan program, program akan berhenti pada titik ini dan masuk ke mode debugging sehingga dapat dilihat dalam bentuk bahasa rakitan.
Untuk menampilkan kode yang telah dibongkar (disassembled code), jalankan program hingga berhenti, lalu buka menu Debug dan pilih Windows. Pada menu Windows, di dekat bagian bawah, cari “Disassembly.” Register juga dapat ditampilkan untuk melangkah (step through) melalui program dalam bahasa rakitan.
Seperti yang dapat Anda lihat, jika program didebug dengan cara yang dijelaskan, jumlah kode yang dihasilkan sangat besar dan dapat dikurangi secara signifikan jika ditulis ulang menggunakan inline assembler. Contoh 7–13 menggambarkan versi bahasa rakitan dari fungsi Convert::ToInt32. Fungsi ini jauh lebih pendek (jika didebug dan dilihat di jendela Disassemble) dan dieksekusi berkali-kali lebih cepat dibandingkan fungsi Convert pada Contoh 7–12.
Contoh ini menyoroti ketidakefisienan kode yang dihasilkan oleh bahasa tingkat tinggi, yang mungkin tidak selalu menjadi masalah, tetapi dalam banyak kasus dibutuhkan kode yang rapat dan efisien—dan itu hanya bisa ditulis dalam assembly language. Saya berasumsi bahwa ketika kecepatan prosesor mencapai titik jenuh, lebih banyak hal akan ditulis dalam bahasa rakitan. Selain itu, instruksi baru seperti MMX dan SSE tidak tersedia dalam bahasa tingkat tinggi. Instruksi tersebut membutuhkan pemahaman yang sangat baik tentang kode rakitan.
Masalah utama dalam menggunakan kode rakitan inline adalah kode tersebut tidak dapat ditempatkan ke dalam aplikasi forms Windows yang dikelola dalam kelas yang dikelola (managed class). Untuk dapat menggunakan assembler, …
Fungsi harus ditempatkan sebelum kelas yang dikelola (managed class) agar dapat dikompilasi. Oleh karena itu, pada Project Properties, Common Runtime Support juga harus diubah menjadi /clr dari pengaturan default /clr:pure agar dapat dikompilasi dengan sukses. (Lihat Gambar 7–6 untuk tangkapan layar tentang cara mengubah dukungan Common Language Runtime ke /clr.)
Program yang dikelola berjalan di bawah mesin virtual .NET, sedangkan aplikasi yang tidak dikelola dijalankan dalam mode asli (native mode) komputer. Inline assembler menghasilkan kode asli untuk mikroprosesor, sehingga kode tersebut harus bersifat unmanaged dan ditempatkan sebelum managed class di dalam program.
Contoh 7–13 menggambarkan bagaimana mengganti sebagian dari algoritma Horner dengan kode assembly dalam sebuah fungsi yang disebut Adjust. Fungsi Adjust menguji angka apakah lebih besar dari 9, dan jika ya, ia menambahkan 0x07 lalu 0x30 untuk mengonversinya menjadi ASCII, yang kemudian dikembalikan. Perhatikan dalam contoh tersebut bahwa kode assembly ditempatkan tepat setelah bagian using
di bagian atas program. Di situlah semua fungsi assembly harus ditempatkan agar program dapat berfungsi dengan benar. Aplikasi dimulai dalam native mode dan beralih ke managed mode ketika menemukan kelas yang dikelola. Dengan menempatkan kode assembly sebelum kelas yang dikelola, kode tersebut tersedia untuk seluruh aplikasi dan dijalankan dalam mode unmanaged/native.
Di akhir Contoh 7–13, terdapat versi alternatif dari Adjust yang lebih efisien. Versi alternatif ini tidak memiliki instruksi return, lalu bagaimana bisa berfungsi? Yang tidak tampak adalah bahwa fungsi assembly secara otomatis mengembalikan nilai melalui AL untuk sebuah byte, AX untuk sebuah word/short, dan EAX untuk sebuah integer. Perlu dicatat bahwa nilai kembalian menentukan ukuran data yang dikembalikan.
Gambar 7–14 menunjukkan modifikasi pada fungsi button1_click sehingga Adjust dipanggil sebagai pengganti kode yang ada pada Contoh 7–12. Kode yang digunakan untuk menyiapkan aplikasi form yang muncul di antara Contoh 7–13 dan 7–14 tidak ditampilkan.
Perhatikan bahwa fungsi assembly menggunakan short sebagai pengganti character. Short adalah bilangan 16-bit yang digunakan dalam unmanaged mode, sedangkan Char adalah bilangan 16-bit yang digunakan dalam managed mode untuk merepresentasikan karakter Unicode. Di sini digunakan cast untuk mengonversi ke Char, karena tanpa konversi tersebut nilai numerik akan ditampilkan alih-alih kode ASCII.
MIXED ASSEMBLY AND C++ OBJECTS
Seperti yang telah disebutkan pada bagian sebelumnya, inline assembler memiliki keterbatasan karena tidak dapat menggunakan urutan MACRO dan direktif alur program bersyarat (conditional program flow directives) yang telah dijelaskan pada Bab 6. Dalam beberapa kasus, akan lebih baik jika program dikembangkan dalam bentuk modul bahasa assembly yang kemudian di-link dengan C++ untuk fleksibilitas yang lebih tinggi. Hal ini terutama berlaku jika aplikasi sedang dikembangkan oleh sebuah tim pemrogram.
Bagian bab ini menjelaskan penggunaan berbagai objek yang di-link untuk membentuk sebuah program dengan menggunakan bahasa assembly dan C++ secara bersamaan.
Menghubungkan Bahasa Assembly dengan Visual C++
Contoh 7–15 memperlihatkan sebuah prosedur model flat yang akan di-link dengan program C++. Kita menandai bahwa modul assembly tersebut adalah modul C++ dengan menambahkan huruf C setelah kata flat pada pernyataan model. Bentuk linkage yang ditentukan oleh huruf C sama untuk bahasa C maupun C++. Model flat memungkinkan perangkat lunak assembly memiliki panjang hingga 2 GB. Perlu diperhatikan bahwa switch .586 muncul sebelum pernyataan model, yang membuat assembler menghasilkan kode yang berfungsi dalam mode terlindungi 32-bit.
Prosedur Reverse, yang ditunjukkan pada Contoh 7–15, menerima sebuah string karakter dari program C++, membalik urutannya, kemudian mengembalikannya ke program C++. Perhatikan bagaimana program ini menggunakan instruksi alur program bersyarat (conditional program flow instructions), yang tidak tersedia pada inline assembler seperti yang dijelaskan pada bagian sebelumnya dari bab ini.
Modul bahasa assembly dapat memiliki nama apa saja dan dapat berisi lebih dari satu prosedur, selama setiap prosedur berisi pernyataan PUBLIC yang mendefinisikan nama prosedur tersebut sebagai public. Parameter apa pun yang ditransfer dalam program C++ dan program assembly ditunjukkan dengan tanda garis miring terbalik (backslash) setelah nama prosedur. Hal ini menamai parameter untuk program assembly (namanya dapat berbeda di C++) dan menunjukkan ukuran parameter tersebut.
Satu-satunya hal yang tidak berbeda antara program pemanggil C++ dan program assembly adalah urutan parameternya. Dalam contoh ini, parameternya adalah pointer ke sebuah string karakter dan hasilnya dikembalikan sebagai pengganti string asli.
Contoh 7–16 memperlihatkan sebuah program bahasa C++ untuk aplikasi konsol DOS yang menggunakan prosedur Reverse dari bahasa assembly. Pernyataan EXTERN digunakan untuk menunjukkan bahwa ada prosedur eksternal bernama Reverse yang akan digunakan dalam program C++. Nama prosedur bersifat case-sensitive, jadi pastikan penulisannya sama persis baik di modul assembly maupun di modul C++.
Pernyataan EXTERN pada Contoh 7–16 menunjukkan bahwa prosedur eksternal bahasa assembly tersebut menerima sebuah string karakter untuk diproses dan tidak mengembalikan data. Jika prosedur assembly mengembalikan data, maka data tersebut dikembalikan dalam bentuk nilai di register EAX untuk tipe data byte, word, atau doubleword. Jika angka floating-point yang dikembalikan, maka nilainya harus dikembalikan melalui floating-point coprocessor stack. Sedangkan jika yang dikembalikan adalah pointer, maka nilainya harus berada di EAX.
Setelah program C++ dan program bahasa assembly selesai ditulis, sistem pengembangan Visual C++ harus diatur agar dapat link keduanya. Untuk proses linking dan assembly, kita akan mengasumsikan bahwa modul bahasa assembly diberi nama Reverse.txt (Anda tidak dapat menambahkan ekstensi file .asm ke dalam daftar file proyek, jadi gunakan saja ekstensi .txt dan tambahkan file dengan ekstensi .txt), sedangkan modul bahasa C++ diberi nama Main.cpp. Kedua modul ini disimpan di direktori C:\PROJECT\MINE atau direktori lain sesuai pilihan Anda. Setelah modul ditempatkan di dalam workspace project yang sama, program Programmer’s Workbench digunakan untuk mengedit modul bahasa assembly maupun modul bahasa C++.
Untuk mengatur Visual C++ Developer Studio agar dapat compile, assemble, dan link file-file ini, ikuti langkah-langkah berikut:
Jalankan developer studio dan pilih New dari menu File.
a. Pilih New Project.
b. Saat Application Wizard muncul, klik Visual C++ Projects.
c. Pilih C++ Console Application, lalu beri nama proyek Mine.
d. Klik OK.Anda akan melihat proyek tersebut di jendela Solution di sisi kiri tengah layar. Di sana akan terdapat sebuah file bernama Main.cpp, yaitu file program C++. Ubah file ini agar sesuai dengan yang ditunjukkan pada Contoh 7–16.
Untuk menambahkan modul bahasa assembly, klik kanan pada baris Source Files lalu pilih Add dari menu. Pilih Add New Item dari daftar. Gulir ke bawah daftar tipe file hingga Anda menemukan Text Files, lalu pilih itu, kemudian masukkan nama file sebagai Reverse dan klik Open. Hal ini akan membuat modul assembly bernama Reverse.txt. Anda dapat memasukkan kode assembly dari Contoh 7–15 ke dalam file ini.
Di bawah daftar Source Files pada Solution Explorer, klik kanan pada Reverse.txt lalu pilih Properties. Gambar 7–7 menunjukkan apa yang harus dimasukkan dalam wizard ini setelah Anda mengklik langkah Custom Build. Pastikan Anda memasukkan nama file objek (Reverse.obj) di kotak Outputs dan perintah ml /c /Cx /coff Reverse.txt di kotak Command Line. File bahasa assembly Reverse akan di-assemble dan disertakan dalam proyek.
Jika Contoh 7–15 dan Contoh 7–16 sudah dimasukkan serta semua langkah sudah selesai dilakukan, maka program akan dapat dijalankan dengan baik.
Akhirnya, Anda dapat mengeksekusi program tersebut. Klik pada tanda panah hijau. Anda akan melihat dua baris data teks ASCII ditampilkan. Baris pertama ditampilkan dalam urutan maju yang benar, sedangkan baris kedua dalam urutan terbalik. Walaupun ini hanya sebuah aplikasi sederhana, contoh ini menunjukkan bagaimana cara membuat dan menghubungkan (link) bahasa C++ dengan bahasa assembly.
Sekarang setelah kita memahami dengan baik cara menghubungkan bahasa assembly dengan C++, kita membutuhkan contoh yang lebih panjang yang menggunakan beberapa prosedur bahasa assembly dalam sebuah program C++. Contoh 7–17 memperlihatkan sebuah paket bahasa assembly yang mencakup sebuah prosedur (Scan) untuk menguji sebuah input karakter terhadap sebuah tabel pencarian (lookup table) dan mengembalikan sebuah angka yang menunjukkan posisi relatif dalam tabel tersebut. Prosedur kedua (Look) menggunakan angka yang ditransfer kepadanya dan mengembalikan sebuah string karakter yang merepresentasikan kode Morse. (Kodenya sendiri tidak terlalu penting, tetapi jika Anda tertarik, Tabel 7–2 menampilkan kode Morse).
Tabel pencarian (lookup table) pada Contoh 7–17 berisi 2 byte untuk setiap karakter dari huruf A hingga Z. Sebagai contoh, kode untuk huruf A adalah 2, yang menunjukkan bahwa karakter Morse untuk huruf A terdiri dari dua tanda, baik kombinasi titik maupun garis, dan 1 adalah kode untuk huruf A (. –
), di mana bentuk biner 01 (untuk dua digit) mewakili sebuah titik diikuti oleh sebuah garis.
Tabel pencarian ini diakses oleh prosedur Scan untuk memperoleh kode Morse yang benar dari tabel tersebut, yang kemudian dikembalikan dalam AX sebagai parameter untuk pemanggilan program C++. Sisa kode assembly lainnya bersifat rutin (mundane).
Contoh 7–18 menampilkan program C++ yang memanggil dua prosedur yang tercantum pada Contoh 7–17. Perangkat lunak ini cukup mudah dipahami, sehingga tidak perlu dijelaskan lebih lanjut.
Meskipun contoh-contoh yang disajikan di sini adalah untuk aplikasi konsol, metode yang sama untuk menginstruksikan Visual Studio agar melakukan assemble dan link sebuah modul bahasa assembly juga digunakan pada aplikasi Visual untuk Windows. Perbedaan utamanya adalah bahwa aplikasi Windows tidak menggunakan printf atau cout.
Bab berikutnya menjelaskan bagaimana file pustaka (library files) juga dapat digunakan dengan Visual C++ serta memberikan lebih banyak contoh pemrograman.
Menambahkan Instruksi Bahasa Assembly Baru ke dalam Program C/C++
Dari waktu ke waktu, ketika prosesor baru diperkenalkan oleh Intel, instruksi bahasa assembly baru juga diperkenalkan. Instruksi-instruksi baru ini tidak dapat digunakan dalam C++ kecuali Anda membuat sebuah macro di C++ untuk menyertakannya ke dalam program.
Salah satu contohnya adalah instruksi bahasa assembly CPUID. Instruksi ini dapat dijalankan dalam blok _asm di C++, tetapi inline assembler tidak mengenalinya. Kelompok instruksi baru lainnya termasuk instruksi MMX dan SEC. Instruksi-instruksi ini juga dikenali, tetapi untuk mengilustrasikan bagaimana cara menambahkan instruksi baru yang tidak ada di assembler, teknik berikut diperlihatkan.
Untuk menggunakan instruksi baru apa pun, pertama-tama cari kode machine language-nya di Lampiran B atau di situs web Intel di www.intel.com. Sebagai contoh, kode machine untuk instruksi CPUID adalah 0F A2. Instruksi 2-byte ini dapat didefinisikan sebagai sebuah macro C++, seperti yang ditunjukkan pada Contoh 7–19. Untuk menggunakan macro baru tersebut dalam program C++, kita hanya perlu mengetik CPUID. Macro _emit menyimpan byte yang mengikutinya ke dalam program.
RANGKUMAN
Inline assembler digunakan untuk menyisipkan potongan kode assembly yang pendek dan terbatas ke dalam program C++. Keterbatasan utama dari inline assembler adalah tidak dapat menggunakan urutan macro maupun instruksi alur program bersyarat (conditional program flow instructions).
Terdapat dua versi bahasa C++ yang tersedia. Satu dirancang untuk aplikasi konsol DOS 16-bit dan satu lagi untuk aplikasi Windows 32-bit. Jenis yang dipilih tergantung pada lingkungan yang digunakan, tetapi dalam sebagian besar kasus saat ini, para pemrogram menggunakan Windows dengan versi Visual Express 32-bit.
Aplikasi bahasa assembly 16-bit menggunakan perintah DOS INT 21H untuk mengakses perangkat dalam sistem. Aplikasi assembly 32-bit tidak dapat mengakses fungsi panggilan DOS INT 21H dengan efisien atau mudah, meskipun banyak di antaranya tersedia.
Metode yang paling fleksibel dan sering digunakan untuk menghubungkan bahasa assembly dalam program C++ adalah melalui modul bahasa assembly terpisah. Perbedaannya hanya pada keharusan mendefinisikan modul assembly tersebut dengan menggunakan direktif C setelah pernyataan .model, agar linkage modul didefinisikan sebagai kompatibel dengan C/C++.
Pernyataan PUBLIC digunakan dalam modul bahasa assembly untuk menunjukkan bahwa nama prosedur bersifat publik dan dapat digunakan oleh modul lain. Parameter eksternal didefinisikan dalam modul assembly dengan menggunakan nama prosedur pada pernyataan PROC. Parameter dikembalikan melalui register EAX ke prosedur C/C++ pemanggil dari prosedur assembly.
Modul bahasa assembly dinyatakan sebagai eksternal dalam program C++ dengan menggunakan direktif extern. Jika direktif extern diikuti dengan huruf C, maka direktif tersebut digunakan dalam program bahasa C/C++.
Saat menggunakan Visual Studio, kita dapat menginstruksikannya untuk melakukan assemble modul bahasa assembly dengan mengklik Properties pada modul tersebut, lalu menambahkan program bahasa assembly (ml /c /Cx /coff Filename.txt) dan file keluarannya sebagai file objek (Filename.obj) pada langkah Custom Build untuk modul tersebut.
Modul bahasa assembly dapat berisi banyak prosedur, tetapi tidak boleh berisi program yang menggunakan direktif .startup.
Komentar
Posting Komentar