Autor Thema: Kein Multiboot trotz Linkereintrags  (Gelesen 6461 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 15. July 2010, 12:00 »
Hallo,

ich habe ein Problem mit meinem Linker.
Ich habe mir zwei eigene Sektionen definiert (preboot und boot) und möchte in die boot-Sektion den Multiboot-Header geladen haben.
Leider funktioniert das nicht so ganz und ich weiß nicht warum.

Hier mein Linker-Skript:
/* the linker script to link the kernel */
ENTRY(_start) /* the entry-point of the kernel */
OUTPUT_FORMAT(elf32-i386) /* the output-format */

/* some constants to link the code correctly */
ALIGNMENT = 0x1000; /* the alignment of the sections */
PHYS_ADDRESS = 0x100000; /* the physical address of the kernel */
VIRT_ADDRESS = 0x100000; /* the virtual address of the kernel */
REMAP_OFFSET = VIRT_ADDRESS - PHYS_ADDRESS; /* the offset between physical and virtual addresses */

/* define the different sections of the kernel */
SECTIONS
{
. = VIRT_ADDRESS; /* move the kernel to the correct start-address */

__kernel_virt_entry = .; /* the beginning with virtual addresses */
__kernel_phys_entry = . - REMAP_OFFSET; /* the beginning with physical addresses */

.preboot : AT(ADDR(.preboot) - (REMAP_OFFSET + 0x1000))
{
__preboot_entry = .; /* the entry-symbol to get the space of the preboot-section */
*(.preboot)
__preboot_end = .; /* the end-symbol to get the space of the preboot-section */
}

. = ALIGN(ALIGNMENT);

.boot : AT(ADDR(.boot) - REMAP_OFFSET)
{
__boot_entry = .; /* the entry-symbol of the boot-section */
*(.boot)
__boot_end = .; /* the end-symbol of the boot-section */
}

. = ALIGN(ALIGNMENT);

.init : AT(ADDR(.init) - REMAP_OFFSET)
{
__init_entry = .; /* the entry-symbol of the init-section */
*(.init)
__init_end = .; /* the end-symbol of the init-section */
}

. = ALIGN(ALIGNMENT);

.text : AT(ADDR(.text) - REMAP_OFFSET)
{
__ro_data_entry = .; /* the entry-symbol of the read-only-section */
*(.text)
*(.rodata)
__ro_data_end = .; /* the end-symbol of the read-only-section */
}

. = ALIGN(ALIGNMENT);

.data : AT(ADDR(.data) - REMAP_OFFSET)
{
__rw_data_entry = .; /* the entry-symbol of the read-write-sections */
*(.data)
*(.bss)
__rw_data_end = .; /* the end-symbol of the read-write-sections */
}

. = ALIGN(ALIGNMENT);

__kernel_phys_end = . - REMAP_OFFSET; /* the end of the physical addresses */
__kernel_virt_end = .; /* the end of the virtual addresses */
}

Hier meine Multiboot-Datei:
.section .boot

// the following flags are every time set
#define MB_MAGIC 0x1badb002
/*
 * MB_FLAGS[0] == load modules 4k-aligned
 * MB_FLAGS[1] == calculate mbs_mem_lower,mbs_mem_upper and mbs_mmap_length, mbs_mmap_addr if possible
 * MB_FLAGS[2] == load some informations about the video-mode into the multiboot-structure
 * MB_FLAGS[16] == calculates some informations about the kernel-image
 */
#define MB_FLAGS 0x8007
#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS)
// the following flags are defined, if MB_FLAGS[16] is set
#define MB_HEADER_ADDR 0x0
#define MB_LOAD_ADDR 0x0
#define MB_LOAD_END_ADDR 0x0
#define MB_BSS_END_ADDR 0x0
#define MB_ENTRY_ADDR 0x0
// the following flags are defined, if MB_FLAGS[2] is set
#define MB_MODE_TYPE 0x0
#define MB_MODE_WIDTH 0x0
#define MB_MODE_HEIGHT 0x0
#define MB_MODE_DEPTH 0x0

.align 4
.int MB_MAGIC
.int MB_FLAGS
.int MB_CHECKSUM
.int MB_HEADER_ADDR
.int MB_LOAD_ADDR
.int MB_LOAD_END_ADDR
.int MB_BSS_END_ADDR
.int MB_ENTRY_ADDR
.int MB_MODE_TYPE
.int MB_MODE_WIDTH
.int MB_MODE_HEIGHT
.int MB_MODE_DEPTH

Wenn ich mir nun meine boot-Sektion mir readelf oder objdump anschaue, steht dort nur sinnloses Zeug.
Ausgabe von objdump:
Disassembly of section .boot:

00100000 <__boot_entry>:
  100000:       02 b0 ad 1b 07 80       add    -0x7ff8e453(%eax),%dh
  100006:       00 00                   add    %al,(%eax)
  100008:       f7                      (bad) 
  100009:       cf                      iret   
  10000a:       51                      push   %ecx
  10000b:       e4 00                   in     $0x0,%al

mbchk sagt natürlich, dass es keine Multiboot-Header finden konnte.

Woran kann das Problem liegen?

Danke.

Gruß
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 15. July 2010, 12:21 »
Schau dir die objdump-Ausgabe nochmal genau an...

02 b0 ad 1b = 0x1badb002 (Magic)
07 80 00 00 = 0x00008007 (Flags)
f7 cf 51 e4  = 0xe451cff7 (Prüfsumme)

Ist doch ein toller Multiboot-Header? Die Frage ist: Ist er in der Datei innerhalb der ersten 8k wie er sein sollte?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 15. July 2010, 12:31 »
Okay, habe ich übersehen.
Ich habe mir  nun mal mit hexdump die Adresse gesucht.
Dabei kam folgendes Ergebnis:
0005070 0000 0000 0000 0000 b002 1bad 8007 0000

Das sind ja nicht die ersten 8 kB. Woran liegt das?
Muss ich davon noch den elf-header abziehen?

Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 15. July 2010, 12:45 »
Wenn es nicht in den ersten 8k liegt, liegt das meistens daran, dass irgendwelchen anderes Zeug früher in der Datei ist. ;)

