注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

鑫淼梦园的博客

圆你的梦想 从这里开始

 
 
 

日志

 
 

初学 Delphi 嵌入汇编 - 汇编语言与机器语言  

2012-11-05 17:49:36|  分类: delphi xe2 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在网上转来的,文章对学习用DELPHI有很大的帮助的。
主选课本是清华大学王爽老师的《汇编语言》. 推荐 王爽老师的汇编网
--------------------------------------------------------------------------------
汇编语言之前是机器语言.
机器语言是机器指令的集合, 机器指令是一系列二进制数字, 计算机将之转换为一系列高低电平, 而实现运算.
在 PC 机上运行机器指令的是 CPU; 不同的 CPU 有不同的指令, 所以某种汇编语言也只是针对某系列的 CPU.
王爽老师举了一个用机器语言输出 "welcome to masm" 的例子:
00011110
101110000000000000000000
01010000
101110001100011000001111
1000111011011000
1011010000000110
1011000000000000
1011011100000111
101110010000000000000000
1011011000011000
1011001001001111
1100110100010000
1011010000000010
1011011100000000
1011011000000000
1011001000000000
1100110100010000
1011010000001001
10001101000101100010101000000000
1100110100100001
1011010000001010
10001101000101100011000100000000
1100110100100001
1011010000000110
1011000000010100
1011011100011001
1011010100001011
1011000100010011
1011011000001101
1011001000111100
1100110100010000
1101010000000010
1101011100000000
1101000000001100
1101001000010100
1100110100010000
1011010000001001
10001101000101100000000000000000
1100110100100001
11001011
我怀着对计算机先人的无比崇敬, 把它给抄下来, 也不知对也不对.
--------------------------------------------------------------------------------
后来有了汇编, 譬如用:
mov ax,bx {在 Delphi 中相当于 ax := bx}
代替机器指令:
1000100111011000
这样更接近人类的思维; 但最终还是要有编译器把 mov ax,bx 翻译回 1000100111011000 才能被计算机接受.


初学 Delphi 嵌入汇编[2] - 汇编语言关键字
汇编语言不区分大小写.
关键字                              用途
AH 
AL 
AND 
AX 
BH 
BL 
BP 
BX 
BYTE 
CH 
CL 
CS 
CX 
DH 
DI 
DL 
DS 
DWORD 
DX 
EAX 
EBP 
EBX 
ECX 
EDI 
EDX 
EIP 
ES 
ESI 
ESP 
FS 
GS 
HIGH 
LOW 
MOD 
NOT 
OFFSET  
OR 
PTR 
QWORD 
SHL 
SHR 
SI 
SP 
SS  
ST  
TBYTE  
TYPE  
WORD 
XOR 

非常遗憾, 现在我不能给每个关键字做一个哪怕是非常简单的解释, 以后会了再补吧.


初学 Delphi 嵌入汇编[3] - 第一个 Delphi 与汇编的例子


 
前面知道了一个汇编的赋值指令(MOV), 再了解一个加法指令(ADD), 就可以做个例子了.
譬如: ADD AX,BX; 这相当于 Delphi 中的 AX := AX + BX;
另外提前来个列表 - Delphi 可以用汇编管理以下寄存器:
32 位寄存器: EAX EBX ECX EDX ESP EBP ESI EDI
16 位寄存器: AX BX CX DX SP BP SI DI
8 位寄存器 : AL BL CL DL AH BH CH DH
16 位段寄存器: CS DS SS ES 以及协处理器寄存器堆栈: ST
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
//使用汇编的函数
function add(x,y: Integer): Integer;
var
  count: Integer;
begin
  asm
    MOV EAX,x      {把 x 值放入寄存器 EAX}
    MOV ECX,y      {把 y 值放入寄存器 ECX}
    ADD EAX,ECX    {把 EAX + ECX 的值放入 EAX}
    MOV count,EAX  {把 EAX 的值给变量 count}
  end;
  Result := count; {返回值}
{asm 中每个语句换行即可分句, 无须 ; 在这里加上也没有问题}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := add(2,4);
  ShowMessage(IntToStr(i)); {6}
end;
补充嵌入汇编的注释及分句:
1、注释同 Delphi
2、可以用分号 ; 分句
3、可以用换行分句
4、甚至可以用注释分句

初学 Delphi 嵌入汇编[4] - 寄存器在过程与函数中的使用
 
