深入理解计算机系统 第3章 程序的机器级表示

目录

 

第3章 程序的机器级表示

数据格式

操作数指示符

练习题

数据传送指令

习题3.4

访问信息

压入和弹出栈数据

算数和逻辑操作

移位操作

讨论

特殊的算数操作

问题


第3章 程序的机器级表示

数据格式

操作数指示符

操作数的三种类型:

  • 立即数(immediate)

在ATT格式的汇编代码中,立即数的书写方式是‘$’后面跟一个用标准C表示法表示的整数,如:$-577或$0x1F

  • 寄存器(register)

用符号ra来表示任意寄存器a,用引用R[ra]来表示它的值,这是将寄存器集合看成一个数组R,用寄存器标识符作为索引。

  • 内存应用

内存引用会根据计算出来的地址(通常称为有效地址)访问某个内存位置。因为将内存看成一个很大的字节数组,我们用符号Mb[Addr]表示对存储在内存中从地址Addr开始的b个字节值的引用。为了简便,通常省去下标b。

 

 

练习题

假设下面的值存放在指明的内存地址和寄存器中:

填写下表,给出所示操作数的值:

解:

 

 

 

 

 

 

数据传送指令

MOV类:movb、movw、movl、movq,分别对应操作的数据大小为:1、2、4、8字节。

 

习题3.4

此题转载自:https://blog.csdn.net/anlian523/article/details/83997464

有以下的c语言程序:

src_t *sp;

dest_t *dp;

*dp = (dest_t) *sp;

假设转换成汇编语言后, sp 的值存在寄存 %rdi, dp 的值存在 %rsi。而第一个指令都是将sp的值先导入到 %rax寄存器的相应字节中的。

注意第一条指令就得选择好是零拓展还是符合拓展(当从小的到大的时,关心的是源操作数的有无符号),当从大到小时,就不需要选择了,毕竟直接截断就好了。

第一条指令,也得先拓展到目标类型的大小。

第二条指令,只需要关心目的类型的大小以此来决定后缀。

 

 

总结:从小到大或一样大,两条指令的寄存器名字相同(这里指不带括号的,因为带括号的叫内存引用),但除了上表第4行,原因不明。猜想原因可能是:“常规的movq指令只能以表示为32补码数字的立即数作为操作数,然后把这个值符号拓展得到64位的值,放到目的位置”。

 

疑问???第2行为什么加括号?

movl %edx,%eax

两行可以合并成一行吗?

movl 8(%ebp),%eax

 

 

访问信息

压入和弹出栈数据

栈向下增长,这样一来,栈顶元素的地址是所有栈中元素地址中最低的。

栈指针%rsp保存着栈顶元素的地址。

 

算数和逻辑操作

大多数操作都分成了指令类,这些指令类有各种带不同大小操作数的变种,只有leaq没有其他大小变种

指令类A DD的四条加法指令:addb(字节加法)、addw(字加法)、addl(双子加法)、addq(四字加法)

 

leaq指令可以简洁地描述普通的算数操作。leaq指令使用如下:(3rd P129)

long scale(long x,long y,long z)

{

       long t=x+4*y+12*z;

       return t;

}

对应的3条leaq指令如下:

long scale(long x,long y,long z)

x in %rdi, y in %rsi, z in %rdx

scale:

  leaq    (%rdi,%rsi,4),%rax     x+4*y

  leaq    (%rdx,%rdx,2),%rdx  z+2*z=3*z

  leaq    (%rax,%rdx,4),%rax   (x+4*y)+4*(3*z)=x+4*y+12*z

  ret     

 

移位操作

疑问???高位会被忽略是什么意思?导致的结果就是w-1吗?

 

讨论

疑问???第5行没看懂

 

 

练习题3.11 常常可以看到以下形式的汇编代码行:

xorq %rdx,%rdx

但是在产生这段汇编代码的C代码中,并没有出现EXCLUSIVE-OR操作。

  1. 解释这条特殊的EXCLUSIVE-OR指令的效果,它实现了什么有用的操作。
  2. 更直接地表达这个操作的汇编代码是什么?
  3. 比较同样一个操作的两种不同实现的编码字节长度。

疑问???C这里的字节解释没看懂xorq的版本为什么只需要3个字节,而movq的需要7个字节又是为什么,不应该是8个字节吗?

 

特殊的算数操作

Intel把16字节的数称为八字(oct word)。

下面的C函数说明x86-64如何实现除法,它计算了两个64位有符号数的商和余数:

void remdiv(long x,long y,long *qp,long *rp)
{
       long q=x/y;
       long r=x%y;
       *qp=q;
       *rp=r;
}

该函数编译得到如下汇编代码:

void remdiv(long x,long y,long *qp,long *rp)
x in %rdi, y in %rsi, qp in %rdx, rp in %rcx

1 remdiv:
2     movq     %rdx,%r8     copy qp
3     movq     %rdi,%rax    Move x to lower 8 bytes of dividend(被除数)
4     cqto                     Sign-extend to upper 8 bytes of dividend
5     idivq      %rsi              Divide by y
6     movq    %rax,(%r8)   Store quotient at qp
7     movq     %rdx,(%rcx) Store remainder at rp
8     ret

 

上述代码中,必须首先把参数qp保存到另一个寄存器中(第2行),因为除法操作需要使用参数寄存器%rdx。接下来,第3~4行准备“被除数”,复制并符号扩展x。除法之后,寄存器%rax中的商被保存在qp(第6行),而寄存器%rdx中的余数被保存在rp(第7行)中。

 

练习题3.12 3th P135

考虑如下函数,它计算两个无符号64位数的商和余数:

void uremdiv(unsigned long x,unsigned long y,unsigned long *qp,unsigned long *rp)
{
       unsigned long q=x/y;
       unsigned long r=x%y;
       *qp=q;
       *rp=r;
}

修改有符号数除法的汇编代码来实现这个函数。

汇编代码的第4行按照答案解释和书上示例替换为cqto,隐式将符号位(由于是无符号符号位是0)扩展到%rdx的所有位为0。

疑问???汇编代码的第4行的指令为什么不是movq $0,%rdx,为什么用双字的32位指令movl(对应的寄存器为%edx)?

 

控制

条件码

除了整数寄存器,CPU还维护着一组单个位的条件码(condition code)寄存器,它们描述了最近的算术或逻辑操作的属性。

最常用的条件码有:

CF:进位标志。最近的操作使最高位产生了进位。可用来检查无符号操作的溢出。

ZF:零标志。最近的操作得出的结果为0。

SF:符号标志。最近的操作得出的结果为负数。

OF:溢出标志。最近的操作数导致一个补码溢出——正溢出或负溢出。

 

 

问题

1、为什么需要3个字节,其他的只需要2  PPT P25

 

2、练习题3.2 完全不懂 3thP124

3、练习题3.4unsigned charlong的转换不太懂原因 3rd P126

43.5.1加载有效地址疑问???long t = x+4*y+12*z;编译时,该算数运算一定是需要3leaq指令实现吗? 3rd P129

53.5.4讨论的汇编代码第5行没看懂(往上翻有截图)

6、习题3.11C问的字节解释没看懂

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值