关于tcc、tlink的编译链接机制的研究(3)

由上可知,我们所说的只有一个代码段的程序是小程序,它的代码不超过64kb,在编译时会以默认的编译模式:小模式来编译。即前面研究里所说的tcc a.c生成的exe文件有一个代码段,一个栈和数据段就可以理解了。我们用TC2.0的时候不可缺少的相关文件里有关编译模式的是c0s.objcs.lib,所以TC2.0默认的编译模式是小模式。所以默认的编译只能编译代码量不超过64kb的文件。 

关于不同模式的区别,查询资料如下:

C语言编译模式—微模式(Tiny)
    在微模式下程序中的数据及代码均放在同一段内,即它们不超过 64KB。在微模式下代码段、堆栈段和数据段的段地址均相同,即CS=DS=SS=ES。在微模式下,数据指针都是 near,一般小程序可采用此编译模式进行编译。还可用 DOS 中的 EXE2BIN 转换程序将.EXE 程序转换成.COM 程序。代码段、数据段和堆栈段均在同一段内,对它们进行寻址时,均以同一地址偏移的参考点,具有这种特点的段又称为属于同一组段(DGROUP),栈是向上生长的,即每压栈一次,栈指针SP减2,即向地址减少的方向移动,它开始的初始值指向栈底,即0xffff(64KB)。堆是向下生长的,即向增加地址的方向改变。堆和栈地址相向生长,当两者未相遇时,便出现了自由空间。一般程序均是这种状态,当占用栈地址较多时,两者可能重合并覆盖部分堆空间。

C语言编译模式—小模式(Small)
在小模式下,程序中的代码放在64KB的代码段内,数据放在64KB的数据段内。在小模式下,栈段、附加数据段和数据段均指向同一地址,它们合三为一,即DS=SS=ES,指针都是near,一般程序均采用小模式编译。在小模式下,内存分配如下图所示。从图中可以看出数据段、堆栈段和附加段为同一段组,即它们的偏移地址均以同一段地址为参考点。

C语言编译模式—中模式(Medium)
在中模式下,所有数据放在64KB的数据段内,因而数据段内使用near,代码量可以大于64KB(允许达到1MB),因而可以在不同的代码段内,代码段使用(far远程指针)。这种编译模式适用于大代码量、小数据量的大程序。中模式下的内存分配如下图所示。

C语言编译模式—紧凑模式(Compact)

在紧凑模式下,数据量超过64KB时,可放在多个数据段中,数据段内的指针是(far)。代码量不超过64KB时,可在一个段内,因而代码段内指针为近程的(near)。但在该模式下,静态数据仍不能超过64KB,堆用far指针来存取。紧凑模式下的内存结构如下图所示。


C语言编译模式—大模式(Large)

大模式下,代码及数据均采用far指针,且都可达到1MB。静态数据仍跟紧凑模式一样,不能超过64KB。大模式下的内存结构如下图所示。

C语言编译模式—巨模式(Huge)

巨模式下,代码段及数据段均用far指针,代码分布在不同的代码段内,数据也分布在不同的数据段内,它们来自不同的源程序,大堆栈只有一个。而且静态数据大小允许超过64KB。巨模式下的内存结构如下图所示。

即不同模式的区别在于可编译的代码量和数据量不一样。那么在编译的时候对于超过64kb的文件该如何选择编译模式呢?

无论采用哪一种编译模式,C 源程序编译生成的代码和数据量都不能超过64KB,对于超过的源程序,可以视代码或数据多少将其分解成两个或多个程序分别编译。大代码量程序要选用大代码编译模式(中模式、大模式和巨模式),大数据量程序应选用大数据编译模式(紧凑模式、大模式和巨模式),这样编译生成的.obj 文件将会带给连接程序信息,将代码和数据安排在不同段内。这样生成的.exe 文件在加载时将告诉 DOS 该程序应如何装入代码段和数据段,如何初始化寄存器。这样,就可确定在不同编译模式下开辟数据区的大小,即大于64KB,或不超过64KB。

2、解决的问题

(1)TC2.0集成了tcc.exe、tlink.exe,并且包含了更多的功能。而tcc.exe、tlink.exe、c0s.obj、cs.lib、emu.lib、maths.lib是编译c文件必不可少的文件。

(2)怎么打印所有函数的段地址和偏移地址?

答:可以用printf(“%lx”,(long)函数名);来打印,这样段地址和偏移地址是连在一起的,也可以用printf(“%x     %x”,_CS,函数名);来打印,这样段地址和偏移地址是分开的。

(3)为什么输出的段地址和debug调试的段地址不一样?

答:debug调试要加载更多的函数,所以main函数的段地址会相对较大。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/571e793bdc0ee11f7e1f9c7263e4d907.html