CPU 提供了诸多寄存器, 但在 Delphi 的过程和函数中, 只有 EAX ECX EDX 三个寄存器可以自由使用;
如果改变了其他寄存器, 在过程和函数结束前要给恢复.
记得前面学习过 Delphi 的过程和函数默认的调用约定是 Register , 前三个参数通过寄存器传递, 其他参数存与栈.
它所指的三个寄存器就应该是 EAX ECX EDX 了.
看资料介绍应该是: EAX 先接受第一个参数再接受返回值, ECX EDX 接受后面两个参数.
但我不能进行完整的测试.
--------------------------------------------------------------------------------
//测试三个自由寄存器: EAX ECX EDX
procedure Proc(x,y,z: Integer);
var
  a,b: Integer;
begin
  asm
    MOV a,ECX
    MOV b,EDX
  end;
  ShowMessage(Format('%d,%d',[a,b]));
{EAX 我测试不了}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
begin
  Proc(11,22,33); {显示: 33,22}
{看来寄存器 ECX 储存的是第三个参数; EDX 储存第二个参数}
end;

初学 Delphi 嵌入汇编[5] - 寄存器在过程与函数中的使用
 
//测试寄存器: 如果只有两个参数, 看看 ECX EDX 谁来接受第二个参数
procedure Proc(x,y: Integer);
var
  a,b: Integer;
