Belajar C Secara Tunggang Terbalik (1st draft) Bab 1 - Senibina Komputer (80x86) 1.1 Pengenalan Mula-mula sekali kita patut tahu pasal platform programming kita. Semua orang tahu bahawa komputer adalah mesin digital untuk tujuan pengiraan. Komputer bukan sama sekali pandai macam manusia. Tetapi kelebihan komputer adalah kepantasan mengira. Cara pengiraan aritmetik komputer tidak sama dgn manusia kerana komputer hanya boleh mengenali binary digit(bit) iaitu sama ada 0 (off) atau 1 (on). oleh itu, semua pengiraan dalam sistem berasaskan bit. Tujuan pengenalan kepada bahasa perhimpunan untuk memberikan asas kepada pengaturcara dalam proses nyahralat(debugging). Ini kerana selepas program yang ditulis, penterjemah (compiler) akan menterjemahkan ke dalam bahasa mesin. Seterusnya bahasa mesin boleh diterjemah kembali kepada bahasa perhimpunan. 1.2 Sistem Nombor Untuk disesuaikan dalam sistem komputer, nombor asas 2 diperkenalkan dan biasanya berbentuk 11001001. Tetapi kita sebagai manusia akan menjadi kelabu mata untuk mentafsirkan nilai sebenar no binari lebih2 lagi jika nilainya sangat besar spt 100100100110010010011001001001100100100110010010011001001001. Untuk memudahkan kita membaca nombor2 binari, satu lagi asas nombor diperkenalkan iaitu nombor asas 16 ataupun heksadesimal (Hex). Di mana 6 digit nombor diperkenal iaitu A, B, C, D, E, F sebagai tambahan kepada 0, 1, ....,9. Hex diperkenalkan kerana nombor asas 10(desimal) yang digunakan oleh kita seharian tidak berapa relevan dan lebih kompleks untuk ditukar daripada binari. Perhatikan BETUL-BETUL jadual di bawah. hexadecimal | binary | decimal
---------------------------------
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
A 1010 10
B 1011 11
C 1100 12
D 1101 13
E 1110 14
F 1111 15
----------------------------------
Cara penukaran Hex -> Binari dan Binary -> Hex.
Sebagai contoh kita ambil no 0xD39F2A. Caranya "straightforward" dan tidak memeningkan kepala
D | 3 | 9 | F | 2 | A
----------------------------------------
1101 | 0011 | 1001 | 1111 | 0010 | 1010
oleh itu 0xD39F2A dalam binari adalah 110100111001111100101010
Dan penukar binari kepada Hex adalah proses sebaliknya contohnya 1100101011
11 | 0010 | 1011
-------------------
3 | 2 | B
oleh itu 001100101011 = 0x32B
1.3 Asas senibina komputer.
Anda sebagai programmer wajib mengetahui apakah jenis senibina komputer yang akan menjadi platform program kita, kecuali kita hanya ingin membina program Java. Oleh itu, anda akan mengetahui kelebihan, had, dan sebagainya yang ditawarkan oleh sesuatu mikropemproses mengeksploitasinya untuk membina program yang lebih laju dan kurang menggunakan ruangan memory. Disini kita hanya akan membincangkan mengenai platform 80x86 dimana senibina ini telah digunakan selama lebih kurang 30 tahun dan sentiasa berevolusi. Senibina ini dicipta oleh Intel dan terdapat juga clone untuk utk 80x86 yang dibina oleh AMD.
Untuk melakukan pengiraan, Register diperlukan sebagai tempat ruang simpanan sementara. Ada lapan 'general purpose register' iaitu EAX, EBX, ECX, EDX, ESI, EDI, EBP, and ESP. Di mana,
Accumulator [E]AX (AH/AL) Multiply, divide, I/O, fast arithmetic.
Base [E]BX (BH/BL) Pointer to base address (data segment).
Count [E]CX (CH/CL) Count for loops, repeats, and shifts.
Data [E]DX (DH/DL) Multiply, divide, and I/O.
Source Index [E]SI Source string and index pointer.
Destination Index [E]DI Destination string and index pointer.
Base Pointer [E]BP Pointer to stack base address.
Stack Pointer [E]SP Pointer to top of stack.
[E] bermaksud 'extended' ataupun lanjutan kepada 32 bit.Oleh itu 32 bit register boleh menyimpan nilai sehingga 0xFFFFFFF. Bahagian bawah EAX ialah AX yang boleh menyimpan nilai sehingga 0xFFFF (16 bit). Bagi AX pula boleh dipecahkan kepada bahagian atas iaitu AH, dan bahagian bawah iaitu AL. Sebagai contoh:-
jika EAX == CF3922DB2
maka AX == 2DB2 , AH == 2D, dan AL == B2.
Asas pengaturcaraan bahasa perhimpunan.
a. MOV destinasi, sumber
MOV bermaksud 'move' atau pindahkan nilai dari sumber kepada destinasi. Destinasi boleh jadi mana-mana register atau alamat memori. Tetapi sumber boleh jadi nilai segera, register atau alamat memori.
Contoh 1:
Sebelum : EAX = 0x000FFF0F, ECX = 0x00000000, EBX = 0xFE01FCD0, ESP = 0x004AA000
MOV EAX, 0x00965695 ; 0x00965695 adalah nilai segera
MOV ECX, EAX ; nilai dari EAX dipindahkan kepada ECX
MOV DWORD PTR [ESP], EBX ; nilai ESP katakan sebagai alamat memori,
; maka nilai EBX dipindahkan ke ruang memori
MOV DWORD PTR [ESP+4], EAX ; ESP + 4 == 0x004AA004
MOV DWORD PTR [0x004AA008], 0x0004AEFC; nilai segera ke ruang memori
Selepas : EAX = 0x00965695, ECX = 0x00965695, EBX = 0xFE01FCD0, ESP = 0x004AA000
manakala bagi nilai dalam memori
---------------------------
Alamat | nilai
------------|--------------
0x004AA000 | 0xFE01FCD0
0x004AA004 | 0x00965695
0x004AA008 | 0x0004AEFC
---------------------------
Jika diperhatikan, nilai EBX tidak berubah. Ini kerana arahan MOV hanya menyalin nilai dan mengekalkan nilai sumber.
Walaubagaimanapun, arahan MOV untuk menyalin nilai dari memori ke memori tidak dibenarkan. Oleh itu,
MOV DWORD PTR [0x004AA008], DWORD PTR [0x004AA004]
tidak dibenarkan.
DWORD (double word) bermaksud nilai yang hendak dipindahkan dalam lingkungan 32 bit ( 0x00000000 - 0xFFFFFFF).
b. ADD destinasi, sumber (operasi tambah)
Sebelum : EAX = 0x0166AABB, ECX = 0x0002A23C
ADD EAX, ECX ; 0x0166AABB + 0x0002A23C = 0x01694CF7
; hasil tambah disimpan dalam EAX
ADD ECX, 0xA484AFE1 ; 0x0002A23C + 0xA484AFE1 = 0xA487521D
; hasil tambah disimpan dalam ECX
Selepas: EAX = 0x01694CF7, ECX = 0xA487521D
......bersambung, sila hantar komen, maklumbalas, cadangan ke
[email protected]
Bab - 2. Pengenalan kepada Bahasa C.
AFAIK, Bahasa pengaturcaraan C adalah antara bahasa pengaturcaraan yang paling kecil. Jadi untuk menguasai secara asas bahasa ini tidak mengambil masa yang lama. Walaupun begitu, untuk 'mastering' bahasa C bukan kerja yang mudah.
Bahasa C hanya mengandungi 36 'keywords' iaitu,
auto - double - inline - static
break - else - int - struct
case - enum - long - switch
char - extern - register - typedef
complex - float - restrict - union
const - for - return - unsigned
continue - goto - short - void
default - if - signed - volatile
do - sizeof - while - imaginary
Perkara yang menyebabkan bahasa C nampak besar ialah koleksi fungsi2 piawai yang dikepilkan bersamanya. Contoh fungsi piawai ialah seperti printf, scanf untuk tujuan input dan output; strcmp, strcpy untuk memproses perkataan atau huruf (strings), dan lain2.
Bagi pelajaran C untuk hari ini dan seterus, saya akan menggunakan Pelles C yang boleh didapati secara percuma di
http://www.smorgasbordet.com/pellesc/ . Perkara yang menarik mengenai Pelles C ialah dokumentasi fungsi piawai yang agak lengkap. Pengaturcara C mesti membiasakan diri membaca dokumentasi fungsi, kerana setiap platform mempunyai koleksi fungsi tambahan masing2. Sebagai contoh, untuk menulis program di atas mana2 platform mana Microsoft Windows, pengaturcara perlu menggunakan fungsi yang tidak terdapat dalam koleksi fungsi2 piawai C seperti untuk memaparkan 'Message Box'. Tambahan pula, Pelles C dipilih kerana ianya mempunyai IDE yang setanding dengan IDE yang komersil.
Debugger yang akan digunakan ialah OllyDbg juga boleh secara percuma di http://home.t-online.de/home/Ollydbg/ .
2.1 Program C Pertama.
Oleh kerana tujuan komputer dicipta adalah untuk melakukan pengiraan. Program pertama kita akan diarah untuk melakukan beberapa pengiraan aritmetik.
int main()
{
int a = 20;
int b = 0x20;
int jumlah;
int hasil_darab;
jumlah = a + b;
hasil_darab = a * b;
return 0;
}
Analisis:
- int main()
setiap aturcara C yang lengkap mesti mempunyai fungsi main() yang bertindak sebagai 'entry point' iaitu lokasi tempat bermulanya sesebuah aturcara. Bagi setiap fungsi, setiap baris arahannya mesti berada dalam brace, { }.
- int a = 20;
arahan ini adalah untuk mengarahkan compiler supaya menyediakan ruang memori yang bersaiz int, seterusnya ruang memori tersebut diisi dengan nilai 20. Saiz int biasanya 16 bit atau 32 bit bergantung kepada compiler yang digunakan.
- int b = 0x20;
seperti arahan diatas tetapi nilai yang diletakkan dalam ruangan memori b bernilai 32 jika ditukarkan kepada sistem desimal.
- int jumlah;
arahan ini adalah untuk mengarahkan compiler supaya menyediakan ruang memori yang bersaiz int tetapi tidak meletak nilai permulaan dalam ruang memori itu.
- int hasil_darab;
seperti di atas.
- jumlah = a + b;
menjumlah nilai yang berada dalam ruangan memori a dan b, hasilnya pula diletakkan di jumlah.
- hasil_darab = a * b;
mendarabkan nilai dalam ruangan memori a dan b, hasilnya pula diletakkan di hasil_darab.
- return 0;
keluar dari program dan mengembalikan nilai 0 kepada OS.
Walaubagaimanapun, aturcara di atas nampaknya seperti tidak berguna kerana hasil daripada pengiraan aritmetik tidak diketahui. Menyedari keperluan untuk mempaparkan output, fungsi printf dibina dan dijadikan sebagai fungsi piawai untuk tugas ini.
Oleh itu, kita akan menggunakan printf untuk memaparkan hasil dari pengiraan aritmetik. Sebelum membina semula aturcara diatas, lebih baik kita merujuk kepada dokumentasi fungsi printf. Di dalam dokumentasi Pelles C, printf di definisikan sebagai
Syntax:
int printf(const char * restrict format, [argument] ...);
Declared in:
<stdio.h> (printf)
Nampaknya kita perlu memasukkan sekali file stdio.h untuk menggunakan printf. Ini boleh dilakukan dengan arahan pra-compile
#include <stdio.h>
Oleh itu, aturcara kita seperti di bawah
#include <stdio.h>
int main()
{
int a = 20;
int b = 0x20;
int jumlah;
int hasil_darab;
jumlah = a + b;
hasil_darab = a * b;
printf("hasil tambah ialah %i \n", jumlah);
printf("hasil darab ialah %i \n", hasil_darab);
return 0;
}
Untuk menjelaskan secara terperinci bagaimana arahan #include berfungsi kita boleh misalkan kandungan fail stdio.h seperti dibawah.
int printf(const char * restrict format, [argument] ...);
int wprintf(const wchar_t * restrict format, [argument] ...);
char * gets(char *buffer);
int puts(const char *string);
Dengan itu sebelum aturcara di compile, aturcara kita diproses dan kelihatan seperti di bawah.
int printf(const char * restrict format, [argument] ...);
int wprintf(const wchar_t * restrict format, [argument] ...);
char * gets(char *buffer);
int puts(const char *string);
int main()
{
int a = 20;
int b = 0x20;
int jumlah;
int hasil_darab;
jumlah = a + b;
hasil_darab = a * b;
printf("hasil tambah ialah %i \n", jumlah);
printf("hasil darab ialah %i \n", hasil_darab);
return 0;
} ......bersambung, sila hantar komen, maklumbalas, cadangan ke zeph97 [at] gmail [dot] com