【原创】【自制编程语言】2.控制寄存器

如果是从中间来的,建议先从第一篇看起:https://www.cnblogs.com/jisuanjizhishizatan/p/16241991.html

第2天:控制寄存器

上一次,我们写了最基础的简单架构,接下来我们就要开始用上我们的寄存器了。

本次的成品测试代码是这样的:

mov eax 3
mov ebx 2
mov esi eax
debug
end

先从mov指令开始,mov指令时比较简单的一个指令(准确的说并不简单,我们今天只考虑操作数是寄存器的情况,即操作数不可能出现[ebp+16]这类的内存)

于是,为了通过输入的字符串来获得一个寄存器变量,其实为了方便赋值,函数的返回值一般是不可修改的,因此我们就返回指针,写一个函数:

int *getRegister(Word s){//给定一个寄存器字符串,获取它的地址(地址是因为方便赋值) 
	if(s=="eax")return &eax;
	else if(s=="ebx")return &ebx;
	else if(s=="ecx")return &ecx;
	else if(s=="edx")return &edx;
	else if(s=="esi")return &esi;
	else if(s=="edi")return &edi;
	else if(s=="ebp")return (int*)&ebp;
	else if(s=="esp")return (int*)&esp;//它们都是指针类型,要强制转换一下
	else return NULL; 
}

对于ebp和esp,我们以后如果写到函数调用,或许在栈上会使用,因此是指针类型,做了一次强制类型转换(当然这不太好,但是勉强忍受一下吧)

最后一句return NULL,如果函数返回NULL就说明这不是一个寄存器。

然后就是,如果在输入的时候有常数(如mov eax 3)我们就需要把字符串的常数转为数字,可以通过sscanf(当然stringstream也可以,看个人习惯)

int getNum(Word s){//给定一个数字串,获取它的数字形态 
	int res;
	sscanf(s.c_str(),"%d",&res);
	return res;
} 

sscanf第一个参数是作为输入的字符串,第二个参数是格式串,我们通过s,以%d整数的形式,输入到res变量中,相当于进行了一次转换。

然后就是mov语句,对于两个字符串s1和s2,进行赋值操作:

void mov(Word s1,Word s2){
	int *p=getRegister(s1);
	if(p==NULL)error();
	int *q=getRegister(s2);
	if(q==NULL){//不是寄存器,就看做数字处理 
		q=new int;*q=getNum(s2);
	}
	*p=*q;//完成赋值! 
}

题外话:对于正常的汇编语言是这样写mov语句的:

mov eax,1

中间有逗号分隔,其实我们这里也可以用逗号分隔的,实现起来应该也很简单,只不过我懒得弄了。这样就基本把我们的代码完成了。

对了,现在由于还没有输出指令,因此不能查看寄存器的值,所以现在我就考虑写了一个debug指令,用于输出寄存器的值。当然,这个指令只是一个调试指令,后续会考虑专门做个中断函数之类的,或者等call,ret指令写出来之后,直接用call和ret来调用库函数scanf和printf。

完整的代码就是这些了。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
using namespace std;
typedef string Word;
int eax,ebx,ecx,edx,esi,edi;
int *ebp,*esp;
Word *eip;

Word wd[32768+10];
Word getword(){
	return *(eip++);
}

int *getRegister(Word s){//给定一个寄存器字符串,获取它的地址(地址是因为方便赋值) 
	if(s=="eax")return &eax;
	else if(s=="ebx")return &ebx;
	else if(s=="ecx")return &ecx;
	else if(s=="edx")return &edx;
	else if(s=="esi")return &esi;
	else if(s=="edi")return &edi;
	else if(s=="ebp")return (int*)&ebp;
	else if(s=="esp")return (int*)&esp;//它们都是指针类型,要强制转换一下
	else return NULL; 
}
int getNum(Word s){//给定一个数字串,获取它的数字形态 
	int res;
	sscanf(s.c_str(),"%d",&res);
	return res;
} 
void error(){
	printf("Error: EIP %d\n",eip);
	exit(1);
}
void mov(Word s1,Word s2){
	int *p=getRegister(s1);
	if(p==NULL)error();
	int *q=getRegister(s2);
	if(q==NULL){//不是寄存器,就看做数字处理 
		q=new int;*q=getNum(s2);
	}
	*p=*q;//完成赋值! 
}
void debug(){
	printf("eax..%d ebx..%d ecx..%d edx..%d\n",eax,ebx,ecx,edx);
	printf("esi..%d edi..%d ebp..%d esp..%d\n",esi,edi,ebp,esp);
	printf("eip..%p\n",eip);
}
int main(int argc,char** argv){
	if(argc!=2){
		printf("The syntax of the command is incorrect.\n");
		exit(1);
	}
	FILE *fp=fopen(argv[1],"r");
	eip=wd;
	for(;;){
		char s[100];
		int i=fscanf(fp,"%s",s);
		if(i==EOF)break;
		*eip=s;++eip;//*eip就是读取的指令单词 ,存储在wd数组中 
	}
	eip=wd;
	
	for(;;){
		Word s=getword(); 
		if(s=="end"){
			exit(0);
		}
		else if(s=="mov"){
			Word s1,s2;
			s1=getword();s2=getword();
			mov(s1,s2);
		}
		else if(s=="debug"){
			debug();
		}
	}
	
	return 0;
}

本期的内容到此结束,我们下期再见。

posted @ 2022-05-07 16:02  计算机知识杂谈  阅读(137)  评论(0编辑  收藏  举报