??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久亚洲av无码专区喷水,免费一级欧美大片久久网,国产精品美女久久久http://m.shnenglu.com/tdweng/category/14700.htmlzh-cnMon, 11 Oct 2010 08:31:56 GMTMon, 11 Oct 2010 08:31:56 GMT60堆和栈的区别 (转脓(chung))http://m.shnenglu.com/tdweng/articles/129415.html心羽心羽Mon, 11 Oct 2010 02:45:00 GMThttp://m.shnenglu.com/tdweng/articles/129415.htmlhttp://m.shnenglu.com/tdweng/comments/129415.htmlhttp://m.shnenglu.com/tdweng/articles/129415.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/129415.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/129415.html非本Z?因非常经?所以收归旗?与众人阅?原作者不?

堆和栈的区别
一、预备知识—程序的内存分配
一个由c/C++~译的程序占用的内存分ؓ(f)以下几个部分
1、栈区(stackQ?nbsp;q译器自动分配释放 Q存攑և数的参数|局部变量的值等。其操作方式cM于数据结构中的栈?br>2、堆区(heapQ?nbsp;?nbsp;一般由E序员分配释放, 若程序员不释放,E序l束时可能由O(jin)S回收 。注意它与数据结构中的堆是两回事Q分配方式倒是cM于链表,呵呵?br>3、全局区(静态区Q(staticQ—,全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在盔R的另一块区域?nbsp;- E序l束后有pȝ释放 
4、文字常量区—常量字W串是攑֜q里的?nbsp;E序l束后由pȝ释放
5、程序代码区—存攑ևC的二q制代码?br>二、例子程?nbsp;
q是一个前辈写的,非常详细 
//main.cpp 
int a = 0; 全局初始化区 
char *p1; 全局未初始化?nbsp;
main() 

int b; ?nbsp;
char s[] = "abc"; ?nbsp;
char *p2; ?nbsp;
char *p3 = "123456"; 123456\0在常量区Qp3在栈上?nbsp;
static int c =0Q?nbsp;全局Q静态)(j)初始化区 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); 
分配得来?0?0字节的区域就在堆区?nbsp;
strcpy(p1, "123456"); 123456\0攑֜帔R区,~译器可能会(x)它与p3所指向?123456"优化成一个地斏V?nbsp;

 


二、堆和栈的理论知?nbsp;
2.1甌方式 
stack: 
ql自动分配?nbsp;例如Q声明在函数中一个局部变?nbsp;int b; pȝ自动在栈中ؓ(f)b开辟空?nbsp;
heap: 
需要程序员自己甌Qƈ指明大小Q在c中malloc函数 
如p1 = (char *)malloc(10); 
在C++中用newq算W?nbsp;
如p2 = (char *)malloc(10); 
但是注意p1、p2本n是在栈中的?nbsp;


2.2 
甌后系l的响应 
栈:(x)只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出?nbsp;
堆:(x)首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ 
?x)遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将该结点的I间分配l程序,另外Q对于大多数pȝQ会(x)在这块内存空间中的首地址处记录本ơ分配的大小Q这P代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正好等于申L(fng)大小Q系l会(x)自动的将多余的那部分重新攑օI闲链表中?nbsp;

2.3甌大小的限?nbsp;
栈:(x)在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是pȝ预先规定好的Q在WINDOWS下,栈的大小?MQ也有的说是1MQM是一个编译时q定的常数Q,如果甌的空间超q栈的剩余空间时Q将提示overflow。因此,能从栈获得的I间较小?nbsp;
堆:(x)堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地址的,自然是不q箋的,而链表的遍历方向是由低地址向高地址。堆的大受限于计算机系l中有效的虚拟内存。由此可见,堆获得的I间比较灉|Q也比较大?nbsp;


2.4甌效率的比较:(x) 
栈由pȝ自动分配Q速度较快。但E序员是无法控制的?nbsp;
堆是由new分配的内存,一般速度比较慢,而且Ҏ(gu)产生内存片,不过用v来最方便. 
另外Q在WINDOWS下,最好的方式是用VirtualAlloc分配内存Q他不是在堆Q也不是在栈是直接在q程的地址I间中保留一快内存,虽然用v来最不方ѝ但是速度快,也最灉|?nbsp;

2.5堆和栈中的存储内?nbsp;
栈:(x) 在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的地址Q然后是函数的各个参敎ͼ在大多数的C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变量。注意静态变量是不入栈的?nbsp;
当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是dC的下一条指令,E序p点l运行?nbsp;
堆:(x)一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容有程序员安排?nbsp;

2.6存取效率的比?nbsp;

char s1[] = "aaaaaaaaaaaaaaa"; 
char *s2 = "bbbbbbbbbbbbbbbbb"; 
aaaaaaaaaaa是在q行时刻赋值的Q?nbsp;
而bbbbbbbbbbb是在~译时就定的; 
但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?快?nbsp;
比如Q?nbsp;
#include 
void main() 

char a = 1; 
char c[] = "1234567890"; 
char *p ="1234567890"; 
a = c[1]; 
a = p[1]; 
return; 

对应的汇~代?nbsp;
10: a = c[1]; 
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 
0040106A 88 4D FC mov byte ptr [ebp-4],cl 
11: a = p[1]; 
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 
00401070 8A 42 01 mov al,byte ptr [edx+1] 
00401073 88 45 FC mov byte ptr [ebp-4],al 
W一U在d时直接就把字W串中的元素d寄存器cl中,而第二种则要先把指针D到edx中,在根据edxd字符Q显然慢了?nbsp;


2.7结Q?nbsp;
堆和栈的区别可以用如下的比喻来看出:(x) 
使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P(j)、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会(x)切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度?nbsp;
使用堆就象是自己动手做喜Ƣ吃的菜_(d)比较ȝ(ch)Q但是比较符合自q口味Q而且自由度大?nbsp;



windowsq程中的内存l构


在阅L文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基知识?nbsp;

接触q编E的人都知道Q高U语a都能通过变量名来讉K内存中的数据。那么这些变量在内存中是如何存放的呢Q程序又是如何用这些变量的呢?下面׃(x)Ҏ(gu)q行深入的讨论。下文中的C语言代码如没有特别声明,默认都用VC~译的release版?nbsp;

首先Q来了解一?nbsp;C 语言的变量是如何在内存分部的。C 语言有全局变量(Global)、本地变?Local)Q静态变?Static)、寄存器变量(Regeister)。每U变量都有不同的分配方式。先来看下面q段代码Q?nbsp;

#include <stdio.h> 

int g1=0, g2=0, g3=0; 

int main() 

static int s1=0, s2=0, s3=0; 
int v1=0, v2=0, v3=0; 

//打印出各个变量的内存地址 

printf("0x%08x\n",&v1); //打印各本地变量的内存地址 
printf("0x%08x\n",&v2); 
printf("0x%08x\n\n",&v3); 
printf("0x%08x\n",&g1); //打印各全局变量的内存地址 
printf("0x%08x\n",&g2); 
printf("0x%08x\n\n",&g3); 
printf("0x%08x\n",&s1); //打印各静态变量的内存地址 
printf("0x%08x\n",&s2); 
printf("0x%08x\n\n",&s3); 
return 0; 

~译后的执行l果是:(x) 

0x0012ff78 
0x0012ff7c 
0x0012ff80 

0x004068d0 
0x004068d4 
0x004068d8 

0x004068dc 
0x004068e0 
0x004068e4 

输出的结果就是变量的内存地址。其中v1,v2,v3是本地变量,g1,g2,g3是全局变量Qs1,s2,s3是静态变量。你可以看到q些变量在内存是q箋分布的,但是本地变量和全局变量分配的内存地址差了十万八千里,而全局变量和静态变量分配的内存是连l的。这是因为本地变量和全局/静态变量是分配在不同类型的内存区域中的l果。对于一个进E的内存I间而言Q可以在逻辑上分?个部份:(x)代码区,静态数据区和动态数据区。动态数据区一般就?#8220;堆栈”?#8220;?stack)”?#8220;?heap)”是两U不同的动态数据区Q栈是一U线性结构,堆是一U链式结构。进E的每个U程都有U有?#8220;?#8221;Q所以每个线E虽然代码一P但本地变量的数据都是互不q扰。一个堆栈可以通过“基地址”?#8220;栈顶”地址来描q。全局变量和静态变量分配在静态数据区Q本地变量分配在动态数据区Q即堆栈中。程序通过堆栈的基地址和偏U量来访问本地变量?nbsp;


├———————┤低端内存区域 
?nbsp;…… ?nbsp;
├———————┤ 
?nbsp;动态数据区 ?nbsp;
├———————┤ 
?nbsp;…… ?nbsp;
├———————┤ 
?nbsp;代码?nbsp;?nbsp;
├———————┤ 
?nbsp;静态数据区 ?nbsp;
├———————┤ 
?nbsp;…… ?nbsp;
├———————┤高端内存区域 