begin
  asm
    MOV a,ECX
    MOV b,EDX
  end;
  ShowMessage(IntToStr(a) + #44 + IntToStr(b));
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
begin
  Proc(11,22); {显示: 0,22}
{看来是 EDX 一直接受第二个值; 那么 ECX 肯定接受第三个值了}
end;

初学 Delphi 嵌入汇编[6] - & 操作符
 
//在汇编中访问 Delphi 的变量可以使用 & 操作符
procedure Proc(str1,str2: string);
var
  s1,s2: string;
begin
  asm
    mov ecx, &str1  {}
    mov edx, &str2
    mov &s1, ecx   {}
    mov &s2, edx
  end;
  ShowMessage(s1 + s2);
end;
{在没有歧义的情况下, 操作符 & 是可以省略的, 譬如上面的例子就可以省略}
//测试
procedure TForm1.Button1Click(Sender: TObject);
begin
  Proc('我是', '万一'); {显示: 我是万一}
end;
--------------------------------------------------------------------------------
//在什么情况下不能省略呢? 例如:
procedure TForm1.Button2Click(Sender: TObject);
var
  ecx: Integer;    {这个变量和其中一个寄存器重名了}
begin
  ecx := 99;
  asm
    mov ecx, &ecx  {现在 ecx 是寄存器; &ecx 是变量}
    add ecx, 1
    mov &ecx, ecx
  end;
  ShowMessage(IntToStr(ecx)); {100}
end;
--------------------------------------------------------------------------------
{现在也得知: 其实这之前的例子, 只要是在汇编中使用的本地变量都可以加 & }

初学 Delphi 嵌入汇编[7] - 使用常量
 
//在汇编中使用常量
var
  a: Integer;
const
  n = $10;
begin
  asm
    mov ecx, 10             {使用十进制常数}
    mov a, ecx
  end;
  ShowMessage(IntToStr(a)); {10}
  asm
    mov ecx, $10            {使用十六进制常数}
    mov a, ecx
  end;
  ShowMessage(IntToStr(a)); {16}
  asm
    mov ecx, 10H            {可以加 H 或 h 表示十六进制}
    mov a, ecx
  end;
  ShowMessage(IntToStr(a)); {16}
  asm
    mov ecx, n              {使用预定义常量}
    mov a, ecx
  end;
  ShowMessage(IntToStr(a)); {16}
end;

初学 Delphi 嵌入汇编[8] - 8 位寄存器、16 位寄存器与 32 位寄存器
 
王爽老师书上说, CPU 内部主要就是寄存器.
现在我们在 32 位的系统下工作, 当然主要使用的是 32 位寄存器; 那它和 8 位、16 位的寄存器又有什么关系呢?
从网上找到一个简洁明了的图片:

EAX 是 32 位的, 也就是 4 个字节大小; 它的低两位就是 AX;
AX 是 16 位的, 又分 2 个字节; 它的高字节是 AH、低字节是 AL;
AH 与 AL 是 8 位的.
这样就兼容了以前的 16 位与 8 位.
同理,
EBX 就包含着 BX BH BL;
ECX 就包含着 CX CH CL;
EDX 就包含着 DX DH DL;
好啊, 一下子认识了那么多寄存器!
按照这个道理, 如果给 EAX 赋了值, 那么 AX AH AL 也就都有了值;
如果给 AL 赋了值, 那么 AX EAX 也就有了值.
//测试1
var
  i: integer;  
{4 字节、32 位}
  w: word;    
{2 字节、16 位}
  b1,b2: byte;
{1 字节、 4 位}
begin
  i  := maxint;
  w  := 0;
  b1 := 0;
  b2 := 0;
  
asm
    mov ecx, i
    mov w, cx
    mov b1, ch
    mov b2, cl
  
end
;
  ShowMessage(Format(
'w=%d; b1=%d; b2=%d'
,[w,b1,b2]));
{结果显示: w=65535; b1=255; b2=255
  果然没错, 给 ecx 赋值后, cx ch cl 都有值了!
}
end
;
//测试2
var
  i: integer;  
{4 字节、32 位}
  w: word;    
{2 字节、16 位}
  b: byte;    
{1 字节、 4 位}
begin
  b := 255;
  i := 0;
  w := 0;
  
asm
    mov cl, b
    mov w, cx
    mov i, ecx
  
end;
  ShowMessage(Format(
'i=%d; w=%d',[i,w]));
{结果显示: i=255; w=255
  这好像是没有问题的, 我用 al ax eax 三个寄存器测试也是如此;
  
但用 dl dx edx 测试, 就会有意外的结果, 奇怪呀!
}
end;

初学 Delphi 嵌入汇编[9] - asm 可以代替 begin
 
//可以用 asm 代替 begin
function Fun(x: Integer): Integer;
asm
  mov eax, x
  inc eax
end;
{
  汇编中的 inc 指令和 Delphi 中的 inc 是一样的;
  本例也同时证明 eax 寄存器确实保存着函数的返回值.
}
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := 8;
  i := Fun(i);
  ShowMessage(IntToStr(i)); {9}
end;

初学 Delphi 嵌入汇编[10] - 函数返回值与寄存器
 
返回类型 寄存位置
Char、Byte AL 寄存器
SmallInt、Word AX 寄存器
Integer、LongWord、AnsiString、Pointer、Class EAX 寄存器
Real48 EAX 寄存器中是栈内返回值的指针
Int64 EDX、EAX  寄存器对
Single、Double、Extended、Comp 栈首寄存器 ST(0)
短字符串或变体类型 在@Result指向的临时位置中返回


学 Delphi 嵌入汇编[11] - 用汇编重写一个 Delphi 函数
 
//Delphi 函数
function DelphiFun(x: Integer): Integer;
begin
  Result := x * 2;
end;
//汇编函数, 和上面的函数是同样的功能
function AsmFun(x: Integer): Integer;
asm
  add eax, eax   {eax 可以获取第一个参数, 同时又是函数的返回值, 所以可以如此简洁!}
end;
//测试 DelphiFun
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := 34;
  i := DelphiFun(i);
  ShowMessage(IntToStr(i)); {68}
end;
//测试 AsmFun
procedure TForm1.Button2Click(Sender: TObject);
var
  i: Integer;
begin
  i := 34;
  i := AsmFun(i);
  ShowMessage(IntToStr(i)); {68}
end;
做本例时, 我同时做了一个测试:
循环执行 1,000,000 次以内, 基本没有区别; 循环执行 10,000,000 次时, 才有 10 几毫米的差距.
这说明 Delphi 本身速度就足够快了!

初学 Delphi 嵌入汇编[12] - 在汇编代码中可以直接使用 Result
 
//在汇编代码中使用 Result
function Fun(x: Integer): Integer;
asm
  mov ecx, &x
  dec ecx           {汇编中的 dec 是减 1 指令, 和 Delphi 是一样的}
  mov @Result, ecx  {在本例中去掉 @ 也可以, 暂时不知怎么回事}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := 100;
  i := Fun(i);
  ShowMessage(IntToStr(i)); {99}
end;

初学 Delphi 嵌入汇编[13] - 地址参数用 [] 取值
 
//关于地址参数(var/out)
function Fun(var x,y: Integer): Integer;
asm
  mov eax, x         {现在 eax 中只是 x 的地址}
  mov eax, [eax]     { [eax] 是取值, 是不是类似于 P^ ? }
  mov edx, y
  add eax, [edx]
  //mov @Result, eax {在这里, 这句可有可无}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  a,b: Integer;
begin
  a := 1;
  b := 8;
  a := Fun(a,b);
  ShowMessage(IntToStr(a)); {9}
end;

初学 Delphi 嵌入汇编[14] - 常量与变量在汇编中的一个区别
//常量可以在汇编语句中运算
function Fun: Integer;
const
  a = 11;
  b = 5;
asm  mov eax, a-b
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := Fun;
  ShowMessage(IntToStr(i)); {6}
end;
//变量不可以, 方法中的参数也都属于变量
function Fun: Integer;
var
  x,y: Integer;
asm
  mov x, 11
  mov y, 5
//mov eax, x-y {不能这样使用}
  mov eax, x
  sub eax, y     {sub 是减, 就像 add 是加一样}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);var
  i: Integer;
