Autor Thema: globale Variablen im C++ Kernel funktionieren nicht  (Gelesen 7538 mal)

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« am: 01. August 2013, 13:14 »
Hallo Allerseits,

das ganze ist noch Neuland für mich, also habe ich mich an dem Artikel http://www.lowlevel.eu/wiki/C%2B%2B-Kernel_mit_GRUB orientiert. Ich habe alle Anweisungen auf der Seite befolgt und das ganze mal kompiliert und mit bochs ausgeführt. Ich musste feststellen, dass das screen Objekt, was global in der Video.cpp erstellt wird, scheinbar nicht über den Konstruktor initialisiert wurde, weil auf dem Bildschirm nichts passiert. Wenn ich ein Video Objekt hingegen in der kernelMain Funktion erstelle, dann funktioniert die Bildschirmausgabe. Ich weiß nicht, was ich falsch gemacht haben soll. Eigentlich sollten doch alle Konstruktoren von globalen und statischen Objekten mit der initialiseConstructors Funktion aufgerufen werden. Die Startup.cpp sieht bei mir so aus:

typedef void (*constructor)();
 
// Im Linkerskript definiert
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
 
extern "C" void initialiseConstructors();
 
// Ruft die Konstruktoren für globale/statische Objekte auf
void initialiseConstructors()
{
  for (constructor* i = &start_ctors;i != &end_ctors;++i)
    (*i)();
}

Das einzig Auffällige ist die Warnung, die beim kompilieren erscheint (ich glaube, mit dem Problem hat die Warnung allerdings nicht viel zutun):

Kernel.cpp:8:6: Warnung: unbenutzter Parameter »multiboot_structur« [-Wunused-parameter]

lg
Developer30

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 01. August 2013, 14:18 »
Einen offensichtlichen Fehler sehe ich nicht, also muss ich mal die ganz dumme Frage stellen: initialiseConstructors() wird schon auch irgendwo aufgerufen?

Ansonsten könntest du mal versuchen, ein bisschen Debugcode in die Funktion einzubauen, dass du siehst, welche Konstruktoren (falls überhaupt) er aufruft. Nur vielleicht nicht grad mit der Video-Klasse, die wäre für die Ausgaben nützlich... Du kannst auch mal mit objdump/readelf oder so anschauen, ob deine ctors-Section überhaupt einen Inhalt hat und ob das der erwartete ist.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 01. August 2013, 15:25 »
initialiseConstructors() wird schon auch irgendwo aufgerufen?
ja, es wird in der asmKernel.asm aufgerufen, unmittelbar bevor die kernelMain aufgerufen wird.

loader:
  mov esp,0x200000
  push eax
  push ebx
  call initialiseConstructors    ; Konstruktoren aufrufen
  call kernelMain      ; kernelMain aufrufen

Ansonsten könntest du mal versuchen, ein bisschen Debugcode in die Funktion einzubauen, dass du siehst, welche Konstruktoren (falls überhaupt) er aufruft.
Wie kann ich mir das denn am besten ausgeben lassen?

Du kannst auch mal mit objdump/readelf oder so anschauen, ob deine ctors-Section überhaupt einen Inhalt hat und ob das der erwartete ist.
Ich habe noch nie mit objdump gearbeitet (also sorry falls ich da jetzt was falsch verstehe). Ich habe mir mal mit objdump -h kernel.bin alle sections angezeigt.

$ objdump -h kernel.bin
kernel.bin:     Dateiformat elf32-i386

Sektionen:
Idx Name          Größe     VMA       LMA       Datei-Off Ausr.
  0 .text         00000370  00100000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .eh_frame     000001b8  00100370  00100370  00001370  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .init_array   00000004  00100528  00100528  00001528  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .fini_array   00000004  0010052c  0010052c  0000152c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss          00000010  00100530  00100530  00001530  2**2
                  ALLOC

Wenn ich das richtig verstanden habe, müsste es doch auch eine .data section geben, wo dann start_ctors und end_ctors drin sein müsste, oder nicht?


kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 01. August 2013, 15:56 »
In .init_array müssten die Konstruktor-Pointer sein, glaube ich. Ob dein Linkerskript start_ctors und end_ctors passend anlegt, musst du selber wissen.

Dass es kein .data gibt, sieht in der Tat komisch aus und könnte auch wieder auf ein Problem mit dem Linkerskript hinweisen, allerdings sind die beiden Symbole nichts, was nach .data gehört. Vielleicht hast du aber auch einfach nichts in .data (dort landen z.B. initialisierte globale Variablen).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 01. August 2013, 16:00 »
Neuere GCC Versionen erzeugen keine ctros-sections mehr sondern init_array und fini_array sections. D.h. deine ctors liste bleibt vermutlich leer (start/end-ctors sind gleich).
nm kernel.elf | grep ctors
Du kannst dir die ctors / dtors etwa so in deinem linkscript zusammen sammeln. (statt dem .ctors* .*dtors zeug wie es im Tutorial steht)
       __init_array = .;
       KEEP(*( .init_array ));
       KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* )));
       __init_array_end = .;
 
        /* List all Destructors here */
       __fini_array = .;
       KEEP(*( .fini_array ));
       KEEP(*(SORT_BY_INIT_PRIORITY( .fini_array.* )));
       __fini_array_end = .;
__init_array entspricht dann start_ctors etc.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 01. August 2013, 16:32 »
Danke für eure Hilfe Kevin und MNemo.. Die linkscript Lösung von MNemo hat das Problem gefixt. Danke :wink:

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 01. August 2013, 16:56 »
MNemo, magst du das zufällig ins Wiki packen? :)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen