2016-01-05 4 views
1

Я следую this half-completed tutorial, чтобы разработать простую ОС. Один шаг (на стр. 50) заключается в компиляции простого ядра с $ld -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary. Однако я не совсем понимаю, что делает вариант -Ttext.Что такое опция «ld -Ttext»?

Для того, чтобы вопрос конкретно, почему в следующем эксперименте md5s из kernel_1000.bin & kernel.bin равного kernel_1001.bin & kernel_1009.bin равны, и kernel_1007.bin & kernel_1017.bin равны, в то время как все остальные пары не равны?

Мой эксперимент

Я попытался собрать несколько различных ядер с различными -Ttext Понравился в следующем Makefile:

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

kernel.bin: kernel.o 
    ld -o [email protected] kernel.o --oformat binary 

kernel_1000.bin: kernel.o 
    ld -o [email protected] -Ttext 0x1000 kernel.o --oformat binary 

kernel_1001.bin: kernel.o 
    ld -o [email protected] -Ttext 0x1001 kernel.o --oformat binary 
... 

А потом я проверил их 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 

ядро. c

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

Среда разработки

$ 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 

ответ

4

Опция -Ttext ставит .text часть вашей программы по данному адресу. Например, если вы скомпилировать этот сборочный код:

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 

с:

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

И будет смотреть на него с objdump, вы увидите, что он был связан по адресу по умолчанию, что-то около 0x0000000000400000 для 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 
    ... 
    ... 
    ... 

И все адреса в программе (по крайней мере, в разделе .text) будет относительно этот адрес. Если вы добавите опцию -Ttext 1000, вы увидите:

~ $ objdump -D тест

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 

Что вы программа будет связана начать с 0x1000 адреса и адреса всех (в том числе JMP и т.д.) будет относиться к 0x1000.

Это важно для двух вещей. Короче говоря, когда ядро ​​операционной системы загружает вашу программу, оно загружает ваш исполняемый файл, который находится в формате elf или в другом двоичном формате, и читает, где начинается раздел .text. В нашем случае вы можете связать свой kernel.bin так, как вы хотите, потому что в качестве ядра операционной системы нет загрузчиков, и вы являетесь хозяином всего пространства памяти.

Поэтому, если вы свяжете kernel.bin, чтобы начать с 0x1000, вы узнаете, где код начинает работать (конечно, если он действительно будет загружен в этом месте в памяти), и если вы знаете базовый адрес вашего кода, вы можете получить все адреса внутри него, что-то вроде my_label_inside_program - _start.

Смежные вопросы