首页
社区
课程
招聘
[翻译][超基础][超简单][译]数据传送指令深窥
2005-5-3 21:44 7356

[翻译][超基础][超简单][译]数据传送指令深窥

2005-5-3 21:44
7356
出处:http://www.osix.net/modules/article/?id=595

说明:虽然超简单,竟也被我奇迹般的译的错误百出,只望大侠们一笑.

译者:aalloverred

数据传送指令深窥

数据传送(及拷贝)汇编语言中应被充分理解的一项基本技术.本文将深入的解读
我们如何在程序内部来回传送数据,以及如何做到高效.

尽管本文是为新手写的,但是熟练的程序员也可借此重温已有技术.文后还有小测
验可以测试你新学到的技能.

-----------------------
汇编语言-基本指令
数据传送指令深窥
-----------------------
作者 Giovanni Tropeano 于11/2004
为 OSIX 而作

<<文章目录<<

...前言
...数据拷贝-必要动作
...测测你学到了什么

:::前言:::
这是我为OSIX做的第3篇文章,而且我已经开始喜欢上了写教程这个东东.这次我
们将详细的复习汇编语言中用于传送数据的基本指令.

读完本文之后,你将学会:
如何在内存和CPU寄存器之间拷贝数据
如何在寄存器之间拷贝数据
如何使用xchg指令
传送数据的操作码
MOV的限制

本文针对新手,但熟练的汇编程序员也可能从中学到些东西.

现在开始...

::: 数据拷贝-必要动作 :::
几乎所有的程序都会将数据从一个地方拷贝到另一个地方.使用汇编语言时,它是
通过使用MOV指令完成的.每个MOV指令都有如下的形式:

MOV 目的,源

它将一个字节,字或双字从源操作数地址拷贝到目的操作数地址.原地址的数据不
会变化.而目的和源必须大小相同.MOV指令与高级语言中的赋值表达式相似,例如
在Visual Basic中:

myNumber = 128
myVariable = myNumber

在汇编中的对应形式会象下面这样:

mov myVariable, ecx ;myVariable = myNumber

(假设ECX包含myNumber中的数据,而myVariable双字大小,位于内存中)
可是再复杂些这种类比就会不成立,比如下面的例子:
myVariable = 3 * myNumber + 1
就不可能只用一个MOV指令标示出来.事实上,要完成这句需要几行指令(稍候我们
再实现).在将结果拷贝到目的地之前需要用乘法指令计算右边表达式的值.

80x86处理器中使用MOV指令有些限制.其中一条就是不能由内存拷贝到内存,比如
下面的做法就是不正确的,

这将产生错误:
mov 变量1, 变量2

如果仔细观察一下,你会发现传送字和传送双字的MOV指令的操作码是相同的。
的确,80x86处理器为每个活动的段保存一个段描述,其中有一位就是用来决定操
作数默认是16位还是32位的.这位为1表示操作数是32位的.所以比如 B8 操作数
意思是将操作数中双字立即数拷贝到EAX,而不是将字立即数拷贝到AX.如果你编
写16位指令 mov ax,0 那么编译器将在目标码前插入字节66,实际生成为66 B8
0000.一般讲,前缀66告诉编译器,对于前缀后的那条指令,操作数要由默认的大小
(32位或16位)转而使用另一种大小(16位或32位).

/*你究竟是怎么知道这些的,Trope(作者)?!?试试就知道了.*/

有时候指令会影响标志寄存器中的某些位.一条指令可能有三种影响:

没有标志变化
某些特定的标志根据指令的结果变为某个特定值
一些指令会发生变化,但它们的值无法预测

所有的mov指令都属第一类,即任何mov指令都不会改变任何标志.

时刻都记住重要的一点,即一些你认为好像合乎逻辑的事情恰恰是mov指令办不到
的.其中就有下面这些指令:

