Lowlevel
Lowlevel => Softwareentwicklung => Thema gestartet von: sebi2020 am 21. March 2011, 12:27
-
Hallo,
habe seit ich graumer Zeit nicht mehr an meinem Kernel geschrieben habe wieder angefangen.
Ich habe vorher auf einem 32 Bit- Windows kompiliert und kompiliere nun unter einem 64-Bit Debian.
Auf jeden Fall hab ich meinen Kernel mit gcc kompiliert als elf32 (-m32) und im nasm mit -f elf32.
Das ganze dann gelinkt mit ld OUTPUT_FORMAT(elf32-i386) & OUTPUT_ARCH(i386:i386).
Ich bekomme dann aber beim booten unter VirtualBox von Grub immer gesagt:
Error 13: Invalid or unsupported executable format.
Hat jemand vielleicht eine Idee was ich falsch gemacht haben könnte?
Ich füge hier mal noch einen Objdump vom kernel und die Assemblerdatei für den Multiboot-Header und den spring in die init an.
Hoffentlich habt ihr ne Idee, woran es liegen könnte. Ich bin mit meinem Latein am Ende.
Gruß Sebi2020
; Written by Sebi2020
; Licensed under the GPL (General Public License)
; Project name: InfoOS
global loader
global load_selectors
MB_MAGIC equ 0x1badb002
MB_FLAGS equ 0x3
MB_CHECKSUM equ - (MB_MAGIC + MB_FLAGS)
section multiboot
; Multiboot Header
align 4 ; Durch 4 teilbare Adressen
dd MB_MAGIC
dd MB_FLAGS
dd MB_CHECKSUM
section .text
extern init ; Init ist extern (C-Code)
loader:
mov esp, 0x200000 ; Stack bei 2 MiB
push ebx ; Multiboot Struktur
call init ; Kernel initalisieren
kernel_end:
hlt ; Prozessor anhalten
jmp kernel_end
; Selektoren laden
load_selectors:
mov ax,0x10 ; Selektor 0x10 nach ax
mov ds,ax ; Datensegment updaten
mov es,ax ; Extra-Segement updaten
mov ss,ax ; Stack-Segment updaten
jmp 0x8:continue ; Selektor 0x8 nach CS laden und EIP erhöhen (far-jump)
continue:
ret ; Zu Init zurückkerhen (s. C-Code)
kernel: file format elf32-i386
Program Header:
LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**21
filesz 0x00102254 memsz 0x00122ac0 flags rwx
STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000000 memsz 0x00000000 flags rwx
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000200a 00100000 00100000 00100000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .rodata 00000190 0010200c 0010200c 0010200c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .data 000000b4 001021a0 001021a0 001021a0 2**5
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00020860 00102260 00102260 00102254 2**5
ALLOC
4 .comment 0000001c 00000000 00000000 00102254 2**0
CONTENTS, READONLY
Disassembly of section .text:
00100000 <loader-0x10>:
100000: 02 b0 ad 1b 03 00 add 0x31bad(%eax),%dh
100006: 00 00 add %al,(%eax)
100008: fb sti
100009: 4f dec %edi
10000a: 52 push %edx
10000b: e4 00 in $0x0,%al
10000d: 00 00 add %al,(%eax)
10000f: 00 bc 00 00 20 00 53 add %bh,0x53002000(%eax,%eax,1)
00100010 <loader>:
100010: bc 00 00 20 00 mov $0x200000,%esp
100015: 53 push %ebx
100016: e8 bb 00 00 00 call 1000d6 <init>
0010001b <kernel_end>:
10001b: f4 hlt
10001c: e9 fa ff ff ff jmp 10001b <kernel_end>
00100021 <load_selectors>:
100021: 66 b8 10 00 mov $0x10,%ax
100025: 8e d8 mov %eax,%ds
100027: 8e c0 mov %eax,%es
100029: 8e d0 mov %eax,%ss
10002b: ea 32 00 10 00 08 00 ljmp $0x8,$0x100032
00100032 <continue>:
100032: c3 ret
100033: 00 55 89 add %dl,-0x77(%ebp)
-
Sagt mbchk irgendwas interessantes? Wie sieht denn das Linkerskript aus? In welches (elf-)Segment geht die 'multiboot' Sektion?
-
"Der Multiboot-Header sollte in den ersten 8192 [0x2000] Bytes des OS-Images liegen."
Deine .text-Section in der sich dein Multiboot-Header befindet, hat einen FileOffset von 0x00100000, wird also von GRUB nicht gefunden.
Wie man das Fixt kann ich dir leider nicht sagen.
-
Also das Grub Programm steht komischerweise unter Debian nicht zur verfügung... Vielleicht sollte ich Grub noch mal neu installieren...
Der Multiboot-Header geht in die Text-Section. Das System wird bei 0x100000 in den Speicher geladen, was sonst auch immer geklappt hat (bei meinen alten Versionen, die sich aber von der Speicheradresse und vom MB-Header eig nicht unterschieden haben.
Naja hier auf jeden Fall noch mal das Linker-Script: (ursprünglich)
ENTRY (loader)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386:i386)
SECTIONS
{
. = 0x100000;
kernel_start = .;
.text :
{
build/object/start.o(multiboot);
*(.text)
}
.data :
{
*(.data)
}
.bss :
{
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
/* Auf 4k Adresse aufrunden */
. = ALIGN(4096);
kernel_ende = .;
}
Hab es nochmal so probiert, dass hat aber keine Besserung gebracht (nur das die Image Datei statt 1,7 Mb nun stolze 3,7 Mb groß ist:
ENTRY (loader)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386:i386)
SECTIONS
{
. = 0x0;
kernel_start = .;
.text :
{
build/object/start.o(multiboot);
. = 0x100000;
*(.text)
}
.data :
{
*(.data)
}
.bss :
{
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
/* Auf 4k Adresse aufrunden */
. = ALIGN(4096);
kernel_ende = .;
}
-
Also das Grub Programm steht komischerweise unter Debian nicht zur verfügung... Vielleicht sollte ich Grub noch mal neu installieren...
Das gibts nur bei grub legacy.
-
Vielleicht hilft dir ja das hier weiter: en:Grub Error 13 (http://wiki.osdev.org/Grub_Error_13)
-
Also ich hab mal nach dem Tut geschaut, die machen es nicht viel anders als ich, was das linkerscript angeht.
Hat keine Besserung gebracht. Vielleicht hab ich ja was übersehen, aber irgendwie klappt das auch nicht.
Hab jetzt diverse Errors von Grub bekommen.
So wie ich es bis jetzt gemacht habe ( Mutlibootheader . = 0x1000).
Und der Rest bei (0x100000 (1MB)).
Jetzt findet er den Multiboot-Header und sagt, Error 28: Selected Item doesn't fit into memory.
(Ich hab 160 MB Hauptspeicher für die Maschine genommen.)
(Das Kernel-Image ist 1 MB groß,.)
Wenn ich alles bei 0x1000 reinpacke, dann sagt er mir Loading below 1MB not supportet. Also den Error 28 verstehe ich nicht.
Macht iwi kein sinn 1 MB < 160 MB ?!?!
-
Naja, die beiden Fehler sagen ja nur aus, dass du Grub zerstört hast und das deine Partition-Table defekt ist. Mich wundert aber, dass er es überhaupt versucht. Grub müsste dich eigentlich rausschmeißen. Er lädt nichts unterhalb der 1MB Grenze. Du verstehst das auch falsch. Es geht grub nicht darum, dass es an eine bestimmte geladen werden soll. Er sucht in deinem ELF-File innerhalb der ersten 8 kB nach dem Header. Du musst dafür sorgen, dass das Zeug mit dem Multiboot-Header möglichst weit vorne in der Datei liegt.
-
Naja, die beiden Fehler sagen ja nur aus, dass du Grub zerstört hast und das deine Partition-Table defekt ist. Mich wundert aber, dass er es überhaupt versucht. Grub müsste dich eigentlich rausschmeißen. Er lädt nichts unterhalb der 1MB Grenze. Du verstehst das auch falsch. Es geht grub nicht darum, dass es an eine bestimmte geladen werden soll. Er sucht in deinem ELF-File innerhalb der ersten 8 kB nach dem Header. Du musst dafür sorgen, dass das Zeug mit dem Multiboot-Header möglichst weit vorne in der Datei liegt.
Das versteh ich schon, hab ich auch gemacht, und wie gesagt, dann kommt ein Fehler von Grub Selectet Item doesn't fit into memory.
Und welche Partitionstabelle meinst du? Also ich lad von CD...
Ist so ein Fehler wie du mal hattest (Error 7). Ich weiß nicht, aber ich benutze auf jeden Fall elf.
Problem ist FileOffset = Speicheradresse, was z.B. sonst nicht der Fall ist:
PhysAddr 0x0100000 FileOffset 0x1000
Bei mir ist es PhysAddr 0x1000 fileOffset 0x1000
Naja, was soll das mit Grub zu tun haben, (Grub zerstört?). Naja ich mein ich weiß, dass ich es weit vorner in der Datei haben soll. Tu ich das, wie gesagt, dann kommt dass mit unter 1 MB. Pack ich die Sachen zu hoch >= 1 MB findet er den header nicht. Pack ich den MB_HEADER bei ca. 0x1000 und den Rest bei 1 MB, dann kommt doesnt fit into Memory. Ich hab ehrlich gesagt keine Ahnung,wie ich es schaffe, die Adresse, an der es später in den Speicher soll zu verändern, ohne die Adresse in der Datei zu verändern. Ich mein, ich weiß nicht was grub für nen Problem damit hat, wenn ich den mb-header bei 0x1000 mach und den rest bei 1 mb. Ich hätte ja gern alles am anfang der datei, aber im speicher nachher alles bei 1 MB.
ich dachte , dass . = ADDR nur die Speicheradresse ändert, aber nicht den FileOffset.
-
Also das Grub Programm steht komischerweise unter Debian nicht zur verfügung... Vielleicht sollte ich Grub noch mal neu installieren...
Das gibts nur bei grub legacy.
Hab Grub legacy jetzt mal installiert und folgendes von mbchk erhalten:
kernel.bin: The Multiboot header is found at the offset 256.
kernel.bin: Page alignment is turned on.
kernel.bin: Memory information is turned on.
kernel.bin: Address fields is turned off.
kernel.bin: All checks passed.
-
Bei welcher Version sagt dir mbchk, dass es klappt?
Ich hatte den 1MB Fehler, weil ich die Address Fields geladen haben wollte und die wollte er mir unter 1 MB legen. Nachdem ich die abgeschaltet hatte, ging alles.
-
Bei welcher Version sagt dir mbchk, dass es klappt?
Ich hatte den 1MB Fehler, weil ich die Address Fields geladen haben wollte und die wollte er mir unter 1 MB legen. Nachdem ich die abgeschaltet hatte, ging alles.
Also die Meldung bekomme ich bei folgendem Script:
ENTRY (loader)
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH("i386:i386")
SECTIONS
{
. = 0x1000;
kernel_start = .;
.__mbHeader : AT(0x100000)
{
*(multiboot)
}
.text :
{
*(.text)
}
.rodata :
{
*(.rodata*)
}
.data :
{
*(.data)
}
.bss :
{
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
/* Auf 4k Adresse aufrunden */
. = ALIGN(4096);
kernel_ende = .;
}
objdump:
kernel.bin: file format elf32-i386
Program Header:
LOAD off 0x00000000 vaddr 0x00000000 paddr 0x000ff000 align 2**21
filesz 0x00003254 memsz 0x00023ac0 flags rwx
STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000000 memsz 0x00000000 flags rwx
Sections:
Idx Name Size VMA LMA File off Algn
0 .__mbHeader 0000000c 00001000 00100000 00001000 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 00001ffa 00001010 00100010 00001010 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 00000190 0000300c 0010200c 0000300c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .data 000000b4 000031a0 001021a0 000031a0 2**5
CONTENTS, ALLOC, LOAD, DATA
4 .bss 00020860 00003260 00102260 00003254 2**5
ALLOC
5 .comment 0000001c 00000000 00000000 00003254 2**0
CONTENTS, READONLY
Hm, ich weiß nicht, vielleicht liegt es daran, das VMA immer noch 0x1000 ist.
Mit AT (0x100000) wollte ich eigentlich erreichen, dass die Sachen dann am Ende auf jedenfall bei 1 MB landen, was aber wohl nicht der Fall ist. Zu den Adress Fields. Ich kenn mich jetzt nicht super mit der Spezi aus, aber falls dies die Informationen beinhaltet, wo Grub seine Daten hinpackt brauch ich die für das Memory Management.
-
Hallo,
ich denke, dass das *(multiboot) mit in .text gehört, so ist das jedenfalls in OS-Dev für Einsteiger und in tyndur.
EDIT: Damit meine ich dies:
.text : {
*(multiboot)
*(.text)
}
oern
-
Hallo,
ich denke, dass das *(multiboot) mit in .text gehört, so ist das jedenfalls in OS-Dev für Einsteiger und in tyndur.
EDIT: Damit meine ich dies:
.text : {
*(multiboot)
*(.text)
}
oern
Naja, ich hatte es vorher in der Text-Section, aber da hat es auch schon nicht funktioniert.
Außerdem stand im OS-dev. Grub Err. 13 link so. Außerdem steht bei allen andren Kernel - Dumps immer VMA = 0x100000 , bei meinem alten auch, nur bei dem hier jetzt nicht.
Gruß Sebi2020
-
Naja, dein ELF sagt GRUB folgendes: Lade mir den Code mal bitte nach 1MB und der Code ist ausfuehrbar an Adresse 0x1000. Also sind die ganzen Sprungadressen deines Codes an 0x1000 orientiert. Das bedeutet, dass dein derzeitiger Kernel schon Paging verlangt. Das macht soweit auch sinn, da du im Linker-Skript ja nicht die Adresse direkt angibst, sondern ihm nur sagst woran er sich orientieren soll.
Zur Klaerung: Dein GCC erzeugt Code, der noch keine Adressen enthaelt (auszer der relativen Spruenge). Alles andere wird durch Labels angegeben. Der Linker nimmt dann diese Dateien und loest die Labels auf und setzt als Offset 0x1000, da du das von ihm verlangst. Danach sagst du ihm, dass die erste Sektion (dein MB-Header) in dem Speicher an Adresse 1MB liegen soll und somit auch der ganze Code danach.
Wenn ich mich recht entsinne, habe ich mein Problem mit dem nicht vorhandenem MB-Header so geloest, dass ich die Reihenfolge meiner Object-Files so abgeaendert habe, dass die Datei mit dem MB-Header ganz vorne steht. so hatte er es mir dann richtig hingelegt.
Wie sehen deine LD-Parameter aus? Es gibt so haessliche Flags, dass LD die Wahl hat, wo er bestimmte Sachen in die Datei legen soll, damit es am Ende schneller sein soll oder so, was dir die ganze Geschichte auch noch kaputt machen kann, falls du das Flag nicht explizit abschaltest (mir faellt leider gerade nicht ein, wie es heiszt)
-
Naja, dein ELF sagt GRUB folgendes: Lade mir den Code mal bitte nach 1MB und der Code ist ausfuehrbar an Adresse 0x1000. Also sind die ganzen Sprungadressen deines Codes an 0x1000 orientiert. Das bedeutet, dass dein derzeitiger Kernel schon Paging verlangt. Das macht soweit auch sinn, da du im Linker-Skript ja nicht die Adresse direkt angibst, sondern ihm nur sagst woran er sich orientieren soll.
Zur Klaerung: Dein GCC erzeugt Code, der noch keine Adressen enthaelt (auszer der relativen Spruenge). Alles andere wird durch Labels angegeben. Der Linker nimmt dann diese Dateien und loest die Labels auf und setzt als Offset 0x1000, da du das von ihm verlangst. Danach sagst du ihm, dass die erste Sektion (dein MB-Header) in dem Speicher an Adresse 1MB liegen soll und somit auch der ganze Code danach.
Wenn ich mich recht entsinne, habe ich mein Problem mit dem nicht vorhandenem MB-Header so geloest, dass ich die Reihenfolge meiner Object-Files so abgeaendert habe, dass die Datei mit dem MB-Header ganz vorne steht. so hatte er es mir dann richtig hingelegt.
Wie sehen deine LD-Parameter aus? Es gibt so haessliche Flags, dass LD die Wahl hat, wo er bestimmte Sachen in die Datei legen soll, damit es am Ende schneller sein soll oder so, was dir die ganze Geschichte auch noch kaputt machen kann, falls du das Flag nicht explizit abschaltest (mir faellt leider gerade nicht ein, wie es heiszt)
Eigentlich nur der -T Parameter:
ld -T link.ld -o "build/binary/kernel" "build/object/start.o" "build/object/kernel.o" "build/object/display.o" "build/object/libc.lib" "build/object/asm_stub.o" "build/object/task.o" "build/object/timer.o" "build/object/interrupt.o" "build/object/igdt.o" "build/object/ports.o" "build/object/pmm.o"
Der Punkt ist ja, wenn ich (wie in allen Tutorials . = 0x10000) mache heißt das auch gleich beim Fileoffset das er bei 1 MB anfängt. Das heißt, dass er bei 0x0 den Elf Header rein macht und dann bis 0x10000 leer lässt, also Null. Aber mein Ziel ist ja wirklich das er in der Datei bei 0x1000 anfängt, dann aber die Sprünge alle von 1 MB aus Orientiert Addressiert, natürlich aber auch alles bei 1 MB im Ram hinpackt. Heißt bei mir also auch wirklich ohne Paging. Sondern noch alles wirklich physikalisch.
-
Das wuerde aber bedeuten, dass deine Datei graeszer als 1 MB ist. Was gibt objdump denn fuer eine bin ohne den "fix" mit der 0x1000 an?
Das . = x bedeutet aber nicht, dass er da mit der Datei anfaengt, sondern dass er den Code gegen diese Adresse linken soll.
Ich kann mir nicht erklaeren, warum er so einen Bloedsinn macht. Vllt hilft der andere Dump. Ich lenke zum Beispiel meinen Kernel gegen 3GB und das passt. Da muss noch was anderes falsch laufen.
-
Hängt es denn jetzt nur noch an den falschen Adressen, oder meckert GRUB immer noch rum? die adressen müssten sich ja so hinbiegen lassen:
…
.__mbHeader 0 : AT(0x100000)
{
*(multiboot)
}
. += 0x100000;
.text :
{
*(.text)
}
…
-
Ich hab mein Problem mehr oder weniger Zufriedenstellend gelöst...
Ich habe mir gestern mal ein Ubuntu 32Bit installiert als Virtuelle Maschine und dort noch mal alles kompiliert und nun arbeitet
der ld wie er soll. Sehr komische Sache, ich weiß auch nicht womit das jetzt zusammen hängt. Debian hat ne ältere Version von ld.
Vielleicht hat die einen Bug. Ich weiß es nicht. Gefallen tut mir die Lösung nicht und ich versteh zwar bis jetzt nicht warum das so ist, aber unter Ubuntu klappt das.
Vielen dank für eure Hilfe!
Ich glaube daran hätte man jetzt nicht gedacht, das ld spinnt...
ich hätte noch Stunden unter Debian probieren können, und es wäre nicht besser geworden...
-
Ich bezweifel, dass es ein Fehler in LD ist, da das so elementare Fehler sind, die schon haeufiger aufgefallen waeren.
So auf den ersten Blick wuerde ich vermuten, dass LD aus Debian andere Default-Settings hat als das von Ubuntu, wodurch in dem einen Fall nichts sinnvolles entsteht.