Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is "ld -Ttext" option doing?

Tags:

linker

kernel

ld

I am following this half-completed tutorial to develop a simple OS. One step (on page 50) is to compile a simple kernel with $ld -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary. However I don't really understand what is the option -Ttext doing.

To make the question specific, why in the following experiment are md5s of kernel_1000.bin & kernel.bin equal, kernel_1001.bin & kernel_1009.bin equal, and kernel_1007.bin & kernel_1017.bin equal, while all other pairs are not equal?

My experiment

I tried to compile several different kernels with different -Ttext like the in the following Makefile:

...
kernel.o: kernel.c
    gcc -ffreestanding -c kernel.c

kernel.bin: kernel.o
    ld -o $@ kernel.o --oformat binary

kernel_1000.bin: kernel.o
    ld -o $@ -Ttext 0x1000 kernel.o --oformat binary

kernel_1001.bin: kernel.o
    ld -o $@ -Ttext 0x1001 kernel.o --oformat binary
...

And then I checked their md5:

$ ls *.bin | xargs md5sum
d9248440a2c816e41527686cdb5118e4  kernel_1000.bin
65db5ab465301da1176b523dec387a40  kernel_1001.bin
819a5638827494a4556b7a96ee6e14b2  kernel_1007.bin
d9248440a2c816e41527686cdb5118e4  kernel_1008.bin
65db5ab465301da1176b523dec387a40  kernel_1009.bin
216b24060abce034911642acfa880403  kernel_1015.bin
e92901b1d12d316c564ba7916abca20c  kernel_1016.bin
819a5638827494a4556b7a96ee6e14b2  kernel_1017.bin
d9248440a2c816e41527686cdb5118e4  kernel.bin

kernel.c

void main() {
  char* video_memory = (char*) 0xb8000;
  *video_memory = 'X';
}

Development environment

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10) 
$ uname -a
Linux localhost 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u1 (2015-12-14) x86_64 GNU/Linux
like image 627
wlnirvana Avatar asked Jan 05 '16 22:01

wlnirvana


1 Answers

The -Ttext option puts the .text section of your program by the given address. For example if you are compile this assembly code:

section .text
global _start
_start:
    mov al, '!'
    jmp l
l:  mov ah, 0x0e
    mov bh, 0x00
    mov bl, 0x07

    int 0x10
    jmp $

times 510-($-$$) db 0

db 0x55
db 0xaa

with:

nasm -f elf64 -o test.o test.S
ld -o test test.o

And will look on it with the objdump, you will see that it was linked by default address, something around 0x0000000000400000 for the x86_64:

~$ objdump -D test

test:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:   b0 21                   mov    $0x21,%al
  400082:   eb 00                   jmp    400084 <l>

0000000000400084 <l>:
  400084:   b4 0e                   mov    $0xe,%ah
  ...
  ...
  ...

And all addresses in the program (at least in the .text section) will be relative to this address. If you will add the -Ttext 1000 option, you will see:

~$ objdump -D test

test:     file format elf64-x86-64


Disassembly of section .text:

0000000000001000 <_start>:
    1000:   b0 21                   mov    $0x21,%al
    1002:   eb 00                   jmp    1004 <l>

0000000000001004 <l>:
    1004:   b4 0e                   mov    $0xe,%ah

That you program will be linked to start at 0x1000 address and all addresses (including jmp and etc.) will be relative to the 0x1000 to.

This important for two things. In short words, when an operating system kernel loads your program, it loads your executable which is in elf format or in other binary format and reads where the .text section starts. In our case, you can link your kernel.bin as you want, because there are no loaders as an operating system kernel and your are master of all memory space.

So if you will link your kernel.bin to start at 0x1000, you will know where the code starts to work (of course if it will actually loaded at this place in memory) and if you know the base address of your code, you can get all addresses inside it, something like my_label_inside_program - _start.

like image 94
0xAX Avatar answered Nov 11 '22 09:11

0xAX