传送的源和目的都在存储器内
立即数传送到段寄存器
由标志寄存器中传入或传出
传送到指令指针寄存器
由一个段寄存器传送到另一个段寄存器
传送的操作数大小不相等
几个对象一同传送

那要是真需要执行这些操作怎么办呢?好问题!让我们解决其中一些.
尽管没有mov指令实现由内存到内存的传送,我们可以用下面的方法实现.比如,

不正确的内存到内存传送
mov Count, Number ; 两个内存操作数是不正确的

但是我们可以用下面的方法达到这个目的:
mov eax, Number ; Count := Number
mov Count, eax

每条指令都是用了寄存器EAX作为一个操作数.你也可以使用其他的可用的寄存
器.

现在,如果想要将一个立即数载入到段寄存器,可以这样实现:

使用一个16位Mov将立即数传送到寄存器
再使用一个mov将16位寄存器传送到段寄存器

要将数据由字大小变为字节大小,如下面的做法就是合理的,即将字传入16位寄存
器,然后仅将其高字节或低字节传送到目的地.反过来,我们也可以16位寄存器的
高低字节合在一起,将产生的结果字传送到某个目的地.

比如已经将源地址和目的地址声明为了

source DWORD 4 DUP(?)
dest DWORD 4 DUP(?)

要将四个双字由源传送到目的,一种方法就是使用四条指令

mov dest, source ; 拷贝第一个双字
mov dest+4, source+4 ; 拷贝第二个双字
mov dest+8, source+8 ; 拷贝第三个双字
mov dest+12, source+12 ; 拷贝第四个双字

形如source+4的地址指向地址source后的四个字节(一个双字)处.因为四个双字
在内存中是连续存储的,所以source+4指向第二个双字.

下面要说一个功能强大的命令,汇编中的XCHG指令.它能由一条指令完成高级语言
中3,4指令才能完成的功能.

现假设要交换Value1和Value2的值.在高级语言中会由类似下面的方法实现:
Temp := Value1; { 交换 Value1 和 Value2 }
Value1 := Value2;
Value2 := Temp;
假定Value1在EAX中,Value2在EBX中,要实现与上面相同的功能可以这样:
xchg eax, ebx ; 交换 Value1 和 Value2
也可以不使用xchg这样实现:
模仿XCHG指令
     mov ecx, eax ; 交换 Value1 和 Value2
     mov eax, ebx
     mov ebx, ecx
不能用xchg 交换两个都在内存中的操作数.

与mov指令相同,xchg指令也不影响任何一个状态标志.就是说,xchg指令执行
后,EFLAGS寄存器中的内容与指令执行前相比保持不变.

::: 结论 :::
好了,你一路读了过来,希望你从文章中学到了些什么.如果我能得到文章的反馈,
我会很高兴做的更多-只要还有人读它们!;)

现在...开心一下.做做下面的测试.如果你愿意的话,将答案发给我!

::: 测试自己!! :::

如果有兴趣,将你的答案通过OSIX的PM将你的答案发给我,我会告诉你你做的怎么
样.(仅对新手o!)
1.在问题的每一部分中,假定了给定的mov执行的"执行前"值.请给出要求的"执行后"值./*好运!*/

执行前-指令-执行后
(a) BX: FF 75      
                - mov bx, cx- BX, CX
    CX: 01 A2

(b) AX: 01 A2- mov ax, 100- AX

(c) AX: 01 4B- mov ah, 0 AX- AX

(d) ECX: 00 00 00 00- mov ecx, 128- ECX

(e) AL: 64- mov al, -1- AL

祝 好!
Trope

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞7
打赏
分享
最新回复 (2)
雪    币: 85496
活跃值: (198820)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
linhanshi 2005-5-3 22:16
2
0
辛苦了
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
qiweixue 19 2005-5-7 18:16
3
0
深入机器语言....一张庞大复杂的真值表
游客
登录 | 注册 方可回帖
返回