堆栈是一个先q后出的数据l构Q栈地址L于{于栈的基地址。我们可以先了解一下函数调用的q程Q以便对堆栈在程序中的作用有更深入的了解。不同的语言有不同的函数调用规定Q这些因素有参数的压入规则和堆栈的^衡。windows API的调用规则和ANSI C的函数调用规则是不一L(fng)Q前者由被调函数调整堆栈Q后者由调用者调整堆栈。两者通过“__stdcall”?#8220;__cdecl”前缀区分。先看下面这D代码:(x) 

#include <stdio.h> 

void __stdcall func(int param1,int param2,int param3) 

int var1=param1; 
int var2=param2; 
int var3=param3; 
printf("0x%08x\n",¶m1); //打印出各个变量的内存地址 
printf("0x%08x\n",¶m2); 
printf("0x%08x\n\n",¶m3); 
printf("0x%08x\n",&var1); 
printf("0x%08x\n",&var2); 
printf("0x%08x\n\n",&var3); 
return; 

int main() 

func(1,2,3); 
return 0; 

~译后的执行l果是:(x) 

0x0012ff78 
0x0012ff7c 
0x0012ff80 

0x0012ff68 
0x0012ff6c 
0x0012ff70 


├———————┤<—函数执行时的栈ӞESPQ、低端内存区?nbsp;
?nbsp;…… ?nbsp;
├———————┤ 
?nbsp;var 1 ?nbsp;
├———————┤ 
?nbsp;var 2 ?nbsp;
├———————┤ 
?nbsp;var 3 ?nbsp;
├———————┤ 
?nbsp;RET ?nbsp;
├———————┤<?#8220;__cdecl”函数q回后的栈顶QESPQ?nbsp;
?nbsp;parameter 1 ?nbsp;
├———————┤ 
?nbsp;parameter 2 ?nbsp;
├———————┤ 
?nbsp;parameter 3 ?nbsp;
├———————┤<?#8220;__stdcall”函数q回后的栈顶QESPQ?nbsp;
?nbsp;…… ?nbsp;
├———————┤<—栈底(基地址 EBPQ、高端内存区?nbsp;


上图是函数调用q程中堆栈的样子了。首先,三个参数以从又到左的ơ序压入堆栈Q先?#8220;param3”Q再?#8220;param2”Q最后压?#8220;param1”Q然后压入函数的q回地址(RET)Q接着跌{到函数地址接着执行Q这里要补充一点,介绍UNIX下的~冲溢出原理的文章中都提到在压入RET后,l箋压入当前EBPQ然后用当前ESP代替EBP。然而,有一介lwindows下函数调用的文章中说Q在windows下的函数调用也有q一步骤Q但Ҏ(gu)我的实际调试Qƈ未发现这一步,q还可以从param3和var1之间只有4字节的间隙这点看出来Q;W三步,栈?ESP)减去一个数Qؓ(f)本地变量分配内存I间Q上例中是减?2字节(ESP=ESP-3*4Q每个int变量占用4个字?Q接着初始化本地变量的内存空间。由?#8220;__stdcall”调用p调函数调整堆栈,所以在函数q回前要恢复堆栈Q先回收本地变量占用的内?ESP=ESP+3*4)Q然后取回地址Q填入EIP寄存器,回收先前压入参数占用的内?ESP=ESP+3*4)Ql执行调用者的代码。参见下列汇~代码:(x) 

;--------------func 函数的汇~代?------------------ 

:00401000 83EC0C sub esp, 0000000C //创徏本地变量的内存空?nbsp;
:00401003 8B442410 mov eax, dword ptr [esp+10] 
:00401007 8B4C2414 mov ecx, dword ptr [esp+14] 
:0040100B 8B542418 mov edx, dword ptr [esp+18] 
:0040100F 89442400 mov dword ptr [esp], eax 
:00401013 8D442410 lea eax, dword ptr [esp+10] 
:00401017 894C2404 mov dword ptr [esp+04], ecx 

……………………Q省略若q代码)(j) 

:00401075 83C43C add esp, 0000003C ;恢复堆栈Q回收本地变量的内存I间 
:00401078 C3 ret 000C ;函数q回Q恢复参数占用的内存I间 
;如果?#8220;__cdecl”的话Q这里是“ret”Q堆栈将p用者恢?nbsp;

;-------------------函数l束------------------------- 


;--------------ȝ序调用func函数的代?------------- 

:00401080 6A03 push 00000003 //压入参数param3 
:00401082 6A02 push 00000002 //压入参数param2 
:00401084 6A01 push 00000001 //压入参数param1 
:00401086 E875FFFFFF call 00401000 //调用func函数 
;如果?#8220;__cdecl”的话Q将在这里恢复堆栈,“add esp, 0000000C” 

聪明的读者看到这里,差不多就明白~冲溢出的原理了。先来看下面的代码:(x) 

#include <stdio.h> 
#include <string.h> 

void __stdcall func() 

char lpBuff[8]="\0"; 
strcat(lpBuff,"AAAAAAAAAAA"); 
return; 

int main() 

func(); 
return 0; 

~译后执行一下回怎么P哈,“"0x00414141"指o(h)引用?0x00000000"内存。该内存不能?read"?#8221;Q?#8220;非法操作”喽!"41"是"A"?6q制的ASCII码了Q那明显是strcatq句出的问题了?lpBuff"的大只?字节Q算q结\0Q那strcat最多只能写??A"Q但E序实际写入?1?A"外加1个\0。再来看看上面那q图Q多出来?个字节正好覆盖了RET的所在的内存I间Q导致函数返回到一个错误的内存地址Q执行了错误的指令。如果能_ֿ构造这个字W串Q它分成三部分Q前一部䆾仅仅是填充的无意义数据以辑ֈ溢出的目的,接着是一个覆盖RET的数据,紧接着是一DshellcodeQ那只要着个RET地址能指向这Dshellcode的第一个指令,那函数返回时p执行shellcode了。但是Y件的不同版本和不同的q行环境都可能媄(jing)响这Dshellcode在内存中的位|,那么要构造这个RET是十分困隄。一般都在RET和shellcode之间填充大量的NOP指o(h)Q得exploit有更强的通用性?nbsp;


├———————┤<—低端内存区?nbsp;
?nbsp;…… ?nbsp;
├———————┤<—由exploit填入数据的开?nbsp;
?nbsp;?nbsp;
?nbsp;buffer ?lt;—填入无用的数据 
?nbsp;?nbsp;
├———————┤ 
?nbsp;RET ?lt;—指向shellcodeQ或NOP指o(h)的范?nbsp;
├———————┤ 
?nbsp;NOP ?nbsp;
?nbsp;…… ?lt;—填入的NOP指o(h)Q是RET可指向的范围 
?nbsp;NOP ?nbsp;
├———————┤ 
?nbsp;?nbsp;
?nbsp;shellcode ?nbsp;
?nbsp;?nbsp;
├———————┤<—由exploit填入数据的结?nbsp;
?nbsp;…… ?nbsp;
├———————┤<—高端内存区?nbsp;


windows下的动态数据除了可存放在栈中,q可以存攑֜堆中。了解C++的朋友都知道QC++可以使用new关键字来动态分配内存。来看下面的C++代码Q?nbsp;

#include <stdio.h> 
#include <iostream.h> 
#include <windows.h> 

void func() 

char *buffer=new char[128]; 
char bufflocal[128]; 
static char buffstatic[128]; 
printf("0x%08x\n",buffer); //打印堆中变量的内存地址 
printf("0x%08x\n",bufflocal); //打印本地变量的内存地址 
printf("0x%08x\n",buffstatic); //打印静态变量的内存地址 

void main() 

func(); 
return; 

E序执行l果为:(x) 

0x004107d0 
0x0012ff04 
0x004068c0 

可以发现用new关键字分配的内存即不在栈中,也不在静态数据区。VC~译器是通过windows下的“?heap)”来实现new关键字的内存动态分配。在?#8220;?#8221;之前Q先来了解一下和“?#8221;有关的几个API函数Q?nbsp;

HeapAlloc 在堆中申请内存空?nbsp;
HeapCreate 创徏一个新的堆对象 
HeapDestroy 销毁一个堆对象 
HeapFree 释放甌的内?nbsp;
HeapWalk 枚D堆对象的所有内存块 
GetProcessHeap 取得q程的默认堆对象 
GetProcessHeaps 取得q程所有的堆对?nbsp;
LocalAlloc 
GlobalAlloc 

当进E初始化Ӟpȝ?x)自动?f)q程创徏一个默认堆Q这个堆默认所占内存的大小?M。堆对象ql进行管理,它在内存中以铑ּl构存在。通过下面的代码可以通过堆动态申请内存空_(d)(x) 

HANDLE hHeap=GetProcessHeap(); 
char *buff=HeapAlloc(hHeap,0,8); 

其中h(hun)Heap是堆对象的句柄,buff是指向申L(fng)内存I间的地址。那q个hHeapI竟是什么呢Q它的值有什么意义吗Q看看下面这D代码吧Q?nbsp;

#pragma comment(linker,"/entry:main") //定义E序的入?nbsp;
#include <windows.h> 

_CRTIMP int (__cdecl *printf)(const char *, ...); //定义STL函数printf 
/*--------------------------------------------------------------------------- 
写到q里Q我们顺便来复习(fn)一下前面所讲的知识Q?nbsp;
(*?printf函数是C语言的标准函数库中函敎ͼVC的标准函数库由msvcrt.dll模块实现?nbsp;
由函数定义可见,printf的参C数是可变的,函数内部无法预先知道调用者压入的参数个数Q函数只能通过分析W一个参数字W串的格式来获得压入参数的信息,׃q里参数的个数是动态的Q所以必ȝ调用者来q堆栈Q这里便使用了__cdecl调用规则。BTWQW(xu)indowspȝ的API函数基本上是__stdcall调用形式Q只有一个API例外Q那是wsprintfQ它使用__cdecl调用规则Q同printf函数一Pq是׃它的参数个数是可变的~故?nbsp;
---------------------------------------------------------------------------*/ 
void main() 

HANDLE hHeap=GetProcessHeap(); 
char *buff=HeapAlloc(hHeap,0,0x10); 
char *buff2=HeapAlloc(hHeap,0,0x10); 
HMODULE hMsvcrt=LoadLibrary("msvcrt.dll"); 
printf=(void *)GetProcAddress(hMsvcrt,"printf"); 
printf("0x%08x\n",hHeap); 
printf("0x%08x\n",buff); 
printf("0x%08x\n\n",buff2); 

执行l果为:(x) 

0x00130000 
0x00133100 
0x00133118 