begin
  i := Fun;
  ShowMessage(IntToStr(i)); {6}
end;

初学 Delphi 嵌入汇编[15] - 需要保护的寄存器


 
前面提到 32 位的寄存器有: EAX EBX ECX EDX ESP EBP ESI EDI; 其中, EAX ECX EDX 是自由使用的.
那么剩下的 EBX ESP EBP ESI EDI 五个寄存器就是应该保护的!
所谓保护, 并不是不可以使用, 而是在使用前先把其中的值寄存在另外一个地方, 用完后再恢复其值.
如果不这样做, 有可能会发生意想不到的错误.
举例:
//使用应该保护的 ebx 寄存器
function Fun(x: Integer): Integer;
asm
  push ebx           {push 是入栈指令, 栈就是系统自动分配的内存}
  mov  ebx, x
  inc  ebx
  mov  @Result, ebx
  pop  ebx           {pop 是出栈指令, 也就是恢复 ebx 寄存器原来的值}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := Fun(8);
  ShowMessage(IntToStr(i)); {9}
end;

初学 Delphi 嵌入汇编[16] - 进制的表示方法
 
关于进制:
生活中有 7进制(星期)、60进制(小时)、10进制(算术)等等.
计算机要用到 10进制、16进制、2进制和 8进制.
8进制用得少了, 但也有, 譬如 Unix 服务器上的文件属性.
2进制是计算机容易识别的; 10进制是人容易识别的, 据说 10进制源自于人有十个手指.
计算机为什么会使用 8进制和 16进制呢? 因为: 23=8; 24=16; 这样比较容易和 2进制换算.
从这里也能看出, 2进制和 10进制的换算相对复杂些.
下面例子中说明了进制的表示方法, 七个函数都会返回整数 255:
//十进制
function Fun0: Integer;
asm
  mov eax, 255
end;
//十进制数后面也可以加个 D(大小写无关)
function Fun1: Integer;
asm
  mov eax, 255D
end;
//二进制后面加 B(大小写无关)
function Fun2: Integer;
asm
  mov eax, 11111111B
end;
//八进制后面加 O(大小写无关)
function Fun3: Integer;
asm
  mov eax, 377O
end;
//十六进制前面加 $
function Fun4: Integer;
asm
  mov eax, $FF
end;
//十六进制也可以是后面加 H(大小写无关)
function Fun5: Integer;
asm
  mov eax, 0FFH {使用这种方法, 数字的首位不能是字母, 不然会被认为成标识符}
end;
//非汇编代码的 Delphi 只支持用 $ 表示十六进制
function Fun6: Integer;
begin
  Result := $FF;
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Fun0)); {255}
  ShowMessage(IntToStr(Fun1)); {255}
  ShowMessage(IntToStr(Fun2)); {255}
  ShowMessage(IntToStr(Fun3)); {255}
  ShowMessage(IntToStr(Fun4)); {255}
  ShowMessage(IntToStr(Fun5)); {255}
  ShowMessage(IntToStr(Fun6)); {255}
end;

初学 Delphi 嵌入汇编[17] - 逻辑运算
 
AND: 逻辑与指令
OR : 逻辑或指令
XOR: 逻辑异或指令
NOT: 逻辑非指令
这和 Delphi 的逻辑命令完全一致.
//逻辑非 Not:
{
  not 1 = 0;
  not 0 = 1;
}
var
  ByteNum: Byte;
begin
  //赋值 11111111B (255) 取反:
  asm
    mov al, 11111111B {eax 包含 ax; ax 包含 al; al 是 eax 的低八位}
    not al            {给 11111111 取反会得到 00000000}
    mov ByteNum, al   {把寄存器 al 中的值给变量 ByteNum}
  end;
  ShowMessage(IntToStr(ByteNum)); {0}
  //赋值 00000001B (1) 取反:
  asm
    mov al, 00000001B
    not al            {给 00000001 取反会得到 11111110}
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {254}
  //赋值 10000000B (128) 取反:
  asm
    mov al, 00000001B
    not al            {给 10000000 取反会得到 01111111}
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {127}
end;
--------------------------------------------------------------------------------
//逻辑或 Or:
{
  1 or 0 = 1;
  0 or 1 = 1;
  1 or 1 = 1;
  0 or 0 = 0;
}
var
  ByteNum: Byte;
