首页 > 其他分享 >CSCI 2122 C语言进行编码

CSCI 2122 C语言进行编码

时间:2024-03-25 14:02:49浏览次数:18  
标签:操作数 2122 rS 标签 CSCI C语言 rD 指令 寄存器

CSCI 2122任务4 截止日期:2024年3月22日星期五晚上11:59,通过git提交
目标
本作业的目的是练习用C语言进行编码,并强化课堂上讨论的程序表示概念。
在这个任务1中,您将实现一个类似Rosetta3的二进制翻译器2。您的程序将从一个简单的指令集(比x86简单得多)转换为x86,并生成x86汇编代码。然后将通过组装和运行代码来测试代码。为了使其更简单,此任务分为两部分。在第一部分中,您将实现加载程序和一个简单的翻译器,它可以翻译更简单的指令。在第二部分中,您将扩展翻译器以翻译更复杂的指令。
准备
1.完成工作分配0,或确保已安装完成工作分配所需的工具。
2.克隆您的作业存储库:
https://git.cs.dal.ca/courses/2024-winter/csci-2122/assignment-4/????.git
哪里是您的CSID。如果需要,请参阅作业0中的说明和Brightspace教程
你不知道怎么做。
在存储库中有一个目录:xtra,用于编写代码。目录中有一个测试目录,其中包含每次提交代码时将执行的测试。请不要修改测试目录或其他目录中满足要求的.gitlab-ci.ymlfileth。修改这些文件可能会破坏测试。代 写CSCI 2122 对作业进行评分时,这些文件将替换为原始文件。您将获得可用于构建程序的示例Makefile文件。如果您正在使用CLion,将从CLion生成的CMakeLists.txt文件中生成Makefile。
背景
对于此分配,您将把简化的基于RISC的16位指令集中的二进制转换为x86-64程序集。具体地,X指令集包括少量(大约30条)指令,其中大多数指令的大小为两个字节(一个字)。
X体系结构具有16位字大小和16个通用16位寄存器(r0…r15)。几乎所有指令都对16位的数据块进行操作。因此,所有值和地址的大小都是16位。所有16位值也都以big-endian格式编码,这意味着最高有效字节位于第一位。
除了16个通用寄存器外,该体系结构还有两个特殊的16位寄存器:程序计数器(PC)和状态(F),前者存储将要执行的下一条指令的地址,后者存储表示CPU状态的位标志。状态寄存器(F)的最低有效位是条件标志,它表示最后一次逻辑测试操作的真值。如果条件为true,则该位设置为true,否则设置为false。
1这项任务的想法间接来自于凯尔·史密斯。2.https://en.wikipedia.org/wiki/Binary_translation
3.https://en.wikipedia.org/wiki/Rosetta_软件

此外,CPU使用最后一个通用寄存器r15来存储指向程序堆栈的指针。当一个项从堆栈中弹出时,此寄存器将增加2,当一个项目被推到堆栈上时,此注册表将减少2。程序堆栈用于存储临时值、函数的参数和函数调用的返回地址。
X指令集
指令集包括大约30条指令,用于执行算术和逻辑、数据移动、堆栈操作和流控制。大多数指令将寄存器作为操作数,并将运算结果存储在寄存器中。但是,有些指令也将立即值作为操作数。因此,有四类指令:0操作数指令、1操作数指令,2操作数指令和扩展指令,它们采用两个字(4字节)而不是一个字。
除了扩展指令之外的所有指令都被编码为单个字(16位)。扩展指令也是一个字,但后面跟着一个额外的一个字操作数。因此,如果该指令是扩展指令,则PC在执行该指令期间需要2的额外增量。如前所述,大多数指令都被编码为一个单词。字的最高有效两位表示指令是0操作数指令(00)、1操作数指令、2操作数指令或扩展指令(11)。对于0操作数指令编码,最多两个sig-
重要的比特是00,接下来的六个比特表示指令标识符。指令的第二个字节是0。
对于1操作数指令编码,两个最高有效位为01,下一位表示操作数是立即数还是寄存器,接下来的五位表示指令标识符。如果第三个最高有效位为0,则第二个字节的四个最高有效位数
对要操作的寄存器进行编码(0…15)。否则,如果第三个最高有效位是1,则第二个字节对立即值进行编码。
对于2操作数指令编码,两个最高有效位为10,并且
接下来的六个比特表示指令标识符。第二个字节将两个寄存器操作数编码为两个四位块。每个4位块标识一个寄存器(r0…r15)。
对于扩展指令编码,两个最高有效位为11,下一位指示是否使用第二个寄存器操作数,接下来的五位表示指令标识符。如果第三个最高有效位为0,则该指令仅使用一个字immedi-
ate指令后面的操作数。否则,如果第三个最高有效位是1,则第二个字节的四个最高有效比特编码作为第二个操作数的寄存器(1…15)。
指令集如表1、表2、表3和表4所示。每个描述都包括助记符(和语法)、指令的编码、指令的描述和函数。例如,add、loadi和push指令具有以下描述:
loadi V,rD 11100001 D 0将立即值或地址V加载到rD中← 内存[PC]寄存器rD.PC← PC+2
记忆编码描述函数
添加rS,rD
10000001 S D
将寄存器rS添加到寄存器rD。
rD← rD+rS
推动rS
01000011 S 0
将寄存器rS推到程序堆栈上。
r15← r15-2内存[r15]← rS