hHeap的值怎么和那个buff的值那么接q呢Q其实hHeapq个句柄是指向HEAP首部的地址。在q程的用户区存着一个叫PEB(q程环境?的结构,q个l构中存攄一些有兌E的重要信息Q其中在PEB首地址偏移0x18处存攄ProcessHeap是q程默认堆的地址Q而偏U?x90处存放了指向q程所有堆的地址列表的指针。windows有很多API都用进E的默认堆来存放动态数据,如windows 2000下的所有ANSI版本的函数都是在默认堆中甌内存来{换ANSI字符串到Unicode字符串的。对一个堆的访问是序q行的,同一时刻只能有一个线E访问堆中的数据Q当多个U程同时有访问要求时Q只能排队等待,q样侉K成E序执行效率下降?nbsp;

最后来说说内存中的数据寚w。所位数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍,DWORD数据的内存v始地址能被4除尽QW(xu)ORD数据的内存v始地址能被2除尽Qx86 CPU能直接访问对齐的数据Q当他试图访问一个未寚w的数据时Q会(x)在内部进行一pd的调_(d)q些调整对于E序来说是透明的,但是?x)降低运行速度Q所以编译器在编译程序时?x)尽量保证数据对齐。同样一D代码,我们来看看用VC、Dev-C++和lcc三个不同~译器编译出来的E序的执行结果:(x) 

#include <stdio.h> 

int main() 

int a; 
char b; 
int c; 
printf("0x%08x\n",&a); 
printf("0x%08x\n",&b); 
printf("0x%08x\n",&c); 
return 0; 

q是用VC~译后的执行l果Q?nbsp;
0x0012ff7c 
0x0012ff7b 
0x0012ff80 
变量在内存中的顺序:(x)b(1字节)-a(4字节)-c(4字节)?nbsp;

q是用Dev-C++~译后的执行l果Q?nbsp;
0x0022ff7c 
0x0022ff7b 
0x0022ff74 
变量在内存中的顺序:(x)c(4字节)-中间盔R3字节-b(?字节)-a(4字节)?nbsp;

q是用lcc~译后的执行l果Q?nbsp;
0x0012ff6c 
0x0012ff6b 
0x0012ff64 
变量在内存中的顺序:(x)同上?nbsp;

三个~译器都做到了数据对齐,但是后两个编译器昄没VC“聪明”Q让一个char占了4字节Q浪费内存哦?nbsp;


基础知识Q?nbsp;
堆栈是一U简单的数据l构Q是一U只允许在其一端进行插入或删除的线性表。允许插入或删除操作的一端称为栈Ӟ另一端称为栈底,对堆栈的插入和删除操作被UCؓ(f)入栈和出栈。有一lCPU指o(h)可以实现对进E的内存实现堆栈讉K。其中,POP指o(h)实现出栈操作QPUSH指o(h)实现入栈操作。CPU的ESP寄存器存攑ֽ前线E的栈顶指针QEBP寄存器中保存当前U程的栈底指针。CPU的EIP寄存器存放下一个CPU指o(h)存放的内存地址Q当CPU执行完当前的指o(h)后,从EIP寄存器中d下一条指令的内存地址Q然后l执行?nbsp;


参考:(x)《Windows下的HEAP溢出?qing)其利用》by: isno 
《windows核心~程》by: Jeffrey Richter 



摘要Q?nbsp;讨论常见的堆性能问题以及(qing)如何防范它们。(?nbsp;9 )(j)

前言
(zhn)是否是动态分配的 C/C++ 对象忠实且幸q的用户Q?zhn)是否在模块间的往q通信中频J地使用?#8220;自动?#8221;Q?zhn)的程序是否因堆分配而运行v来很慢?不仅仅?zhn)遇到q样的问题。几乎所有项目迟早都?x)遇到堆问题。大安惌Q?#8220;我的代码真正好,只是堆太?#8221;。那只是部分正确。更深入理解堆及(qing)其用法、以?qing)?x)发生什么问题,是很有用的?/p>

什么是堆?
Q如果?zhn)已经知道什么是堆,可以跛_“什么是常见的堆性能问题Q?#8221;部分Q?/p>

在程序中Q用堆来动态分配和释放对象。在下列情况下,调用堆操作:(x) 

事先不知道程序所需对象的数量和大小?/p>


对象太大而不适合堆栈分配E序?br>堆用了在运行时分配l代码和堆栈的内存之外的部分内存。下囄Z堆分配程序的不同层?br>

GlobalAlloc/GlobalFreeQMicrosoft Win32 堆调用,q些调用直接与每个进E的默认堆进行对话?/p>

LocalAlloc/LocalFreeQWin32 堆调用(Z?nbsp;Microsoft Windows NT 兼容Q,q些调用直接与每个进E的默认堆进行对话?/p>

COM ?nbsp;IMalloc 分配E序Q或 CoTaskMemAlloc / CoTaskMemFreeQ:(x)函数使用每个q程的默认堆。自动化E序使用“lg对象模型 (COM)”的分配程序,而申L(fng)E序使用每个q程堆?/p>

C/C++ q行?nbsp;(CRT) 分配E序Q提供了 malloc() ?nbsp;free() 以及(qing) new ?nbsp;delete 操作W。如 Microsoft Visual Basic ?nbsp;Java {语a也提供了新的操作Wƈ使用垃圾攉来代替堆。CRT 创徏自己的私有堆Q驻留在 Win32 堆的剙?/p>

Windows NT 中,W(xu)in32 堆是 Windows NT q行时分配程序周围的薄层。所?nbsp;API 转发它们的请求给 NTDLL?/p>

Windows NT q行时分配程序提?nbsp;Windows NT 内的核心堆分配程序。它由具?nbsp;128 个大从 8 ?nbsp;1,024 字节的空闲列表的前端分配E序l成。后端分配程序用虚拟内存来保留和提交页?/p>

在图表的底部?#8220;虚拟内存分配E序”Q操作系l用它来保留和提交c(din)所有分配程序用虚拟内存进行数据的存取?/p>

分配和释攑֝不就那么单吗Qؓ(f)何花费这么长旉Q?/p>

堆实现的注意事项
传统上,操作pȝ和运行时库是与堆的实现共存的。在一个进E的开始,操作pȝ创徏一个默认堆Q叫?#8220;q程?#8221;。如果没有其他堆可用,则块的分配?#8220;q程?#8221;。语aq行时也能在q程内创建单独的堆。(例如QC q行时创建它自己的堆。)(j)除这些专用的堆外Q应用程序或许多已蝲入的动态链接库 (DLL) 之一可以创徏和用单独的堆。Win32 提供一整套 API 来创建和使用U有堆。有兛_函数Q英文)(j)的详指|请参?nbsp;MSDN?/p>

当应用程序或 DLL 创徏U有堆时Q这些堆存在于进E空_(d)q且在进E内是可讉K的。从l定堆分配的数据在同一个堆上释放。(不能从一个堆分配而在另一个堆释放。)(j)

在所有虚拟内存系l中Q堆ȝ在操作系l的“虚拟内存理?#8221;的顶部。语aq行时堆也驻留在虚拟内存剙。某些情况下Q这些堆是操作系l堆中的层,而语aq行时堆则通过大块的分配来执行自己的内存管理。不使用操作pȝ堆,而用虚拟内存函数更利于堆的分配和块的用?/p>

典型的堆实现由前、后端分配程序组成。前端分配程序维持固定大块的空闲列表。对于一ơ分配调用,堆尝试从前端列表扑ֈ一个自由块。如果失败,堆被q从后端Q保留和提交虚拟内存Q分配一个大块来满h。通用的实现有每块分配的开销Q这耗费执行周期Q也减少了可使用的存储空间?/p>

Knowledge Base 文章 Q10758Q?#8220;?nbsp;calloc() ?nbsp;malloc() 理内存” Q搜索文章编P(j), 包含了有兌些主题的更多背景知识。另外,有关堆实现和设计的详l讨Z可在下列著作中找刎ͼ(x)“Dynamic Storage Allocation: A Survey and Critical Review”Q作?nbsp;Paul R. Wilson、Mark S. Johnstone、Michael Neely ?nbsp;David BolesQ?#8220;International Workshop on Memory Management”, 作?nbsp;Kinross, Scotland, UK, 1995 q?nbsp;9 ?http://www.cs.utexas.edu/users/oops/papers.html)Q英文)(j)?/p>

Windows NT 的实玎ͼWindows NT 版本 4.0 和更新版本)(j) 使用?nbsp;127 个大从 8 ?nbsp;1,024 字节?nbsp;8 字节寚w块空闲列表和一?#8220;大块”列表?#8220;大块”列表Q空闲列表[0]Q?nbsp;保存大于 1,024 字节的块。空闲列表容U了用双向链表链接在一L(fng)对象。默认情况下Q?#8220;q程?#8221;执行攉操作。(攉是将盔RI闲块合q成一个大块的操作。)(j)攉耗费了额外的周期Q但减少了堆块的内部片?/p>

单一全局锁保护堆Q防止多U程式的使用。(请参?#8220;Server Performance and Scalability Killers”中的W一个注意事? George Reilly 所著,?nbsp;“MSDN Online Web Workshop”上(站点Q?img border=0 align=absMiddle src="http://club.5ivb.net/pic/url.gif">http://msdn.microsoft.com/workshop/server/iis/tencom.aspQ英文)(j)。)(j)单一全局锁本质上是用来保护堆数据l构Q防止跨多线E的随机存取。若堆操作太频繁Q单一全局锁会(x)Ҏ(gu)能有不利的影响?/p>

什么是常见的堆性能问题Q?br>以下是?zhn)使用堆时会(x)遇到的最常见问题Q?nbsp;

分配操作造成的速度减慢。光分配p费很长旉。最可能Dq行速度减慢原因是空闲列表没有块Q所以运行时分配E序代码?x)耗费周期L较大的空闲块Q或从后端分配程序分配新块?/p>


释放操作造成的速度减慢。释放操作耗费较多周期Q主要是启用了收集操作。收集期_(d)每个释放操作“查找”它的盔R块,取出它们q构造成较大块,然后再把此较大块插入I闲列表。在查找期间Q内存可能会(x)随机到Q从而导致高速缓存不能命中,性能降低?/p>


