mov指令与内存

今天在啃《深入理解计算机系统》的时候遇到了下面这段代码:

movl 12(%ebp), %eax
imull 8(%ebp)
movl %eax, (%esp)
movl %edx, 4(%esp)

代码的作用就是将两个数的乘积存回栈顶。代码没有问题,让我疑惑的是书上这两句话:

存储两个寄存器的位置对小端机器来说是对的——寄存器 %edx 中的高位存在相对于 %eax 的低位偏移量为 4 的地方。 栈是向低地址方向增长的,也就是说低位在栈顶。

在考虑这两句话的时候,突然发现自己对 mov 的操作并不是特别的清楚,就去查了查,大致搞明白了一些。

mov指令

我们知道 mov 在 IA32 中有基础的三类操作,即 b,w,l。 而 mov 在使用时大致如下:

movb %al, (%edx)  # 将 al 寄存器的内容放到以 %edx 的值为地址的内存区域

这里因为是 b 类型的,只有一个字节,所以直接将该字节放到那个地址对应的地方即可。然而对于 w 和 l,源不止一个字节,这个时候,一个内存地址只能表示存放开始的地方,想要存储源操作数,需要多个地址,表达可能不清楚,用代码来说明:

movl %eax, (%edx)

我们知道内存是按字节整理的,也就是说 edx 代表的那个地址也就只有 1 个字节,而源操作数 eax 却是 4 个字节,因而,需要多个地址进行存放,我们假设下 %eax = 0x0A0B0C0D,%edx = 4,则内存图如下表:

地址 内容
0 ...
1 ...
2 ...
3 ...
4 0D
5 0C
6 0B
7 0A

这里是假设机器为小端。可见,占用了 4~7 的内存地址。所以,mov 指令实际占用内存地址的情况是与源操作数的字节数有关的,而多出来的地方,是通过开始地址(即指令中的目标操作数)往上加的。

回归问题

既然知道了 mov 的行为,再回过头来看看那段代码。假设乘积为 0x010203040A0B0C0D,%esp = 104,小端机器,则该段代码执行后内存应该是如下这样的:

地址 0-7 8-15 16-23 24-31
... ... ... ... ..
104 0D 0B 0C 0A
108 04 03 02 01
... ... ... ... ...

很明显了,低位 (0D) 在 栈顶 (104),这就解释了:

栈是向低地址方向增长的,也就是说低位在栈顶。

但是。。

%edx 的高位存在相对于 %eax 的低位偏移量为 4 的地方

这句话还是没法解释。。%edx 的高位 (01) 相对于 %eax 的低位 (0D),偏移量好像不是 4 啊。。

有啥想说的就留个言呗~

comments powered by Disqus