begin
  asm
    mov al, 10101010B {170}
    mov cl, 01010101B {85}
    or  al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {255}
end;
--------------------------------------------------------------------------------
//逻辑与 And:
{
  1 and 1 = 1;
  1 and 0 = 0;
  0 and 1 = 0;
  0 and 0 = 0;
}
var
  ByteNum: Byte;
begin
  //例1
  asm
    mov al, 11111111B {255}
    mov cl, 11111111B {255}
    and al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {255}
  //例2
  asm
    mov al, 00000000B {0}
    mov cl, 00000000B {0}
    and al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {0}
  //例3
  asm
    mov al, 11111111B {255}
    mov cl, 00000000B {0}
    and al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {0}
  //例4
  asm
    mov al, 10101010B {170}
    mov cl, 01010101B {85}
    and al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {0}
end;
--------------------------------------------------------------------------------
//逻辑异或 Xor:
{
  1 Xor 0 = 1;
  0 Xor 1 = 1;
  1 Xor 1 = 0;
  0 Xor 0 = 0;
}
var
  ByteNum: Byte;
begin
  //例1
  asm
    mov al, 11111111B {255}
    mov cl, 11111111B {255}
    xor al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {0}
  //例2
  asm
    mov al, 11111111B {255}
    mov cl, 00000000B {0}
    xor al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {255}
  //例3
  asm
    mov al, 10101010B {170}
    mov cl, 01010101B {85}
    xor al, cl
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {255}
end;

初学 Delphi 嵌入汇编[18] - SHL 与 SHR
 
汇编中的SHL(左移)、SHR(右移)命令也是和 Delphi 一样的
var
  ByteNum: Byte;
begin
  //右移 shr
  asm
    mov al, 10000000B {128}
    shr al, 1         {shr 10000000 一次会得到 01000000}
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {64; shr 相当于 ÷2}
  //左移 shl
  asm
    mov al, 00000001B {1}
    shl al, 1            {shl 一次会得到 00000010}
    shl al, 1            {shl 两次会得到 00000100}
    mov ByteNum, al
  end;
  ShowMessage(IntToStr(ByteNum)); {4; shl 相当于 ×2}
end;

初学 Delphi 嵌入汇编[19] - Delphi 的无符号整数类型
 
var
  B: Byte;
  W: Word;
  C: Cardinal;
begin
  {Byte 是1字节(8位)无符号整型, 其最大值是 111111112}
  asm
    mov B, 11111111B;
  end;
  ShowMessage(IntToStr(B)); {255}
  {Word 是2字节(16位)无符号整型, 其最大值是 11111111 111111112}
  asm
    mov W, 1111111111111111B;
  end;
  ShowMessage(IntToStr(W)); {65535}
  {Cardinal 是4字节(32位)无符号整型, 其最大值是 11111111 11111111 11111111 111111112}
  asm
    mov C, 11111111111111111111111111111111B;
  end;
  ShowMessage(IntToStr(C)); {4294967295}
  {它们的最小值都是 0}
end;

初学 Delphi 嵌入汇编[20] - Delphi 的 Integer 类型别
 
var
  I: Integer;
begin
//Integer 类型是4字节(32位)有符号整数, 最高位是符号位, 如果是正数, 符号位是 0、负数的符号位是1
//所以 Integer 的最大值是: 01111111 11111111 11111111 111111112
  asm
    mov I, 01111111111111111111111111111111B;
  end;
  ShowMessage(IntToStr(I)); {2147483647}
//有符号整数的负数等于相同正数的反码 + 1; Integer 最大值是:
//01111111 11111111 11111111 111111112; 其反码是:     
//10000000 00000000 00000000 000000002; 反码 + 1 以后是:
//10000000 00000000 00000000 000000012
  asm
    mov I, 10000000000000000000000000000001B;
  end;
  ShowMessage(IntToStr(I)); {-2147483647}
//那 Integer 的最小值是多少呢?
//应该是: 10000000 00000000 00000000 000000002
  asm
    mov I, 10000000000000000000000000000000B;
  end;
  ShowMessage(IntToStr(I)); {-2147483648}
//11111111 11111111 11111111 111111112 是?
  asm
    mov I, 11111111111111111111111111111111B;
  end;
  ShowMessage(IntToStr(I)); {-1}
//Integer 类型的 0 在内存中是: 00000000 00000000 00000000 000000002
  asm
    mov I, 00000000000000000000000000000000B;
  end;
  ShowMessage(IntToStr(I)); {0}
