程序访问信息

IA32的整数寄存器

在IA32中央处理单元(CPU)中,包含了8个32位整数寄存器(如下图)。从图中可以看到在每个32位寄存器的名字前面都会有一个%e,在这里可以把e理解成extended(扩展的),因为早期的8086寄存器是16位,所以加e之后就变成32位的了。

这里写图片描述

虽然现在的寄存器是32位的了,但仍然不影响我们对16位寄存器的使用,图中的ax,cx,dx,bx,si,di,sp,bp均是16位寄存器,并且也可用通过ah访问ax的高8位,al访问ax的低8位(cx,dx,bx访问方法类似)。

一般而言,前面6个32位寄存器都是通用的,除开某些特定操作会用到特定的寄存器之外,你可以随意使用它们。除此之外,在过程(functions)处理中,针对前3个寄存器的处理会不同于后3个,但目前来说,你并不需要关心这些差异。
但值得注意的是:最后两个寄存器是不能随便乱动的,因为它们保存着指向程序栈重要位置的指针。

下面做一个简单的总结,让条理清晰一点:
1、IA32中总共有8个32位寄存器(请不要太过关注这些寄存器奇怪的名字),如果要访问寄存器中32位数据的值,你需要使用%e??这种形式,如果要访问某个寄存器低16位的值你需要使用%?x, %?i 或者 %?p 这种形式,如果你需要访问高8位需要使用 %?h这种形式,如果要访问低8位,则需要使用%?l这种形式。

2、前6个寄存器是通用的(在遵循一定的使用规则前提下,可以随意更改寄存器中的值),后两个寄存器是不能随意更改的。

3、IA32寄存器被划分为了8个32位寄存器,8个16位寄存器,以及8个8位寄存器。但实质上只有8个32位寄存器,无外乎玩了一场位游戏。

示例:

假设32位寄存器%eax存储的值如下:
%eax : aa bb cc dd
那么下面寄存器对应的值为
%ax:cc dd
%ah:cc
%al::dd

因为第一个%ax代表取寄存器低16位的值,%ah代表取低16位中的高8位值,%al代表取低16位中的低8位值。

操作数指示符

大多数指令有一个或者多个操作数,指示出执行一个操作中要引用的源数据值以及放置结果的目标位置。
操作数的类型:

(1)立即数
书写方式:‘ C -123, $0x1f.
任何能放进一个32位的字里的数值都可以用作立即数

(2)寄存器
表示某个寄存器的内容,对于双字操作来说,可以是8个32位寄存器的一个(例如,%eax),对于字操作来说,可以是8个单字节寄存器元素中的一个(例如,%al)。
用符号Ea来表示任意寄存器a,用引用R[Ea]来表示他的值,这是将寄存器集合看成一个数组R,用寄存器标识符作为索引。

(3)存储器引用
它会根据计算出来的地址(通常称为有效地址)访问某个寄存器位置。

数据传送指令

将数据从一个位置复制到另一个位置的指令使用数据传送指令。
a. MOV指令
MOV类指令将源操作数的值复制到目的操作数中。源操作数指定的值是一个立即数,存储在寄存器或者存储器中。目的操作数指定一个位置,要么是一个寄存器,要么是一个存储器地址。

IA32有限制,传送指令的两个操作数不能都指向存储器位置。
将一个值从一个存储器位置复制到另一个存储器位置需要两条指令——第一条指令将源值加载到寄存器中,第二条指令将该寄存器写入目的位置。
b. MOVS指令和MOVZ指令
MOVS指令和MOVZ指令类都是讲一个较小的源数据复制到一个较大的数据位置,高位用符号扩展(MOVS)或者零扩展(MOVZ)进行填充。

用符号位扩展,目的位置的所有高位用源值的最高位数值进行填充,用零扩展,所有高位都用零填充。

这两个类中每个都有三条指令,包括了所有源大小为1个和2个字节,目的大小为2个和4个的情况(省略了冗余的组合movsww和movzww)。

示例:
源代码:

int exchange(int *p, int y)
{ 
    int x = p;
    *p = y;
    return x;
}

这里写图片描述

前三条指令说明了如何用MOV指令从存储器中读值到寄存器,第四条指令说明了如何从寄存器写到存储器。

字节传送指令比较

仔细观察可以发现,三个字节传送指令movb, movsb1和movzbl之间有细微的差别。

//假设%dh = CD, %eax = 98765432
mov  %dh, %al               %eax = 987654CD
movsbl   %dh,  %eax      %eax = FFFFFFCD
movzbl   %dh,  %eax      %eax = 000000CD

例子中都是将寄存器%eax的低位字节设置成%edx的第二个字节。movb指令不改变其他三个字节。根据源字节的最高位,movsbl指令将其他三个字节设为全1或全0。movzbl指令无论如何都是将其他三个字节设置为全0.

栈操作:压栈是减少栈指针(寄存器%esp)的值,并将数据存放到存储器中,而出栈是从存储器中读,并增加栈指针的值
pushl指令的功能是把数据压入到栈上,popl指令时弹出数据,
这些指令只有一个操作数。

将一个双字值压入栈中,首先要把栈指针减4,然后将值写入到新的栈顶地址。

pushl   %ebp  等价于   
subl  $4 ,  %ebp
movl   %ebp , (%esp)

区别:
在目标代码中1pushl指令编码为1字节,而以上两条指令应该需要6字节。

弹出一个双字的操作包括从栈顶位置读出数据,然后将栈指针加4.

popl  %eax等价于
movl  (%ebp),   %eax
addl   $4,  %esp
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值