1.转移控制——
-
call指令:后接被调用过程的起始的指令地址。效果是将返回地址入栈,并跳转到被调用过程的起始处。
-
ret指令:从栈中弹出地址,并跳转到这个位置。
练习题:
找出下列代码的错误之处?
movb $0xf,(%bl) ---目的操作数只能是一个寄存器或者一个存储器地址。(%bl)表示一个值
movw (%eax),4(%esp)---目的操作数与源操作数不能都是存储器
movb %si, 8(%ebp)---指令后缀与寄存器地址不匹配
int arith(int x,int y,int z) { int t1 = x^y;
int t2 = 3*t1;
int t3 = ~t2;
int t4 = t3-z;
return t4;
下面的代码片段常常出现在库函数的编译版本中:
call next
next:
popl %eax
A.寄存器%eax被设置成了什么值?
%eax被设置成popl的地址。
B.解释为什么这个调用没有与之匹配的ret指令
这不是一个真正的过程调用,因为根本是按照与指令相同的顺序进行的,而返回值是从栈中弹出的。
C.这段代码完成了什么功能?
这是IA32中将程序计数器中的值放到整数计数器中的唯一办法。
SEQ硬件结构
- 在SEQ中,所有硬件单元的处理都在一个时钟周期内完成。
- SEQ线路图的画图惯例:
- 浅灰色方框表示硬件单元
- 控制逻辑块是用灰色圆角矩形表示的
- 线路的名字在白色椭圆中说明
- 宽度为字长的数据连接用中等粗度的线表示
- 宽度为字节或者更窄的数据连接用细线表示
- 单个位的连接用虚线表示
SEQ的时序
- SEQ的实现包括组合逻辑和两种存储器设备:
- 时钟寄存器 程序计数器和条件码寄存器
- 随机访问存储器 寄存器文件、指令存储器和数据存储器
- 每个时钟周期,程序计数器都会装在新的指令地址;只有在执行整数运算指令时,才会装载条件码寄存器;只有在执行rmmovl、pushl或call指令时,才会写数据存储器;寄存器文件的两个写端口允许每个时钟周期更新两个程序寄存器。
- 组织计算原则:处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。
- 用时钟来控制状态元素的更新,值通过组合逻辑传播。
SEQ阶段的实现
- 取指阶段:
- 以PC为第一个字节的地址,一次读6个字节。
icode
:控制逻辑块计算指令ifun
:功能码- 三个一位的信号(根据icode值计算):
instr_valid
:发现不合法的指令;need_regids
:包含寄存器指示符字节吗;need_valC
:包括常数字吗 - 后五个字节是寄存器指示符字节和常数字的组合编码。
- 译码和写回阶段:
- 都需要访问寄存器文件,根据四个端口的情况,判断应该读哪个寄存器产生信号valA、valB。
- 寄存器文件,支持同时进行两个读和两个写,每个端口有一个地址连接(寄存器ID)和一个数据连接(32根线路),既可以作为寄存器文件的输出字,又可以作为他的输入字。
- 执行阶段:
- 包括算数/逻辑单元(ALU),输出为valE信号。ALU通常作为加法器使用
- 包括条件码寄存器
- 每次运行产生:零、符号、溢出、产生信号set_cc
- 访存阶段
- 读或者写程序数据。
- 两个数据块产生存储器地址和存储器输入证据的值,两个产生控制信号表明应该是读还是写。当执行读操作时,数据存储器产生valM。
- 根据icode,imem_error,instr_valid,dmem_error,从指令执行的结果计算状态码Stat。
- 更新PC阶段
- 产生程序计数器的新值,依据指令的类型和是否要选择分支,新的PC可能是valC、valM或者valP。
请说明为什么C语言代码中只有一个if语句,而汇编代码包含两个条件分支?
答:第一个条件分支是&&表达式实现的一部分。如果对p为非空的测试失败,代码会跳过对a>0的测试。
Y86模拟器的安装
- 可以参考这篇帖子:(http://www.cnblogs.com/hrhguanli/p/4594724.html),