//Integer 类型的 10010 的二进制是: 00000000 00000000 00000000 011001002
  asm
    mov I, 00000000000000000000000001100100B;
  end;
  ShowMessage(IntToStr(I)); {100}
//算 Integer 类型的 -10010:
//00000000 00000000 00000000 01100100 的反码是:
//11111111 11111111 11111111 10011011 ; 反码 + 1 以后是:
//11111111 11111111 11111111 10011100
  asm
    mov I, 11111111111111111111111110011100B;
  end;
  ShowMessage(IntToStr(I)); {-100}
end;

初学 Delphi 嵌入汇编[21] - Delphi 的其他整数类型
 
除了 Byte、Word、Cardinal、Integer 外, Delphi 的整数类型还有:
Longint、Longword、Shortint、Smallint、Int64
其中 Longint 相当于 Integer; Longword 相当于 Cardinal. 这样还有三种类型:
Shortint、Smallint、Int64
--------------------------------------------------------------------------------
//Shortint 是1字节(8位)有符号整数
var
  I: Shortint;
begin
  //其最大值是: 011111112
  asm
    mov I, 01111111B
  end;
  ShowMessage(IntToStr(I)); {127}
  //其最小值是: 100000002
  asm
    mov I, 10000000B
  end;
  ShowMessage(IntToStr(I)); {-128}
end;
--------------------------------------------------------------------------------
//Shortint 是2字节(16位)有符号整数
var
  I: Smallint;
begin
  //其最大值是: 01111111 111111112
  asm
    mov I, 0111111111111111B
  end;
  ShowMessage(IntToStr(I)); {32767}
  //其最小值是: 10000000 000000002
  asm
    mov I, 1000000000000000B
  end;
  ShowMessage(IntToStr(I)); {-32768}
end;
--------------------------------------------------------------------------------
//Int64 是8字节(64位)的, 暂时的汇编知识, 我还测试不了它.

初学 Delphi 嵌入汇编[22] - 在汇编代码中使用记录
 
//自定义记录用于测试
Type
  TMyRec = record
    i: Integer;
    c: Char;
  end;
//在汇编中使用记录的过程
procedure GetRec(Rec: TMyRec);
asm
  mov eax.TMyRec.i, 100 {eax 会接受第一个参数}
  mov eax.TMyRec.c, 'M'
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  myRec: TMyRec;
begin
  GetRec(myRec);
  ShowMessage(Format('%d, %s',[myRec.i, myRec.c])); {100, M}
end;

初学 Delphi 嵌入汇编[23] - LOOP 循环
 
//计算 x 的 n 次方的函数
function Fun(x,n: Integer): Integer;
asm
//mov eax, x           {因为 eax 会先获取第一个参数, 这句可以省略}
  mov ecx, n             {ecx 是个计数寄存器, 会记录循环的次数, 没循环一次 ecx 的值就会减1}
  @Lable1: add eax, eax  {内部标签必须使用 @ 前缀; 也可以使用 Delphi 的标签}
  loop @Lable1           {循环到标签执行}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Fun(2,10))); {2048}
end;

初学 Delphi 嵌入汇编[24] - 汇编语言的简单数据类型
 
类型 助记符 助记符简写 所占字节数 数值范围
字节 BYTE DB 1 0..255
WORD DW 2 0..65535
双字 DWORD DD 4 0..4294967295
远字 FWORD DF 6  
四字 QWORD DQ 8  
十字节 TBYTE DT 10  
有符号字节 SBYTE   1 -128..127
有符号字 SWORD   1 -32768..32767
有符号双字 SDWORD   1 -2147483648..2147483647

书上抄的, 还没有测试 Delphi 支持情况.

初学 Delphi 嵌入汇编[25] - 在汇编中调用函数
 
//准备一个在汇编中要调用的函数
function DelphiFun(x,y: Integer): Integer;
begin
  Result := x + y;
end;
//汇编函数
function AsmFun: Integer;
asm
  mov eax, 1      {eax 对应函数的第一个参数, 这里给第一个参数赋值为 1}
  mov edx, 2      {edx 对应函数的第二个参数, 这里给第二个参数赋值为 2}
  call DelphiFun  {call 是调用命令; 返回值在 eax}
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
var
  num: Integer;
begin
  num := AsmFun;
  ShowMessage(IntToStr(num)); {3}
end;

初学 Delphi 嵌入汇编[26] - 大小写字母转换
 
//小写字母转大写字母
function Fun1(C: Char): Char;
asm
  sub C, 32
//sub C, 'a'-'A' {竟也可以这样写}
end;
//大写字母转小写字母
function Fun2(C: Char): Char;
asm
  add C, 32