首先,观察加法指令获取两个寄存器操作数,并将第一个寄存器与第二个寄存器相加。所有2操作数指令仅在寄存器上操作,第二个寄存器既是源寄存器也是目标寄存器,而第一个寄存器是源寄存器。它是一条2操作数指令;因此前两位是10,其指令标识符是000001,因此指令的第一个字节是0x81。
其次,loadi指令是一条扩展指令,它采用16位立即数并将其存储在寄存器中。因此,前两位为11,寄存器位设置为1,指令标识符为00001。因此,第一个字节被编码为0xE1。
第三,push指令是一条1操作数指令,取单个寄存器操作数。因此,前两个比特是01,立即数比特是0,指令标识符是00011。因此,第一个字节被编码为0x43。
请注意,S和D是表示S和D的4位矢量。表1:0-操作数指令
记忆编码描述函数
ret
00000001 0
从过程调用返回。
P C← 存储器← r15+2
cld 00000010 0表1:1-操作数指令
停止调试模式
逻辑地否定寄存器rD。递减rD。
将堆栈中的值弹出到寄存器r中。
如果条件位为true,则分支相对于标签L。
从寄存器rD减去寄存器rS。用寄存器rD减寄存器rS。
X或寄存器rS与寄存器rD。
请参阅下面的调试模式。
rD←!rD
rD← rD–1
rD← 存储器← r15+2
如果F&0x0001==0x001:PC← PC+L–2
rD← rD-rS rD← rD和rS rD← rD^rS
std
00000011 S 0
启动调试模式
请参阅下面的调试模式。
记忆编码描述函数
负rD
01000001第0天
否定寄存器rD。
rD← −rD
不是rD dec rD
pop rD br L
01000010 D 0 01001001 D 0
01000100 D 0 01100001 L
inc rD公司
01001000 D 0
增量rD。
rD← rD+1
推动rS
01000011 S 0
将寄存器rS推到程序堆栈上。
r15← r15–2内存[r15]← rS
输出rS
01000111 S 0
将rS中的字符输出到std-out。
输出← rS(见下文)
jr L
01100010升
相对于标签L跳转。
个人计算机← PC+L–2
表3:2-操作数指令
记忆编码描述函数
添加rS,rD
10000001 S D
将寄存器rS加到寄存器rD。
rD← rD+rS
sub-rS,rD和rS,rD-xor rS,rD
10000010秒D 10000101秒D 10000111秒D
多个rS,rD
10000011 S D
将寄存器rD乘以寄存器rS。
rD← rD*rS
或rS、rD
10000110秒/天
或者用寄存器rD寄存器rS。
rD← rD|rS

测试rS1、rS2
10001010秒/天
当且仅当rS1∧rS2不为0时,将条件标志设置为true。
ifrS1&rS2=0:
F← F|0x0001
其他的
F← &0xFFFE
cmp rS1,rS2
10001011秒/天
将条件标志设置为true当且仅当rS1<rS2。
如果rS1<rS2:
F← F|0x0001
其他的
F← &0xFFFE
equ rS1,rS2
10001100秒/天
当且仅当rS1rS2时,将条件标志设置为true。
如果rS1
rS2:
F← F|0x0001
其他的
F← &0xFFFE
mov rS,rD stor rS,r D
10001101秒D 10001111秒D
10010001 S D表3:扩展指令
将寄存器rS复制到寄存器rD。
将字从寄存器rS存储到寄存器rD中地址处的存储器中。
将字节从寄存器rS存储到寄存器rD中地址处的存储器中。
rD← rS内存[rD]← rS
(字节)内存[rD]← rS
负载rS,rD
10001110秒/天
将字从寄存器rS指向的存储器加载到寄存器rD中。
rD← 内存[rS]
加载b rS,rD
10010000秒/天
将字节从寄存器rS指向的内存加载到寄存器rD中。
rD← (字节)内存[rS]
storb rS,rD
记忆编码描述函数