Bei dir konkret würde ich vermuten, dass .preboot zu groß ist.Grundsätzlich würde ich den Multiboot-Header ganz an den Anfang im Linkerskript packen, damit er direkt nach dem ELF-Header kommt.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 15. July 2010, 12:46 »
Habe das Problem gelöst, allerdings verstehe ich es nicht.
Ich habe eine init-Funktion, die auch in die Sektion muss. Nachdem ich sie dort eingetragen habe, hat es funktioniert.
Wieso wird boot sonst anscheinend anders gelinkt?
Meine preboot-Sektion ist noch leer.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Programm Noob

  • Gast
Gespeichert
« Antwort #5 am: 15. July 2010, 13:03 »
rizor warum muss die init Funktion umbedingt in diese section?

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 15. July 2010, 13:21 »
Ich habe eine Init-Funktion, die das System startet und danach an den speicher manager freigegeben werden soll. In die Sektion soll der ganze Code, der für den Bootvorgang und danach nie wieder benötigt wird. Dadurch soll das System speicherschonender sein.
In die Init-Sektion kommt dann der erste Task (wobei ich nicht weiß, ob die Sektion benutzt wird).
Durch diese Aufteilung kann ich dem Speichermanager ganz einfach sagen, welcheSeiten freigegeben werden sollen.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Programm Noob

  • Gast
Gespeichert
« Antwort #7 am: 15. July 2010, 17:15 »
da geht es um ein paar kb ich würde den aufwand sein lassen und lieber an anderer stelle sparen. Das ist meine meinung.

Programm Noob

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 15. July 2010, 18:40 »
Naja, das System soll so effektiv wie möglich sein.
Dazu gehört für mich auch diese Organisation.
Es heißt ja nicht automatisch, dass ich an anderen Stellen spare ;).
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Programm Noob

  • Gast
