3.3数据定义和数据类型强制转换

  BASM可以使用所有通过Delphi语法定义的变量、常量。BASM扩展了ASM的语法,用于访问记录、数组、对象等复杂的数据结构。下例简单解释了如何进行数据定义和访问:

type
TRec=record
    rI:Integer;
    rS:String;
end;
var
    I:Integer;
    R:TRec;
    s:String =1234567;
    A:Array [0..10]of char = 'abcdefghij'#0;
const
    C=3124;
    Str='abcde';
asm
    mov eax,I//I的值送入eax
    mov eax,OFFSETI//I的地址送入eax,相当于eax=er
    mov eax,R.rI//域rI的值送入eax
    mov eax,[TRec.rI+R]//同上
    mov eax,[Offset R+TRec.rI]//同上
    mov ebx,S
    dec ebx//忽略s[0]
    mov esi,4
    mov al,BYTE [ebx+esi]//将s[4]的字符值送入al
    mov al,BYTE [ebx+4]//同上
    mov eax,[ebx+4]//将s[4]..s[7]四字节以DWORD值送入eax,eax=$37363534
    mov ebx,OFFSET A
    mov eax,[ebx+4]//将A[4]..S[7]四字节以DWORD值送入eax,eax=$68676665
    mov eax,C//eax=3124
    mov eax,[c]//eax=PInteger(3124),非法的内存地址访问
end;

  在上例中,常量C总是作为数值直接被编码。因此,“mov eax,C”中,它作为立即数3124被送入EAX。而在“mov eax,[C]”却表明要访问内存地址“3124”,因为“[C]”表明是内存引用。
  由于常量总是被直接编码,上例中,无法访问常量Str——Str的长度大于4,所以无法送入EAX。同样的原因,在BASM中,对常量使用OFFSET是没有意义的一—尽管在Delphi中,字符串常量可以具有内存地址。下例中,EAX总是被送入Str的值,而非地址。

  BASM不支持访问数组下标(可以用地址运算来替代这样的语法)。尽管类似“mov eax,TYPE Arr[2]”这样的语句可以编译通过,但它总是返回数组的整个长度(如上一节例子中的值11)。这也正好解释了“mov al,Arr[2]”这样的语句为什么不能被编译——因为要将一个类型长度为11的数据放入al寄存器,是无法做到的。
  BASM中支持两种类型强制转换的语法,效果是完全一致的。

type
TCode=Record
    I:Integer;
    s:String;
end;
var
    aRec:TCode;
    aInt:Integer;
asm
mov eax,arnt.TCode.I//使用“表达式。类型”的强制转换格式
mov eax,integer(aRec)//使用“类型(表达式)”的强制转换格式
end;

  这里的强制转换的语义与Delphi是一样的。但是,BASM的强制转换,只是把地址上的变量强制识别成目标类型,而不进行长度校验。因此可以看到,TCode的长度为8,而整型长度为4,它们之间仍然可以转换,这样的转换在Delphi中是行不通的。
  BASM代码块中,也可以定义数据。但是,用BASM语句定义的数据总是在代码段里,这也是对Delphi无法在代码段里定义数据的一个弥补。
  BASM支持四个用于定义数据的汇编指令DB/DW/DD/0Q。与ASM不同,不能为这些数据命名。例如:

asm
    DBOFFH//定义一个字节
    avar DBOFFH//在ASM中可用,但在BASM中不支持
end;

  可以通过一些技巧来解决命名问题。但是,必须同时用操作系统的API来打开代码访问权限,才能真正的写这些数据。下面的例子展示数据定义、命名和读取的方法:

type
TCode=packed Record
    CODE:WORD;//jmp e,2 Bytes
    I:Integer;
    s1:array [1..26]of char;
    s2:array [1..11] of byte;
end;
var
    I:Integer;
    s:String;
    Code:^TCode;
function ReadCode:Integer;
asm
    jmpe
    DD 12344213
    DB'ABCDEFGHIJKLMJNOORSTUVWXYZ'
    DB 32,32,32,32,32,32,32,32,32,32,32
    mov Code,offset ReadCode
    mov EAX,Readcode.TCode.I
end;

I:=Readcode;//I=12344213
s:= Code .S1;//S=ABCDEFGHIJKLMINOQRSTUVWXYZ'

  这个例子以例程名作为变量的地址,但并不是一个好的例子(尽管很多代码这样做)。更方便的方法是使用标号作为变量名,与上例类同的例子是这样:

type
TCode=packed Record
    I:Integer;
end;
var
    I:Integer;
function ReadCode:Integer;
asm
    jmp @
@codeRec:
    DD 12344213
@:
    mov EAX,@CodeRec.TCode.I//使用标号作为变量
end;
I := Readcode;//I=12344213

 

转载于:https://www.cnblogs.com/YiShen/p/9881232.html

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值