堆竞争造成的速度减慢。当两个或多个线E同时访问数据,而且一个线El进行之前必ȝ待另一个线E完成时发生竞争。竞争LDȝ(ch)Q这也是目前多处理器pȝ遇到的最大问题。当大量使用内存块的应用E序?nbsp;DLL 以多U程方式q行Q或q行于多处理器系l上Q时导致速度减慢。单一锁定的用—常用的解决Ҏ(gu)—意味着使用堆的所有操作是序列化的。当{待锁定时序列化?x)引L(fng)E切换上下文。可以想象交叉\口闪烁的U灯处走走停停导致的速度减慢?nbsp;
竞争通常?x)导致线E和q程的上下文切换。上下文切换的开销是很大的Q但开销更大的是数据从处理器高速缓存中丢失Q以?qing)后来线E复zL的数据重建?/p>

堆破坏造成的速度减慢。造成堆破坏的原因是应用程序对堆块的不正确使用。通常情Ş包括释放已释攄堆块或用已释放的堆块,以及(qing)块的界重写{明N题。(破坏不在本文讨论范围之内。有兛_存重写和泄漏{其他细节,请参?nbsp;Microsoft Visual C++(R) 调试文 。)(j)


频繁的分配和重分配造成的速度减慢。这是用脚本语a旉常普遍的现象。如字符串被反复分配Q随重分配增长和释放。不要这样做Q如果可能,量分配大字W串和用缓冲区。另一U方法就是尽量少用连接操作?br>竞争是在分配和释放操作中D速度减慢的问题。理x况下Q希望用没有竞争和快速分?释放的堆。可惜,现在q没有这L(fng)通用堆,也许来?x)有?/p>

在所有的服务器系l中Q如 IIS、MSProxy、DatabaseStacks、网l服务器?nbsp;Exchange 和其他)(j), 堆锁定实在是个大瓉。处理器数越多,竞争p?x)恶化?/p>

量减少堆的使用
现在(zhn)明白用堆时存在的问题了,N(zhn)不x有能解决q些问题的超U魔吗Q我可希望有。但没有法能堆运行加快—因此不要期望在产品之前的最后一星期能够大ؓ(f)改观。如果提前规划堆{略Q情况将?x)大大好转。调整用堆的方法,减少对堆的操作是提高性能的良斏V?/p>

如何减少使用堆操作?通过利用数据l构内的位置可减堆操作的次数。请考虑下列实例Q?/p>

struct ObjectA {
   // objectA 的数?nbsp;
}

struct ObjectB {
   // objectB 的数?nbsp;
}

// 同时使用 objectA ?nbsp;objectB

//
// 使用指针 
//
struct ObjectB {
   struct ObjectA * pObjA;
   // objectB 的数?nbsp;
}

//
// 使用嵌入
//
struct ObjectB {
   struct ObjectA pObjA;
   // objectB 的数?nbsp;
}

//
// 集合 – 在另一对象内?nbsp;objectA ?nbsp;objectB
//

struct ObjectX {
   struct ObjectA  objA;
   struct ObjectB  objB;
}

避免使用指针兌两个数据l构。如果用指针关联两个数据结构,前面实例中的对象 A ?nbsp;B 被分别分配和释放。这?x)增加额外开销—我们要避免q种做法?/p>


把带指针的子对象嵌入父对象。当对象中有指针Ӟ则意味着对象中有动态元素(癑ֈ之八十)(j)和没有引用的C|。嵌入增加了位置从而减了q一步分?释放的需求。这提高应用程序的性能?/p>


合ƈ对象Ş成大对象Q聚合)(j)。聚合减分配和释放的块的数量。如果有几个开发者,各自开发设计的不同部分Q则最l会(x)有许多小对象需要合q。集成的挑战是要找到正的聚合边界?/p>


内联~冲够满百分之八十的需要(aka 80-20 规则Q。个别情况下Q需要内存缓冲区来保存字W串/二进制数据,但事先不知道d节数。估计ƈ内联一个大能满癑ֈ之八十需要的~冲区。对剩余的百分之二十Q可以分配一个新的缓冲区和指向这个缓冲区的指针。这P减分配和释放调用q增加数据的位置I间Q从Ҏ(gu)上提高代码的性能?/p>


在块中分配对象(块化Q。块化是以组的方式一ơ分配多个对象的Ҏ(gu)。如果对列表的项q箋跟踪Q例如对一?nbsp;{名称Q值} 对的列表Q有两种选择Q选择一是ؓ(f)每一?#8220;名称-?#8221;对分配一个节点;选择二是分配一个能容纳Q如五个Q?#8220;名称-?#8221;对的l构。例如,一般情况下Q如果存储四对,可减少节点的数量,如果需要额外的I间数量Q则使用附加的链表指针?nbsp;
块化是友好的处理器高速缓存,特别是对?nbsp;L1-高速缓存,因ؓ(f)它提供了增加的位|?nbsp;—不用说对于块分配,很多数据块会(x)在同一个虚拟页中?/p>

正确使用 _amblksiz。C q行?nbsp;(CRT) 有它的自定义前端分配E序Q该分配E序从后端(Win32 堆)(j)分配大小?nbsp;_amblksiz 的块。将 _amblksiz 讄高的D潜在地减对后端的调用次数。这只对q泛使用 CRT 的程序适用?br>使用上述技术将获得的好处会(x)因对象类型、大及(qing)工作量而有所不同。但总能在性能和可升羃性方面有所收获。另一斚wQ代码会(x)有点Ҏ(gu)Q但如果l过深思熟虑,代码q是很容易管理的?/p>

其他提高性能的技?br>下面是一些提高速度的技术:(x) 

使用 Windows NT5 ?nbsp;
׃几个同事的努力和辛勤工作Q?998 q初 Microsoft Windows(R) 2000 中有了几个重大改q:(x)

改进了堆代码内的锁定。堆代码Ҏ(gu)堆一个锁。全局锁保护堆数据l构Q防止多U程式的使用。但不幸的是Q在高通信量的情况下,堆仍受困于全局锁,D高竞争和低性能。Windows 2000 中,锁内代码的(f)界区竞争的可能性减到最?从而提高了可׾~性?/p>


使用 “Lookaside”列表。堆数据l构对块的所有空闲项使用了大在 8 ?nbsp;1,024 字节Q以 8-字节递增Q的快速高速缓存。快速高速缓存最初保护在全局锁内。现在,使用 lookaside 列表来访问这些快速高速缓存空闲列表。这些列表不要求锁定Q而是使用 64 位的互锁操作Q因此提高了性能?/p>


内部数据l构法也得到改q?br>q些改进避免了对分配高速缓存的需求,但不排除其他的优化。?nbsp;Windows NT5 堆评估?zhn)的代码;它对?nbsp;1,024 字节 (1 KB) 的块Q来自前端分配程序的块)(j)是最佳的。GlobalAlloc() ?nbsp;LocalAlloc() 建立在同一堆上Q是存取每个q程堆的通用机制。如果希望获得高的局部性能Q则使用 Heap(R) API 来存取每个进E堆Q或为分配操作创q堆。如果需要对大块操作Q也可以直接使用 VirtualAlloc() / VirtualFree() 操作?/p>

上述改进已在 Windows 2000 beta 2 ?nbsp;Windows NT 4.0 SP4 中用。改q后Q堆锁的竞争率显著降低。这使所?nbsp;Win32 堆的直接用户受益。CRT 堆徏立于 Win32 堆的剙Q但它用自q块堆,因而不能从 Windows NT 改进中受益。(Visual C++ 版本 6.0 也有改进的堆分配E序。)(j)

使用分配高速缓?nbsp;
分配高速缓存允?dng)R速缓存分配的块,以便来重用。这能够减少对进E堆Q或全局堆)(j)的分?释放调用的次敎ͼ也允许最大限度的重用曄分配的块。另外,分配高速缓存允许收集统计信?以便较好地理解对象在较高层次上的使用?/p>

