本文已参与「新人创作礼」活动,一起开启掘金创作之路。
汇编器名字为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,名称为源文件的名字,下图为第一版的展示图)
代码详见github,网址如下:
可编译的指令如下:
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为生成的文件:
在VM上的设置如下,os.img为生成的文件:
早期代码很粗糙,很多地方写的非常冗余,未来如果有时间还是需要更多优化的。