Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1685|回复: 2

通用寄存器的作用

[复制链接]

1214

主题

1975

帖子

7486

积分

认证用户组

Rank: 5Rank: 5

积分
7486
发表于 2020-2-10 13:00:54 | 显示全部楼层 |阅读模式
通用寄存器的作用

数据寄存器不讲,简单的说,段寄存器(ES,CS,SS,DS,FS,GS)和变址寄存器(SI,DI)是配合使用访问段数据的,指针寄存器(BP,SP)是用来操作堆栈的,BP指向栈的基址,SP则永远指向栈顶。

另外指令指针EIP存放的是要执行的下一条指令在代码段里的偏移量,在实方式下,每个段的最大范围都是64K,所以EIP的高16位都是0

寄存器的分类
寄存器
主 要 用 途
数据
 
寄存器
AX
乘、除运算,字的输入输出,中间结果的缓存
AL
字节的乘、除运算,字节的输入输出,十进制算术运算
AH
字节的乘、除运算,存放中断的功能号
BX
存储器指针
CX
串操作、循环控制的计数器
CL
移位操作的计数器
DX
字的乘、除运算,间接的输入输出
变址
寄存器
SI
存储器指针、串指令中的源操作数指针
DI
存储器指针、串指令中的目的操作数指针
变址
寄存器
BP
存储器指针、存取堆栈的指针
SP
堆栈的栈顶指针
指令指针
IP/EIP
[size=9.0000pt]
标志位寄存器
Flag/EFlag
[size=9.0000pt]
32
CPU
段寄存器
16CPU
段寄存器
ES
附加段寄存器
CS
代码段寄存器
SS
堆栈段寄存器
DS
数据段寄存器
新增加的
段寄存器
FS
附加段寄存器
GS
附加段寄存器