典型圎ͼ自定义堆分配E序在进E堆的顶部实现。自定义堆分配程序与pȝ堆的行ؓ(f)很相伹{主要的差别是它在进E堆的顶部ؓ(f)分配的对象提供高速缓存。高速缓存设计成一套固定大(?nbsp;32 字节?4 字节?28 字节{)(j)。这一个很好的{略Q但q种自定义堆分配E序丢失与分配和释放的对象相关的“语义信息”?nbsp;

与自定义堆分配程序相反,“分配高速缓?#8221;作ؓ(f)每类分配高速缓存来实现。除能够提供自定义堆分配E序的所有好处之外,它们q能够保留大量语义信息。每个分配高速缓存处理程序与一个目标二q制对象兌。它能够使用一套参数进行初始化Q这些参数表Cƈ发别、对象大和保持在空闲列表中的元素的数量{。分配高速缓存处理程序对象维持自qU有I闲实体池(不超q指定的阀|(j)q用私有保护锁。合在一P分配高速缓存和U有锁减了与主pȝ堆的通信量,因而提供了增加的ƈ发、最大限度的重用和较高的可׾~性?/p>

需要用清理程序来定期(g)查所有分配高速缓存处理程序的zd情况q回收未用的资源。如果发现没有活动,释攑ֈ配对象的池,从而提高性能?/p>

可以审核每个分配/释放zd。第一U信息包括对象、分配和释放调用的L。通过查看它们的统计信息可以得出各个对象之间的语义关系。利用以上介l的许多技术之一Q这U关pd以用来减内存分配?/p>

分配高速缓存也起到了调试助手的作用Q帮助?zhn)跟踪没有完全清除的对象数量。通过查看动态堆栈返回踪q和除没有清除的对象之外的签名,甚至能够扑ֈ切的失败的调用者?/p>

MP ?nbsp;
MP 堆是对多处理器友好的分布式分配的E序包,?nbsp;Win32 SDKQWindows NT 4.0 和更新版本)(j)中可以得到。最初由 JVert 实现Q此处堆抽象建立?nbsp;Win32 堆程序包的顶部。MP 堆创建多?nbsp;Win32 堆,q试囑ְ分配调用分布C同堆Q以减少在所有单一锁上的竞争?/p>

本程序包是好的步?nbsp;—一U改q的 MP-友好的自定义堆分配程序。但是,它不提供语义信息和缺乏统计功能。通常?nbsp;MP 堆作?nbsp;SDK 库来使用。如果用这?nbsp;SDK 创徏可重用组Ӟ(zhn)将大大受益。但是,如果在每?nbsp;DLL 中徏立这?nbsp;SDK 库,增加工作设|?/p>

重新思考算法和数据l构 
要在多处理器机器上׾~,则算法、实现、数据结构和g必须动态׾~。请看最l常分配和释攄数据l构。试问,“我能用不同的数据l构完成此工作吗Q?#8221;例如Q如果在应用E序初始化时加蝲了只读项的列表,q个列表不必是线性链接的列表。如果是动态分配的数组非常好。动态分配的数组减内存中的堆块和片Q从而增强性能?/p>

减少需要的对象的数量减少堆分配程序的负蝲。例如,我们在服务器的关键处理\径上使用五个不同的对象,每个对象单独分配和释放。一起高速缓存这些对象,把堆调用从五个减到一个,显著减少了堆的负载,特别当每U钟处理 1,000 个以上的h时?/p>

如果大量使用“Automation”l构Q请考虑从主U代码中删除“Automation BSTR”Q或臛_避免重复?nbsp;BSTR 操作。(BSTR q接Dq多的重分配和分?释放操作。)(j)

摘要
Ҏ(gu)有^台往往都存在堆实现Q因此有巨大的开销。每个单独代码都有特定的要求Q但设计能采用本文讨论的基本理论来减堆之间的相互作用?nbsp;

评h(hun)(zhn)的代码中堆的用?/p>


改进(zhn)的代码Q以使用较少的堆调用Q分析关键\径和固定数据l构?/p>


在实现自定义的包装程序之前用量化堆调用成本的方法?/p>


如果Ҏ(gu)能不满意,误?nbsp;OS l改q堆。更多这c请求意味着Ҏ(gu)q堆的更多关注?/p>


要求 C q行时组针对 OS 所提供的堆制作y的分配包装程序。随着 OS 堆的改进QC q行时堆调用的成本将减小?/p>


操作pȝQWindows NT 家族Q正在不断改q堆。请随时x和利用这些改q?br>Murali Krishnan ?nbsp;Internet Information Server (IIS) l的首席软g设计工程师。从 1.0 版本开始他p?nbsp;IISQƈ成功发行?nbsp;1.0 版本?nbsp;4.0 版本。Murali l织q?nbsp;IIS 性能l三q?nbsp;(1995-1998), 从一开始就影响 IIS 性能。他拥有威斯h?nbsp;Madison 大学?nbsp;M.S.和印?nbsp;Anna 大学?nbsp;B.S.。工作之外,他喜Ƣ阅诅R打排球和家庭烹饪?br>


http://community.csdn.net/Expert/FAQ/FAQ_Index.asp?id=172835
我在学习(fn)对象的生存方式的时候见CU是在堆?stack)之中Q如?nbsp; 
CObject  object;  
q有一U是在堆(heap)?nbsp; 如下  
CObject*  pobject=new  CObject();  
 
请问  
Q?Q这两种方式有什么区别?  
Q?Q堆栈与堆有什么区别?Q?nbsp; 
 
 
---------------------------------------------------------------  
 
1)  about  stack,  system  will  allocate  memory  to  the  instance  of  object  automatically,  and  to  the
 heap,  you  must  allocate  memory  to  the  instance  of  object  with  new  or  malloc  manually.  
2)  when  function  ends,  system  will  automatically  free  the  memory  area  of  stack,  but  to  the 
heap,  you  must  free  the  memory  area  manually  with  free  or  delete,  else  it  will  result  in  memory
leak.  
3)栈内存分配运内|于处理器的指o(h)集中Q效率很高,但是分配的内存容量有限?nbsp; 
4Q堆上分配的内存可以有我们自己决定,使用非常灉|?nbsp; 
---------------------------------------------------------------  



心羽 2010-10-11 10:45 发表评论
]]>
汇编常用ȝ(ȝ)http://m.shnenglu.com/tdweng/articles/124507.html心羽心羽Tue, 24 Aug 2010 01:02:00 GMThttp://m.shnenglu.com/tdweng/articles/124507.htmlhttp://m.shnenglu.com/tdweng/comments/124507.htmlhttp://m.shnenglu.com/tdweng/articles/124507.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/124507.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/124507.html1.mov eax [esi+4]与lea eax  [esi+4]
   mov是把esi+4所在地址的gleaxQ也是把esi+4看成指针Q然后eax = *(esi+4)Q而lea是把esi+4的gleaxQ也是eax = esi + 4

心羽 2010-08-24 09:02 发表评论
]]>
汇编中各寄存器的作用http://m.shnenglu.com/tdweng/articles/120852.html心羽心羽Tue, 20 Jul 2010 02:16:00 GMThttp://m.shnenglu.com/tdweng/articles/120852.htmlhttp://m.shnenglu.com/tdweng/comments/120852.htmlhttp://m.shnenglu.com/tdweng/articles/120852.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/120852.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/120852.html
  英文名称QRegister

寄存器定?/h2>   寄存器是中央处理?/u>内的l成部䆾?wbr>寄存器是有限存贮定w的高速存贮部Ӟ它们可用来暂存指令?wbr>数据和位址。在中央处理器的控制部g中,包含的寄存器?a rel=nofollow target=_blank>指o(h)寄存?/u>(IR)?a rel=nofollow target=_blank>E序计数?/u>(PC)?wbr>在中央处理器的算术及(qing)逻辑部g中,包含的寄存器?a rel=nofollow target=_blank>累加?/u>(ACC)?br>
  寄存器是内存阶层中的最端Q?wbr>也是pȝ获得操作资料的最快速途径?wbr>寄存器通常都是以他们可以保存的位元数量来估量,举例来说Q一?“8 位元寄存?#8221;?“32 位元寄存?#8221;。寄存器现在都以寄存器档案的方式来实作,但是他们也可能用单独的正反器、高速的核心内存?wbr>薄膜内存以及(qing)在数U机器上的其他方式来实作出来?
  寄存器通常都用来意指由一个指令之输出或输入可以直接烦(ch)引到的暂存器组。更适当的是UC们ؓ(f) “架构寄存?#8221;?
  例如Qx86 指o(h)?qing)定义八?32 位元寄存器的集合Q但一个实?x86 指o(h)集的 CPU 可以包含比八个更多的寄存器?br>
  寄存器是CPU内部的元Ӟ寄存器拥有非帔R的读写速度Q?wbr>所以在寄存器之间的数据传送非常快?

寄存器用?/h2>   1.可将寄存器内的数据执行算术及(qing)逻辑q算Q?br>
  2.存于寄存器内的地址可用来指向内存的某个位置Q即dQ?br>
  3.可以用来d数据到电(sh)脑的周边讑֤?

