1、1,第7章 目标代码生成,7.1 汇编语言虚拟计算机模型 7.2 从四元式到汇编语言的翻译 7.3 一个简单目标代码生成器 7.4 静态地址分配,2,任务将中间代码变换成目标代码,实现源程序的最后翻译。由于涉及到目标机器的系统结构,此阶段的工作最复杂。 目标代码的形式 已定位的机器语言代码编译后可立即执行。 待装配的机器语言代码模块目前大多数编译系统所产生的目标代码均为可重定位的机器指令。在执行前,将它和系统函数(源程序中使用)的机器指令连接成一个程序,对未确定的地址进行定位(用户程序为0地址空间),形成可执行的机器语言程序。在执行时,操作系统可将目标代码装入内存的任意位置。 汇编语言代码需经
2、汇编程序翻译,将其转换成可执行的机器语言代码。由于硬件厂商提供机器的汇编程序,所以编译程序的目标代码通常为汇编语言形式。 目标代码生成要求 目标代码数与中间代码数的比值尽可能小(即目标代码数尽可能少)。 充分利用寄存器,减少访问内存的次数。 删除不必要的临时变量。,3,7.1 汇编语言虚拟计算机模型,内存 共有64k个字,1个字有16个二进制位(2Byte),内存地址标识为0-65535。 划分为256页,页号0-255,每页的长度为256个字,页内位移为0-255。 地址计算:页号*256+页内位移。 255页用作系统堆栈区。 寄存器 通用寄存器(2字节)共有4个,分别标记为R0、R1、R2
3、、R3,用于存放操作数和计算结果,R3还可用于变址寻址。 标志寄存器FlagReg保存CMP指令比较结果。 堆栈寄存器TopReg(2字节)TopReg用作系统堆栈栈顶指针。,4,指令系统(简单指令系统)指令格式: (定长、2字节),操作码 Read 从键盘读一个字到第一地址。 Write 从第一地址写一个字到屏幕。 Load 从第二地址将字装入第一地址。 Store 将第一地址中的字存放到第二地址。 Call 控制转移到第二地址指定的内存单元,断点保留在系统堆栈中。 Ret 由系统堆栈获得断点,返回。 Add 将第一地址中的字加上第二地址中的字,结果保留第一地址中。 Sub Mul Div
4、Cmp 将第一地址中的字和第二地址中的字比较,由系统置位FlagReg。 FlagReg=-1,表示第一地址中的字小于第二地址中的字。 FlagReg=1,表示第一地址中的字大于第二地址中的字。 FlagReg=0,表示第一地址中的字等于第二地址中的字。,低8位用于第二地址的补充定义,5,JMP 无条件转移到第二地址指定的内存单元。 JMPNEG 若FlagReg中的值0,转移到第二地址指定的内存单元。 JMPPOS 若FlagReg中的值0,转移到第二地址指定的内存单元。 JMPZERO 若FlagReg中的值0,转移到第二地址指定的内存单元。 HALT 终止程序执行。 第一地址只能是寄存器
5、(R0-R3) 第二地址有四种寻址方式 直接地址寻址(M)Load Ri , MXX Ri(XX)XX范围00-FF(第0页),用16进制表示。 寄存器寻址(R)Load Ri , Rj Ri(Rj) 寄存器(间址)寻址(R)Load Ri , Rj Ri(Rj) 直接数寻址(D)Load Ri , XX RiXXXX范围00-FF,用16进制表示。 变址寻址(C R3)Load Ri , CR3 Ri(C*256+(R3)C为常数(范围00-FF),用16进制表示。,6,指令分类 零地址指令 Ret、Halt A型一地址指令(无第二地址) Write、Read例:Read R0 /从键盘输入
6、一个数,将其存放在R0中。 B型一地址指令(无第一地址) Call、Jmp、JmpNeg、JmpZero、JmpPos例:Jmp 2R3 /无条件转移至地址2*256+(R3)单元 二地址指令 Load、Store、Add、Sub、Mul、Div、Cmp例:Add R3,1 /R3的内容加1程序举例用汇编程序编写程序,求5的阶乘。,Load R0,1 /R0的范围15 Load R1,1 /初值为1,存放5!。 Add R0,1 Mul R1,R0 Cmp R0,5 JmpNeg M2 Write R1 Halt,7,7.2 从四元式到汇编语言的翻译,符号表、常数表和临时变量表的内存位置四元式
7、中含有变量在符号表和临时变量表中的入口,以及常数在常数表中的地址,所以先确定符号表、临时变量表和常数表在内存中的位置,然后再讨论四元式的翻译。 无符号实常数表(第254页,按地址递减使用) 起始地址:254*256+255=65279,每个实常数占用2个字(4Byte)。 无符号整常数表(第254页,按地址递增使用) 起始地址:254*256=65024,每个整常数占用1个字(2Byte)。 符号表(第252、253页,按地址递减使用) 起始地址:253*256+255=65023,每个标识符占用4个字(8Byte)。 临时变量表(第252、253页,按地址递增使用) 起始地址:252*256
8、=64512,每个临时变量占用4个字(8Byte)。 注:四元式中最多允许出现512/4=128个不同的变量,包括临时变量在内。,8,虚拟内存示意图 (共64K、分255页、每页255字节),9,设源程序为:a=2+(+b+1),它的四元式代码为+ &b 0 &T1+ &T1 &1 &T2+ &2 &T2 &T3= &T3 0 &a 假设 整常数1在无符号整常数表中的地址为65024(254*256+0) 整常数2在无符号整常数表中的地址为65025(254*256+1) 变量a的符号表入口为65023(253*256+255) 变量b的符号表入口为65019(253*256+251) 临时变
9、量T1的临时变量表入口为64512(252*256+0) 临时变量T2的临时变量表入口为64516(252*256+4) 临时变量T3的临时变量表入口为64520(252*256+8)实际四元式代码序列应为+ 65019 0 64512+ 64512 65024 64516+ 65025 64516 64520= 64520 0 65023,10,单个四元式的翻译四元式的翻译关键是确定地址,约定如下: 指令的第一地址使用R0。 指令的第二地址使用R3(兼作变址寄存器)。 ARG1、ARG2为变量地址或常数地址,RESULT一定是变量地址。 C1=ARG1/256、D1=ARG1%256。 C2
10、=ARG2/256、D2=ARG2%256。 C3= RESULT/256、D3= RESULT %256。 注:C1、C2、C3表示页码,D1、D2、D3表示页内位移。,例1:(+,ARG1,ARG2, RESULT) 设ARG1是变量在符号表或临时变量表入口,ARG2是常数在常数表中的地址。解: Load R3,D1 /R30Load R0,C1R3 /R0(252*256+0)=(64512)Load R0,R0 /R0的内容为存放临时变量T1值的地址Load R3,D2 /R30Add R0,C2R3 /R0(254*256+0)=(65024)Load R3,D3 /R34Load
11、R3,C3R3 /R3(252*256+4)=(64516) Store R0,R3 /R3内容为存放临时变量T2值的地址,+ &T1 &1 &T2 上述四元式的地址表示 + 64512 65024 64516 C1=64512/256=252 /T1 D1=64512%256=0 C2=65024/256=254 /常数1 D2=65024%256=0 C3=64516/256=252 /T2 D3=64516%256=4,11,例2:(=,ARG1,0,RESULT) 其中ARG1是常数地址。 解: Load R3,D1 /R38 Load R0,C1R3 /R0(252*256+8)=(
12、64520)Load R3,D3 /R3255Load R3,C3R3 /R3(253*256+255)=(65023)Store R0,R3 /R3的内容为存放变量a值的地址,单个四元式的翻译四元式的翻译关键是确定地址,约定如下: 指令的第一地址使用R0。 指令的第二地址使用R3(兼作变址寄存器)。 ARG1、ARG2为变量地址或常数地址,RESULT一定是变量地址。 C1=ARG1/256、D1=ARG1%256。 C2=ARG2/256、D2=ARG2%256。 C3= RESULT/256、D3= RESULT %256。 注:C1、C2、C3表示页码,D1、D2、D3表示页内位移。,
13、= &T3 0 &a 上述四元式的地址表示 = 64520 0 65023 C1=64520/256=252 D1=64520%256=8 C3=65023/256=253 D3=65023%256=255,12,对照表一条四元式代码通常译成若干条汇编语句,为了便于转移四元式的翻译,应建立一张对照表,记录一个四元式所对应的汇编语句的个数以及汇编语句的编号。对照表结构如下:,7.3 一个简单目标代码生成器 不考虑充分利用寄存器,仅仅使用R0和R3。指令的第一地址使用R0,指令的第二地址使用R3(兼作变址寄存器)。算法描述详见下一页。,13,0. procedure GenCode(op,arg1
14、,arg2,result) /一个简单目标代码生成器 1. c1arg1/256:d1arg1%256; 2. c2arg2/256:d2arg2%256; 3. c3result/256:d3result%256; 4. comment:R0(ARG1) 5. output “Load R3,“:output d1:output 换行 6 output “Load R0,“: output c1: output “R3“ :output 换行 7. if c1=252 or c1=253 then /ARG1是符号表或临时变量表的入口 8. output “Load R0,R0“:outpu
15、t 换行 9. end if /ARG1是常数表入口无需上述指令 10. comment:R0运算结果 处理加法运算(ARG20)处理一元正运算(ARG2=0)处理减法运算(ARG20) /详见下一页处理一元负运算(ARG2=0) /详见下一页赋值运算(无需任何处理) 11. comment:RESULT(R0) 12. output “Load R3,“ :output d3:output 换行 13. output “Load R3,“ :output c3:output “R3“ :output 换行 14. output “store R0,R3“ :output 换行 15. end
16、 procedure,14,/处理减法运算(ARG20)comment: R0运算结果if op=“-“ and arg20 thenoutput “Load R3,“ :output d2:output 换行if c2= 252 or c2=253 then /ARG2是符号表或临时变量表的入口output “Load R3,“:output c2:output “R3“:output 换行output “Sub R0,R3“:output 换行else /ARG2是常数表地址output “Sub R0,“:output c2:output “R3“endl;end ifend if /处
17、理一元负运算(ARG2=0)if op=“-“ and arg2=0 then / -ARG1=0-ARG1output “Load R3,R0“:output 换行 /将ARG1送R3output “Load R0,0“:output 换行 /将0送R0output “Sub R0,R3“:output 换行 /R0-R3送R0end if,15,实例设源程序为:a=2+(+b+1),它的四元式代码为+ &b 0 &T1+ &T1 &1 &T2+ &2 &T2 &T3= &T3 0 &a假设 整常数1在无符号整常数表中的地址为65024(254*256+0) 整常数2在无符号整常数表中的地址
18、为65025(254*256+1) 变量a的符号表入口为65023(253*256+255) 变量b的符号表入口为65019(253*256+251) 临时变量T1的临时变量表入口为64512(252*256+0) 临时变量T2的临时变量表入口为64516(252*256+4) 临时变量T3的临时变量表入口为64520(252*256+8)实际四元式代码序列应为+ 65019 0 64512+ 64512 65024 64516+ 65025 64516 64520= 64520 0 65023,16,假定四元式代码存放在文件Quad.txt中,经简单目标代码生成器加工,所生成的汇编语言目标程序存放在文件Asm.txt中,如图所示。,17,静态地址分配: 在程序运行前,将各变量的绑定于内存的某一单元地址。可选择内存某区域(例第251页)为数据存储区。根据符号表,整型变量分配一个单元(2Byte),实型变量分配二个单元(4Byte),并将地址填入符号表和临时变量表的addr处。,7.4 静态地址分配,符号表,第251页,251页用于存放变量值,第0页,第255页,65023,64507,第252页, ,64511,65019,251*256+255=64511,251*256+251=64507,18,结 束,