---------------------------------
1、数据寄存器
数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。
32CPU432位的通用寄存器EAXEBXECXEDX。对低16位数据的存取,不会影响高16位的数据。这些低16位寄存器分别命名为:AXBXCXDX,它和先前的CPU中的寄存器相一致。
416位寄存器又可分割成8个独立的8位寄存器(AXAH-ALBXBH-BLCXCH-CLDXDH-DL),每个寄存器都有自己的名称,可独立存取。程序员可利用数据寄存器的这种可分可合的特性,灵活地处理字/字节的信息。
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps1.png
寄存器AX[size=9.0000pt]和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps2.png
寄存器BX称为基地址寄存器(Base Register)。它可作为存储器指针来使用;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps3.png
寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps4.png
寄存器DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。
16CPU中,AXBXCXDX不能作为基址和变址寄存器来存放存储单元的地址,但在32CPU中,其32位寄存器EAXEBXECXEDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性。详细内容请见第3.8——32位地址的寻址方式。
2、变址寄存器
32CPU232位通用寄存器ESIEDI。其低16位对应先前CPU中的SIDI,对低16位数据的存取,不影响高16位的数据。
寄存器ESIEDISIDI称为变址寄存器(Index Register),它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器操作数的寻址方式(在第3章有详细介绍),为以不同的地址形式访问存储单元提供方便。
变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
它们可作一般的存储器指针使用。在字符串操作指令的执行过程中,对它们有特定的要求,而且还具有特殊的功能。具体描述请见第5.2.11节。
3、指针寄存器
32CPU232位通用寄存器EBPESP。其低16位对应先前CPU中的SBPSP,对低16位数据的存取,不影响高16位的数据。
寄存器EBPESPBPSP称为指针寄存器(Pointer Register),主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器操作数的寻址方式(在第3章有详细介绍),为以不同的地址形式访问存储单元提供方便。
指针寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
它们主要用于访问堆栈内的存储单元,并且规定:
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps5.png
BP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps6.png
SP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶。
4、段寄存器
段寄存器是根据内存分段的管理模式而设置的。内存单元的物理地址由段寄存器的值和一个偏移量组合而成的,这样可用两个较少位数的值组合成一个可访问较大物理空间的内存地址。
CPU内部的段寄存器:
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps7.png
CS——代码段寄存器(Code Segment Register),其值为代码段的段值;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps8.png
DS——数据段寄存器(Data Segment Register),其值为数据段的段值;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps9.png
ES——附加段寄存器(Extra Segment Register),其值为附加数据段的段值;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps10.png
SS——堆栈段寄存器(Stack Segment Register),其值为堆栈段的段值;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps11.png
FS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值;
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml6184\wps12.png
GS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值。
16CPU系统中,它只有4个段寄存器,所以,程序在任何时刻至多有4个正在使用的段可直接访问;在32位微机系统中,它有6个段寄存器,所以,在此环境下开发的程序最多可同时访问6个段。
32CPU有两个不同的工作方式:实方式和保护方式。在每种方式下,段寄存器的作用是不同的。有关规定简单描述如下:
实方式:
4个段寄存器CS[size=9.0000pt]、DS[size=9.0000pt]、ES[size=9.0000pt]和SS与先前CPU中的所对应的段寄存器的含义完全一致,内存单元的逻辑地址仍为段值:偏移量的形式。为访问某内存段内的数据,必须使用该段寄存器和存储单元的偏移量。
保护方式:
在此方式下,情况要复杂得多,装入段寄存器的不再是段值,而是称为选择子”(Selector)的某个值。段寄存器的具体作用在此不作进一步介绍了,有兴趣的读者可参阅其它科技资料。
5、指令指针寄存器
32CPU把指令指针扩展到32位,并记作EIPEIP的低16位与先前CPU中的IP作用相同。
指令指针EIPIP(Instruction Pointer)是存放下次将要执行的指令在代码段的偏移量。在具有预取指令功能的系统中,下次要执行的指令通常已被预取到指令队列中,除非发生转移情况。所以,在理解它们的功能时,不考虑存在指令队列的情况。
在实方式下,由于每个段的最大范围为64K,所以,EIP中的高16位肯定都为0,此时,相当于只用其低16位的IP来反映程序中指令的执行次序。
2.7 int 10h bois中断说明
INT 10H 是由 BIOS 对屏幕及显示器所提供的服务程序,而后倚天公司针对倚天中文提供了许多服务程序,这些服务程序也加挂在 INT 10H 内。使用 INT 10H 中断服务程序时,先指定 AH 寄存器为下表编号其中之一,该编号表示欲调用的功用,而其他寄存器的详细说明,参考表后文字,当一切设定好之后再调用 INT 10H。底下是它们的说明:
AH
功 能
调用参数
返回参数 / 注释
1
 置光标类型
  (CH0―3 = 光标开始行[size=9.0000pt]
  (CL0―3 = 光标结束行
[size=9.0000pt]
2
 置光标位置
  BH = 页号 [size=9.0000pt]
  DH = [size=9.0000pt]
  DL = 列  
[size=9.0000pt]
3
 读光标位置
  BH = 页号
 CH = 光标开始行[size=9.0000pt]
 CL = 光标结束行[size=9.0000pt]
  DH = [size=9.0000pt]
 DL =
4
 置显示页
  AL = 显示页号
[size=9.0000pt]
5
 屏幕初始化或上卷
[size=9.0000pt]
[size=9.0000pt]
6
 屏幕初始化或上卷
  AL = 上卷行数 [size=9.0000pt]
  AL =0全屏幕为空白 [size=9.0000pt]
  BH = 卷入行属性[size=9.0000pt]
  CH = 左上角行号 [size=9.0000pt]
  CL = 左上角列号 [size=9.0000pt]
  DH = 右下角行号 [size=9.0000pt]
  DL = 右下角列号
[size=9.0000pt]
7
 屏幕初始化或下卷
  AL = 下卷行数[size=9.0000pt]
  AL = 0全屏幕为空白 [size=9.0000pt]
  BH = 卷入行属性[size=9.0000pt]
  CH = 左上角行号 [size=9.0000pt]
  CL = 左上角列号 [size=9.0000pt]
  DH = 右下角行号 [size=9.0000pt]
  DL = 右下角列号
[size=9.0000pt]
8
 读光标位置的属性和字符
  BH = 显示页
 AH = 属性[size=9.0000pt]
 AL = 字符
9
 在光标位置显示字符及其属性
  BH = 显示页[size=9.0000pt]
  AL = 字符[size=9.0000pt]
   BL = 属性[size=9.0000pt]
  CX = 字符重复次数
[size=9.0000pt]
A
 在光标位置只显示字符
  BH = 显示页[size=9.0000pt]
  AL = 字符 [size=9.0000pt]
   CX = 字符重复次数
[size=9.0000pt]
E
 显示字符(光标前移)
  AL = 字符[size=9.0000pt]
  BL = 前景色
 光标跟随字符移动
13
 显示字符串
  ES:BP = 串地址 [size=9.0000pt]
  CX = 串长度 [size=9.0000pt]
  DHDL = 起始行列 [size=9.0000pt]
  BH = 页号[size=9.0000pt]
  AL = 0BL = 属性 [size=9.0000pt]
  串:Charchar……char[size=9.0000pt]
  AL = 1BL = 属性 [size=9.0000pt]
  串:Charchar……char [size=9.0000pt]
   AL = 2 [size=9.0000pt]
  串:Charattr……charattr [size=9.0000pt]
  AL = 3 [size=9.0000pt]
  串:Charattr……charattr
[size=9.0000pt]
[size=9.0000pt]
[size=9.0000pt]
[size=9.0000pt]
 光标返回起始位置[size=9.0000pt]
[size=9.0000pt]
 光标跟随移动[size=9.0000pt]
[size=9.0000pt]
[size=9.0000pt]
 光标返回起始位置[size=9.0000pt]
[size=9.0000pt]
[size=9.0000pt]
 光标跟随串移动

回复

使用道具 举报

11

主题

17

帖子

940

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
940
发表于 2020-2-17 19:43:44 | 显示全部楼层
SS, SP, BP 三个寄存器

SS:存放栈的段地址;
SP:堆栈寄存器SP(stack pointer)存放栈的偏移地址;
BP: 基数指针寄存器BP(base pointer)是一个寄存器,它的用途有点特殊,是和堆栈指针SP联合使用的,作为SP校准使用的,只有在寻找堆栈里的数据和使用个别的寻址方式时候才能用到
比如说,堆栈中压入了很多数据或者地址,你肯定想通过SP来访问这些数据或者地址,但SP是要指向栈顶的,是不能随便乱改的,这时候你就需要使用BP,把SP的值传递给BP,通过BP来寻找堆栈里数据或者地址.一般除了保存数据外,可以作为指针寄存器用于存储器寻址,此时它默认搭配的段寄存器是SS-堆栈段寄存器.BP16位的,再扩充16位就是EBP,用于32位编程环境的.一般高级语言的参数传递等等,转换为汇编后经常由BP/EBP来负责寻址\处理.
SP,BP一般与段寄存器SS 联用,以确定堆栈寄存器中某一单元的地址,SP用以指示栈顶的偏移地址,BP可 作为堆栈区中的一个基地址,用以确定在堆栈中的操作数地址。
(下面这个像Win32汇编中的)
bp为基址寄存器,一般在函数中用来保存进入函数时的sp的栈顶基址
每次子函数调用时,系统在开始时都会保存这个两个指针并在函数结束时恢复spbp的值。像下面这样:
在函数进入时:
push bp     // 保存bp指针
mov bp,sp  // sp指针传给bp,此时bp指向sp的基地址。
                  // 这个时候,如果该函数有参数,则[bp + 2*4]则是该子函数的第一个参数,[bp+3*4]则是该子函数的 第二个参数,以此类推,有多少个参数则[bp+(n-1)*4]
.....
.....
函数结束时:
mov sp,bp  // 将原sp指针传回给sp
pop bp       // 恢复原bp的值。
ret              // 退出子函数

http://my.oschina.net/orion/blog/15879
下面是按调用约定__stdcall 调用函数test(int p1,int p2)的汇编代码
;假设执行函数前堆栈指针ESPNN
push   p2    ;参数2入栈, ESP -= 4h , ESP = NN - 4h
push   p1    ;参数1入栈, ESP -= 4h , ESP = NN - 8h
call test       ;压入返回地址 ESP -= 4h, ESP = NN - 0Ch (注意CALL指令会把返回地址压入堆栈)
;//进入函数内
{
push   ebp                                     ;保护先前EBP指针, EBP入栈, ESP-=4h, ESP = NN - 10h
mov    ebp, esp                             ;设置EBP指针指向栈顶 NN-10h
mov    eax, dword ptr  [ebp+0ch]  ;ebp+0chNN-4h,即参数2的位置 这里可以看到了BP的作用了
mov    ebx, dword ptr  [ebp+08h]  ;ebp+08hNN-8h,即参数1的位置 这里可以看到了BP的作用了
ub    esp, 8                                  ;局部变量所占空间ESP-=8, ESP = NN-18h (栈底的地址大)
                                                      ;这里就是为局部变量申请空间.
...
add    esp, 8                                  ;释放局部变量, ESP+=8, ESP = NN-10h
                                                      ;(假设在上面的指令中EBP没变的话, 直接MOV ESP, EBP即可达到堆栈平衡,
                                                      ; 事实上也经常这么用)
pop    ebp                                      ;出栈,恢复EBP, ESP+=4, ESP = NN-0Ch
ret    8                                           ;ret返回,弹出返回地址,ESP+=4, ESP=NN-08h,
                                                     ; 后面加操作数8为平衡堆栈,ESP+=8,ESP=NN, 恢复进入函数前的堆栈
                                                     ; 为什么是8? 因为Test子函数有两个参数, 8就是对应了两个参数入栈时SP减少了8
}
原来ESP就是一直指向栈顶的指针,EBP只是存取某时刻的栈顶指针,以方便对栈的操作,如获取函数参数、局部变量等

回复 支持 反对

使用道具 举报

1214

主题

1975

帖子

7486

积分

认证用户组

Rank: 5Rank: 5

积分
7486
 楼主| 发表于 2020-2-17 20:53:06 | 显示全部楼层
SS, SP, BP 三个寄存器

SS:存放栈的段地址;
SP:堆栈寄存器SP(stack pointer)存放栈的偏移地址;
BP: 基数指针寄存器BP(base pointer)是一个寄存器,它的用途有点特殊,是和堆栈指针SP联合使用的,作为SP校准使用的,只有在寻找堆栈里的数据和使用个别的寻址方式时候才能用到
比如说,堆栈中压入了很多数据或者地址,你肯定想通过SP来访问这些数据或者地址,但SP是要指向栈顶的,是不能随便乱改的,这时候你就需要使用BP,把SP的值传递给BP,通过BP来寻找堆栈里数据或者地址.一般除了保存数据外,可以作为指针寄存器用于存储器寻址,此时它默认搭配的段寄存器是SS-堆栈段寄存器.BP16位的,再扩充16位就是EBP,用于32位编程环境的.一般高级语言的参数传递等等,转换为汇编后经常由BP/EBP来负责寻址\处理.
SP,BP一般与段寄存器SS 联用,以确定堆栈寄存器中某一单元的地址,SP用以指示栈顶的偏移地址,BP可 作为堆栈区中的一个基地址,用以确定在堆栈中的操作数地址。
(下面这个像Win32汇编中的)
bp为基址寄存器,一般在函数中用来保存进入函数时的sp的栈顶基址
每次子函数调用时,系统在开始时都会保存这个两个指针并在函数结束时恢复spbp的值。像下面这样:
在函数进入时:
push bp     // 保存bp指针
mov bp,sp  // sp指针传给bp,此时bp指向sp的基地址。
                  // 这个时候,如果该函数有参数,则[bp + 2*4]则是该子函数的第一个参数,[bp+3*4]则是该子函数的 第二个参数,以此类推,有多少个参数则[bp+(n-1)*4]
.....
.....
函数结束时:
mov sp,bp  // 将原sp指针传回给sp
pop bp       // 恢复原bp的值。
ret              // 退出子函数

http://my.oschina.net/orion/blog/15879
下面是按调用约定__stdcall 调用函数test(int p1,int p2)的汇编代码
;假设执行函数前堆栈指针ESPNN
push   p2    ;参数2入栈, ESP -= 4h , ESP = NN - 4h
push   p1    ;参数1入栈, ESP -= 4h , ESP = NN - 8h
call test       ;压入返回地址 ESP -= 4h, ESP = NN - 0Ch (注意CALL指令会把返回地址压入堆栈)
;//进入函数内
{
push   ebp                                     ;保护先前EBP指针, EBP入栈, ESP-=4h, ESP = NN - 10h
mov    ebp, esp                             ;设置EBP指针指向栈顶 NN-10h
mov    eax, dword ptr  [ebp+0ch]  ;ebp+0chNN-4h,即参数2的位置 这里可以看到了BP的作用了
mov    ebx, dword ptr  [ebp+08h]  ;ebp+08hNN-8h,即参数1的位置 这里可以看到了BP的作用了
ub    esp, 8                                  ;局部变量所占空间ESP-=8, ESP = NN-18h (栈底的地址大)
                                                      ;这里就是为局部变量申请空间.
...
add    esp, 8                                  ;释放局部变量, ESP+=8, ESP = NN-10h
                                                      ;(假设在上面的指令中EBP没变的话, 直接MOV ESP, EBP即可达到堆栈平衡,
                                                      ; 事实上也经常这么用)
pop    ebp                                      ;出栈,恢复EBP, ESP+=4, ESP = NN-0Ch
ret    8                                           ;ret返回,弹出返回地址,ESP+=4, ESP=NN-08h,
                                                     ; 后面加操作数8为平衡堆栈,ESP+=8,ESP=NN, 恢复进入函数前的堆栈
                                                     ; 为什么是8? 因为Test子函数有两个参数, 8就是对应了两个参数入栈时SP减少了8
}
原来ESP就是一直指向栈顶的指针,EBP只是存取某时刻的栈顶指针,以方便对栈的操作,如获取函数参数、局部变量等

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|firemail ( 粤ICP备15085507号-1 )

GMT+8, 2024-3-29 01:54 , Processed in 0.073342 second(s), 19 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表