0 引言
最近我看到不少兄弟在问关于 HLA 学习的事,他们大多买了<<汇编语言编程艺术>>
这本书,作者是美国的 Randall Hyde。这本书写的总的来说还是不错的。刚开始的
时候比较简单,有些简单的地方又说的略显啰嗦。但如果你耐心看一段时间就能体会
其中乐趣。虽然该书有些地方讲的让初学者感到困惑:比如讲到 类和对象汇编实现
的时候,开始的一大部分用来做上机实操时得到关于类方法的执行都是会出错的,因为
有个关键地方没有设置,即:
VMT(classname);
mov(&tBaseClass._VMT_,bc.pVMT_);
而这个设置在后面才会讲到,但开始却没有丝毫提起,所以会让很多人以为是hla
实现上有问题,其实不然。
当然本书自身翻译的不自然和漏字错字也还是存在的,这也算翻译作品的通病吧。而
且译者好像缺乏了一点幽默感(我没看过英文原著),但从某些句子段落的咀嚼似乎
又能让你会到原作作者的幽默天才(很多原作作者的语言都是很生动和诙谐幽默的,
例如另一本:<<WIN32 API 编程 for VB>>)。但不管如何该书还是很有看头的,其中
还探讨了使用 HLA 强大的编译时语言编写高级语言语法的功能,还有浮点指令,MMX
指令的用法,类和对象的实现等等。
我写此作的目的是希望正在学习 HLA 的朋友能够将遇到的问题和学习的经验和心得和
大家共享,本人才疏学浅,通假字连篇,所以不当之处恳请各位多多指出,在此谢过了。
PART 1
我想先抛砖引玉先说2点:
<<汇编语言编程艺术>> 这本书中使用的是 masm32 的编译器,但书中对 win32 SDK
编程好像只是一笔带过,并无详细说明,我在这里就先给出对于 win32 SDK 的简单
实现,相信大家可以举一反三:
//* * * * * * * * * * * * * *
//code by hopy|侯佩 *
//to use Win32 API with HLA *
//2006-07-12 *
//* * * * * * * * * * * * * *
programWin32ApiNow;
#include("w.hhf");
#include("wpa.hhf");
const
txt:string:="I'm Hopy";
cp:string:="windows XP";
beginWin32ApiNow;
w.MessageBox(NULL,txt,cp,w.MB_OK);
endWin32ApiNow;
(未完待续...以前画漫画的时候经常为这4个字给人骂死...呵呵)
PART 2
关于 enum 的研究。书上 P154 页略微提到了一点 HLA 对枚举表达的实现,但作者
同时指出内部是使用 8bits 变量存放 enum 的元素,所以enum元素数量不能超过
256个,有趣的是在 P155 页的脚注上作者却提示:HLA 提供了一个机制,该机制可以
指定 enum 数据类型占用 2 个或 4 个字节的空间,到此本书再也闭口不提如何达到
该目的。那么到底可不可以让枚举占用超过1字节的空间呢?
我在 HLA 编程指南中找到这么一段话(原话):
By default, HLA uses eight-bit values to represent enumerated data types.
This means that you can represent up to 256 differentsymbols using an
enumerated data type. This should prove sufficient for most applications.
HLA provides a special"compile-time variable" that lets you change the size
of an enumerated type from one to two or four bytes. In theory, all you’
vegot to do is assign the value two or four to this variable and HLA will automatically resize the storage for enumerated types tohandle longer
lists of objects. In practice, however, this feature has never been tested
so it’s questionable if it works well. If youneed enumerated lists with
more than 256 items, you might consider using HLA const definitions rather
than an enum list, just to be on the safe side. Fortunately, the need for
such an enum list is exceedingly remote.
上面的确提到 HLA 可以对超过256个枚举元素的支持,其主要思想为(部分翻译如下):
HLA 自动地根据 enum 元素的数量改变空间的大小,理论上可以支持超过 256 个枚举
元素。但实际上不管怎样这个特性从来没有被测试过,它有可能工作不正常。如果您要
创建超过 256 个枚举元素,您可能在 const 段中定义更好一些...
观看不试是没有用的,下面我创建了一个含有 500 个元素的 enum 类型,为了简便起
见,我使用了 HLA 的编译时语言的支持,而不是真的手工输入500个元素(谁叫偶懒哩):
program EnumTest;
#include("stdlib.hhf");
type
//以下是创建500个元素的 color 枚举:
color:enum{
?i:=0;
#while(i<500)
@text("a"+ string(i)+",")
?i:=i+1;
#endwhile
a500
};
static
EC:color:=a500;
begin EnumTest;
//nothing...
end EnumTest;
结果是编译无法通过:
F:/HLA>hla a.hla
Assembling: a.asm
a.data.inc(2) : error A2071: initializer magnitude too large for specified size
Error returned by Assembler = 1
真的行么?下面我将 EC:color:=a500; 改为 EC:word:=a500; 如下:
program EnumTest;
#include("stdlib.hhf");
type
//以下是创建500个元素的 color 枚举:
color:enum{
?i:=0;
#while(i<500)
@text("a"+ string(i)+",")
?i:=i+1;
#endwhile
a500
};
static
EC:word:=a500;
begin EnumTest;
//nothing...
end EnumTest;
OK,编译成功,用 ollydbg 查看, EC 变量的值正确的被赋为: 01f4h
PART 3&4
3 关于 HLA 中的 intmul 指令,大家如果在 intel 指令手册中找的话,结果可能会
失望,因为没有该条指令。其实他只是 imul 的变种(异型?)之一:
imul r32,r/m32,imm8/32
4 在看到移位指令的时候,我就在想是否可以不用位指令来实现移位(bt之类的指令
也不用)。答案是肯定的,以下是左移一位的代码:
programmainmy;
#include("stdlib.hhf");
readonly
bitstr:byte[8]:=[%0000_0001,%0000_0010,%0000_0100,
%0000_1000,%0001_0000,%0010_0000,
%0100_0000,%1000_0000];
var
mb:byte;
procedurelm1(var mb:byte);
var
tmpa:byte;
tmpb:byte;
tmpi32:int32;
beginlm1;
push(eax);
push(ebx);
mov(mb,eax);
mov([eax],al);
mov(al,tmpb);
mov(al,tmpa);
mov(6,tmpi32);
while(tmpi32>=0) do
mov(tmpi32,ebx);
and(bitstr[ebx],al);
mov(bitstr[ebx+1],al);
jnzt0;
not(al);
and(al,tmpb);
jmpt1;
t0:
or(al,tmpb);
t1:
dec(tmpi32);
mov(tmpa,al);
endwhile;
and(%1111_1110,tmpb);
mov(mb,eax);
mov(tmpb,bl);
mov(bl,[eax]);
pop(ebx);
pop(eax);
end lm1;
beginmainmy;
mov(%0101_0111,mb);
stdout.put("the value before transfer is ",mb,nl);
lm1(mb);
stdout.put("after transfer the value is ",mb,nl);
endmainmy;
PART 5
我在上面说过了 HLA 的编译时语法的功能是很强的,现在做一个小的实例是通过
编译时宏将 ascii字符串 转换成 宽字符串。要说明的是这个转换很简单,只是一
个小例子其中还有很多没考虑到的地方:
programtest0;
#include("stdlib.hhf");
#macroctrlstr(thestr);
?maxlen:=@length(thestr);
?i:=0;
@text("ustr:char[maxlen*2+2]:=[")
#while(i<maxlen)
?strnow:=@substr(thestr,i,1);
@text("#0,'"+strnow+"',")
#print(strnow)
?i:=i+1;
#endwhile
@text("#0,#0];")
#endmacro;
static
ctrlstr("kinds");
begintest0;
//do nothing ...
endtest0;