SAST weekly 是由电子工程系学生科协推出的科技系列推送,内容涵盖信息领域技术科普、研究前沿热点介绍、科技新闻跟进探索等多个方面,帮助同学们增长姿势,开拓眼界,每周更新,欢迎关注!欢迎愿意分享知识的同学投稿至 eesast@mail.tsinghua.edu.cn , 期待你的作品!
电子系的同学在大二夏季学期要写一个MIPS32指令集架构的CPU。写完代码之后,就是我们最爱的仿真测试环节。大部分情况下,我们先手写出MIPS32的汇编指令序列,然后将这些指令送入CPU进行测试。由于写入指令存储器的指令必须是二进制机器码,所以这个过程中就存在由汇编指令到二进制机器码指令的转换问题。相信大家也不想自己一条一条从汇编指令翻译成32个bits吧:)
今天想和大家分享如何在Linux系统上搭建一个交叉编译环境,并将整个编译过程形成一个批处理文件,以方便同学们完成即将到来的小学期大作业。
全过程可大体分为两步。第一,使用buildroot搭建一个MIPS32的交叉编译环境。第二,在此交叉编译环境下编写批处理文件,得到自己想要的指令的二进制编码。
搭建MIPS交叉编译环境
我们使用buildroot搭建交叉编译环境。关于buildroot,官网如是说:
Buildroot is a simple, efficient and easy-to-use tool to generate embedded Linux systems through cross-compilation.
总之我们可以知道,它在Linux系统上运行,并且可以搭建各种处理器的编译环境。
搭建过程分为三步:
下载buildroot
编译配置
配置结束后编译
首先下载源码,以下两种方案均可。
git方式获取:
$ git clone https://github.com/buildroot/buildroot.git
wget方式直接下载:
$ wget https://buildroot.org/downloads/buildroot-2020.02.tar.bz2 $ tar -jxvf buildroot-2020.02.tar.bz2
接着,
#下载依赖库, 用于显示后面的配置窗口 $ sudo apt-get install libncurses5-dev patch #编译配置 $ cdbuildroot-2020.02 $ make clean $ make menuconfig
执行make menuconfig
后首先会进入这样的界面,选择Target options
![9b5e11264b0ae5d207a9bc7b2a4ac3b6.png](https://i-blog.csdnimg.cn/blog_migrate/cdcf26672b18fbca0d60594311691b80.png)
然后在此选择Target Architecture
,也就是选择目标的体系结构。
![8ba4665709b92c577f2068a23825d30e.png](https://i-blog.csdnimg.cn/blog_migrate/1dea0c9e939cfb4853578c739360686d.png)
接着我们在这里按照自己的需要选择选择MIPS(big endian)
或者 MIPS(little endian)
,也就是MIPS的大端表示法或是小端表示法。如果设置的不对,后面编译的时候也可以使用参数来改变。
![66c9929f070c34774806dc5eb4e5b6b1.png](https://i-blog.csdnimg.cn/blog_migrate/95cf91ee4e705e71cc157c84bd78abe4.png)
选择后回退到最初的界面,在这里选中第三项Toolchain
![e5a5ee9ba50b996938c75aa810707cbb.png](https://i-blog.csdnimg.cn/blog_migrate/836ed1b3a47339d0594589eee0904658.png)
进入后选中Kernel Headers
,也就是选择合适自己当前操作系统的内核版本。
![823ec5855219e1f3a155f364cabb8c8d.png](https://i-blog.csdnimg.cn/blog_migrate/12badd8c9f793d124ac4fefac1d0c5a4.png)
如何查看自己的内核版本呢?
可以先退出配置窗口,而后使用 uname -r
命令即可看到自己的版本号。
![18cf1b8c74f18dd0125d4c448c972a27.png](https://i-blog.csdnimg.cn/blog_migrate/ef47c4f4eef610bdbbb8f8c7c35ab7d5.png)
继续刚才的操作,在Kernel Headers
这里选择合适的版本号。最后返回,Save
后Exit
。
![518187668ed4a7d6916b28d2db7cf07b.png](https://i-blog.csdnimg.cn/blog_migrate/01976e611219fa1d4268e155dfdcb99b.png)
处理完之后,就可以直接make
啦!
$ make
注意此时要保持网络状态良好,因为过程中需要安装一些依赖库。
最后让我们来康康是否安装成功了,打开/buildroot-2020.02/output/host/bin,就可以看到可以安装好的各种编译工具啦!
![0e8eaacd9d72c140e3ca92bebf2bb0aa.png](https://i-blog.csdnimg.cn/blog_migrate/5aed3dfde6b60e6f7cfdb68e62e53083.jpeg)
到这里安装已经完成了!接下来,我们做下一步——制作一个批处理文件来直接编译。
创建批处理文件将 MIPS32 汇编文件编译二进制文件
首先,我们先弄清楚编译应该是这样一个过程:
创建汇编文件
.org 0x0.global_start.setnoat_start: #需要加以上四行,以便后续编译 ori$1,$0,0x1100 #$1=$0 | 0x1100
编译,得到可重定位目标文件
./mips-linux-astest.S -o test.o
链接,得到可执行目标文件
需要在目录下增加链接表述脚本,如果没有则无法链接成功。文件名为ram.ld,如下,注意文件格式要求,空格不可随意省略。这个文件定义了一个存储块ram及其起始地址、长度;包括三个section,每个section对应着输入文件的.text,.data,.bss。
MEMORY { ram :ORIGIN = 0x00000000,LENGTH = 0x00001000 }SECTIONS{ .text: { *(.text) } > ram .data: { *(.data) }> ram .bss: { *(.bss) }> ram}ENTRY (_start)
然后链接
./mips-linux-ld -T ram.ld test.o -o test.om
将可执行文件转成二进制文件,注意此时使用vi编辑器打开未必能看到的是二进制,此时可以在vi下输入命令
:%!xxd
,此时即可看到十六进制的指令./mips-linux-objcopy -O binary test.om test.bin
但得到的十六进制指令依旧不能直接作为CPU的指令输入,因为它除了指令外还包含可执行文件不可缺少的一些内容。像下面这样的:
00000000: 0002 4942 0023 5006 0002 2403 0026 2807 ..IB.#P...$..&(.00000010: 3c01 0101 3c02 1011 0000 0000 0022 1825 <...>
那么我们需要写一个小小的程序将中间的指令提取出来,并且注意到中间的数字并非全是指令,所以可能得给我们的小程序传递指令个数的参数,因为我们准备写批处理文件,所以应该将参数放到一个文件(在我这里是inst_num.txt)里,到时候读取文件。处理的小程序是obj2inst,最终结果输出到inst_rom.data。
梳理清楚之后我们就可以写Makefile文件了,将代码直接贴在下面:
ifndefCROSS_COMPILE CROSS_COMPILE =./mips-linux- endif CC = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump OBJECTS = inst_rom.o export CROSS_COMPILE all: inst_rom.data %.o: %.S $(CC) $
关于以上代码做一些说明:注意第2行的应该写出Makefile文件和在/buildroot-2020.02/output/host/bin/下面的编译文件的相对地址。例如如果是和buildroot-2020.02同级的目录下应该写./buildroot-2020.02/
output/host/bin/mips-linux-。
这里提一下makefile语法
目标:依赖文件 命令
$^ :所有依赖文件
$< :第一个依赖文件
$@ :目标文件
最后说明几点:
本文安装buildroot部分参考了buildroot的安装手册和一些相关博客,同学们可以自行百度;
写批处理文件部分,参考了《自己动手写CPU》(雷思磊);
在不同机器上操作还是有一些出入,或许同学们尝试之后发现自己的和我上面描述的有不同,但总体上方法如此,可以自己稍作探索,应该就能找到方法解决。
所有代码放在beenleyi.github.com/MIPS32_CPU
_design/MIPS32_assinst2bin中
撰稿人: 易璐
审稿人:钟宏涛
![d8bf2cc34bdf9d51feba4a23ed5d7e54.png](https://i-blog.csdnimg.cn/blog_migrate/d88731b6eb85359858aa4e25bcd51105.jpeg)