end;
//测试
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(Fun1('b')); {B}
  ShowMessage(Fun2('B')); {b}
end;

初学 Delphi 嵌入汇编[27] - XCHG 指令: 交换寄存器的内容
 
//XCHG 指令: 交换寄存器的内容
var
  x,y: Integer;
begin
  x := 1; y := 9;
  asm
    mov eax, x
    mov ecx, y
    xchg eax, ecx {xchg 的参数必须至少一个是寄存器, 不能有 xchg x,y 类似的操作}
    mov x, eax
    mov y, ecx
  end;
  ShowMessage(Format('x=%d, y=%d',[x,y])); {x=9, y=1}
end;

初学 Delphi 嵌入汇编[28] - 把 EAX 的值置为 0 的三种方法与效率
 
//以下三个函数功能一样, 但效率不同
{Fun1 需要读取常数 0, 最慢}
function Fun1: Integer;
asm
  mov eax, 0
end;
{Fun2 与 Fun3 只是操作 CPU 的寄存器, 比 Fun1 快}
function Fun2: Integer;
asm
  sub eax, eax
end;
{Fun3 最快}
function Fun3: Integer;
asm
  xor eax, eax
end;
//速度测试
procedure TForm1.Button1Click(Sender: TObject);
var
  t: Cardinal;
  i: Integer;
begin
  t := GetTickCount;
  for i := 0 to 100000000 do Fun1;
  t := GetTickCount - t;
  ShowMessage(IntToStr(t)); {均: 600 多}
  t := GetTickCount;
  for i := 0 to 100000000 do Fun2;
  t := GetTickCount - t;
  ShowMessage(IntToStr(t)); {均: 500 多}
  t := GetTickCount;
  for i := 0 to 100000000 do Fun3;
  t := GetTickCount - t;
  ShowMessage(IntToStr(t)); {均: 400 多}
end;


初学 Delphi 嵌入汇编[29] - 寄存器所能接受的数值范围
 
譬如 EAX AX AH AL 四个储存器, 真实存在的其实只有一个 EAX, AX AH AL 不过是不同的访问方式.
11111111 11111111 11111111 11111111 : EAX
11111111 11111111 11111111 11111111 : AX
11111111 11111111 11111111 11111111 : AH
11111111 11111111 11111111 11111111 : AL
//譬如 AX 是一个16位2字节储存器, 它能接受的最大整数是 65535
{下面函数会返回 65535}
function Fun: Integer;
asm
  mov ax, 65535 {给 AX 赋值就是给 EAX 赋值}
end;
{下面函数会出错}
function Fun: Integer;
asm
  mov ax, 65536 {超出了 AX 的容量}
end;
//同样给 AL AH 赋值不能超过 255
{下面函数会返回 255}
function Fun: Integer;
asm
  mov al, 255
end;
{下面函数会返回 65280}
function Fun: Integer;
asm
  mov ah, 255
end;
{为什么不是 255? 因为给 AH 赋值 255 后, EAX 中的值是 00000000 00000000 11111111 000000002}
//上面演示的是通过立即数(常量)赋值, 通过变量也是如此; 但在其他运算中会不会溢出是 CPU 之前不会知道的, 譬如:
{下面的函数不会出错, 但返回的是 0 }
function Fun: Integer;
asm
  mov eax, 4294967295 {这是 eax 所能接受的最大整数}
  add eax, 1          {再 +1 就放不下了}
end;
{因为结果会是: 1 00000000 00000000 00000000 000000002; EAX 只能放下32位, 前面的一位就被忽略了.}
//如果 AX 溢出, EAX 会不会接着?
{下面的函数也会返回 0 , 看来不会进位到 EAX; AX 虽然是 EAX 的一部分, 但使用时也是相对独立的}
function Fun: Integer;
asm
  mov ax, 65535
  add ax, 1
end;
//AH AL 也是如此
{返回 0}
function Fun: Integer;
asm
  mov al, 255
  add al, 1
end;
//对于负数呢?
{下面函数不会有问题, 返回 -1 }
function Fun: Integer;
asm
  mov eax, -1
end;
{它们能接受的最小负整数分别是: }
function Fun: Integer;
asm
  mov al,  -256
  mov ah,  -256
  mov ax,  -63356
  mov eax, -4294967296
end;
{再小于这个数字就会报错! }
//但它们的返回值缺不能所愿, 譬如:
{下面函数会返回 0 }
function Fun: Integer;
asm
  mov eax, -4294967296