大多数测试都使用std指令来开启调试,并在每条指令执行后输出寄存器的状态。对于大多数测试,被比较的输出是寄存器值。
实例
原始X汇编代码转换的x86代码
loadi 2,r0
负载i 3,r1
负载i 4,r2
负载i 5,r3
负载i 7,r5
std#打开调试
将r2、r3相加
mul r2,r1
cld#关闭调试neg r0
inc r5公司
.literal 0
.globl测试
测验
推送%rbp
mov%rsp,%rbp
mov$2,%rax
mov$3,%rbx
mov$4,%rcx
mov$5,%rdx
mov$7,%rdi
调用调试
添加%rcx、%rdx
调用调试
模拟%rcx,%rbx
调用调试
负%rax
inc%rdi公司
弹出%rbp
ret
任务2:完整的翻译人员
您的第二个任务是扩展xtra以翻译任务1中免除的指令。请参阅以下说明。
实施trans-
说明书说明
ret
从过程调用返回。
br L
jmp L
加载rS,rD加载b rS,r输出rS
如果条件位为true,则分支相对于标签L。
绝对跳转到标签L。
将字从寄存器rS指向的内存加载到寄存器rD。将字节从寄存器rS指向的存储器加载到寄存器rD。将rS中的字符输出到stdout。
jr L
相对于标签L跳转。
呼叫L
绝对呼唤标签L。
stor rS,rD
将字从寄存器rS存储到寄存器rD中地址处的存储器中。
storb rS,rD
将字节从寄存器rS存储到寄存器rD中地址处的存储器中。

输入
输入与任务1相同。
处理
处理过程与任务1相同。挑战在于翻译更具挑战性。
首先,对于许多附加指令,您将需要发出多个程序集指令。对于条件分支和输出指令尤其如此。
其次,对于分支指令,您需要计算分支到的标签。简单的解决方案是为正在翻译的每条指令创建一个标签。标签应在名称中对地址进行编码。例如,L1234将是地址1234处的X指令的标签。通过这样做,您将不需要保留标签的列表或数据库。
第三,加载和存储所使用的地址是完整的64位值。
输出
输出与任务1相同。
实例
原始X汇编代码转换的x86代码
loadi 1,r0
jmp j1 j2:
loadi 3,r0
jmp j3 j1:
loadi 2,r0
jmp j2 j3:
std#打开调试
负载i 4,r0
.literal 0
.globl测试
测验
推送%rbp
mov%rsp,%rbp
.10000:
mov$1,%rax
.10004:
jmp。2010年10月
.10008:
mov$3,%rax
.L00c:
jmp。2018年10月
.10010:
mov$2,%rax
.10014:
jmp。2008年10月
.10018:
.L001a:
调用调试
mov$4,%rax
.L001e:
调用调试
弹出%rbp
ret
提示和建议
•对所有寄存器和索引使用无符号短型。
•使用两个文件:一个用于主程序,另一个用于翻译器循环。
•早点开始,这是本学期最难的任务,任务中有很多内容需要消化
规范。

作业提交
提交和测试使用Git、Gitlab和Gitlab CI/CD完成。您可以在截止日期前提交任意次数。每次提交时,都会执行功能测试,您可以查看测试结果。若要提交,请使用与分配0相同的过程。
分级
如果你的程序没有编译,它将被认为是不起作用的,质量极差,这意味着你将收到0的解决方案。
作业将根据三个标准进行评分:
功能:“它是否按照规范工作?”。这是通过在多个输入上运行程序并确保输出与预期输出匹配来自动确定的。分数是根据你的程序通过的测试次数来确定的。所以,如果你的程序通过了t/t测试,你将获得该比例的分数。
解决方案质量:“这是一个好的解决方案吗?”这会考虑解决方案中的方法和算法是否正确。这是通过目视检查代码来确定的。即使您有导致代码无法通过某些测试的错误,也有可能在这一部分获得好成绩。
代码清晰度:“它写得好吗?”这考虑了解决方案的格式是否正确,文档是否完整,是否遵循编码风格准则。为了清晰起见,将指定一个整体标记。请参阅Brightspace课程作业部分的风格指南。
将使用以下分级方案:
任务100%80%60%40%20%0%
功能性(20分)
等于通过的测试数。
解决方案质量任务1
(15分)
正确实施。代码是健壮的。
正确实施。代码不健壮。
一些小错误。
实施方面的重大缺陷
已经进行了尝试。
解决方案质量任务2
(5分)
正确实施。代码是健壮的。
正确实施。代码不健壮。
一些小错误。
实施方面的重大缺陷
已经进行了尝试
代码清晰度(10分)缩进,用于遮片、命名、注释
代码看起来专业且遵循所有风格准则
代码看起来不错,而且大多遵循样式指南。
代码可读性很强,主要遵循一些样式准则
代码很难阅读,而且很少遵循样式指南
代码不清晰
未提交代码或
代码未编译

