Jump to content
Sign in to follow this  
Ancient One

Fasm

Recommended Posts

FASM Macros

Kepada pengguna fasm (http://www.flatassembler.net), kat sini korang bleh la

share macros yang korang rase berguna untuk kita semer. Kalau ader soalan related

to fasm pun bleh gak letak kat sini. Kalau nak kutuk fasm pun bleh letak kat sini.

Pendek kata aper menatang yang related to fasm korang bleh buang kat sini.

Note all macros apply to 32-bit code only.

1. _TEXT macro - Untuk define C-style string constant. It recognizes "\" escape

character in the string constant (lebih kurang cam C laa). Aku cuma support

"\n" (newline, dos crlf), "\t" (tab), "\\", dan "\0" (null). Actually kita tak gunakan _TEXT

macro tu sendiri tapi aliasnya seperti TEXT (for ASCII), TEXTW (for UNICODE).

Saiz (in bytes, including null) dan Panjang (characters count, not including null)

juga disertakan sekali (lihat contoh).

ASCII fix _ASCII,
WIDE fix _WIDE,
struc _TEXT Enc,[String] {
common
  local ..start
  ..start:
  virtual at 0
    db String
    Len=$
  end virtual
  Current=0
  PutWord=0
  Chars=0
  repeat Len
    DontPutChar=0
    if Current < Len
      virtual at 0
        db String
        load char from Current
      end virtual
      if char='\'
        Current=Current+1
        if Current < Len
          virtual at 0
            db String
            load char from Current
          end virtual
          Current=Current+1
          if char='n'
            if Enc eq _WIDE
              Chars=0x000A000D
            else
              Chars=0x0A0D
            end if
            PutWord=1
          else
            PutWord=0
            if char='t'
              Chars=0x09
            else if char='\'
              Chars='\'
            else if char='0'
              Chars=0
            else
              DontPutChar=1
            end if
          end if
        else
          DontPutChar=1
        end if
      else
        PutWord=0
        Chars=char
        Current=Current+1
      end if
      if ~DontPutChar
        if PutWord
          if Enc eq _WIDE
            dd Chars
          else
            dw Chars
          end if
        else
          if Enc eq _WIDE
            du Chars
          else
            db Chars
          end if
        end if
      end if
    end if
  end repeat
  if Enc eq _WIDE
    du 0
  else
    db 0
  end if
  .SIZE=($-..start)
  if Enc eq _WIDE
    .LEN=.SIZE/2-1
  else
    .LEN=.SIZE-1
  end if
}
CSTR fix _TEXT ASCII
TEXT fix _TEXT ASCII
CSTRW fix _TEXT WIDE
TEXTW fix _TEXT WIDE
Contoh: foo CSTR "Simple ASCII String." foobar _TEXT WIDE "This is a UNICODE string." c_string TEXT "C style ascii string.\n After new line.\t After tab." another_sample TEXT "\\WINDOWS\\SYSTEM32\\USER32.DLL" c_string2 TEXTW "C style unicode string." ;getting the length and size foo_length dd foo.LEN foobar_size dd foobar.SIZE Korang boleh gantikan struc dengan macro kalau korang nak gunakannya seperti CSTR "Simple ASCII String" 2. PUSH macro - Seperti yang kita tau, dalam fasm (atau most assembler yang lain), kita takleh push mcm2 benda, contohnya string constant (pointer to string) yang maner string tersebut sebagai parameter kepada push instruction. Even nak push floating point constant pun takleh gak. Payah! Dengan universal PUSH instruction nih, kita bleh push mcm2 benda. Korang bleh extend kalau korang perlukan push yang lain, contohnya address to constant array dan sebagainya. Please note korang perlukan "macro" version of _TEXT macro kat atas (just make a copy of the _TEXT struc and change the "struc" to "macro").
DOUBLE equ
double equ
DOUBLENEG equ
doubleneg equ
FLOAT equ
float equ
L equ
l equ
ADDR equ
addr equ
INT64 equ
int64 equ
NEG equ
neg equ

macro PUSH [Operand] {
forward
  if Operand eqtype 1.0
    if _#Operand in <_DOUBLE Operand, _double Operand>
      virtual at 0
        dq Operand
        load ..Oper dword from 0
        load ..Oper1 dword from 4
      end virtual
      push dword ..Oper1
      push dword ..Oper
    else if _#Operand in <_DOUBLENEG Operand, _doubleneg Operand>
      virtual at 0
        dq -Operand
        load ..Oper dword from 0
        load ..Oper1 dword from 4
      end virtual
      push dword ..Oper1
      push dword ..Oper
    else
      virtual at 0
        if _#Operand in <_NEG Operand, _neg Operand>
          dd -Operand
        else
          dd Operand
        end if
        load ..Oper dword from 0
      end virtual
      push dword ..Oper
    end if
  else if Operand eqtype ''
    local ..l1
    call ..l1
    if _#Operand in <_L Operand, _l Operand>
      _TEXT WIDE Operand
    else
      _TEXT ASCII Operand
    end if
    ..l1:
  else
    if _#Operand in <_ADDR Operand, _addr Operand>
      lea edx, Operand
      push edx
    else if _#Operand in <_INT64 Operand, _int64 Operand>
      virtual at 0
        dq Operand
        load ..Oper dword from 0
        load ..Oper1 dword from 4
      end virtual
      push ..Oper1
      push ..Oper
    else
      push Operand
    end if
  end if
}
Contoh : ;normal push PUSH ebx, esi, edi ;push string constant (you need to use L to push unicode string) PUSH "ascii string", L "unicode string" ;push floating point constant (single prec, 4 bytes; double prec, 8 bytes; fp values are supported) PUSH 0.07 ;single prec fp constant PUSH neg 0.07 ;single prec negative fp constant PUSH double 1.4235e10 ;double prec fp constant PUSH doubleneg 0.07e100 ;double prec negative fp constant ;push int64 constant PUSH int64 0x123456789ABCDEF0 ;push runtime effective address (e.g address of local vars) PUSH addr [ebp+4] Korang blehla gunakan PUSH macro di dlaam invoke/call macro korang untuk dapatkan code seperti : invoke MessageBox, NULL, "Hello World", "Test", MB_ICONINFORMATION .. invoke gluPerspective, double 45.0, double 2.0, double 0.1, double 100.0 dan sebagainya. Tak nampak cam assembly language kan smile.gif (at least tak nampak asm instructions wink.gif). 3. IDATA macro - FASM adalah flat assembler. Maknanya dia assemble source korang ikut aper yang korang tulis. Kita takleh define data relative to some section. Data yang korang define dalam code akan tetap kat situ. Dengan IDATA macro (it's actually a macro set), kita leh kumpul data kat satu kawasan (e.g .data section).
macro IDATA [DataDeclaration] {
common
  macro IDATA_DATA _m
    DataDeclaration
  m_
  DECLARE_IDATA_ARG fix DECLARE_IDATA_ARG,
}

macro @DECLARE_IDATA Dummy1, [Dummies] {
forward
  macro REVERSE_IDATA_DATA _m
    IDATA_DATA
    purge IDATA_DATA
    align 4
  m_
forward
  REVERSE_IDATA_DATA
  purge REVERSE_IDATA_DATA
common
  DECLARE_IDATA_ARG fix
}

macro DECLARE.IDATA {
  IDATA
  @DECLARE_IDATA DECLARE_IDATA_ARG
}
DECLARE_IDATA_ARG fix
_m fix {
m_ fix }

Gunakan IDATA untuk define initialized data. Ia takkan letakkan data tu kat maner korang

define unless korang gunakan DECLARE.IDATA (korang blehla gantikan nama macro ni ikut

nama yang korang suker). DECLARE.IDATA declare semua data yang korang define dengan IDATA.

Contohnya :

format PE GUI

enrty Mula

section "ancient1" code executable readable

Mula :

;data dalam IDATA ni cuma akan dihasilkan dengan menggunakan DECLARE.IDATA

IDATA MsgText db "String using ""db"" directive", 0

IDATA MsgTitle TEXT "String using ""TEXT"" macro"

push 0

push MsgTitle

push MsgText

push 0

call [MessageBox]

ret

section "ancient2" data readable writeable

DECLARE.IDATA ;all data declared using IDATA will be placed here.

;import dir and thunk kat sini

MessageBox dd ?

Cukup laa kot 3 macros untuk hari ni. Esok lusa aku tambah lagi. Korang bleh tengok sendiri

camne macros bleh mencantikkan (atau memburukan) dan memudahkan (atau menyusahkan) keje2

pengaturcaraan korang smile.gif. ENJOY!!!!

Share this post


Link to post
Share on other sites

1. mcm mana nak declare local variable dalam satu function?

Kalau guna default includes kat fasm (1.52, aku rase 1.53 nyer proc macro dah lain sikit, aku tak test lagi). Jangan risau pasal esp tak align kepada dword. macro

akan align untuk kiter :

proc MyProc, arg1, arg2
local1 dd ?  ;ni local
local2 MSG ;ni local (struct)
local3 db ? ;ni local gak
  enter
  mov eax, [local1] ;access local1 local var
  ..
  ..
endp
actually aku tak penah guna fasm nyer default proc macro. aku guna aku nyer sendiri. minggu depan aku post (basically sama je).
2. cmp [wparam], BN_CLICK shl 16 + IDOK shl tuh internal assembler ke atau macro?
shl tu fasm nyer operator untuk constant expression. As long as BN_CLICK shl 16 + IDOK menghasilkan constant then it will compiled. note : shl tu assembly instruction gak :
mov eax, BN_CLICK
shl  eax, 16
add eax, IDOK

Share this post


Link to post
Share on other sites

#include <windows.h>

struct account{

char name[33];

char account_no[10];

};

struct account p_array[10];

main(){

int i;

char nama[] = "nama awak";

char no_acc[] = "532821-A";

for (i = 0; i <10; i++){

wsprintf(p_array.name, "%s",nama );

wsprintf(p_array.account_no, "%s", no_acc);

}

return 0;

}

------------------------------------------------

aku nak buat small database program.. and dbase tu

akan diencrypt guna blowfish, aes, etc..

and of course aku akan gunakan dynamic memory allocation

soalannya...

macam mana nak buat uninitialize array of structure

menggunakan macro dalam fasm.. jadi

kita boleh pakai structure lebih kurang syntax C.

takpun sekurang2nya spt

invoke GetDlgItemText, [hwnd], IDC_NAMA,esi+MyData.nama,30

dimana esi adalah index..

aku dah ada cara iaitu guna table indexing..truly in asm

tapi nak cari cara yg senang sket

data aku lebih kurang gini..

struc MyData

{

.nama rb 30

.no_acc rb 30

.alamat rb 50

}

p/s:

dah 2 hari fikir..tak jumpa solution

iq aku rendah jer..tak boleh fikir banyak2

plus aku tak boleh buang masa banyak sangat utk benda ni

mintak tolong yerrr..

Share this post


Link to post
Share on other sites

#include <windows.h>

struct account{

char name[33];

char account_no[10];

};

struct account p_array[10];

main(){

int i;

char nama[] = "nama awak";

char no_acc[] = "532821-A";

for (i = 0; i <10; i++){

wsprintf(p_array.name, "%s",nama );

wsprintf(p_array.account_no, "%s", no_acc);

}

return 0;

}

------------------------------------------------

aku nak buat small database program.. and dbase tu

akan diencrypt guna blowfish, aes, etc..

and of course aku akan gunakan dynamic memory allocation

soalannya...

macam mana nak buat uninitialize array of structure

menggunakan macro dalam fasm..  jadi

kita boleh pakai structure lebih kurang syntax C.

takpun sekurang2nya spt

invoke GetDlgItemText, [hwnd], IDC_NAMA,esi+MyData.nama,30

dimana esi adalah index..

aku dah ada cara iaitu guna table indexing..truly in asm

tapi nak cari cara yg senang sket

data aku lebih kurang gini..

struc MyData

{

.nama      rb 30

.no_acc    rb 30

.alamat    rb 50

}

p/s:

dah 2 hari fikir..tak jumpa solution

iq aku rendah jer..tak boleh fikir banyak2

plus aku tak boleh buang masa banyak sangat utk benda ni

mintak tolong yerrr..

kalau kiter guna struct macro dalam default include files, ia ader define offset to fields. So, bila kiter define some struc, lets say


struc MyData
{
.nama rb 30
.no_acc rb 30
.alamat rb 50
}
struct MyData  ;tambahan
seperti yang hang tulis, kita leh refer offset dengan MyData.<fieldname> so let say kita declare MyData struc :

;data
foo MyData

;code
somelabel :
    mov esi, foo          ;address of the structure
    lea   esi, [esi+MyData.alamat]       ;address of .alamat field in foo (Mydata) structure

kalau hang nak refer structure fields dengan expression yang complex sebagai index (e.g wsprintf(p_array[i+j*2].name, ....)), takde cara yang mudah dalam assembly, hang kena kire sendiri la (lagipun ni kan bahasa aras rendah). Tapi

kalau setakat index yang normal je, kita tambah je saiz structure dan gunakannya sebagai pointer (in index).

Share this post


Link to post
Share on other sites

Kali ni aku nak berikan FUNCTION macros yang tersangatla penting sebab ia memudahkan

kita membina subroutines dengan mudah. Macro FUNCTION/PROC, ENTER, EXIT, ENDF/ENDP

adalah satu set untuk subroutine declaration. CALL macro plak digunakan untuk call

fungsi yang korang define dengan FUNCTION macro. Rules berkaitan dengan calling convention

dipatuhi secara automatik so contohnya korang tak perlu risau untuk remove params from stack

lepas call fungsi yang korang declare dengan __cdecl calling convention. CALL macro bergantung

kepada PUSH macro. Lihat contoh cara penggunaan kat bawah :

Winapi=0
Cdecl=1
Pascal=2
Fastcall=3

__stdcall fix ,STDCALL
__winapi fix __stdcall
__callback fix __stdcall
__cdecl fix ,CDECL
__pascal fix ,PASCAL
WINAPI fix STDCALL
CALLBACK fix STDCALL

macro FUNCTION FName, CConv, [Param] {
common
  CurrentFunctionName fix FName
  if used FName
    label FName dword
    if CConv eq STDCALL
      ..#FName#.CC=Winapi
    else if CConv eq CDECL
      ..#FName#.CC=Cdecl
    else if CConv eq PASCAL
      ..#FName#.CC=Pascal
    else
      display "Function : "#`FName#" - Unknown Calling Convention", CRLF
      HALT!
    end if
    virtual at (ebp+8)
forward
      if ~Param eq
        FName#.#Param dd ?
        Param equ FName#.#Param
      end if
common
      if CConv eq STDCALL | CConv eq PASCAL
        ..REMOVE_FROM_STACK=$-(ebp+8)
      else if CConv eq CDECL
        ..REMOVE_FROM_STACK=0
      end if
    end virtual
    local ..dyn_data,..dyn_size
    dyn_data equ ..dyn_data
    dyn_size equ ..dyn_size
    virtual at ebp-dyn_size
      dyn_data :
}
PROC fix FUNCTION

macro ENTER {
      rb (4-($-dyn_data) and 11b) and 11b
      dyn_size=$-dyn_data
    end virtual
    enter dyn_size, 0
}

macro EXIT {
    leave
    if ..REMOVE_FROM_STACK<>0
      ret ..REMOVE_FROM_STACK
    else
      ret
    end if
}

macro ENDF FName {
    align 4
  end if
}
ENDP fix ENDF

macro CALL FName, [Arg] {
common
  if ~Arg eq
    if ..#FName#.CC=Winapi
reverse
      PUSH Arg
common
      call FName
    else if ..#FName#.CC=Cdecl
      ..SIZE=0
reverse
      PUSH Arg
      ..SIZE=..SIZE+4
common
      call FName
      if ..SIZE <> 0
        add esp, ..SIZE
      end if
    else if ..#FName#.CC=Pascal
forward
      PUSH Arg
common
      call FName
    end if
  else
    call FName
  end if
}
Korang akan dapati terdapat beberapa kelemahan, terutamanya tang argument names tu. Korang bleh improve lagi macros ni sebenarnya ikut kesesuaian korang. Aku suker camni sebab ia memaksa aku untuk gunakan local labels dalam function args, local vars dan labels inside function.
format PE GUI
entry mula

PROC mula __cdecl
    ENTER
    CALL    Funct1, 1, 2
    CALL    CFunc1, 1, 2
    CALL    PFunc1, 1, 2
    EXIT
ENDP

;atau FUNCTION Funct1, STDCALL, .Arg1, .Arg2
FUNCTION Funct1 __stdcall, Arg1, Arg2
.Local1 dd ?
.Local2 db ?
.Local3 rb 100
    ENTER
    push    ebx esi
    mov     eax, [Arg1]
    xor     ebx, ebx
   ;..
   ;..
    pop     esi edi
    EXIT
ENDF

;atau FUNCTION CFunc1, CDECL, .Arg1, .Arg2
FUNCTION CFunc1 __cdecl, Arg1, Arg2
    ENTER
    push    ebx esi
    mov     eax, [Arg1]
    xor     ebx, ebx
   ;..
   ;..
    pop     esi edi
    EXIT
ENDF

;atau PROC PFunc1, PASCAL, .Arg1, .Arg2
PROC PFunc1 __pascal, Arg1, Arg2
    ENTER
    push    ebx esi
    mov     eax, [Arg1]
    xor     ebx, ebx
   ;..
   ;..
    pop     esi edi
    EXIT
ENDF

Share this post


Link to post
Share on other sites

Tuto kecik ni explains mengenai fasm. Di sini aku akan terangkan camne fasm proses

kiter punyer source file. Secara ringkasnya, kiter nyer source melalui 4 fasa - preprocessing,

parsing, assembling dan formatting. Kalau nak compare ngan C compiler, preprocessing, parsing

dan assembling tu dalam proses compilation laa, part formatting tu dalam proses linking laa.

Preprocessing cuma berlaku SEKALI sahaja untuk setiap source file (1 pass) manakala proses assembly

boleh berlaku berulang kali (maximum 65536 passes). Ni la yang kita katakan multipass assembler

yang mana antara kebaikannya adalah code optimization (i.e for jump instructions), forward references

dan sebagainya. So katakan la aku ader kod cam kat bawah :

Kod Pertama :

    FOO_CONSTANT=0
   ;other constants
    mov eax, FOO_CONSTANT
Kod Kedua:
    mov eax, FOO_CONSTANT
    FOO_CONSTANT=0
Dalam single pass assembler, cuma Kod pertama yang boleh dikompil. Kod kedua tidak boleh kerana semasa assemble "mov eax, FOO_CONSTANT", dia tak jumpe lagi pemalar FOO_CONSTANT. FASM boleh kompil kedua-dua jenis kod di atas. Kod di atas adalah contoh forward reference. Akan tetapi, dalam forward reference fasm, kiter takleh redefine constant. Contohnya :
    mov eax, FOO_CONSTANT
    FOO_CONSTANT=0
    FOO_CONSTANT=1
akan menyebabkan error. Tapi
    FOO_CONSTANT=0
    mov eax, FOO_CONSTANT
    FOO_CONSTANT=1
bleh dikompil. In this case, FOO_CONSTANT dalam "mov eax, FOO_CONSTANT" adalah 0. [General Info] Korang tak perlu ingat any command line options untuk fasm sebab ia takde command line options. Aper yang dia perlukan hanyalah fail yang mengandungi kod kiter. fasm menyokong output format flat binary (default), DOS MZ, Win32 PE, COFF (and MS COFF), dan ELF. fasm menyokong 8/16/32-bit Intel x86 general/system assembly instructions. Begitu juga dengan FPU instructions, MMX, SSE, SSE2, extension to SSE/SSE2 (Presscot), dan juga 3DNow!. Mengenai source file. Macam biasa la, fasm cuma terima source file dalam bentuk ascii/plain text. Korang kena letak hanya satu arahan/directives set dalam satu line. Simbol ; digunakan untuk single line comment (takde multiple line comment dalam fasm). Symbol \ digunakan untuk menyambungkan line seterusnya kepada line sebelumnya. Contohnya
    dd \
    100
akan jadi
    dd 100
Mengenai Nombor. Nombor dalam kod boleh ditulis dalam format binari (bin), oktal (oct), desimal (dec) dan heksadesimal (hex). Formatnya adalah : binary :- terdiri daripada 0 dan 1 dan diakhiri dengan simbol "b". Contohnya 10001b, 1111111111111b dan sebagainya. octal :- terdiri daripada 0 hingga 7 dan diakhiri dengan simbol "o". Contohnya 1234567o, 1111111111111o dan sebagainya. decimal :- normal numbers. Contohnya 1, 2, 2174681267 dan sebagainya. hex :- terdiri daripada nombor 0 hingga 9 dan huruf a-f. Terdapat 3 jenis format yang boleh digunakan iaitu dengan awalan "0x" (C style), dengan awalan "$" (Pascal style) dan juga dengan akhiran "h" (traditional style smile.gif. Contohnya : 0x12345678, 1234567890ABCDEFh, $10101010 Untuk real numbers plak, ader 3 cara korang boleh tulis : (i) secara normal, yang mengandungi "." seperti 4.3142, 0.5, etc (ii) dengan akhiran "f" seperti 3f (berbeza dengan 3). (iii) scientific notation dengan "E" sebagai simbol kuasa 10 seperti 1E1, 3142E-3, etc. Mengenai String. Korang boleh letakkan (Text) string dalam source dengan menggunakan ' atau " secara berpasangan. Sebagai contoh "foo" atau 'foo' adalah sama. Kalau nak gunakan simbol ' atau " itu sendiri di dalam string, korang kena gandakan jika ia digunakan sebagai simbol untuk define string tersebut. Contohnya jika korang gunakan ' untuk define string, maka kalau korang nak letak ' dalam string tersebut, korang kena gunakan '' instead of '. Tapi kalau korang nak letakkan ", korang cuma perlu gunakan satu je. Contoh :
    "foo"      ;string = foo
    'foo''"'   ;string = foo'"
    "foobar'   ;invalid
    "foo""     ;invalid, should use "foo"""
    'foo''""'  ;string = foo'""
Mengenai constant dan label. Constant (numerical constant) dan labels basically adalah benda yang sama. Korang bleh define constant seperti :
MSGF_MESSAGEBOX=1
IDOK=1
WM_MYMSG=WM_USER+123
dan sebagainya. Labels plak hanyalah alias kepada lokasi memory. Please note yang labels bukanlah nama yang merujuk kepada variable seperti yang boleh dilakukan dalam MASM dan juga all high level language. So bila nak access data in labels kita kena gunakan indirect reference la. Terdapat beberapa jenis labels. Yang pertama adalah labels yang diakhiri dengan simbol :. Ini adalah global simbol yang akan menjadi scope baru untuk local labels. Local labels adalah any labels yang dimulakan dengan single dot seperti ".foo" dan sebagainya. Kemudian kita ader gak global labels yang takkan jadi scope baru untuk local labels. Ia dimulakan dengan dua dots seperti "..foo". Kita juga bleh gunakan anonymous labels dengan simbol "@@". Labels juga bleh diikuti dengan data definition/reservation directives. Akhir sekali, kita bleh define labels dengan "label" directive.
    foo:
    .bar:
        ...
        ...
    ..bar:
    foobas dd ?
    .bar:
        ...
        ...
    label .foobas
label "foo" adalah global label yang bleh diakses dari maner2 lokasi dalam source file kiter. Ia juga menjadi parent kepada local label bernama ".bar" (note that local label ".bar" wujud dalam dua scope iaitu pada "foo" scope dan pada "foobas" scope). Katakan kita berada dalam scope "foobas" (e.g under label ".foobas") dan nak akses local label ".bar" pada "foo" scope :
    foo:
    .bar:
        ...
        ...
    ..bar:
    foobas dd ?
    .bar:
        ...
        ...
    label .foobas
    jmp foo.bar;jmp ke address ".bar" (line kedua)
    jmp .bar   ;jump ke address ".bar" dalam scope yang sama dengan ".foobas" (to line 7)
    jmp ..bar  ;jump ke address "..bar"
Version baru fasm melebarkan jurang perbezaan di antara constant ngan label. Version dulu2 (kalau tak silap aku laaa.. sebelum 1.50 kot), constant jugak bleh jadi new scope untuk local labels. Jadi kod kat bawah ni bleh dikompil (label ".bar" yang di bawah sekali adalah dalam scope "constant"). Tapi versi baru fasm tidak membenarkan ini dan label ".bar" yang di bawah sekali adalah dalam scope "foobas" yang akan menyebabkan error "symbol already defined" semasa compilation.
    foo:
    .bar:
        ...
        ...
    ..bar:
    foobas dd ?
    .bar:
        ...
        ...
    label .foobas
    constant=0
    .bar:
Mengenai data plak, korang boleh define/reserve data dengan data definition/reserve directives berikut : (i) 1 byte data :- Korang boleh define data atau array bersaiz 1 byte setiap satunya dengan "db" directive. Array of data boleh dipisahkan dengan koma (simbol ,). "db" directive terima satu (1 byte data) atau lebih arguments (array). Simbol ? boleh digunakan yang bermakna it's an uninitialized data. Korang boleh letakkan aper sahaja sebagai arguments kepada "db" as long as ia bersaiz byte dan menghasilkan constant semasa compilation. Kalau korang gunakan text string sebagai argument, maka ia adalah sama seperti array of bytes (untuk define ascii string). Contoh :
    db  "foo", 0       ;null terminated string -> 0x66, 0x6f, 0x6f, 0
    db  1, 2, 3, 4, 5  ;array of bytes
    db  ?              ;uninitialized 1 byte data
    db  ?, ?, ?, ?, ?  ;uninitialized array of 5 bytes data
    db  0xff-0x32+2    ;1 byte data = 0xCF
    db  256            ;invalid - 256 is out of range value.
    db  foo
    foo=0
Untuk reserve data dalam unit 1 byte, korang boleh gunakan "rb". Directive "rb" cuma terima satu argument je iaitu bilangan unit yang korang hendak reserve dalam memory. Contohnya :
    rb  10
    rb  0xffffff
    MAX_PATH_NAME=256
    rb  MAX_PATH_NAME
Note that ini adalah cara yang betul kalau korang nak define uninitialized data (data yang korang akan initialized hanya semasa runtime) sebab ia tak makan ruang dalam fail (disk). Also, gunakan ? adalah sama dengan rb dengan 1 sebagai argument.
    rb  1
    db  ?
Selain daripada tu, korang boleh juga include chain of bytes (raw data) daripada external file ke dalam output program korang dengan "file" directive. Basically "file" directive terima 1 argument iaitu nama fail yang mana isi kandungannya korang nak include dalam output program. Contohnya :
    file "encrypted_data.bin"
Kadangkala korang cuma nak sedikit data daripada suatu file tersebut. Untuk kes ni, korang boleh gunakan "file" directive dengan menyatakan offset dan juga size data yang korang kehendaki daripada fail tersebut. Offset dinyatakan selepas nama fail dan didahului dengan simbol :. Selepas itu boleh diikuti dengan saiz (didahului dengan koma). Contohnya :
    file 'mydata.bin' :100 ;include raw data from mydata.bin starting from offset 100 to the end of the file.
    file 'mydata.bin' ,100 ;include raw data from mydata.bin starting from offset 0 and put 100 bytes.
    file 'mydata.bin' :5,5 ;include raw data from mydata.bin starting from offset 5 and put 5 bytes.
    file "my_data.bin"     ;same as >> file "my_data.bin" :0
(ii) 2 bytes data (1 word) - Korang bleh define 1 word data/array dengan "dw" atau "du" directive. "dw" bleh digunakan dengan cara yang sama seperti "db" directive, kecuali jika argument adalah string. Walaupun "dw" directive bleh terima string sebagai argument, string ni hendaklah mempunyai saiz 1 word sahaja (maknanya 2 ascii chars). "du" plak adalah special version of "dw" di mana ia bleh proses string sama seperti "db" directive. Tapi instead of define array of bytes untuk string, ia define array of word (suitable for winnt unicode-16 string). Contohnya :
    dw  "food"         ;error
    dw  "fo", "od"     ;okies, output will be "food"
    dw  1, 2, 3, 4, 5  ;array of words
    dw  ?              ;uninitialized 1 word data
    dw  ?, ?, ?, ?, ?  ;uninitialized array of 5 words data
    dw  0xff-0x32+2    ;1 word data = 0x00CF
    dw  65536          ;error - 65536 is out of range
    dw  foo
    foo=0
    du  "food"         ;okies, output will be 0x66, 0, 0x6f, 0, 0x6f, 0, 0x64, 0
(iii) 4 bytes data (1 dword) - Korang bleh define 1 dword data/array dengan "dd" directive dan reserve dengan "rd" directive. Penggunaannya sama je macam "dw" directive, tapi dd juga bleh terima real numbers (single precision) :
    dd  "food"         ;okies, output will be "food"
    dd  "a", "b", "c"  ;okies, output will be 0x61,0,0,0,0x62,0,0,0,0x63,0,0,0
    dd  "foobar"       ;error
    dd  ?, ?, ?        ;uninitialized arraty of 3 dword data
    _SHIFT_ = 2
    foo=0x1234578 shl _SHIFT_
    dd  foo
    EPSILON=0.00001
    foo dd EPSILON
Memandangkan cuma ketiga-tiga directives ni yang paling banyak kita gunakan, aku cuma bincangkan yang ni je la. Actually ader lagi directives yang lain iaitu : "dp" atau "df" - define 6 bytes data (1 fword) (selector:offset address style). "rp" atau "rf" - reserve data in fword unit "dq" - define 8 bytes data (1 qword), e.g for double precision floating point numbers. "rq" - reserve data in qword unit "dt" - define 10 bytes data (1 tword) - ONLY for double extended precision fp numbers. "rt" - reserve data in tword unit Okeh.. tu je la kot pasal data declaration nih. Terdapat beberapa operators yang korang bleh gunakan dalam constant mathematical expression seperti untuk penambahan, penolakan, dan sebagainya. Operators matematik yang biasa adalah + (tambah), - (tolak), / (bahagi) dan * (darab). Selain daripada tu, operator "mod" digunakan untuk mendapatkan baki daripada pembahagian, operator "and", "or" dan "xor" melakukan operasi logikal terhadap constant, begitu juga dengan "shl" dan "shr". Aku rase korang tau ler kan aper tugas setiap operators ni? Secara amnya, layout Win32 program source file dalah seperti berikut :
;use format directive untuk specify jenis output
format PE <GUI/console> <Subsystem Version> <DLL?> <at ImageBase> <on DosStub>
;use entry directive untuk specify permulaan program
entry <entrypoint_symbol>

;section directive untuk bina section baru, contohnya
;section ".code" code executable readable
section <section_name> <attributes>
;...section data


section <section_name> <attributes>
;...section data
Sebelum aku terangkan lebih lanjut mengenai fasm, meh kita bincangkan topik paling penting dalam assembler nih - preprocessor. [The preprocessor] Takde cara lain lagi untuk menggunakan fasm secara efektif selain memahami prapemproses fasm secara details. Aku tak la sure sangat aper yang aku terangkan kat sini betul belaka since aku tak penah study fasm nyer preprocessor engine dengan lebih mendalam. Preprocessor (pp) adalah stage pertama dalam source compilation by fasm. Sebelum aper2 terjadi terhadap source file korang, fasm akan preprocess dulu file ni terlebih dahulu. 2 bahagian penting dalam pp engine adalah line converter dan line pp. Setiap line dalam source file korang akan diproses oleh line converter dulu dan hasil daripada line converter diserahkan kepada line pp. Sebelum aku terangkan dengan lebih lanjut lagi, korang kena la tau beberapa perkara : 01. symbol characters recognize by fasm : null,tab,lf,cr,space,0x1A,#&()*+,-/\:<>={}|~`; -(0x1A used internally by fasm for various purpose). -"`" and "#" can only be used inside macroinstructions. -Setiap simbol blehla dikira sebagai 1 token kecuali yang dibuang daripada source (seperti tab, cr,lf dan space). Any chains of characters yang tak include salah satu symbol characters kat atas adalah dikira sebagai 1 symbol name (1 token). Contohnya :
     foo bar bas:              ;4 tokens - foo, bar, bas dan character :
     macro foo arg1, arg2 {}   ;7 tokens
     

02. preprocessor directives :

macro, struc, equ, fix, purge, restore, include

03. macro directives :

local, common, forward, reverse

...bersambung...

Share this post


Link to post
Share on other sites

Sekarang macro kiter related to export directory. Macro nih create export directory

dalam program korang. It supports all features of export directory, including forwarded

export, custom ordinal dan sebagainya. Dia trime satu solo argument dan 3 arguments dalam

group. DllName adalah quoted string yang menyatakan internal name dll korang (internal

dll name sepatutnya sama dengan nama fail dll tersebut). "Name" argument adalah quoted string yang menyatakan

namaa simbol (fungsi/data) yang korang nak export. Nama ni digunakan oleh program yang nak import

simbol tersebut (e.g "ExitProcess" dan sebagainya). Kalau korang tak specify quoted string (atau specify nothing)

for the "Name" argument, it is assumed that you only want it to be exported by ordinal. "Ordinal" argument adalah

ordinal untuk fungsi tersebut (must be 0 < ordinal < 65536). Manakala "Entrypoint" argument

menyatakan address fungsi tersebut (labels for the exported function in source). Note that kalau

korang berikan quoted string sebagai "Entrypoint" argument, it's assumed that this is a forwarded export.

Korang bleh tengok contoh kat bawah. Macro ni cuma perlu digunakan dalam PE executable (format PE).

macro EXPORT DllName, [Name, Ordinal, Entrypoint] {
common
  BaseOrdinal=0xffff
  HighestOrdinal=0
  ExpByOrdinal=0
  ExpByName=0
forward
  if Ordinal=0 | Ordinal>65535 | Ordinal eq
    display "Error : [EXPORT] Invalid Ordinal - You Must Supply a Valid Ordinal.",13,10
    HALT!
  end if
  if BaseOrdinal>Ordinal
    BaseOrdinal=Ordinal
  end if
  if HighestOrdinal<Ordinal
    HighestOrdinal=Ordinal
  end if
  EXPORT@#Ordinal=0
forward
  EXPORT@#Ordinal=EXPORT@#Ordinal+1
  if EXPORT@#Ordinal>1
    display "Error : [EXPORT] Duplicate Ordinal.",13,10
    HALT!
  end if
common
  align 4
  dd 0, %t, 0, rva ExportDllName, BaseOrdinal, HighestOrdinal-BaseOrdinal+1
forward
  if Name eqtype ""
    ExpByName=ExpByName+1
  else
    ExpByOrdinal=ExpByOrdinal+1
  end if
common
  dd ExpByName, rva ExpFunctionTable, rva ExpNameTable, rva ExpNameOrdTable
  ExpFunctionTable:
  repeat HighestOrdinal-BaseOrdinal+1
    NoExpFunction=0
forward
    if %+BaseOrdinal-1=Ordinal
      if Entrypoint eqtype ""
        dd rva Forward@#Ordinal
      else
        dd rva Entrypoint
      end if
    else
      NoExpFunction=NoExpFunction+1
    end if
common
    if NoExpFunction=ExpByName+ExpByOrdinal
      dd 0
    end if
  end repeat
forward
  if Entrypoint eqtype ""
    Forward@#Ordinal db Entrypoint,0
  end if
common
  align 4
  if ExpByName
    ExpNameTable:
forward
    if Name eqtype ""
      local _Name
      dd rva _Name
    end if
common
  else
    ExpNameTable=ImageBase
  end if
  ExpNameOrdTable:
forward
  if Name eqtype ""
    dw Ordinal-BaseOrdinal
  end if
forward
  if Name eqtype ""
    _Name db Name,0
  end if
common
  ExportDllName db DllName,0
}
Contoh :
format PE GUI DLL
entry DllMain

section ".code" code executable
DllMain:
   ;....
    mov     eax, 1
    ret     12

Exp1 :
   ;...
    ret

Exp2 :
   ;...
    ret

DataExp dd ?

section ".rdata" data readable export
EXPORT "MYDLL.DLL", \
       "DataExp",1,DataExp,\   ;export data DataExp by name as "DataExp", ordinal = 1.
       "Exp1",4,Exp1,\         ;export function Exp1 by name as "Exp1", ordinal = 4.
       ORD, 5, Exp2,\          ;export function Exp2 by ordinal 5.
       "UniMsgBox", 6, "USER32.MessageBoxW",\  ;forwarded export to MessageBoxW in USER32.DLL,
       \                                       ;exported by name "UniMsgBox", ordinal = 6.
       ORD, 7, "USER32.#477"                   ;forwarded export to MessageBoxA (ordinal 477) in
                                               ;USER32.DLL (XP Pro Retail), exported by ordinal 7.

Share this post


Link to post
Share on other sites

sambung dgn uninitialized array sekali yer smile.gif

isk.. minggu ni takde tutorial la.. nanti la kot aku post 2 sekali.

Share this post


Link to post
Share on other sites

Biler source file kiter diproses oleh fasm preprocessor engine, ia akan diproses line by

line melalui 2 peringkat iaitu line converter (lc) dan line preprocessor (lpp).

The Line Converter.

Tugas utama lc adalah menyediakan source line yang telah diproses untuk diproses pulak oleh

lpp. Ini termasuklah tokenizing, removal of garbage characters dan line concatenation. Dalam lc,

semer symbol characters kat atas bertindak sebagai simbol dan juga symbol separator. Tabs dan spaces

hanya bertindak sebagai symbol separator dan akan dibuang semasa ia ditemui oleh lc. Simbol ;

menyebabkan semua characters (termasuk simbol ; sendiri) selepas ; to be ignored

by lc sehingga newline characters ditemui. lc menggunakan cr (0xD) atau lf (0xA) atau kombinasi kedua-duanya

sebagai newline characters. They mark the end of a line and lc akan berhenti di sini. Akan tetapi, apabila

lc menemui line continuation symbol \, sejurus sebelum newline characters, maka line seterusnya

akan disambung kepada line yang sedang diproses. For the concatenation to be valid, takde characters yang boleh

diletakkan selepas \ kecuali tabs, spaces dan ;. Line seterusnya must be a line,

not blank. Ni bermakna, selepas \, there should be at least newline characters. Contohnya (anggap

crlf adalah newline characters) :

[B]crlf[/B]
[B]crlf[/B]
dd 10 \[B]crlf[/B]
kod di atas adalah valid sebab after \ ia temui newline characters. Contoh kod kat bawah plak tak valid (eof means end of file).
[B]crlf[/B]
[B]crlf[/B]
dd 10 \[B]eof[/B]
Bila lc temui simbol " atau ', maka ia assume characters seterusnya adalah string definition. Dalam string definition, all symbol characters are significant dan dimasukkan dalam output oleh lc. Secara ringkas, dalam string, quotation mark mesti berpasangan, kecuali ia berada di dalam string defined with different quotation mark. Sebagai contoh, kalau kiter gunakan " untuk define string, any usage of " inside the string must be paired (e.g "" mewakili satu "), tapi tidak '. Contoh :
"foo"      ;valid, string is "foo
"foo'bar"  ;valid, string is "foo'bar
"foo""bar" ;valid, string is "foo"bar
'foo'bas'  ;invalid, it should be 'foo''bas'
'foo''''''';valid, string is "foo'''
Seperti yang kiter tengok, kecuali di dalam string definition, takde lagi spaces, tabs, cr, lf, \, dan ' characters di dalam output yang dihasilkan oleh lc. " is used to mark a symbol as string. ; is used to mark macro declaration contents. Bila source line dah diproses oleh lc, lc akan menghasilkan "line" baru dan diberikan kepada lpp untuk diproses. "Line" baru ni cuma difahami oleh lpp je. Contoh output kepada lpp (not in internal format) :
foo fix\
bar fix\
foo fix\

akan menjadi
foo fix bar fix foo fix    ;6 symbols
foo: fix bar
akan jadik
foo: fix bar   ;3 symbol names, 1 symbol character
foo equ db '"foobas"'
akan menjadi
foo equ db "foobas ;3 symbol names, 1 string
The Line Preprocessor. Since lc dah banyak buat keje untuk lpp, tugas lpp hanyalah proses pp directives dan aper2 je la yang related to preprocessing, seperti macro invocation, symbol replacement dan sebagainya. "Line" yang dihasilkan oleh lc contains only symbols. lpp boleh membezakan jenis simbol ni sebab lc dah tandakan setiap simbol ni dengan special value, termasuklah panjang setiap symbol pada permulaan symbol. Normal symbol names are preceded with value 0x1A (byte), diikuti dengan panjangnya (1 byte - ni sebabnya korang takleh gunakan simbol lebih panjang daripada 255 characters). Kalau korang nak tengok camne output yang dihasilkan oleh lc, load fasm executable (CUI) with source file and output name as arguments. Kemudian set breakpoint pada instruction "call preprocess_line" (under "preprocess_source" label), dan dump memory pada address yang dipegang oleh register edi. Beberapa bytes sebelum address ni adalah output yang dihasilkan oleh convert_line function (lc). So, for example, kalau kiter ader source file dengan line seperti berikut :
foo: fix db "foobar"\
,0

output yang terhasil daripada lc adalah (in hex raw data format) :
    .. 1A 03 66 6F 6F 3A 1A 03 66 69 78 1A 02 64 62   ..foo:..fix..db
    22 06 00 00 00 66 6F 6F 62 61 72 2C 1A 01 30 00  "....foobar,..0.
    ..
As you can see, normal symbol name ditandakan dengan value 0x1A, diikuti dengan panjang (foo=3, fix=3, db=2 dan sebagainya). Special character symbols yang dikenali oleh pp (seperti yang aku dah senaraikan kat atas) tidak mempunyai aper2 marker sebab lpp akan mengenalinya. Kemudian string plak mempunyai symbol " sebagai marker diikuti oleh panjang string (4 bytes storage) dan string itu sendiri. Kalau korang perhatikan jugak, dalam preprocessor, nombor pun bleh jadik symbol gak, so kiter bleh buat benda2 pelik seperti "0 fix 1" dan sebagainya! Lpp proses output yang dihasilkan oleh lc mengikut beberapa peraturan dan turutan seperti yang akan aku bincangkan kat bawah : 1. Pertama sekali, lpp akan proses fix directive (directive ni ader la bau2 bacang dengan equ directive). Simbol kedua (dalam "line" yang sedang diproses) akan diperiksa samada ia adalah simbol fix atau tidak (semer check berkaitan dengan pp directives adalah case-sensitive). Kalau simbol kedua tersebut adalah fix, maka lpp consider "line" tersebut adalah constant definition using fix directive (high priority constant definition) atau ringkasnya fix definition. Contoh :
foo fix bar    ;fix definition
foo fix fix bar;fix definition
fix fix equ    ;fix definition
foo! fix if bar+0=1+6-2;fix definition, [B]![/B] bukan special symbol, so it's part of foo symbol name.
foo+ fix bar   ;not a fix definition (second symbol is "+", not "fix").
SatuDuaTigaEmpatLimaEnamTujuhLapanSembilanSepuluh fix 1,2,3,4,5,6,7,8,9,10 ;fix definition
SomeLabel: fix bar ;not a fix definition
fix bar        ;not a fix definition
foo fix        ;fix definition
Bila fix definition ditemui, sekarang makna fix definition (iaitu semer simbol selepas fix) tuh akan tertakluk kepada fix replacement (change to previously defined fix definition). Sebagai contoh, dalam source file:
foo fix bar
foo fix foo bar
Line pertama adalah fix definition di mana simbol foo dalam line seterusnya akan ditukarkan kepada simbol bar. Then pada line kedua juga adalah fix definition. foo sebelum fix tak akan ditukar kepada bar akan tetapi foo selepas fix akan ditukar kepada bar. So, selepas preprocessing kedua-dua line tersebut, simbol foo hanya mempunyai satu makna, iaitu bar bar. Ini membolehkan kiter redefine fix definition. Contoh lagi :
bignop fix times 8 nop
bignop     ;8 NOPs
bignop fix times 4 nop
bignop     ;4 NOPs
Tu kalau line yang diproses adalah fix definition. Jika tidak, semer symbols pada line tersebut akan tertakluk kepada fix replacement. Contoh (full preprocessing):
foo fix bar
fix fix equ
foo: fix bar
bar fix foo
foo+bar
Hasilnya adalah
;foo fix bar
;fix fix equ
bar: equ bar
;bar fix bar
bar+bar
Pada line ketiga, all symbols are subjected to fix replacement (specifically foo dan fix). Bila "line" yang sedang diproses tersebut adalah fix definition, lpp berhenti di sini dan line seterusnya akan diproses oleh lc kemudian oleh lpp. Jika tidak, lpp akan teruskan proses ke bahagian 2 2. Lpp sampai kat sini hanya jika "line" yang diproses bukan fix definition. Kat sini, fix replacement dah dilakukan. Sekarang Lpp akan proses symbol character ` (name to string conversion operator) dan juga # (symbol/string concatenation operator). Note that kedua-dua symbols ni hanya bleh digunakan di dalam macro invocation (occur when you "use" a macro) sahaja, so lpp check global flag (macro_status dalam preproce.inc) untuk memastikan samada ia sedang memproses "line" yang berada dalam macro invocation atau tidak. Jika tidak, ia akan terus ke bahagian 3. Jika ya, ia akan proses dua symbol characters tersebut jika ia wujud di dalam "line" tersebut. ` digunakan untuk menukarkan nama simbol kepada string manakala # digunakan untuk concatenate 2 strings atau dua symbol names (but not mix). Bila dah abish proses, lpp terus ke bahagian 3. (iii)Here, lpp checks a global flag to see whether it is currently processing a macro declaration. If it is, skip them (find end of macro declaration, "}") and lpp ends here. otherwise, proceed to level (iv). 3. Kat sini lpp check global flag (macro_status variable) samada ia sedang process macro declaration atau sedang berada dalam macro declaration. Aper2 pun skip semernya dan lpp berhenti di sini. Jika tidak, ia akan terus ke bahagian 4. Note : Petikan kat bawah diambik daripada flat assembler message board yang menerangkan mengenai macro_status :
The lower nibble (bits 0-3) contains the info related to the macroinstruction that is currently being declared, while the higher nibble (bits 4-7) contain the status of processing the macro. The values of lower nibble can be: 0 - no macro is being declared currently, default value; 1 - the declaration of macro has started, but no { - macro contents opening character has been found yet; 2 - the contents of macro declaration is being preprocessed; The higher nibble consist of flags, currently only two are defined: bit 4 (value 10h) - some macro is currently processed; bit 5 (value 20h) - internal flag of macro preprocessor, used to determine whether we are in the place where some macro directive might be used Note that both higher and lower nibble can have non-zero value at the same time, since macro can define some other macro.
4. Sekarang lpp akan check penggunaan pp directives. Directives yang akan diproses di sini adalah include, macro, purge, restore dan struc. Lpp akan check simbol pertama pada "line" ini untuk memastikan ia adalah pp directives. Jika salah satu directives ni ditemui, ia akan diproses : Untuk include directive, jika ia digunakan dengan betul (ia cuma receive quoted string yang menyatakan nama fail untuk diproses), lpp akan preprocess keseluruhan fail tersebut. Lpp berhenti di sini. Untuk purge dan restore, nama simbol yang diberikan sebagai argument akan dibuang daripada internal symbol table. Lpp berhenti di sini. Untuk macro dan struc, lpp akan define/redefine new macro dan set macro_status variable yang menyatakan ia sedang memproses macro definition (atau inside macro definition). Lpp berhenti di sini. Note: Multiline macro contents are also skipped as lpp progress through each line of macro declaration (read of level (iii) again). Note that although procedure (i) and (ii) run before (iii), nothing will affect a macro declaration except a fix replacement. Kalau takde aper2 berlaku kat sini ("line" ni takde pp directives), maka lpp akan ke bahagian 5. Penerangan seterusnya aku singkatkan.. 5. Lpp checks macro invocation yang kiter define sebelumya dengan "macro" directive jika ada. Jika ia adalah macro invocation, lpp proses dan berhenti di sini. Jika tidak ia akan teruskan ke bahagian 6. 6. Lpp preprocess label yang kiter define dengan character : dan kemudian ia akan loop semula daripada bahagian 4 di mana simbol selepas : akan menjadi simbol pertama plak. Equate replacement bleh berlaku di sini. 7. Lpp process symbolic constant definition yang kiter define dengan equ directive. Jika ia bukan equ definition maka lpp ke bahagian 8. 8. Lpp checks macro invocation yang kiter define sebelumnya dengan "struc" directive jika ada. Jika ia adalah macro (struc) invocation, lpp proses dan berhenti di sini. Jika tidak ia akan teruskan ke bahagian 9. 9. Akhir sekali lpp akan process equate replacement. Tu je la kot mengenai fasm preprocessor. Aku tak reti nak explains secara details sad.gif since benda ni kompleks dan recursive. Tapi aku akan cuba explain mengenai macro dengan lebih mendalam lagi as we use them. Macro yang kiter define dengan macro dan struc directives tak banyak bezanya, cuma cara penggunaannya berbeza. Dengan macro, nama macro tersebut mestilah yang menjadi simbol pertama manakala dengan struc, macro tersebut hendaklah menjadi simbol kedua. Contohnya : macro macro :
macro SZTEXT [Text] {
common
local _start
    _start:
    db Text, 0
    .SIZE = $-_start
    .LEN = .SIZE-1
}
SZTEXT "Hello Putera.com"
.LEN dan .SIZE takde parent label. Kiter takleh invoke SZTEXT macro seperti
foo SZTEXT "Hello Putera.com"
Sebaliknya struc macro :
struc SZTEXT [Text] {
common
local _start
    _start:
    db Text, 0
    .SIZE = $-_start
    .LEN = .SIZE-1
}
foo SZTEXT "Hello Putera.com"
.LEN dan .SIZE will be attached to foo label. Kiter takleh invoke SZTEXT struc seperti
SZTEXT "Hello Putera.com"
Okeylah.. meh kiter bincangkan mengenai macro dengan lebih terperinci. Macroinstructions (macro) actually bertujuan untuk define kiter nyer instructions sendiri yang lebih kompleks. Selain daripada tu ia juga bertujuan untuk memudahkan tugas kiter (normally dalam tugas berulang) dan juga menambah keupayaan instructions yang sedia ada. Meh kiter amik contoh memindahkan variable daripada satu lokasi memory ke lokasi yang lain. The x86 asm "mov" instruction tak benarkan arahan seperti ni. So instead of writing something like :
;code
..
mov eax, [ebp+0x10]
mov [Somevar], eax
..
;data
SomeVar dd ?
kiter bleh extend "mov" instruction dengan macro :
macro mov dest, src {
    if dest eqtype [] & src eqtype []
        push    dword src
        pop     dword dest
    else
        mov     dest, src
    end if
}
;after "mov" macro is defined, semer "mov" instruction sebenarnya adalah
;macro "mov" dan bukannya internal "mov" asm instruction.
mov     eax, ebx
mov     [SomeVar], [ebp+14];now this will compiled correctly
SomeVar    dd ?
Contoh kat atas cuma apply to 32 bit operands je. Dah tentulah korang bleh buat yang lebih baik. Ni cuma contoh je. Bila menggunakan macros, kiter perlu tau mengenai internal working of the preprocessor untuk dapatkan hasil yang lebih memuaskan hati sebab fasm nyer macro facility sangatlah berkuasa (tapi taklah sampai bleh buat aper je yang kiter nak). Terdapat beberapa operators dan directives yang hanya bleh digunakan dalam macro seperti common, local, forward, reverse, ` dan juga #. Meh kiter tengok format macro. Untuk define macro, kiter kena gunakan directive macro atau struc, diikuti oleh nama macro dan arguments yang bleh diterimanya (lebih kurang je macam kiter define function). Aper yang mandatori dalam macro definition adalah nama dan juga simbol { dan } yang menandakan permulaan dan pengakhiran suatu macro definition. Please note, macro definition contents bermula pada { yang pertama ditemui dan } yang pertama ditemui. Contoh macro : 1. no-argument macro :
macro display_hello {display "hello",13,10}
2. one-argument macro :
macro display_text text {display text,13,10}
Setiap text yang ditemui dalam macro tersebut akan digantikan dengan argument yang korang berikan untuk text. Contohnya, jika kiter invoke macro display_text seperti :
display_text "foo"
maka macro tersebut akan menjadi seperti berikut
display "foo",13,10
since kiter berikan string "foo" sebagai text argument. Kiter bleh define macro yang terima bilangan arguments yang tidak tetap (seperti dalam C language ...) iaitu dengan menggunakan [] seperti :
macro display_text [text] {
   ;macro contents
}
Argument yang dikurungkan dengan [] cuma bleh diletakkan sebagai argument terakhir. So
macro foo arg1, [argn] {
}
is valid, tapi tidak
macro foo [argn], arg1 {
}
Terdapat beberapa macro directives yang kiter gunakan untuk define "block of execution". Ia cuma bleh digunakan biler kiter menerima bilangan arguments yang pelbagai. Contohnya, kiter nak suatu arahan tersebut dilaksanakan untuk semer arguments yang kiter terima, maka kiter letakkan arahan2 tersebut di bawah block "common". Bila2 masa kiter gunakan maner2 directive "common", "forward" dan "reverse", arahan di bawahnya adalah tertakluk kepada blok ini sehinggalah directive baru digunakan. Contohnya, kiter bleh gunakan feature nih untuk bina macro "stdcall" yang memanggil fungsi dengan stdcall calling convention :
macro stdcall function, [args] {
reverse
    push    args
common
    call    function
}
;usage example
stdcall [MessageBoxA], 0, Msg, Caption, 0
;data
Msg db "test", 0
Caption db "title", 0
;iat
MessageBoxA dd  ?
Macro stdcall menerima dua argument, di mana argument yang kedua adalah group of arguments dan argument yang pertama adalah single argument. Apabila suatu macro menerima group of arguments, default blok jika tiada "common", "forward" atau "reverse" directive digunakan adalah "forward". Dalam stdcall macro di atas, "reverse" menyebabkan arahan di bawahnya diulang sebanyak mana bilangan argument yang diberikan dalam group of arguments, bermula daripada yang terakhir sehinggalah yang terawal. Sebagai contoh, biler kiter gunakan stdcall macro seperti :
stdcall foo, a, b, c, d
argument foo adalah argument pertama (yang dirujuk sebagai "function" dalam macro declaration) dan argument a, b, c dan d adalah berada dalam group of arguments (yang dirujuk sebagai "args" dalam macro declaration). Arahan "push args" dalam macro tersebut berada di antara directive "common" dan "reverse" di mana ia berada di skop "reverse". Ini bermakna, ia akan dilaksanakan sebanyak 4 kali, bermula daripada argument d, c, b dan berakhir pada argument a. So,
..
reverse
    push args
..
actually expands to
push    d
push    c
push    b
push    a
Blok "reverse" berakhir apabila preprocessor menemui plak directive "common". Arahan di bawah block "common" cuma akan dilaksanakan sekali, common to all arguments. Ni bermakna, arahan "call function" di bawah "common" blok cuma akan diulang sekali, tidak kira berapa banyak argument yang diberikan dalam group arguments. So
..
common
    call    function
..
will expands to
call    foo
dalam penggunaan "stdcall foo, a, b, c, d". Dah tentulah "foo", "a", "b", "c" dan "d" must be valid operands untuk "push" dan "call" instructions. Please note, block directives ni cuma apply kepada macro yang mempunyai group arguments. Dalam macro juga kiter bleh define local symbols yang local kepada macro tersebut. Each time kiter invoke macro ni label ni akan berubah nama so kiter tak akan dapat duplicate label name setiap kali kiter gunakan macro tersebut. Ini dicapai dengan "local" directive. Contohnya :
macro foo {
    local foobar
    foobar:
}
foo
foo
Setiap kali kiter invoke macro foo, label "foobar" akan berubah nama (modified internally by preprocessor) since it's local to the macro. Aku akan discuss mengenai macroinstructions lagi sepanjang tutorial nih. Sebelum tuh meh kiter tengok dulu beberapa assembler directives yang berguna. Pertama sekali adalah use16 dan use32 directives. Directives ni menyebabkan instructions selepasnya dihimpunkan dalam mode yang ditetapkan (16 bit atau 32 bit). Contohnya :
use16
  mov eax, ebx ;fasm insert operand size override prefix (0x66) since opers adalah 32 bit register
use32
  mov eax, ebx ;takde oper size override prefix
use16
  mov ax, bx   ;takde oper size override prefix
use32
  mov ax, bx   ;ader oper size override prefix
Tanpa format directive ataupun explicit use* directive, fasm akan assume 16 bit code untuk dihasilkan (use16). Kemudian kiter ader org directive yang membolehkan kiter berikan new value untuk current address (dalam MEMORY) di maner arahan sedang dikompil. Kiter bleh dapatkan current address dengan operator $. Contohnya :
use32
;kat sini $ adalah 0.
foobar db 0
mov eax, foobar;foobar = 0 --> mov eax, 0
org 10
foobas db 0
mov eax, foobas;foobas = 10 --> mov eax, 10

...bersambung...

Share this post


Link to post
Share on other sites

Maser aku tulis benda alah ni, FASM 1.54 dah kluar dah. Takde feature yang baru, cuma

perubahan preprocessor behaviour di maner fasm sekarang dah terima commands selepas

end of macro declaration. Contohnya, sebelum version 1.54 kuar, kod

macro foo {} foobas fix bar
takleh pakai. Tapi dalam version 1.54 ia dah bleh dipakai dah dan foobas symbol selepas } diterima sebagai fix definition. Lain dari tu takde yang menarik, cuma perubahan kepada formatter dan MS COFF symbols. Oh yerr.. aku baru plak perasan yang kiter bleh gunakan real numbers sebagai memory address. Walaupun tak laa nampak ader kegunaannya tapi aku rase menarik gak dan ia bleh menyelesaikan beberapa masalah. Tapi biasanya kiter takkan guna feature ni. Contoh penggunaan adalah biler kiter nak push floating point constant, kiter bleh gunakan arahan seperti berikut :
    lea     edx, [1.234]
    push    edx
hehehe.. menarik gak. Actually aku tak tau plak aper nak citer lagi. Aku ingat pas ni nak citer pasal assembler lain laa, terutama mengenai RosAsm (Assembler yang kononnya dibina khas untuk ReactOS) dan juga GoAsm. Actually dah braper tahun dah aku tak sentuh assembler lain daripada FASM. Ni baru je download latest version. RosAsm sebenarnya bleh dikatakan menarik gak tapi sayangnya penulisnya terrrrrlalu... tah la aper nak cakap. Benda pertama yang aku benci pasal RosAsm adalah IDEnya. Takde command line version. IDE plak bukannya tak cukup power.. tapi tak sesuai (dan memang tak cukup power) untuk aku. Pastu syntax yang pelik dan tah aper2. Macro facilities bagus gak, takde komen, cuma aku tak suker jenis camni.. payah nak paham biler dah buat macro yang kompleks. Namun begitu, ia membolehkan kiter buat macro yang ringkas. Contohnya STDCALL macro :
[push | push #1 | #+1]
[STDCALL | push #L>2 | call #1]
Ringkas je kan.. Tapi aku takleh nak ingat la part symbols macro argument ni selalunya. So kalau aku nak tulis macro dalam RosAsm, selalu je kena bukak manual.. Bosan! FASM pun sebenarnya banyak gak problems. Yang pertama dia takde built-in conditional preprocessing. Kalau ader benda alah ni, aku dapat rasakan kiter bleh buat macros yang panjang dan kompleks tanpa melembabkan keseluruhan proses kompilasi program. Pastu plak kod yang simple camni
if ~defined foo
    foo=0
end if
pun dia takleh kompil. kemudian kiter takleh test constant yang belum kena define seperti
if foo = 0
   ;...
end if
Nak tak nak kena la buat camni
if defined foo
    if foo=0
       ;...
    end if
end if
At least kalau bleh buat camni pun bagus gak
if defined foo & foo=0
   ;...
end if
Kiter takleh buat camni sebab walaupun if defined foo dah salah, fasm tetap evaluate foo=0. Maknanya error (seperti yang pertama tadi). Kalau dia buat short-circuit evaluation, expression foo=0 dia tak perlu la test lagi. Part macro pun banyak gak kelemahan, contohnya dia tak fully support nested macros declaration so kiter tak perlu la buat fix constant yang pelik2. Biasanya kiter akan buat nested macro (contoh 1 level depth) camni :
macro foo {
    macro bar { %end%
}
%end% fix }
Kiter takleh tutup macro kat dalam dengan } kerana ia akan menyebabkan macro foo akan berakhir di situ (dan } yang kedua akan menyebabkan preprocessing error). Maknanya kalau kiter ader nested macros sehingga 2 levels, kiter kena buat camni :
macro foo {
  macro bar {
    macro bas {
    %end01%
  %end%
}
%end01% fix %end%
%end% fix }
3 levels plak :
macro foo {
  macro bar {
    macro bas {
      macro foobar {
      %end02%
    %end01%
  %end%
}
%end02% fix %end01%
%end01% fix %end%
%end% fix }
dan seterusnya laaa.. Begitu jugak dengan symbol characters ` dan #. Tu belum lagi kalau dah ader multiple files. Kan elok kalau fasm bleh treat nested macros camni :
macro level0 {
    macro level1 {
        macro level2 {
            macro level3 {
            }
        }
    }
}
Satu lagi problem adalah pada macro yang ader group argument ni. Dia nyer forward atau reverse at least jalan sekali walaupun takde argument diberikan. Contohnya :
macro foo [arg] {
forward
  display "test",13,10
}
foo

(Actually kalau kiter fikir lagi mengenai benda ni, memang tak salah pun smile.gif... aku sajer2 je.).

Aku berenti kat sini je la.. takde modal la ari ni. Tak tau nak citer aper. Lagipun aku nak create

include files baru yang serasi dengan fasm 1.54 aku smile.gif... Enjoy!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...