end;
{这个好理解, 函数的返回值是 Integer; Integer 的最小值是 -2147483648; 怎么可能放得下 -4294967296? 又被忽略了.}
//其他情况也大概如此, 现在给 AX 一个绝对放得下的一个值: -1
{竟然返回一个正数: 65535, 为什么?}
function Fun: Integer;
asm
  mov ax, -1
end;
{
  因为 -1 在 AX 中被存为: 11111111 111111112;
  这样 EAX 的值是: 00000000 00000000 11111111 111111112;
  EAX 的最高位只有是 1 才有可能是个负数, 现在 EAX 中的值就是: 65535
}
//下面两个函数也是同样的道理:
{返回 255}
function Fun: Integer;
asm
  mov al, -1
end;
{返回 65280}
function Fun: Integer;
asm
  mov ah, -1
end;
//其他允许单独访问低16位和低8位的32位寄存器, 情况肯定也是如此.
 


初学 Delphi 嵌入汇编[30] - 寄存器表
 
类型 名称 二进制码 寄存器说明
多功能寄存器 AL 0 累加寄存器低八位
AH 100 累加寄存器低八位
AX 0 16 位累加寄存器
EAX 0 32 位累加寄存器
BL 11 基址寄存器低八位
BH 111 基址寄存器低八位
BX 11 16 位基址寄存器
EBX 11 32 位基址寄存器
CL 1 计数寄存器低八位
CH 101 计数寄存器低八位
CX 1 16 位计数寄存器
ECX 1 32 位计数寄存器
DL 10 数据寄存器低八位
DH 110 数据寄存器低八位
DX 10 16 位数据寄存器
EDX 10 32 位数据寄存器
指针寄存器 SP 100 16 位堆栈指针寄存器
ESP 100 32 位堆栈指针寄存器
BP 101 16位基址指针寄存器
EBP 101 32 位基址指针寄存器
变址寄存器 DI 111 16 位目标变址寄存器
EDI 111 32位目标变址寄存器
SI 110 16 位源变址寄存器
ESI 110 32位源变址寄存器
专用寄存器 IP * 16 位指令指针寄存器
EIP * 32 位指令指针寄存器
FLAGS * 16 位标志寄存器
EFLAGS * 32位标志寄存器
段寄存器 CS 1 代码段寄存器
DS 11 数据段寄存器
ES 0 附加段寄存器
SS 10 堆栈段寄存器
FS 100 标志段寄存器
GS 101 全局段寄存器
控制寄存器 CR0 0 控制寄存器零
CR1* 1 控制寄存器一
CR2 10 控制寄存器二
CR3 11 控制寄存器三
CR4 100 控制寄存器四
CR5* 101 控制寄存器五
CR6* 110 控制寄存器六
CR7* 111 控制寄存器七
调试寄存器 DR0 0 调试寄存器零
DR1 1 调试寄存器一
DR2 10 调试寄存器二
DR3 11 调试寄存器三
DR4* 100 调试寄存器四
DR5* 101 调试寄存器五
DR6 110 调试寄存器六
DR7 111 调试寄存器七
任务寄存器 TR0 0 任务寄存器零
TR1 1 任务寄存器一
TR2 10 任务寄存器二
TR3 11 任务寄存器三
TR4 100 任务寄存器四
TR5 101 任务寄存器五
TR6 110 任务寄存器六
TR7 111 任务寄存器七
浮点寄存器 ST0 0 浮点寄存器零
ST1 1 浮点寄存器一
ST2 10 浮点寄存器二
ST3 11 浮点寄存器三
ST4 100 浮点寄存器四
ST5 101 浮点寄存器五
ST6 110 浮点寄存器六
ST7 111 浮点寄存器七
多媒体寄存器 MM0 0 媒体寄存器零
MM1 1 媒体寄存器一
MM2 10 媒体寄存器二
MM3 11 媒体寄存器三
MM4 100 媒体寄存器四
MM5 101 媒体寄存器五
MM6 110 媒体寄存器六
MM7 111 媒体寄存器七
单指令流、多数据流寄存器 XMM0 0 单指令流、多数据流寄存器零
XMM1 1 单指令流、多数据流寄存器一
XMM2 10 单指令流、多数据流寄存器二
XMM3 11 单指令流、多数据流寄存器三
XMM4 100 单指令流、多数据流寄存器四
XMM5 101 单指令流、多数据流寄存器五
XMM6 110 单指令流、多数据流寄存器六
XMM7 111 单指令流、多数据流寄存器七
注: 英文名称有星号"*"的表示作为保留域, 实际并没有使用, 二进制码有星号"*"表示无需二进制数表示

  评论这张
 
阅读(568)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017