数据寄存?/h2>   8086 ?4?6位寄存器Q这14个寄存器按其用途可分ؓ(f)(1)通用寄存器?2)指o(h)指针?3)标志寄存器和(4)D寄存器{?cR?br>
  (1)通用寄存?/strong>?? 又可以分?l?一l是数据寄存?4?,另一l是指针寄存器及(qing)变址寄存?4?.
  数据寄存器分?
  AH&ALQAX(accumulator)Q?/strong>累加寄存器,常用于运?在乘除等指o(h)中指定用来存放操作数,另外,所有的I/O指o(h)都用这一寄存器与外界讑֤传送数?
  BH&BLQBX(base)Q?/strong>基址寄存器,常用于地址索引Q?br>
  CH&CLQCX(count)Q?/strong>计数寄存器,常用于计敎ͼ常用于保存计?如在UM指o(h),循环(loop)和串处理指o(h)中用作隐含的计数?
  DH&DLQDX(data)Q?/strong>数据寄存器,常用于数据传递?br>
  他们的特Ҏ(gu),q??6位的寄存器可以分为高8? AH, BH, CH, DH.以及(qing)低八位:(x)AL,BL,CL,DL?wbr>q?l?位寄存器可以分别dQƈ单独使用?br>
  另一l是指针寄存器和变址寄存器,包括Q?br>
  SPQStack PointerQ:(x)堆栈指针Q与SS配合使用Q?wbr>可指向目前的堆栈位置Q?br>
  BPQBase PointerQ:(x)基址指针寄存器,可用作SS的一个相对基址位置Q?br>
  SIQSource IndexQ:(x)源变址寄存器可用来存放相对于DSD之源变址指针Q?br>
  DIQDestination IndexQ:(x)目的变址寄存器,可用来存攄对于 ES D之目的变址指针?br>
  q??6位寄存器只能?6位进行存取操作,主要用来形成操作数的地址Q?wbr>用于堆栈操作和变址q算中计操作数的有效地址?br>
  (2) 指o(h)指针IP(Instruction Pointer)
  指o(h)指针IP是一?6位专用寄存器Q?wbr>它指向当前需要取出的指o(h)字节Q?wbr>当BIU从内存中取出一个指令字节后QIPp动加1Q?wbr>指向下一个指令字节。注意,IP指向的是指o(h)地址的段内地址偏移量,又称偏移地址(Offset Address)或有效地址(EAQEffective Address)?br>
  (3)标志寄存器FR(Flag Register)
  
8086有一?8位的标志寄存器FRQ?wbr>在FR中有意义的有9位,其中6位是状态位Q?位是控制位?br>
  OFQ?/strong> 溢出标志位OF用于反映有符h加减q算所得结果是否溢出?wbr>如果q算l果过当前q算位数所能表C的范围Q则UCؓ(f)溢出Q?wbr>OF的D|ؓ(f)1Q否则,OF的D清ؓ(f)0?br>
  DFQ?/strong>方向标志DF位用来决定在串操作指令执行时有关指针寄存?wbr>发生调整的方向?
  IFQ?/strong>中断允许标志IF位用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志ؓ(f)何|CPU都必d应CPU外部的不可屏蔽中断所发出的中断请求,以及(qing)CPU内部产生的中断请求。具体规定如下:(x)
  (1)、当IF=1ӞCPU可以响应CPU外部的可屏蔽中断发出的中断请求;
  (2)、当IF=0ӞCPU不响应CPU外部的可屏蔽中断发出的中断请求?
  TFQ?/strong>跟踪标志TF。该标志可用于程序调试?wbr>TF标志没有专门的指令来讄或清楚?br>
  Q?Q如果TF=1Q则C(j)PU处于单步执行指o(h)的工作方式,此时每执行完一条指令,显CCPU内各个寄存器的当前值及(qing)CPU要执行的下一条指?wbr>?br>
  Q?Q如果TF=0Q则处于q箋工作模式?br>
  SFQ?/strong>W号标志SF用来反映q算l果的符号位Q?wbr>它与q算l果的最高位相同。在微机pȝ中,有符h采用补码表示法,所以,SF也就反映q算l果的正负号?wbr>q算l果为正数时QSF的gؓ(f)0Q否则其gؓ(f)1?
  ZFQ?/strong> 零标志ZF用来反映q算l果是否?。如果运结果ؓ(f)0Q?wbr>则其gؓ(f)1Q否则其gؓ(f)0。在判断q算l果是否?Ӟ可用此标志位?
  AFQ?/strong>下列情况下,辅助q位标志AF的D|ؓ(f)1Q?wbr>否则其gؓ(f)0Q?
  (1)、在字操作时Q发生低字节向高字节q位或借位Ӟ
  (2)、在字节操作Ӟ发生?位向?位进位或借位时?
  PFQ?/strong>奇偶标志PF用于反映q算l果?#8220;1”的个数的奇偶性?wbr>如果“1”的个Cؓ(f)偶数Q则PF的gؓ(f)1Q否则其gؓ(f)0?
  CFQ?/strong>q位标志CF主要用来反映q算是否产生q位或借位?wbr>如果q算l果的最高位产生了一个进位或借位Q那么,其gؓ(f)1Q?wbr>否则其gؓ(f)0?
  4)D寄存器(Segment Register)
  Zq用所有的内存I间Q?086讑֮了四个段寄存器,专门用来保存D地址Q?br>
  CSQCode SegmentQ:(x)代码D寄存器Q?br>
  DSQData SegmentQ:(x)数据D寄存器Q?br>
  SSQStack SegmentQ:(x)堆栈D寄存器Q?br>
  ESQExtra SegmentQ:(x)附加D寄存器?br>
  当一个程序要执行Ӟp军_E序代码?wbr>数据和堆栈各要用到内存的哪些位置Q通过讑֮D寄存器 CSQDSQSS 来指向这些v始位|。通常是将DS固定Q而根据需要修改CS?wbr>所以,E序可以在可dI间于64K的情况下被写成Q意大?所以,E序和其数据l合h的大,限制在DS 所指的64K内,q就是COM文g不得大于64K的原因?wbr>8086以内存做为战场,用寄存器做ؓ(f)军事基地Q以加速工作?br>
  以上?086寄存器的整体概况, ?0386开始,PCq入32bit时代Q其d方式Q?wbr>寄存器大? 功能{都发生了变化:(x)
  =============================以下?0386的寄存器的一些资?=====================================
  寄存器都?2-bits宽?br>
  A、通用寄存?
  下面介绍通用寄存器及(qing)其习(fn)惯用法。顾名思义Q?wbr>通用寄存器是那些你可以根据自q意愿使用的寄存器Q?wbr>修改他们的值通常不会(x)对计机的运行造成很大的媄(jing)响?wbr>通用寄存器最多的用途是计算?
  EAXQ通用寄存器。相对其他寄存器Q在q行q算斚w比较常用?wbr>在保护模式中Q也可以作ؓ(f)内存偏移指针Q此ӞDS作ؓ(f)D?寄存器或选择器)(j)
  EBXQ通用寄存器。通常作ؓ(f)内存偏移指针使用Q相对于EAX?wbr>ECX、EDXQ,DS是默认的D寄存器或选择器?wbr>在保护模式中Q同样可以vq个作用?
  ECXQ通用寄存器。通常用于特定指o(h)的计数。在保护模式中,也可以作为内存偏UL针(此时QDS作ؓ(f) 寄存器或D选择器)(j)?br>
  EDXQ通用寄存器。在某些q算中作为EAX的溢出寄存器Q?wbr>例如乘、除Q。在保护模式中,也可以作为内存偏UL针(此时Q?wbr>DS作ؓ(f)D?寄存器或选择器)(j)?
  同AX分ؓ(f)AH&AL一P上述寄存器包括对应的16-bit分组?-bit分组?
  B、用作内存指针的Ҏ(gu)寄存?br>
  ESIQ通常在内存操作指令中作ؓ(f)“源地址指针”使用。当?dng)?wbr>ESI可以被装入Q意的数|但通常没有人把它当作通用寄存器来用?wbr>DS是默认段寄存器或选择器?
  EDIQ通常在内存操作指令中作ؓ(f)“目的地址指针”使用。当?dng)?wbr>EDI也可以被装入L的数|但通常没有人把它当作通用寄存器来用?wbr>DS是默认段寄存器或选择器?
  EBPQ这也是一个作为指针的寄存器。通常Q?wbr>它被高语言~译器用以徏?#8216;堆栈?来保存函数或q程的局部变量,不过Q还是那句话Q?wbr>你可以在其中保存你希望的M数据?wbr>SS是它的默认段寄存器或选择器?
  注意Q这三个寄存器没有对应的8-bit分组。换a之,你可以通过SI、DI、BP作ؓ(f)别名讉K他们的低16位,却没有办法直接访问他们的?位?
  C、段选择器:(x)
  实模式下的段寄存器到保护模式下摇w一变就成了选择器?wbr>不同的是Q实模式下的“D寄存器”?6-bit的,而保护模式下的选择器是32-bit的?
  CS 代码D,或代码选择器。同IP寄存?E后介绍)一同指向当前正在执行的那个地址?wbr>处理器执行时从这个寄存器指向的段Q实模式Q或内存Q保护模式)(j)中获取指令。除了蟩转或其他分支指o(h)之外Q?wbr>你无法修改这个寄存器的内宏V?
  DS 数据D,或数据选择器。这个寄存器的低16 bitq同ESI一同指向的指o(h)要处理的内存。同Ӟ所有的内存操作指o(h) 默认情况下都用它指定操作D?实模?或内?作ؓ(f)选择器,在保护模式。这个寄存器可以被装入Q意数|然而在q么做的时候需要小心一些。方法是Q首先把数据送给AXQ?wbr>然后再把它从AX传送给DS(当然Q也可以通过堆栈来做).
  ES 附加D,或附加选择器。这个寄存器的低16 bitq同EDI一同指向的指o(h)要处理的内存。同L(fng)Q?wbr>q个寄存器可以被装入L数|Ҏ(gu)和DScM?
  FS FD|F选择?推测F可能是Free?)?wbr>可以用这个寄存器作ؓ(f)默认D寄存器或选择器的一个替代品?wbr>它可以被装入M数|Ҏ(gu)和DScM?
  GS GD|G选择?G的意义和F一P没有在Intel的文中解释)。它和FS几乎完全一栗?
  SS 堆栈D|堆栈选择器。这个寄存器的低16 bitq同ESP一同指向下一ơ堆栈操?push和pop)所要用的堆栈地址。这个寄存器也可以被装入L数|你可以通过入栈和出栈操作来l他赋|不过׃堆栈对于很多操作有很重要的意义,因此Q?wbr>不正的修改有可能造成对堆栈的破坏?
  * 注意 一定不要在初学汇编的阶D|q些寄存器弄淗他们非帔R要,而一旦你掌握了他们,你就可以对他们做L的操作了。段寄存器,或选择器,在没有指定的情况下都是用默认的那个?wbr>q句话在现在看来可能有点E里糊涂,不过你很快就?x)在后面知道如何d?
  指o(h)指针寄存器:(x)
  EIP q个寄存器非常的重要。这是一?2位宽的寄存器 Q同CS一同指向即执行的那条指o(h)的地址?wbr>不能够直接修改这个寄存器的|修改它的唯一Ҏ(gu)是蟩转或分支指o(h)?CS是默认的D|选择?
  上面是最基本的寄存器。下面是一些其他的寄存器,你甚臛_能没有听说过它们?都是32位宽)Q?br>
  CR0, CR2, CR3(控制寄存?。D一个例子,CR0的作用是切换实模式和保护模式?
  q有其他一些寄存器QD0, D1, D2, D3, D6和D7(调试寄存??wbr>他们可以作ؓ(f)调试器的g支持来设|条件断炏V?
  TR3, TR4, TR5, TR6 ?TR? 寄存?试寄存?用于某些条g试

最q在学汇~,看到q篇文章Q文章的原出处已l查不出来了Q但觉得不错Q所以{出来Q当作备份学?fn)?/p>

4个数据寄存器(EAX、EBX、ECX和EDX)
2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)
6个段寄存?ES、CS、SS、DS、FS和GS)
1个指令指针寄存器(EIP) 1个标志寄存器(EFlags)

1、数据寄存器
数据寄存器主要用来保存操作数和运结果等信息Q从而节省读取操作数所需占用ȝ和访问存储器的时间?2位CPU??2位的通用寄存器EAX、EBX、ECX和EDX。对?6位数据的存取Q不?x)?jing)响高16位的数据。这些低16位寄存器分别命名为:(x)AX、BX、CX和DXQ它和先前的CPU中的寄存器相一致?/p>

