如何获取MIPS汇编对应的机器码
在看《自己动手写CPU》的时候,里面需要将MIPS转换成机器码作为输入的指令,不过书上的工具以及一些步骤在实际中是不能用的,因此在这里将“从MIPS汇编转换成机器码”的完整过程下来
安装Linux虚拟机
因为汇编工具需要在Linux的环境下运行,所以需要安装Linux虚拟机,我用的软件是VMware,Linux系统是Ubuntu 18.04,具体的安装过程网上有很多教程,这里就不再详细的叙述了
安装GNU工具链
下载
百度云下载链接:https://pan.baidu.com/s/13RMZTfJNdQwe6hTz2S8Ndw
提取码:9z9w
添加环境变量
下载完成解压之后,在根目录使用vi .bashrc修改.bashrc的内容,在最后一行添加 export PATH=“$PATH:[工具链解压路径]/bin”,如下图所示
添加完成之后重启系统,重启完成后打开终端输入mips-linux-gnu-,然后按两次tab键就会列出刚刚安装的所有编译工具
这样,安装就算完成了,如果没有出现编译工具,那么应该是环境变量没有添加成功,请自行在网上搜索如何添加环境变量
我们会用到的GNU汇编工具
(前面都有mips-linux-gnu-前缀)
as: GNU汇编器,用来将汇编程序编译为目标文件
ld: GNU链接器,将目标文件通过ld链接、重定位数据生成可执行文件
objdump: 用于列出关于二进制文件的各种信息
使用GNU工具链进行编译
新建一个汇编程序文件
文件名为inst_rom.S(因为我是用来生成指令的,你可以替换为相应的文件),文件内容如下:
.org 0x0 #程序从地址0x0开始
.global _start #定义一个全局符号 _start
.set noat #允许使用寄存器 $1
_start:
ori $1,$0,0xf
mtc0 $1,$11,0x0
lui $1,0x1000
ori $1,$1,0x401
mtc0 $1,$12,0x0
mfc0 $2,$12,0x0
_loop:
j _loop
sync
一个简单的mips汇编程序
编译
mips-linux-gnu-as -mips32 inst_rom.S -o inst_rom.o
使用 as 来进行编译,“-mips32” 选项表示按照MIPS32 指令集架构进行编译,”-o” 选项用于指令生成的目标文件
链接
使用 ld 来进行链接,在 ld 的参数中需要声明一个链接描述脚本,链接描述脚本用于描述输入文件各个Section如何映射到输出文件的各个Section中,并控制输出文件中Section和符号的内存布局
新建一个链接描述脚本文件
文件名为 ram.ld,文件内容如下:
MEMORY
{
ram(wrx) :ORIGIN = 0x00000000, LENGTH = 0x00001000
}
SECTIONS{
.text :
{
*(.test)
} > ram
.data :
{
*(.data)
} > ram
.bss :
{
*(.bss)
} > ram
}
ENTRY (_start)
其中定义了一个存储块——ram,并且权限为wrx,wrx在Linux中表示可读、可写以及可运行(我个人的理解,并且没有这个就不能使用),其起始地址为0x0,长度为0x1000,然后只是编译器输出文件包含三个Section,分别是 .text、.data、.bss,这三个Section从ram的起始地址开始依次存放,并且与输入文件中的这三个Section意义对应,最后的ENTRY指定程序的入口地址,也就是前面汇编程序中定义的那个全局符号 _start
链接
mips-linux-gnu-ld -T ram.ld inst_rom.o -o inst_rom.om
得到对应的机器码
获取反编译文件
mips-linux-gnu-objdump inst_rom.om inst_rom.asm
书上是用的 objcopy得到 二进制文件,然后用他的那个工具从中提取出机器码的内容,因为我是看的电子书,没有光盘,在网上也没找到那个小程序,所以只能改为使用 objdump 获取反编译文件
利用小程序提取机器码
小程序的获取:百度云链接:https://pan.baidu.com/s/1uFx2Oae7EMfTz_M0a9hMRA
提取码:2fh3
.myfun.exe inst_rom.asm inst_rom.data
最后生成的inst_rom.data中就是我们需要的机器码文件了
通过Makefile来简化操作
从一个汇编程序打机器码文件,需要四步操作:编译、链接、反编译、提取,有些繁琐,如果对输入文件以及输出文件的名称没有要求的话,可以使用Makefile来简化操作,如果有要求,也可以通过修改Makefile来完成操作,相对来说也很简便
编写Makefile文件
新建一个文件,名为Makefile,文件内容如下
ifndef CROSS_COMPILE
CROSS_COMPILE = mips-linux-gnu-
endif
CC = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJECTS = inst_rom.o
export CROSS_COMPILE
# 前面的应该都好理解,就是一些别名
all:inst_rom.data # 最后要获取的文件
inst_rom.o: inst_rom.S # $<表示输入文件, aaa@qq.com表示输出文件
$(CC) -mips32 $< -o aaa@qq.com # $< 对应inst_rom.S,aaa@qq.com对应inst_rom.o
inst_rom.om: ram.ld $(OBJECTS)
$(LD) -T ram.ld $(OBJECTS) -o aaa@qq.com
inst_rom.asm: inst_rom.om
$(OBJDUMP) -D $< > aaa@qq.com
inst_rom.data: inst_rom.asm
./myfun.exe $< aaa@qq.com
build:
touch inst_rom.data
clean: # make clean时清除以下文件
rm -f *.o *.om *.asm *.data
在makefile中最后要获取的是inst_rom.data文件,而获取inst_rom.data需要inst_rom.asm文件,所以执行 ./myfun 那一步操作,而inst_rom.asm选哟inst_rom.om ,以此类推依次执行makefile中的内容
以后在命令行使用make就可以完成所有的操作了
推荐阅读