要实现打印出子函数的段地址和偏移地址,首先要知道,子函数的段地址和偏移地址放在哪里。我们在《20140426_综合研究2研究报告》中发现:(1)函数的名字就代表它的偏移地址。(2)函数的调用在汇编里是采用call-ret方法实现的。另外我们知道汇编中存储当前段地址的寄存器为CS寄存器。
首先填充main函数,分别打印每一个函数的偏移地址,以及运行函数后CS寄存器的值:
显示结果为:
发现main函数的偏移地址为21b,f1的偏移地址为1fa,f2的偏移地址为205,f3的偏移地址为210,cs寄存器的一直为1a2.那么CS里的值真的是子函数的段地址的值吗?我们用debug加载程序:
发现main()、f1()、f2()、f3()的偏移地址是对的。但是段地址应为076a而不是打印出来的CS寄存器的值1a2。
如果用长整形将main函数和f1的值全部打印出来:
则段地址还是1a2。但是用debug查看并不一样。那么问题在哪里呢?
在网上查看,发现有一个相似问题的解释是这样的:“调试的情况下 是用调试器来实对 单步 断点异常的处理。加载了更多的函数。 当然地址会不一样了。”
我觉得可能是直接运行和debug调试分配的内存空间不一样,如上所说,debug调试要加载更多的函数,所以main函数的段地址会相对较大。
但是这里是子函数和main函数在一个段里,所以子函数的段地址可以在主函数里用_CS
表示,如果子函数和main函数不在一个段里呢?我们知道:用tcc hello.c生成的文件可有两个段,一个为代码段,一个为栈和数据段。所以��函数和主函数都要在同一个代码段里。那么如果代码量超过64kb,一个段存放不下,怎么办?在网上查阅资料如下:
C 语言中提供了6种编译模式,这6种模式是:
微模式(Tiny),小模式(Small),中模式(Medium),紧凑模式(Compact),大模式(Large)和巨模式(Huge)。它们之间的关系如下图所示。用户可以按照自己的程序大小及需要进行选择。
│ 小程序 │ 大程序
━━━━┿━━━━━━┿━━━━━━━━
小数据 │ 微,小 │ 中
大数据 │ 紧凑 │ 大,巨
所谓小程序就是指程序只有一个程序段,大小不超过64KB,缺省的码(函数)指针是near(近程指针)。所谓大程序就是指程序只有多个程序段,每个程序段不超过64KB,但总程序量可超过64KB,缺省的码指针是far(远程指针)。小数据就是指数据只有一个数据段,缺省的数据指针是near。大数据就是指数据有多个数据段,缺省的数据指针是far。