编写程序如下:
编译连接并用 debug 加载,观察 main 函数的内容:
Showchar 函数的内容:
观察发现, main 函数要传递两个参数‘ a ’和 2 ,在汇编代码中是先将 2 赋给 ax ,再将 ax 入栈,然后将 a 赋给 ax, 将 ax 入栈。在 showchar 函数中,程序将 sp 赋给 bp ,再从 bp+4 处取出形参 a 赋给 al ,再将 al 中的值赋给 b800 : 690h ,然后再从 bp+6 处取出形参 b 赋给 al ,再将 al 中的值赋给 b800 : 691h 。可见 main 函数给 showchar 传递参数是把要传递的值赋给 ax ,再将 ax 入栈,且如果有多个要传递的值,是由后往前将参数入栈。 Showchar 函数接收参数是将 sp 赋给 bp ,然后由 bp+4 找到栈中存储的参数 a ,由 bp+6 找到栈中存储的的参数 b ,为什么是 bp+4 和 bp+6 呢?因为程序在将两个参数入栈后, call 指令将 showchar 的地址入栈占 2 个字节,在 showchar 中将 bp 入栈又占 2 个字节,所以要由 bp+4 找到第一个参数的地址。那么我对此提出三个问题:
(1)main 函数将 char 型数据和 int 型数据入栈是占 2 个字节,那么如果是 float 型或者 longint 型、 double 型、 longdouble 型等超过 2 字节的变量类型怎么办?
(2)Showchar 函数将栈中取出的参数赋给 al ,为什么 2 是 int 型也只赋给一个字节的 al ?如果是更大的参数怎么办?
(3)我们注意到这一个指令
是把 al 赋给 es : [bx] ,是不是所有非 ds 的段寄存器都要像这样写?
对于第一个问题,我们把程序中的 char 和 int 改成 float 和 double 看看:
编译连接,用 debug 查看, main 函数为:
Showchar 函数为:
发现 main 函数的入栈值为: 4008 、 0000 、 0000 、 0000 、 4006 、 6666.
再看 showchar 函数的内容,查资料发现 int35h 的作用是读取中断向量,但是不知道它的具体功能, incsi 和 lesax , [06fb] ; int39 的作用是什么呢?这里我对于 c 语言的一些语句在汇编里的实现还是有的不理解,但是这不是我们研究的重点,既然暂时弄不懂,就先跳过这个问题。
再看第三个问题,发现所有 es 作段地址的指令都是如上格式, ds 作段寄存器的指令都把 ds 省略了。
再来看下一个程序:
编译连接,用 debug 加载查看, main 函数为:
Showchar 函数为:
观察 C 语言的 showchar 函数可以发现:第一个参数 n 是要显示的参数数量,第二个参数 color 是要显示的参数颜色,之后的就是要显示的参数。 Showchar 函数通过参数 n 来知道要显示多少个字符。然后通过循环来调用寄存器从栈中提取参数。
但是 printf 函数的参数是要直接输出的,没有一个参数是告诉它下面有多少个参数。但是 printf 里面是要输入 %c 或者 %d ,那么函数是通过统计 %c 和 %d 的数量来判断要输出多少参数的吗?我们写一个 printf 函数来看看:
编译连接并用 debug 加载有:
这里是将参数 1 和 2 入栈,再入栈 194 ,然后执行 printf 函数,那么 194 有什么作用呢?查阅资料知,程序将 %c 和 %d 等符号放在偏移地址 0194 处,结尾加 0 ,通过统计该地址处的 % 个数来确定要输出的字符数量。所以 peintf 函数和 showchar 函数的区别就是 showchar 函数参数个数已给出而 printf 函数是要根据 %c 或 %d 个数来确定参数个数而已。那么我们要实现简单的 printf 函数,可以在 showchar 函数的基础上来改动。
下面是网上找的代码:
void printf(char *,...);
int pow(int, int);
main()
{
/*printf("I think this is interesting :%c and %c and %c",0x61,0x62,0x63);*/
printf("No.%d,%d,%d,this is me %c ing yuan",45,123,8958,'Q');
}
void printf(char *des, ...)
{
/*first sure the length of string des*/
int len=0;
int i=0;
int showp=0; /*define the point of showing chars*/
int parap=0; /*define of parameter position in stack*/
int intValueLength=1;
int signalNum=0;
/*calculate length of stirng des */
while(des[i]!='/0'){
len++;
i++;
}
i=0;
while(des[i]!='/0'){
if(des[i]=='%'){
/*check type of value user want to show.*/
if(des[i+1]=='d'){
/*here show integer value*/
int showIntValue=*(int *)(_BP+6+parap+parap); /*here, we show understand that define one char point value, we just push the point value into stack, but not the string value*/
int reValue=showIntValue;
/* *(int far *)(0xb8000000+160*10+80+showp+showp)=showIntValue;
*(int far *)(0xb8000000+160*10+81+showp+showp)=2;*/
i+=2;
parap++;
intValueLength=1;
/*here we calculate the length of integer value we want to show ,and then we can sure the next value show position*/
while(reValue/10!=0)
{
intValueLength++;
reValue/=10;
}
/*first calculate the length of unmber and show every sigal positon number of Integer *