Assembly - Ukuran Data Memori Statis Register
Register dan Memori
Di dalam bab ini, kita akan mengenal tentang ukuran-ukuran data di dalam komputer, serta memori statis dan register.
Ukuran Data dan Model Data
Apa itu Model Data?
Model Data adalah representasi sebuah ukuran data ke dalam tipe data tunggal di C/C++.
Contohnya, Linux menggunakan Model data lp64 sementara Windows menggunakan Model data llp64.
Karena Linux menggunakan Model data lp64 berarti ukuran long
serta pointer
adalah 64 bit.
Ada sedikitnya 4 ukuran data yang harus diketahui.
Nama | Ukuran |
---|---|
byte | 1 byte / 8 bit |
word | 2 byte / 16 bit |
dword / double word | 4 byte / 32 bit |
qword / quad word | 8 byte / 64 bit |
Representasi model data tersebut dapat dilihat dalam tabel di bawah ini
Tipe data | Ukuran |
---|---|
char |
byte |
short |
word |
int |
dword |
long |
qword |
long long |
qword |
Alasan kenapa long
di Windows ukurannya 32 bit, sementara di Linux ukurannya 64 bit
karena Windows menggunakan Model data llp64 yang mengharuskan menggunakan tipe data long long untuk
menggunakan memori sebesar 64 bit.
Jadi, tidak ada jaminan bahwa ukuran suatu tipe data lebih kecil / lebih besar dari tipe data lainnya dan sebaliknya.
Karena semua OS bisa saja memakai model data yang berbeda.
Jadi, bagaimana agar dapat menggunakan tipe data yang portable ?
Kalian bisa menggunakan typedef (u)int_leastX_t
dari cstdint
di mana X adalah ukuran bitnya
Sebagai, contoh (u)int_least64_t
.
Dengan begitu, kita tidak perlu khawatir akan ukuran tipe data yang berbeda karena typedef
tersebut
secara otomatis akan menyesuaikan dengan model data yang digunakan.
Apakah, ada ukuran data lainnya seelain keempat ukuran di atas ?
Yup, ada oword , tbyte, yword , zword.
Nama | Ukuran |
---|---|
oword / octoword | 16 byte / 128 bit |
tbyte / ten bytes | 10 byte |
yword / YMM word | 32 byte / 256 bit |
zword / ZMM word | 64 byte / 512 bit |
Static Memori
Memori statis dialokasikan di awal program, dan hanya akan dibebaskan ketika program berakhir.
Mendefinisikan data statis
Ini cukup mudah, kita hanya perlu menulis dx
di mana x
awal huruf ukuran data yang kita ingin deklarasikan
contohnya db
untuk define byte(s) dan dq
untuk define qword(s).
data db 1,2,3
sama seperti static char data[] = {1, 2, 3};
data dq 1,2,3
sama seperti static long data[] = {1, 2, 3};
Jika kalian masih tidak paham, perhatikan tabel dibawah ini
define xxx | dx |
---|---|
define byte(s) | db |
define word(s) | dw |
define dword(s) | dd |
define qword(s) | dq |
define oword(s) | do |
define tbyte(s) | dt |
define yword(s) | dy |
define zword(s) | dz |
Deklarasi data statis
Sama seperti mendefinisikan data statis, bedanya kalau definisi menggunakan huruf d
, sementara deklarasi menggunakan kata res
.
dx
menjadi resx
.
data resb 10
sama seperti static char data[10];
data resq 10
sama seperti static long data[10];
reserve xxx | resx |
---|---|
reserve byte(s) | resb |
reserve word(s) | resw |
reserve dword(s) | resd |
reserve qword(s) | resq |
reserve oword(s) | reso |
reserve tbyte(s) | rest |
reserve yword(s) | resy |
reserve zword(s) | resz |
Lengkapnya, kalian bisa baca doc nasm di sini https://www.nasm.us/doc/nasmdoc3.html#section-3.2
Register
Pengenalan Register
Ada dua jenis register, GPR atau General Purpose Register dan Flag Register.
Flag Register akan kita bahas di bab prosedur, fungsi, percabangan.
Ada 16 GPR dalam arch x86-64.
-
RAX Accumulator Register -
RCX Counter Register -
RDX Data Register -
RBX Base Register -
RSP Stack Pointer Register -
RBP Base Pointer Register -
RSI Source Index Register -
RDI Destination Index Register - R8 sampai R15
Register hanyalah nama
Kalian bebas memakai register untuk operasi apapun asalkan
Memperhatikan ABI (tidak sembarangan memakai preserved register).
15 GPR tadi dibagi lagi menjadi 2, Scratch Register dan Preserved Register.
Scratch register adalah register yang bebas kita pakai.
Preserved register adalah register yang tidak bisa sembarangan dipakai.
rax, rdi, rsi, rdx, rcx, r8, r9, r10, dan r11 adalah scratch registers.
rbx, rsp, rbp, r12, r13, r14, dan r15 adalah preserved register.
Register-register di atas berukuran 64 bit, dan memiliki bagian kecilnya, seperti bagian 32 bit, 16 bit, dan 8 bit.
64 bit | 32 bit | 16 bit | 8 bit |
---|---|---|---|
RAX |
EAX |
AX |
AH / AL |
RCX |
ECX |
CX |
CH / CL |
RDX |
EDX |
DX |
DH / DL |
RBX |
EBX |
BX |
BH / BL |
RSP |
ESP |
SP |
SPL |
RBP |
EBP |
BP |
BPL |
RSI |
ESI |
SI |
SIL |
RDI |
EDI |
DI |
DIL |
R8 |
R8D |
R8W |
R8B |
R15 |
R15D |
R15W |
R15B |
Apa beda dari 2 bagian register 8 bit yang terdapat pada
rax
,rcx
,rdx
, danrbx
?
ax, cx, dx, dan bx berukuran 16 bit yang terdiri dari 8 bit atas dan 8 bit bawah.
h menandakan higher bits, atau bagian 8 bit atas dari register 16 bit.
l menandakan lower bits, atau bagian 8 bit bawah dari register 16 bit.
Contoh, ukuran 8 bit.
Jika 127 direpresentasikan dalam bentuk biner.
0111 1111
8 bit ini dipecah menjadi 4 bit atas dan 4 bit bawah
0111
dan 1111
-
0111
ini menjadi 4 bit atas -
1111
ini menjadi 4 bit bawah
Ada hal yang perlu diperhatikan saat mengubah-ubah nilai suatu register.
- Mengubah register 8 bit hanya akan mengubah register tersebut.
- Mengubah register 16 bit akan mengubah nilai register 16 bit dan 8 bit.
- Mengubah register 32 bit selain mengubah register 32 bit dan di bawahnya, juga mengubah bagian 32 bit atas register 64 bit menjadi 0.
- Mengubah register 64 bit mengubah semua register yang ada di bawahnya.
Untuk semua register yang berasal dari ekstensi 64 bit (semua tulisan yang tebal di dalam tabel) membutuhkan encoding tambahan. (REX prefix).
REX.W prefix untuk rax
hingga rdi
REX.R prefix untuk r8
hingga r15
Dan juga, saat menggunakan REX prefix kita tidak bisa mengakses ah
, ch
, dh
, dan bh
.
Sebagai gantinya kita bisa mengaksesspl
, bpl
, sil
, dan dil
.
Contoh, mov eax, 1
lebih optimal dibandingkan mov rax, 1
jika ingin mengubah nilai rax
.
Jika kita lihat gambar di atas, opcode mov eax, 1
lebih sedikit dibandingkan mov rax, 1
karena mengakses rax
menggunakan REX.R prefix.
mov eax, 1
lebih optimal karena tidak menggunakan REX.R prefix.
Begitu juga yang lainnya. Selain R8
hingga R15
. Disarankan untuk mengubah bagian 32 bit saja karena secara implicit juga mengubah bagian 64 bit (32 bit atas).
Sign Extend dan Zero Extend
Perlu diingat, komputer memakai basis 2 (biner) dan manusia memakai basis 10.
127 jika diubah ke bentuk biner 8 bit 0111 1111
.
Tapi bilangan biner 255 serta -1 dalam ukuran 8 bit memiliki bit yang sama! 1111 1111
.
Jika kita tidak mengetahui apakah itu signed atau unsigned kita tidak bisa memperkirakan
apakah nilai bit 1111 1111
adalah -1 atau 255.
Hal ini dapat menyebabkan masalah ketika kita ingin memindahkan nilai antar register yang berbeda ukuran.
Karena -1 dalam ukuran 8 bit berbeda dengan -1 dalam ukuran 16 bit
Dalam Arsitektur x86-64 ini, kita bisa menentukan sebuah bilangan signed
atau unsigned
ketika memindahkan nilai antar register yang berbeda ukuran menggunakan movsx
dan movzx
.
movsx
untuk sign extend atau signed.
movzx
untuk zero extend atau unsigned.
Contoh
mov al, 255
movzx cx, dl
Dengan begitu, nilai cx
akan sama dengan al
yaitu 255. meskipun nilai bit mereka berbeda.
Ref :
- https://en.wikipedia.org/wiki/Signed_number_representations
- https://en.wikipedia.org/wiki/Two%27s_complement