东欧牛人“圣父”的hxdef(黑客守卫者)重新钩起了我对Delphi的兴趣,“圣父”基乎是全用Basm写成了hxdef。
天天都用C/C++,Object Pascal感觉自己怎么也用不熟,昨晚看了一下Object Pascal的Inline ASM,主要是堆栈的安排以及Register和Pascal调用与C的Cdecl及API的Stdcall不太一样,什么引用型变量,指针等在汇编中的内存结构与C中的差不多,对象类型的Self指针(C中叫This指针)都是通过ecx传递,但在Basm中调用类类型的成员函数以及虚拟成员函数都要比C++的Inline调用对象的成员函数和虚拟成员函数要方便很多。
使用Delphi Basm来写Win32程序就不需要考虑引入什么库,uses一下单元文件就可以了,而且Delphi Inline ASM中可以使用db,dd之类的宏,可以方便的将数据与代码混合在一起,虽然在代码段,但只需要将变量占用内存属性改一下,它们就可以被读写,就像它们被定义在数据段一样.
如果只想在Delphi中使用Basm那么就应该将所有的块语句都用asm...end来表示,而不是begin...end.
最主要的还是对Intel x86汇编的掌握,以及编译器从高级语言生成汇编代码的规则的理解,最后用一段巨菜的代码练习一下Basm,基本上是没有Pascal代码的纯Basm汇编。程序使用Delphi5编译运行通过,Delphi7编译不通过很多常量不能用,看来如果是用纯Basm劝你还是用Delphi5,这也是很多牛人还在用Delphi5的原因吧。
//File:Basm.dpr
program Basm;
{$APPTYPE GUI}
uses
Windows,
Messages;
var
strClsName:string='BasmWndCls';
strCaption:string='BasmDemo';
strText:string='Basm还真方便,难道不是吗?';
function WndProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall ;
var
ps:PAINTSTRUCT;
hWndDC:HDC;
asm
mov eax,uMsg
cmp eax,WM_PAINT
je @LWm_Paint
cmp eax,WM_DESTROY
je @LWm_Destroy
cmp eax,WM_CLOSE
je @LWm_Close
//其它的信息做缺省处理
jmp @LDefault
@LWm_Paint:
lea eax,ps
push eax//for endpaint
//BeginPaint(hWnd,&ps);
push eax
push hWnd
call BeginPaint
mov hWndDC,eax
push DT_CENTER or DT_VCENTER or DT_SINGLELINE
lea eax,ps.rcPaint
push eax
push -1
//Delphi BASM中可以这样做类型转换,真方便,string类型的前两个DWORD,
//全别是长度和引用计数,从第9个byte开始才是零终止的字符串,用PChar[]
//编译器会自动引用从9字节开始的地址
push PChar[strText]
push hWndDC
call DrawText
//EndPaint(hWnd,&ps);
push hWnd
call EndPaint
jmp @LQuit
@LWm_Close:
push hWnd
call DestroyWindow
jmp @LQuit
@LWm_Destroy:
push 0
call PostQuitMessage
jmp @LQuit
@LDefault:
push lParam
push wParam
push uMsg
push hWnd
call DefWindowProc
jmp @@1
@LQuit:
xor eax,eax
@@1:
end;
function WinMain(hInstance,PrevInst:HINST;lpszCmdLine:LPTSTR;nShow:DWORD):integer;stdcall ;
var
WndCls:WNDCLASSEX;
MsgV:MSG;
asm
//memset(&MsgV,0,sizeof(MsgV));
lea edi,MsgV
mov ecx,type MsgV
xor eax,eax
rep stosb
//memset(&WndCls,0,sizeof(WndCls));
lea edi,WndCls
mov ecx,type WNDCLASSEX
push ecx
rep stosb
pop WndCls.cbSize
mov WndCls.style, CS_VREDRAW or CS_HREDRAW
mov WndCls.lpfnWndProc,offset WndProc
mov eax,hInstance
mov WndCls.hInstance,eax
//LoadIcon(NULL,IDI_APPLICATION);
xor eax,eax
push IDI_APPLICATION
push eax
call LoadIcon
mov WndCls.hIcon,eax
mov WndCls.hIconSm,eax
//LoadCursor(NULL,IDC_ARROW);
xor eax,eax
push IDC_ARROW
push eax
call LoadCursor
mov WndCls.hCursor,eax
mov WndCls.hbrBackground,COLOR_WINDOW+1
push PChar[strClsName]
pop WndCls.lpszClassName
//RegisterClass(&WndCls);
lea eax,WndCls
push eax
call RegisterClassEx
test eax,eax
je @LQuit
//CreateWindowEx(NULL,strClsname,strCaption,WS_OVERLAPPEDWINDOW,
//CW_USEDEFAULT,CW_USEDEFAULT,
//CW_USEDEFAULT,CW_USEDEFAULT,
//NULL,NULL,
//hInstance,
//NULL);
xor eax,eax
push eax
push hInstance
push eax
push eax
mov eax,CW_USEDEFAULT
push eax
push eax
push eax
push eax
push WS_OVERLAPPEDWINDOW
push PChar[strCaption]
push PChar[strClsName]
push 0
call CreateWindowEx
test eax,eax
je @LQuit
//ShowWindow(hWnd,nShow);
//UpdateWindow(hWnd);
push eax
push nShow
push eax
call ShowWindow
call UpdateWindow
//while(GetMessage(&MsgV,NULL,0,0)
@LMsgLoop:
xor eax,eax
push eax
push eax
push eax
lea eax,MsgV
push eax
call GetMessage
test eax,eax
je @LQuit
//TranslageMessage(&MsgV);
//DispatchMessage(&MsgV);
lea eax,MsgV
push eax
push eax
call TranslateMessage
call DispatchMessage
jmp @LMsgLoop
@LQuit:
end;
asm
push CmdShow
push CmdLine
push 0
push MainInstance
call WinMain
end.