未提交作业测试
通过提交进行测试可能需要一些时间,尤其是在加载了服务器的情况下。您可以使用providedruntests.shscript在不提交代码的情况下运行测试。在没有参数的情况下运行脚本将运行所有测试。使用测试编号运行脚本,即00、01、02、03。。。09,将运行该特定测试。请参阅下面的脚本运行方式。
准备好程序运行
如果您直接在unix服务器上进行开发,
1.通过SSH连接到远程服务器,并确保您在xtra目录中。2.确保程序是通过运行make编译的。
如果您正在使用CLion
1.如CLion教程中所述,在远程服务器上运行程序。2.通过工具打开远程主机终端→ 打开远程主机终端
如果您正在使用VSCode
1.如VSCode教程中所述,在远程服务器上运行程序。
2.单击窗口下半部分的“终端”窗格或通过“终端”→ 新建终端
运行脚本
3.使用以下命令在终端中运行脚本:
./runtest.sh
运行所有测试,或指定运行特定测试的测试编号,例如:
./runtest.sh 07
您将在终端窗口中看到测试运行。
X汇编程序(xas)
提供了一个汇编程序(xas),允许您为X体系结构编写和编译程序。要制作汇编程序,只需在xtra目录中运行“make-xas”即可。要运行汇编程序,请在命令行上指定程序集和可执行文件。例如
./xas example.xas example.xo
将X程序集文件example.xas汇编为X可执行文件example.xo。
程序集文件的格式很简单。
1.任何位于#标记右侧的内容,包括#,都将被视为注释并被忽略。
2.忽略空行。
3.程序集文件中非空白的每一行都必须包含指令、标签和/或指令-
tion。如果行同时包含标签和指令,则标签必须位于第一位。4.标签的形式
标识符:
其中,标识符由任何字母(A-Za-z)、数字(0-9)或下划线()序列组成,只要第一个字符不是数字。冒号(:)必须终止标签。标签表示程序中相应的位置,可用于跳转到代码中的该位置。
5.指令由助记符组成,如add、loadi、push等,后跟零个或多个操作数。操作数必须与助记符用一个或多个空格分隔。多个操作数用逗号分隔。

6.如果操作数是寄存器,则其形式必须为r#,其中#的范围在0到15之间(包括0到15)。例如,r13。
7.如果指令是立即数,那么自变量可以是标签,也可以是整数。注意:标签区分大小写。如果指定了标签,则标签后面不应该有冒号。
8.指令指示汇编程序执行特定的功能或以特定的方式表现。所有指令都以句点开头,后面跟一个关键字。有三个指令:.literal、.words和.glob,每个指令都接受一个操作数。
(a) .literal指令当前编码以null结尾的字符串或整数
程序中的位置。例如。,
mystring:
.literal“Hello World!”myvalue:
.文字42
对以零结尾的字符串进行编码,后跟表示decimal值42的16位(1个字)值。在本例中,每个编码之前都有标签,因此访问这些文字很容易。也就是说,标签mystring表示字符串编码的地址(相对于程序开始),标签myvalue表示值的地址(相对程序开始)。这在hello.xas示例中使用。
(b) 单词的方向性显示了演示文稿中特定单词的数量
程序中的位置。例如,myspace:
.单词6
在程序的当前点分配6个字的内存。这个空间并没有初始化为任何特定的值。和以前一样,指令前面的标签表示相对于程序开始的第一个单词的地址。这在xrt0.xas中用于为程序堆栈留出空间。
(c) 如果在文件中定义了指定的符号(标签),则.glob指令会导出该符号;如果已使用但未在文件中进行定义,则会导入指定的符号。例如。,
.glob-fooo.glob-bar。。。
加载条,r0。。。
foo:
.字面意思是“你好,世界!”
声明了两个符号(标签)foo和bar。符号foo是在这个文件中声明的,因此它将在其他文件中导出(可以访问)。后一个符号bar已使用,但未定义。当链接此文件时,链接器会在其他文件中查找符号(标签)定义,使对符号的所有引用都指向定义符号的位置。
注意:建议您将文字和所有空间分配放在程序的末尾,这样它们就不会干扰程序本身。如果确实将文字放在程序的中间,则需要确保代码在这些分配之间跳转。
提供了几个示例程序集文件(以.xas结尾)。您可以通过调用来组装它们
汇编程序,例如:
./xas example.xas example.xo
此调用将导致汇编程序读入文件example.xas并生成输出文件example.xo。请随意查看汇编程序的代码。

