王爽汇编语言综合研究-不用main函数编程

这一部分继续深入研究用汇编解释c的原理,尝试不用main()函数编写可以正确运行的程序

1、首先编写一个简单的程序

f()
{
	*(char far *)(0xb8000000+160*10+80) = 'a';
	*(char far *)(0xb8000000+160*10+81) = 2;
}

在TC中编译,连接这个程序。出现了一个连接错误

1

Linker Error:Undefined symbol ‘_main’in module C0S(未定义的符号_main在模块C0S中)

这句话说明,c语言的入口函数main函数是被C0S.obj所调用。

现在我们用汇编语言所使用的连接器Link.exe来连接c语言编译后的.obj文件得到一个.exe文件,用debug调试这个.exe文件

2

从反编译后的指令看到,偏移地址为0开始的程序就是我们编写的程序。在资源管理器中看到,这个文件只有541个字节。但是执行后不能正确返回

2、正常的程序

下面编写一个正常的程序

main()
{
	*(char far *)(0xb8000000+160*10+80) = 'a';
	*(char far *)(0xb8000000+160*10+81) = 2;
}

用TC环境编译连接这个程序,执行后屏幕中央显示一个绿色的a,并且正确返回。用Debug分析

3

与上一个不能正确返回的程序比较,这个程序中我们编写的程序位于偏移地址为01FA的位置,这个程序有4.17k字节。但是我们编写的部分两个程序是完全一样的。

继续深入探究,从0偏移地址开始反汇编上面的程序,找到CALL 0aFA 这样的指令

4

如图,C0S模块在这里调用了main函数

继续跟踪执行的过程,可以找到函数返回的代码处

5

这就找到了调用我们程序的指令和返回操作系统的指令,但是这些程序是哪儿来的呢。刚才连接错误指向了C0S.obj,猜想是连接器将C0S和我们的程序编译后的.obj文件连接到一起,也就是调用main函数的指令来自于c0s.obj文件

3、分析C0S.obj文件

用Link.exe连接c0s.obj文件,出现几个错误,不用理它。用debug调试生成的c0s.exe文件

 6 7

观察上边两个程序的代码,发现两个程序中代码非常相似

继续在两个程序中查找main的入口函数

8  9

如图,在m.exe中,call 01fa调用了main函数;在c0s.exe中,相同位置也有一次调用,但是因为没有main函数,连接器找不到main的位置,直接指向了下一条指令

4、生成.exe程序的过程

从上文分析和探索可以看出,tc.exe将c0s.obj和用户.obj一同连接,生成.exe 。所生成的exe程序运行过程如下:

①c0s.obj里的程序先运行,进行相关的初始化。如申请资源,设置ds,ss等相关寄存器

②c0s.obj里的程序调用main函数,从此用户程序开始运行

③用户程序运行结束从main程序返回到c0s.obj的程序中

④c0s.obj的程序接着运行,进行相关的资源释放,环境恢复的工作

⑤c0s.obj的程序调用DOS的int 21h例程的4ch号中断功能,程序返回

由以上资料,c开发系统提供了c程序所必须的初始化和程序返回等相关程序,这些程序放在相关.obj文件中,这些程序和用户写的程序编译后的.obj文件进行连接,用户程序才可正确运行。运行时由c0s.obj文件中的程序调用main函数来运行用户程序

通过这些分析,我们只要重写一个c0s.obj文件即可不用main函数编程

5、不调用用main函数的c0s.obj

编写这样一个汇编程序c0s.asm

assume cs:code

data segment
    db 128 dup (0)
data ends

code segment
start:
    mov ax,data
    mov ds,ax
    mov ss,ax
    mov sp,128
    call s

    mov ax,4c00h
    int 21h

s:
code ends

end start

将这个程序编译成c0s.obj文件,然后替代TC中的c0s.obj

再次连接程序,程序连接成功。运行后成功返回。

用Debug调试这个程序并反汇编

10

发现编写的用户程序(f程序)是作为一个子程序出现在程序中的,这个程序被c0s.obj中的指令所调用,调用完成后返回操作系统。

这个程序模拟了c0s.obj的主要功能

6、继续深入探究

编写程序

#define Buffer ((char *)*(int far *)0x02000000)

f()
{
	Buffer = 0;
	Buffer[10] = 0;
	while (Buffer[10] != 8)
	{
		Buffer[Buffer[10]] = 'a'+Buffer[10];
		Buffer[10]++;
	}
}

这个程序与上一节中程序类似,所不同的是安全空间不是从内存空间中用malloc()来申请,而是直接赋值成为了0,也就是指向内存区域的指针为ds:0。其它详细部分参考使用内存空间的综合研究

验证这个猜想,可以运行程序到返回之前,查看ds段是否写入了a-h,如图

11

如图,程序确实写入到了ds段

posted @ 2010-04-17 16:25  石莹  阅读(3152)  评论(0编辑  收藏  举报