Gespeichert
« Antwort #9 am: 15. July 2010, 18:43 »
Du hast das falsch verstanden du sollst das so im Speicher lassen und statt dessen dann lieber an anderer Stelle Speicherschonend arbeiten. Das bringt mehr.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 15. July 2010, 18:59 »
Das Alignment der Sektionen vergrößert dir übrigens das Abbild im Speicher. Bei fünfmaligem alignen auf 4 kiB sind im Durchschnitt 10 kiB Verschwendung zu erwarten.

Eine Nebensache noch:
Zitat
* MB_FLAGS[16] == calculates some informations about the kernel-image
 */
#define MB_FLAGS         0x8007
Da ist übrigens nicht Bit 16 gesetzt, falls der Kommentar das bedeuten soll. Das gesetzte Bit 15 (0x8000) hat keine zugewiesene Bedeutung. Dass der Bootloader den Kernel trotzdem lädt, ist eigentlich nicht konform mit der Spezifikation.
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 19. July 2010, 09:00 »
0x8000 ist doch bit-16, oder?
Habe das nochmal mit einem Rechner durchgerechnet und der kommt auf das gleiche ergebnis.
Wenn ich das dein Bit setze, dann wird mein Kernel nicht geladen.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 19. July 2010, 09:45 »
0x8000 ist Bit 15, es wird immer ab 0 gezählt. Frag deinen Rechner mal nach 1 << 16. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 01. August 2010, 22:34 »
Ich habe mal eine Frage:
Was kann alles vor der ersten Sektion liegen?
Habe mein Linker-Script jetzt dahingehend umgebaut, dass die Multiboot-Sektion ganz am Anang steht, allerdings liegt die Sektion immer noch an Adresse 0x4040 im Elf-File.
Hier meine Readelf-Ausgabe:
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .multiboot        PROGBITS        00100000 004044 000030 00      0   0  4
  [ 2] .rodata           PROGBITS        00101000 001000 000472 00   A  0   0  4
  [ 3] .text             PROGBITS        00101474 001474 00249a 00  AX  0   0  4
  [ 4] .data             PROGBITS        00104000 004000 000044 00  WA  0   0 32
  [ 5] .bss              NOBITS          00104060 004044 003120 00  WA  0   0 32
  [ 6] .debug_line       PROGBITS        00000000 004074 000a29 00      0   0  1
  [ 7] .debug_info       PROGBITS        00000000 004a9d 001f63 00      0   0  1
  [ 8] .debug_abbrev     PROGBITS        00000000 006a00 000a71 00      0   0  1
  [ 9] .debug_aranges    PROGBITS        00000000 007478 0001a0 00      0   0  8
  [10] .debug_loc        PROGBITS        00000000 007618 000707 00      0   0  1
  [11] .debug_pubnames   PROGBITS        00000000 007d1f 000646 00      0   0  1
  [12] .debug_str        PROGBITS        00000000 008365 000ba0 01  MS  0   0  1
  [13] .comment          PROGBITS        00000000 008f05 000022 01  MS  0   0  1
  [14] .debug_frame      PROGBITS        00000000 008f28 000584 00      0   0  4
  [15] .shstrtab         STRTAB          00000000 0094ac 0000b0 00      0   0  1
  [16] .symtab           SYMTAB          00000000 00982c 000840 10     17  28  4
  [17] .strtab           STRTAB          00000000 00a06c 0005bb 00      0   0  1

Ich habe Keine Idee, warum es soweit hinten liegt.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 01. August 2010, 23:12 »
Wenn ich die Zahlen grad richtig interpretiere, kommen .rodata und .text bei dieser readelf-Ausgabe noch vor .multiboot.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 01. August 2010, 23:32 »
Das kann nicht sein, da mir die Map folgendes ausgibt:
               0x0000000000001000                ALIGNMENT = 0x1000
                0x0000000000100000                PHYS_ADDRESS = 0x100000
                0x0000000000100000                VIRT_ADDRESS = 0x100000
                0x0000000000000000                REMAP_OFFSET = (VIRT_ADDRESS - PHYS_ADDRESS)
                0x0000000000100000                . = VIRT_ADDRESS
                0x0000000000100000                __kernel_virt_entry = .
                0x0000000000100000                __kernel_phys_entry = (. - REMAP_OFFSET)
                0x0000000000100000                __preboot_entry = .
                0x0000000000100000                __multiboot_entry = .