标签:操作数,2122,rS,标签,CSCI,C语言,rD,指令,寄存器
From: https://www.cnblogs.com/rluanguae/p/18094230

相关文章

  • 最全面的C语言的运算符优先级
    C语言是一种广泛应用于系统编程和应用程序开发的高级编程语言。在C语言中,运算符优先级是非常重要的概念,它决定了表达式中各个运算符的执行顺序。本文将详细介绍C语言中各种运算符的优先级,帮助读者更好地理解和使用这些运算符。首先,我们需要了解C语言中运算符的分类。C语言......
  • C语言(结构体,联合体,枚举的讲解)
    这期我们来讲解结构体,联合体,以及枚举的讲解,首先我们从概念开始一步一步的了解。1,结构体1.1概念C语言中的结构体是一种用户自定义的数据类型,它允许你将不同类型的变量组合在一起,从而形成一个新的数据类型。结构体在C语言中非常有用,可以用于表示复杂的数据结构,比如学生信息......
  • 【C语言】字符函数和字符串函数
    前言:在编程的过程中,我们经常要处理字符和字符串,C语言标准库中提供了一系列库函数,接下来我们一起学习一下这些函数。1.字符分类函数C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。这些函数的使⽤都需要包含⼀个头⽂件是ctype.hiscntrl......
  • c语言 实现切片数组
    c语言集合类第一章切片(本章)第二章栈文章目录c语言集合类前言一、接口定义1、创建切片2、销毁切片3、添加元素4、切片长度5、切片容量二、完整代码三、使用示例1、一般使用流程2、直接append3、自定义类型总结前言由于c语言没有集合类的标准库,需要用时只能自......
  • C语言内存函数(1)【memcpy函数的使用与模拟实现】【memmove函数的使用和模拟实现】
    关于内存函数有四个函数需要我们学习。分别是memcpy,memmove,memset和memcmp。都在头文件string.h里面。一.memcpy函数的使用一提到这个函数,我们可能会联想到strcpy函数,但strcpy函数是针对字符串的拷贝。但是我们在写代码的时候不可能只拷贝字符串。 intarr1[]={1,2,3,4,5......
  • 如何使用C语言实现文件操作
    目录文件打开和关闭函数原型案例展示1.引入头文件2.定义字符数组与打开文件3.检查文件打开情况4.读取与写入文件5.关闭文件与清理资源总结文件打开和关闭在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的......
  • 数据结构练习-C语言
    1.假设有一个带头结点的单链表L,每个结点值由单个数字、小写字母和大写字母构成。设计一个算法将其拆分成3个带头结点的单链表L1、L2和L3,L1包含L中的所有数字结点,L2包含L中的所有小写字母结点,L3包含L中的所有大写字母结点。该算法如何设计?首先创建L1、L2、L3的头结点,......
  • c语言程序设计--实验报告二
    实验项目名称:实验报告2数据描述实验项目类型:验证性实验日期:2024年3月21日一、实验目的1、掌握C语言数据类型,熟悉如何定义一个整型、字符型和实型的变量,以及对它们赋值的方法。2、掌握不同数据类型之间赋值的规律。3、学会使用C的有关算术运算符,以及包含这些运算符的表......
  • c语言程序设计——实验报告一
    实验项目名称:实验一熟悉C语言运行环境实验项目类型:验证性实验日期:2023年3月14日一、实验目的下载安装Devc6.0程序。了解在该系统上如何进行编辑、编译、连接和运行一个C程序。通过运行简单的C程序了解C程序的特点。二、实验硬、软件环境Windows计算机、Devc6.0三、......
  • C语言 04 基本数据类型
    整数整数就是不包含小数点的数字,整数包含以下几种类型:short:占用2个字节,16个bit位。int:占用4个字节,32个bit位,能够表示-2^32到2^32之间的数字,默认使用这种类型。long:占用8个字节,64个bit位。浮点浮点类型一般用于保存小数。为啥不叫小数类型而是浮点类......