汇编程序会经过二次遍历,有些符号引用会被标记为可重定位,在编译好后他们的偏移值是其在代码内部的偏移值,即LC计数器的值,当载入内存运行时,由于起始加载地址会不确定,所以会在加载后把代码段所在的内存起始地址加到符号引用原有的偏移上,这就叫重定位。比如一个jmp abc会跳到代码段内部偏移10的地方,但是代码被加载到内存偏移1000,所以实际上那个abc标号偏移10的地方在实际的内存里面偏移是1010,所以再继续往abc(偏移10)跳会出问题,故而给abc的偏移10加上加载处起始地址1000,得出1010,这样jmp 1010就执行正确了,达到重定位的目的。
不加这个选项,默认ld会给代码内所有的偏移加上0x08048000,导致head.s代码内很多16位寄存器盛不开这个大数,报错。而使用-Ttext 0会告诉ld给代码内所有的偏移加上0,这样相当于还是保留了符号引用的原值(即代码内偏移量——LC)。当head程序被boot加载到内存0地址处运行时,真实的内存引用计算方法是代码原偏移+0,也就还是原偏移,而程序里的符号引用的偏移恰好依然是原偏移,所以内存引用正确。
对于一般的汇编程序在OS存在的情况下ld链接,默认的都是把代码段原偏移加上0x08048000然后做成elf可执行文件,因为OS的加载器把elf代码加载到0x08048000处运行,而非0x0处,这样的话内存实际引用是原偏移+0x08048000,而代码段内的符号引用确实已经被改为了原偏移+0x08048000,故而引用正确。
由此来看,我们的手动用-Ttext 0把代码内部符号引用的偏移加上0,然后又把代码手动加载到0处运行,正好是起到了加载器的作用。故,一切正常。