.multiboot      0x0000000000100000       0x30 load address 0x00000000000fe000
Allerdings bleibt 0x4044 in der readelf-Ausgabe stehen.

Edit:
Ich baue mir meinen Kernel auf einem 64-bit System verwende allerdings 32-bit-Tools (Gentoo Cross-Compile).
Wieso gibt mir die Map trotzdem 64-bit Adressen?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 01. August 2010, 23:42 »
Die Map sagt doch nur was über den Speicher im geladenen Code, nicht in der Datei?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 01. August 2010, 23:58 »
Stimmt, aber wie bringe ich den Linker dazu, dass die Sektion auch am Anfang liegt?
Im Linkerscript steht die Multiboot-Sektion explizit am Anfang des Scripts.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 03. August 2010, 15:15 »
Nachdem ich mir noch einmal mein Linker-Skript angeschaut habe und der Fehler immer noch nicht auftaucht, habe ich das Skript etwas umgebaut und wollte, dass ihr da nochmal drüber schaut.
/* the entry-point of the kernel */
ENTRY(_start)
/* the output-format */
OUTPUT_FORMAT(elf32-i386)

/* the start address of the kernel */
KERNEL_START = 0x100000;

/* define the different sections of the kernel */
SECTIONS
{
. = 0x9f000;

/* the beginning of the memory-space of the kernel */
__kernel_mem_entry = .;

/* the entry-symbol to get the space of the preboot-section */
__preboot_entry = .;
.preboot : AT(ADDR(.preboot))
{
*(.multiboot)
*(.preboot)
}
/* the end-symbol to get the space of the preboot-section */
__preboot_end = .;

/* move the kernel to the correct start-address */
. = KERNEL_START;

/* the beginning of the kernel without the preboot-area */
__kernel_entry = .;

/* the entry-symbol of the boot-section */
__boot_entry = .;
.boot : AT(ADDR(.boot))
{
*(.boot)
}
/* the end-symbol of the boot-section */
__boot_end = .;

/* the entry-symbol of the read-only-section */
__ro_data_entry = .;
.rodata : AT(ADDR(.rodata))
{
*(.rodata)
}
.text : AT(ADDR(.text))
{
*(.text)
}
/* the end-symbol of the read-only-section */
__ro_data_end = .;

/* the entry-symbol of the read-write-sections */
__rw_data_entry = .;
.data : AT(ADDR(.data))
{
*(.data)
}

.bss : AT(ADDR(.bss))
{
*(.bss)
}
/* the end-symbol of the read-write-sections */
__rw_data_end = .;

/* the end of the kernel */
__kernel_end = .;
/* the end of the memory-space of the kernel */
__kernel_mem_end = .;
}

Mein Linkeraufruf sieht wie folgt aus:
LDFLAGS=-Iinclude -Map kernel.map -nostdlib --warn-section-align -Tarch/i386/config/linker.ld -L/usr/lib/gcc/i686-pc-linux-gnu/4.4.4/libgcc.a -melf_i386 -O0 -o

Die Warn-Ausgabe ergab folgendes:
i686-pc-linux-gnu-ld: warning: changing start of section .text by 2 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .iplt by 2 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .rel.dyn by 2 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .data by 18 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .bss by 28 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .text by 2 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .iplt by 2 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .rel.dyn by 2 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .data by 18 bytes
i686-pc-linux-gnu-ld: warning: changing start of section .bss by 28 bytes

An was kann der Fehler denn alles liegen?
Google ergab leider nicht wirklich viel.

Gruß,
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 03. August 2010, 21:49 »
Habe die Multiboot-Sektion mal in die .text-Sektion geschoben und schon lag es an der richtigen Stelle.
Habe dann vermutet, dass es an der Auflistung der Object-Dateien liegt und habe die Multiboot-Datei an den Anfang der Liste gezogen und die Sektion wieder ausgelagert, aber das hat auch nicht funktioniert.
Kann man dem Linker sagen, dass er bestimmte Sektionen in einem bestimmten Bereich ablegen muss?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

 

Einloggen