一个小型的汇编编译器

129 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

汇编器名字为train,包含4个源文件与6个头文件,源文件约2200行代码,头文件共约500行,可识别并编译27项16位指令。代码支持vs2013及更高版,支持gcc 6.3.0及更高版本,gcc编译过程如图: (2019.7.26更新,直接在终端输入make来编译,编译文件时可以输入"./train.exe 源文件1.asm 源文件2.asm 源文件3.asm ·······",编译后的文件后缀名默认为bin,名称为源文件的名字,下图为第一版的展示图)

20180425190240367 代码详见github,网址如下:

github.com/lindorx/tra…

可编译的指令如下:

mov,in,out,jbe,jb,jz,je,jmp,shr,shl,cmp,add,sub,mul,push,pop,db,dw,dd,resb,org,int,hlt,and,or,xor,not

为了简化语法,基于nask和nasm语法,做了一定程度修改,借鉴nasm的语法格式和nask简洁的操作数表达形式。 开发最初使用的是c++,但是由于当时并未深入了解面向对象的写法,导致代码结构都是按照c的形式实现的,基本原理就是逐行读取代码,为每个助记符实现了操作函数,根据匹配跳转到指定的函数处理,其中最麻烦的jmp指令,需要联系上下文处理,当时的实现办法是使用几个变量记录当前指令块的进度,然后遇到jmp再确定偏移量。对于指令具体对应的二进制,则用最简单的办法,使用gcc编译汇编,然后用winhex查看,一个一个试出来。

编译效果,测试:

例子: 以下汇编代码用来生成一个fat12格式的软盘文件,是一个非常小的操作系统,在模拟机上引导进入系统后,会在屏幕上显示“hello,world”字样,汇编代码摘自川合秀实的书《30天自制操作系统》。

;hello-os
;TAB=4
org0x7c00;指明程序装载地址
;描述用于标准FAT12格式的软盘
jmp entry
db 0x90
DB    "HELLOIPL"
DW    512
DB    1
DW    1
DB    2
DW    224
DW    2880
DB    0xf0
DW    9
DW    18
DW    2
DD    0
DD    2880
DB    0,0,0x29
DD    0xffffffff
DB    "HELLO-OS   "
DB    "FAT12   "
RESB  18
;程序核心
entry:
mov        ax,0        ;初始化寄存器
mov        ss,ax
mov        sp,0x7c00
mov        ds,ax
mov        es,ax
mov        si,msg
putloop:
mov        al,[si]
add        si,1        ;给si加1
cmp        al,0
 
je        fin
mov        ah,0x0e        ;要显示的一个字符
mov        bx,15        ;指定字符颜色
int        0x10        ;调用14号中断,调用显卡bios
jmp        putloop
fin:
hlt                ;让cpu停止工作,等待指令
jmp        fin        ;无限循环
msg:
db        0x0a,0x0a        ;换行两次
db        "hello,world"        ;要显示的字符串
db        0x0a                ;换行
db        0
 
RESB    0x1fe-$
 
DB    0x55,0xaa
 
DB    0xf0,0xff,0xff,0x00,0x00,0x00,0x00,0x00
RESB  4600
DB    0xf0,0xff,0xff,0x00,0x00,0x00,0x00,0x00
RESB  1469432

在VM上的设置如下,os.img为生成的文件:

20180425190654297 在VM上的设置如下,os.img为生成的文件:

20180425190736726.jpg

早期代码很粗糙,很多地方写的非常冗余,未来如果有时间还是需要更多优化的。