4?6位寄存器又可分割?个独立的8位寄存器(AXQAH-AL、BXQBH-BL、CXQCH-CL、DXQDH-DL)Q每个寄存器都有自己的名Uͼ可独立存取。程序员可利用数据寄存器的这U?#8221;可分可合”的特性,灉|地处理字/字节的信息?br>寄存器AX和AL通常UCؓ(f)累加?Accumulator)Q用累加器进行的操作可能需要更时间。篏加器可用于乘?除、输?输出{操作,它们的用频率很高; 寄存器BXUCؓ(f)基地址寄存?Base Register)。它可作为存储器指针来用; 寄存器CXUCؓ(f)计数寄存?Count Register)。在循环和字W串操作Ӟ要用它来控制循环ơ数Q在位操?中,当移多位Ӟ要用CL来指明移位的位数Q?br>寄存器DXUCؓ(f)数据寄存?Data Register)。在q行乘、除q算Ӟ它可作ؓ(f)默认的操作数参与q算Q也可用于存放I/O的端口地址。在16位CPU中,AX、BX、CX和DX不能作ؓ(f)基址和变址寄存器来存放存储单元的地址Q但?2位CPU中,?2位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑q算l果Q而且也可作ؓ(f)指针寄存器,所以,q些32位寄存器更具有通用性?br>2、变址寄存?br>32位CPU??2位通用寄存器ESI和EDI。其?6位对应先前CPU中的SI和DIQ对?6位数据的存取Q不影响?6位的数据?br>寄存器ESI、EDI、SI和DIUCؓ(f)变址寄存?Index Register)Q它们主要用于存攑֭储单元在D内的偏U量Q用它们可实现多U存储器操作数的d方式Qؓ(f)以不同的地址形式讉K存储单元提供方便。变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储术逻辑q算的操作数和运结果。它们可作一般的存储器指针用。在字符串操作指令的执行q程中,对它们有特定的要求,而且q具有特D的功能?br>3、指针寄存器
32位CPU??2位通用寄存器EBP和ESP。其?6位对应先前CPU中的SBP和SPQ对?6位数据的存取Q不影响?6位的数据?br>寄存器EBP、ESP、BP和SPUCؓ(f)指针寄存?Pointer Register)Q主要用于存攑֠栈内存储单元的偏U量Q用它们可实现多U存储器操作数的d方式Qؓ(f)以不同的地址形式讉K存储单元提供方便。指针寄存器不可分割?位寄存器。作为通用寄存器,也可存储术逻辑q算的操作数和运结果?br>它们主要用于讉K堆栈内的存储单元Qƈ且规定:(x)
BP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据;
SP为堆栈指?Stack Pointer)寄存器,用它只可讉K栈顶?br>4、段寄存?br>D寄存器是根据内存分D늚理模式而设|的。内存单元的物理地址由段寄存器的值和一个偏U量l合而成
的,q样可用两个较少位数的值组合成一个可讉K较大物理I间的内存地址?br>CPU内部的段寄存器:(x)
CS——代码段寄存?Code Segment Register)Q其gؓ(f)代码D늚D|
DS——数据段寄存?Data Segment Register)Q其gؓ(f)数据D늚D|
ES——附加段寄存?Extra Segment Register)Q其gؓ(f)附加数据D늚D|
SS——堆栈段寄存?Stack Segment Register)Q其gؓ(f)堆栈D늚D|
FS——附加段寄存?Extra Segment Register)Q其gؓ(f)附加数据D늚D|
GS——附加段寄存?Extra Segment Register)Q其gؓ(f)附加数据D늚D倹{?/p>

?6位CPUpȝ中,它只?个段寄存器,所以,E序在Q何时刻至多有4个正在用的D可直接讉KQ在32位微机系l中Q它?个段寄存器,所以,在此环境下开发的E序最多可同时讉K6个段?2位CPU有两个不同的工作方式Q实方式和保护方式。在每种方式下,D寄存器的作用是不同的。有兌定简单描q如下:(x)
实方式:(x) ?个段寄存器CS、DS、ES和SS与先前CPU中的所对应的段寄存器的含义完全一_(d)内存单元的逻辑地址仍ؓ(f)”D|(x)偏移?#8221;的Ş式。ؓ(f)讉K某内存段内的数据Q必M用该D寄存器和存储单元的偏移量?br>保护方式Q?在此方式下,情况要复杂得多,装入D寄存器的不再是D|而是UCؓ(f)”选择?#8221;(Selector)的某个倹{?br>5、指令指针寄存器
32位CPU把指令指针扩展到32位,q记作EIPQEIP的低16位与先前CPU中的IP作用相同?br>指o(h)指针EIP、IP(Instruction Pointer)是存放下ơ将要执行的指o(h)在代码段的偏U量。在h预取指o(h)功能的系l中Q下ơ要执行的指令通常已被预取到指令队列中Q除非发生{ULc(din)所以,在理解它们的功能Ӟ不考虑存在指o(h)队列的情c(din)?br>在实方式下,׃每个D늚最大范围ؓ(f)64KQ所以,EIP中的?6位肯定都?Q此Ӟ相当于只用其?6位的IP来反映程序中指o(h)的执行次序?br>6、标志寄存器
一、运结果标志位
1、进位标志CF(Carry Flag)
q位标志CF主要用来反映q算是否产生q位或借位。如果运结果的最高位产生了一个进位或借位Q那么,其gؓ(f)1Q否则其gؓ(f)0。用该标志位的情况有:(x)多字(字节)数的加减q算Q无W号数的大小比较q算Q移位操作,?字节)之间UMQ专门改变CF值的指o(h){?br>2、奇偶标志PF(Parity Flag)
奇偶标志PF用于反映q算l果?#8221;1″的个数的奇偶性。如?#8221;1″的个Cؓ(f)偶数Q则PF的gؓ(f)1Q否则其gؓ(f)0?br>利用PF可进行奇偶校验检查,或生奇偶校验位。在数据传送过E中Qؓ(f)了提供传送的可靠性,如果采用奇偶校验的方法,可使用该标志位?br>3、辅助进位标志AF(Auxiliary Carry Flag)
在发生下列情冉|Q辅助进位标志AF的D|ؓ(f)1Q否则其gؓ(f)0Q?br>(1)、在字操作时Q发生低字节向高字节q位或借位Ӟ
(2)、在字节操作Ӟ发生?位向?位进位或借位时?br>对以?个运结果标志位Q在一般编E情况下Q标志位CF、ZF、SF和OF的用频率较高,而标志位PF和AF的用频率较低?br>4、零标志ZF(Zero Flag)
零标志ZF用来反映q算l果是否?。如果运结果ؓ(f)0Q则其gؓ(f)1Q否则其gؓ(f)0。在判断q算l果是否?Ӟ可用此标志位?br>5、符h志SF(Sign Flag)
W号标志SF用来反映q算l果的符号位Q它与运结果的最高位相同。在微机pȝ中,有符h采用补码表示法,所以,SF也就反映q算l果的正负号。运结果ؓ(f)正数ӞSF的gؓ(f)0Q否则其gؓ(f)1?br>6、溢出标志OF(Overflow Flag)
溢出标志OF用于反映有符h加减q算所得结果是否溢出。如果运结果超q当前运位数所能表C的范围Q则UCؓ(f)溢出QOF的D|ؓ(f)1Q否则,OF的D清ؓ(f)0?#8221;溢出”?#8221;q位”是两个不同含义的概念Q不要؜淆。如果不太清楚的话,h阅《计机l成原理》课E中的有关章节?br>二、状态控制标志位
状态控制标志位是用来控制CPU操作的,它们要通过专门的指令才能之发生改变?br>1、追t标志TF(Trap Flag)
当追t标志TF被置?ӞCPUq入单步执行方式Q即每执行一条指令,产生一个单步中断请求。这U方式主要用于程序的调试。指令系l中没有专门的指令来改变标志位TF的|但程序员可用其它办法来改变其倹{?br>2、中断允许标志IF(Interrupt-enable Flag)
中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志ؓ(f)何|CPU都必d应CPU外部的不可屏蔽中断所发出的中断请求,以及(qing)CPU内部产生的中断请求。具体规定如下:(x)
(1)、当IF=1ӞCPU可以响应CPU外部的可屏蔽中断发出的中断请求;
(2)、当IF=0ӞCPU不响应CPU外部的可屏蔽中断发出的中断请求?br>CPU的指令系l中也有专门的指令来改变标志位IF的倹{?br>3、方向标志DF(Direction Flag)
方向标志DF用来军_在串操作指o(h)执行时有x针寄存器发生调整的方向。具体规定在W?.2.11节——字W串操作指o(h)——中l出。在微机的指令系l中Q还提供了专门的指o(h)来改变标志位DF的倹{?br>三?2位标志寄存器增加的标志位
1、I/OҎ(gu)标志IOPL(I/O Privilege Level)
I/OҎ(gu)标志用两位二q制位来表示Q也UCؓ(f)I/OҎ(gu)U字Dc(din)该字段指定了要求执行I/O指o(h)的特权。如果当前的Ҏ(gu)U别在数g于{于IOPL的|那么Q该I/O指o(h)可执行,否则发生一个保护异常?br>2、嵌套Q务标志NT(Nested Task)
嵌套d标志NT用来控制中断q回指o(h)IRET的执行。具体规定如下:(x)
(1)、当NT=0Q用堆栈中保存的值恢复EFLAGS、CS和EIPQ执行常规的中断q回操作Q?br>(2)、当NT=1Q通过d转换实现中断q回?br>3、重启动标志RF(Restart Flag)
重启动标志RF用来控制是否接受调试故障。规定:(x)RF=0Ӟ表示”接受”调试故障Q否则拒l之。在成功执行完一条指令后Q处理机把RF|ؓ(f)0Q当接受C个非调试故障Ӟ处理机就把它|ؓ(f)1?br>4、虚?086方式标志VM(Virtual 8086 Mode)
如果该标志的gؓ(f)1Q则表示处理机处于虚拟的8086方式下的工作状态,否则Q处理机处于一般保护方式下的工作状?/p>


本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/liguodong86/archive/2009/03/02/3949721.aspx



心羽 2010-07-20 10:16 发表评论
]]>
汇编中的寄存器说?/title><link>http://m.shnenglu.com/tdweng/articles/118903.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Tue, 29 Jun 2010 02:24:00 GMT</pubDate><guid>http://m.shnenglu.com/tdweng/articles/118903.html</guid><wfw:comment>http://m.shnenglu.com/tdweng/comments/118903.html</wfw:comment><comments>http://m.shnenglu.com/tdweng/articles/118903.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/tdweng/comments/commentRss/118903.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/tdweng/services/trackbacks/118903.html</trackback:ping><description><![CDATA[<p>汇编中的寄存器说?br>汇编语言和CPU以及(qing)内存,端口{硬件知识是q在一L(fng). q也是ؓ(f)什么汇~语a没有通用性的原因. 下面单讲讲基本知?针对INTEL x86?qing)其兼容? ============================ <br>x86汇编语言的指?其操作对象是CPU上的寄存?pȝ内存,或者立x. 有些指o(h)表面上没有操作数, 或者看上去~少操作? 其实该指令有内定的操作对? 比如push指o(h), 一定是对SS:ESP指定的内存操? 而cdq的操作对象一定是eax / edx. 在汇~语a?寄存器用名字来访? <br>CPU 寄存器有好几c? 分别有不同的用处: <br>  <span style="COLOR: red"> <strong>1. 通用寄存? EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP(q个虽然通用,但很被用做除了堆栈指针外的用? q些32位可以被用作多种用?但每一个都?专长".</strong></span> <br>   EAX ?累加?(accumulator), 它是很多加法乘法指o(h)的缺省寄存器.<br>   EBX ?基地址"(base)寄存? 在内存寻址时存攑֟地址. <br>   ECX 是计数器(counter), 是重?REP)前缀指o(h)和LOOP指o(h)的内定计数器.<br>   EDX?..(忘了..哈哈)但它L被用来放整数除法产生的余? q?个寄存器的低16位可以被单独讉K,分别用AX,BX,CX和DX. AX又可以单独访问低8?AL)和高8?AH), BX,CX,DX也类? 函数的返回值经常被攑֜EAX?<br>   ESI/EDI分别叫做"?目标索引寄存?(source/destination index),因ؓ(f)在很多字W串操作指o(h)? <br>   DS:ESI指向源串,而ES:EDI指向目标? EBP?基址指针"(BASE POINTER), 它最l常被用作高U语a函数调用?框架指针"(frame pointer). 在破解的时?l常可以看见一个标准的函数起始代码: push ebp ;保存当前ebp mov ebp,esp ;EBP设ؓ(f)当前堆栈指针 sub esp, xxx ;预留xxx字节l函C(f)时变? ... q样一?EBP 构成了该函数的一个框? 在EBP上方分别是原来的EBP, q回地址和参? EBP下方则是临时变量. 函数q回时作 mov esp,ebp/pop ebp/ret 卛_. ESP 专门用作堆栈指针. <br><span style="COLOR: red"><strong>2. D寄存器: CS(Code SegmentQ代码段) 指定当前执行的代码段</strong></span><br>EIP (Instruction pointer, 指o(h)指针)则指向该D中一个具体的指o(h). CS:EIP指向哪个指o(h), CPU 执行它. 一般只能用jmp, ret, jnz, call {指令来改变E序程,而不能直接对它们赋? DS(DATA SEGMENT, 数据D? 指定一个数据段. 注意:在当前的计算机系l中, 代码和数据没有本质差? 都是一串二q制? 区别只在于你如何用它. 例如, CS 制定的段L被用作代? 一般不能通过CS指定的地址M改该D? 然?你可以ؓ(f)同一个段甌一个数据段描述W?别名"而通过DS来访?修改. 自修改代码的E序常如此做. ES,FS,GS 是辅助的D寄存器, 指定附加的数据段. SS(STACK SEGMENT)指定当前堆栈D? ESP 则指D中当前的堆栈顶. 所有push/pop pd指o(h)都只对SS:ESP指出的地址q行操作.<br> <span style="COLOR: red"><strong>3. 标志寄存?EFLAGS): 该寄存器?2?l合了各个系l标?</strong></span><br> EFLAGS一般不作ؓ(f)整体讉K, 而只对单一的标志位感兴? 常用的标志有: q位标志C(CARRY), 在加法生进位或减法有借位时置1, 否则?. 零标志Z(ZERO), 若运结果ؓ(f)0则置1, 否则? W号位S(SIGN), 若运结果的最高位|?, 则该位也|?. 溢出标志O(OVERFLOW), ?带符?q算l果出可表C? 则置1. JXX pd指o(h)是Ҏ(gu)q些标志来决定是否要跌{, 从而实现条件分? 要注?很多JXX 指o(h)是等L(fng), 对应相同的机器码. 例如, JE 和JZ 是一L(fng),都是当Z=1是蟩? 只有JMP 是无条g跌{. JXX 指o(h)分ؓ(f)两组, 分别用于无符h作和带符h? JXX 后面?XX" 有如下字? 无符h? 带符h? A = "ABOVE", 表示"高于" G = "GREATER", 表示"大于" B = "BELOW", 表示"低于" L = "LESS", 表示"于" C = "CARRY", 表示"q位"?借位" O = "OVERFLOW", 表示"溢出" S = "SIGN", 表示"? 通用W号: E = "EQUAL" 表示"{于", {h(hun)于Z (ZERO) N = "NOT" 表示"?, x志没有置? 如JNZ "如果Z没有|位则蟩? Z = "ZERO", 与E? 如果仔细想一?׃(x)发现 JA = JNBE, JAE = JNB, JBE = JNA, JG = JNLE, JGE= JNL, JL= JNGE, .... <br><span style="COLOR: red"><strong>4. 端口 端口是直接和外部讑֤通讯的地斏V?/strong></span><br>外设接入pȝ后,pȝ׃(x)把外讄数据接口映射到特定的端口地址I间Q这P从该端口d数据是从外设读入数据,而向外设写入数据是向端口写入数据。当然这一切都必须遵@外设的工作方式。端口的地址I间与内存地址I间无关Q系ld提供?4K?位端口的讉KQ编?-65535. 盔R?位端口可以组成成一?6位端口,盔R?6位端口可以组成一?2位端口。端口输入输出由指o(h)IN,OUT,INS和OUTS实现Q具体可参考汇~语a书籍</p> <p><br> </p> <img src ="http://m.shnenglu.com/tdweng/aggbug/118903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/tdweng/" target="_blank">心羽</a> 2010-06-29 10:24 <a href="http://m.shnenglu.com/tdweng/articles/118903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://m.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.rongchenjiaxiao.cn" target="_blank">91Ըߺþþþ</a>| <a href="http://www.ccfnt.com.cn" target="_blank">˾þþAV츾ɫ</a>| <a href="http://www.jiqirenedu.cn" target="_blank">ȾþùƷ</a>| <a href="http://www.srxug.cn" target="_blank">ۺϳ˾þС˵ </a>| <a href="http://www.shairproperty.cn" target="_blank">þþƷ˵</a>| <a href="http://www.16pk8.cn" target="_blank">þǿdŮ</a>| <a href="http://www.um258.cn" target="_blank">ҹŷƷþþþþþ</a>| <a href="http://www.gangniao.cn" target="_blank">þ99Ʒ</a>| <a href="http://www.0838auto.cn" target="_blank">ŷƷƵһþþþƷ </a>| <a href="http://www.xabger.cn" target="_blank">þٸ۲AVר</a>| <a href="http://www.danongyao.cn" target="_blank">þ66͵Ʒ9</a>| <a href="http://www.hystech.cn" target="_blank">þûƵ</a>| <a href="http://www.seowiki.com.cn" target="_blank">Ʒþþ</a>| <a href="http://www.sklly.cn" target="_blank">ھƷþþþþþþõӰ</a>| <a href="http://www.itshirts.cn" target="_blank">þþƷ۲ӰԺ</a>| <a href="http://www.sywanfu.cn" target="_blank">þþƷˬӰ</a>| <a href="http://www.ryjv.cn" target="_blank">þþþƷ޳18վ</a>| <a href="http://www.xadfj.cn" target="_blank">þþ㽶ۺϼձ</a>| <a href="http://www.projector8.cn" target="_blank">뾫Ʒþþ</a>| <a href="http://www.kxtravel.com.cn" target="_blank">Ļɫ͵͵þ</a>| <a href="http://www.geishi.cn" target="_blank">þ޵Ӱ</a>| <a href="http://www.51maicha.cn" target="_blank">þùƷҰAV</a>| <a href="http://www.facai365.cn" target="_blank">Ʒþþþþþ</a>| <a href="http://www.buniss.cn" target="_blank">99þһa</a>| <a href="http://www.haowang888.cn" target="_blank">Ĺ˾Ʒþò </a>| <a href="http://www.qraw.cn" target="_blank">þøŮ߳MBA</a>| <a href="http://www.njkyt.cn" target="_blank">þѹۿƵ</a>| <a href="http://www.oysport.cn" target="_blank">ƷŷþþþӰ</a>| <a href="http://www.bjztxdty.cn" target="_blank">¾þþþa</a>| <a href="http://www.hjpz333.cn" target="_blank">þþþĻɫ</a>| <a href="http://www.eu0i.cn" target="_blank">þþƷѴƬƬ</a>| <a href="http://www.ldzx.sh.cn" target="_blank">Ӱһþþþó˾Ʒۺ </a>| <a href="http://www.zjfinancial.cn" target="_blank">avttþþƷ</a>| <a href="http://www.macsales.cn" target="_blank">鶹AV뾫Ʒþ</a>| <a href="http://www.hdmi-cable.cn" target="_blank">޹ƷۺϾþһ</a>| <a href="http://www.3second.cn" target="_blank">þþþƷձһ</a>| <a href="http://www.kwk9605.cn" target="_blank">999Ʒþþþþ</a>| <a href="http://www.emkx1.cn" target="_blank">ݺɫ˾þþƷۺ</a>| <a href="http://www.ffsqblcj.cn" target="_blank">ܻƺ۵վþmimiɫ</a>| <a href="http://www.gven.cn" target="_blank">þþƷһapp</a>| <a href="http://www.tb901.cn" target="_blank">ȫɫƴɫƬѾþþ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>