Autor Thema: Laden eines C-Kernels  (Gelesen 19722 mal)

bscreator

  • Gast
Gespeichert
« am: 18. October 2010, 19:56 »
Hallo,

ich versuche gerade verzweifelt, einen Kernel, welcher in C geschrieben ist, mit NASM zu laden.

Der ganze Bootloader-Code funktioniert, lediglich bei der Anweisung
call _main bringt der NASM-Assembler die Meldung
Zitat
binary output format does not support external references
.
Die Funktion main wurde im Kopf des Bootloaders mit EXTERN _main definiert.
Wo liegt der Fehler ?

Bootloader:
[BITS 16]
EXTERN _main
GLOBAL _boot
_boot db "Der erste C Kernel",13,10,0

org 0x7c00

start:
cli
mov ax,0x9000
mov ss,ax
mov sp,0
sti

xor ax,ax
mov ds,ax

mov ah,0x02
mov al,2     ;Anzahl zu lesender Sektoren
mov cx,2     ;Cylinder=0, Sektor=2
mov dx,0     ;Laufwerk=0=>Floppy
mov bx,0x0800  ;Kernel nach 0x0000:0x0800 laden
mov es,bx
int 0x13

call _main      <- Diese Zeile kann NASM nicht ausführen

times 510-($-$$) db 0
dw 0xAA55



Kann ich den C-Kernel, wenn ich diesen auf den 2. Sektor einer Floppy schreibe und mit der Funktion 2 des INT 0x13 an Adresse 0000:0800 lade (wie oben beschrieben), eigentlich auch statt call _main mit jmp 0000:0800 starten ?

Vielen Dank,
bsc




kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 18. October 2010, 21:05 »
extern kannst du nur benutzen, wenn du die Dateien zusammenlinkst (und das wiederum heißt, dass du zumindest als Zwischenformat für die Objektdateien irgendwas wie ELF nehmen müsstest und keine flachen Binaries). Kernel und Bootsektor zusammenlinken ist natürlich Blödsinn.

Wenn das Laden korrekt funktioniert, nimm die jmp-Variante. So kurz wie dieser Bootsektor ist, bezweifle ich allerdings, dass er sehr zuverlässig ist. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bscreator

  • Gast
Gespeichert
« Antwort #2 am: 19. October 2010, 09:05 »
Da hast Du wahrscheinlich recht.

Nochwas:
Im Internet hab ich den folgenden Code gefunden:
[BITS 16]
EXTERN _main
start:

jmp 07c0h:main_entry

main_entry:
mov ax,cs
mov ds,ax
mov es,ax
cli
mov ss,ax
mov sp,9000h
sti

mov ah,02h
mov al,1
mov cl,2
mov ch,0
mov dl,0
mov dh,0
lea bx,[kernel]    <-------------------------------------- Hier liegt der Fehler
int 13h


call _main
jmp $ ;

GLOBAL _prnt

_prnt:
push bp
mov bp, sp
push ax
push si
mov ax, [bp + 4]
mov si,ax

prnt1:
mov al,[si]
cmp al,0
JE prnte
inc si
mov ah,0eh
int 10h
jmp prnt1

prnte:
pop si
pop ax
pop bp
ret

GLOBAL _boot
_boot db "Der erste C Kernel",13,10,0

times 510-($-$$) db 0
dw 0aa55h

Beim Kompilieren kommt die Meldung, dass er das Label "Kernel" nicht kennt.
(Die Zeile lea bx, [kernel] ist markiert).

Im Skript gibt es lediglich eine Datei namens Kernel.cpp, aber sonst hab ich auch keine Ahnung, wo das kernel herkommt. So wie es ausschaut, lädt es die Adresse des Kernels. Aber damit kann doch nicht die Adresse der Kernel.cpp gemeint sein, oder ?


Vielen Dank für eure Hilfe,
bsc

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #3 am: 19. October 2010, 09:25 »
Hi bsc,

direkt und ohne Umschweife empfehle ich dir dringenst: Schmeiß' den Code weg und lies dir das hier durch und arbeite dich dadurch.

Grundlegende Dinge:
- Eigenen Bootloader schreiben ist ineffizienz und ein eigenes Projekt für sich, benutze lieber GRUB
- Code kopieren ist generell keine gute Idee (da sind schon so einige auf die Schnauze mit gefallen...)

Aber dennoch kurz zu deiner Frage:
kernel scheint eine Funktion zu sein, die irgendwo extern liegt.

Aber wie gesagt: Schmeiß' den Code weg und arbeite dich durch das Tutorial. Damit tust du dir einen großen Gefallen.
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 19. October 2010, 11:37 »
Hallo bscreator,


ich kann DemHartmut nur zustimmen und möchte noch ganz explizit auf den, im Wiki unter "Unverzichtbar" stehenden, Satz hinweisen:
Zitat
Auch die Zusammenhänge von Compiler - Assembler - Linker und den dazwischen liegenden Dateiformaten (linkbare Objekt-Dateien und ausführbare Programm-Dateien) sollten zumindest in Grundzügen geläufig sein.

An den Einsprungspunkt in den Kernel muss Dein Bootloader auf anderen Weg kommen, zusammenlinken geht auf jeden Fall nicht.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 19. October 2010, 13:18 »
Du musst zu deinem Kernel den Einsprungpunkt wissen. Schreibst du ihn in Sektor 2 der Floppy, dann brauchst du den Offset von Sektoranfang zu Einsprungpunkt.

(a) dein Kernel hat ein Executable Format (z.B. ELF), dann kannst du dort drin nachgucken, wo der is
(b) der Offset ist konstant (z.B. "das 4. Byte")
(c) der Offset wird durch eine Magic Number (z.B. "hinter dem ersten 0xDEADC0DE") markiert

Dein Bootloader muss diesen Offset jedenfalls ermitteln (oder die Konstante eingebaut kriegen) und dann per JMP genau auf diesen Punkt springen, der dein Einsprungpunkt im Kernel ist. Du kannst zur Laufzeit keine Quelltextlabels benutzen und flache Binärdateien kann man nicht verlinken. Außerdem sollte der Bootloader unabhängig vom Kernel sein.

Ansonsten: Ich empfehle Multiboot.

Gruß

bscreator

  • Gast
Gespeichert
« Antwort #6 am: 19. October 2010, 15:59 »
Ok, dann werd ich den Code nicht verwenden.

Ich wollt bloß mal einen kleinen C-Kernel starten, der nichts anderes tut, als ne Message auf dem Bildschirm auszugeben, da ich vor langer Zeit mal was gefunden hab, wie man nen C-Kernel mit 16-Bit-ASM startet (da war auch JLOC dabei).

Aber wenn ich aus dem C-Kernel ne OBJ-Datei mach und diese in den 2.Sektor der Floppy kopier, muss ich nur noch die Adresse des Einsprungspunkts in dem C-Kernel wissen, oder ?

Jedenfalls vielen Dank für Eure Antworten,
bsc

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 19. October 2010, 17:14 »
Hallo,


Aber wenn ich aus dem C-Kernel ne OBJ-Datei mach und diese in den 2.Sektor der Floppy kopier
Also wenn ich das lese dann .......
Bitte beherzige meinen (unseren) Rat und beschäftige Dich erst mal mit den Basics.

Eine OBJ-Datei ist keine Flat-Binary, wo Du die hinspeicherst ist erst mal egal aber wenn Du die im Speicher hast und damit was machen willst musst Du die erst "decodieren". Schau Dir wirklich mal an wie ELF funktioniert!


Edit:
Multiboot ist im Prinzip auch eine Art Object-File-Format nur eben auf das absolut Nötigste (einen Einsprungspunkt und ein paar Flags) beschränkt.


Grüße
Erik
« Letzte Änderung: 19. October 2010, 17:23 von erik.vikinger »
Reality is that which, when you stop believing in it, doesn't go away.

bscreator

  • Gast
Gespeichert
« Antwort #8 am: 19. October 2010, 18:13 »
Zitat
beschäftige Dich erst mal mit den Basics.
Die "Basics" sind für mich der Bootloader

ELF ist aber doch ebenso ein Crosscompiler, nur mit der "Einschränkung", dass damit nur PM-Betriebssysteme "bearbeitet" werden können.
Meine Favoriten sind aber immer noch die Real Mode-Betriebssysteme.

Also ist Multiboot auch ein Crosscompiler, oder?

Grüße,
bsc

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 19. October 2010, 20:22 »
ELF und Multiboot sind keine Compiler, weder cross noch anders, sondern Dateiformate.

Der RM ist absolut nutzlos, aber wenn du darauf bestehst, dann wirst du wahrscheinlich einen eigenen Bootloader brauchen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 19. October 2010, 21:29 »
Also ELF (und a.out und PE und LE und was es da noch so gibt) sind Dateiformate. Dadrin sind z.B. Flags, Einsprungpunkte, Teile/Sektionen definiert, die etwas über den Inhalt aussagen.

Multiboot ist eine Spezifikation, also eine Schnittstellenbeschreibung, wie ein Kernel mit dem Bootloader interagieren kann (d.h. dem Bootloader sagen kann, welche Umgebung er gern hätte und auch Informationen vom Bootloader bekommen kann). Dazu kommt eine Dateibeschreibung, damit der Bootloader mit dem Kernel und den Modulen auch etwas anfangen kann.

Mit dem Compiler hat das nichts zu tun, der erzeugt dir Object-Files (.o oder .OBJ oder sowas) - die sind abhängig vom Compiler! Die ELF-Datei erzeugt dir der Linker.

Beschäftige dich mal damit.

ELF ist übrigens auf keinen Prozessormodus festgelegt, Multiboot ist nur für den Protected Mode spezifiziert.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 20. October 2010, 09:59 »
Hallo,


Multiboot ist nur für den Protected Mode spezifiziert.
Du meinst den x86-Proteced-Mode.

Aber es stimmt schon das MultiBoot nicht so ganz ein Executable-Datei-Format ist aber es gibt eben viele Gemeinsamkeiten.
All diese Dateiformate geben Auskunft darüber wie das Programm im Speicher aufgebaut sein soll, also an welche Stelle es in den virtuellen Adressraum soll, wie dieser virtuelle Adressraum aufgebaut sein soll und welche Dinge überhaupt aus der Datei auch in den Speicher sollen (z.B. Debug-Informationen werden meistens nicht in den Speicher des neuen Prozesses geladen). Das trifft alles im wesentlichen auch auf des MZ-EXE-Format von DOS für die Real-Mode-Programme zu.

@bscreator
Bitte beschäftige Dich wirklich mal damit!


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 20. October 2010, 15:06 »
Du meinst den x86-Proteced-Mode.
Ich kenne keine nicht-x86-und-nicht-x86_64-Architektur, die einen "Protected Mode" besitzt. Die haben alle nur einen Modus.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 20. October 2010, 16:43 »
Hallo,


Ich kenne keine nicht-x86-und-nicht-x86_64-Architektur, die einen "Protected Mode" besitzt.
Hm, könnte tatsächlich stimmen. Obwohl, hat der Itanium nicht irgend so einen x86-Emulations-Modus (da gibt es dann doch bestimmt auch den PM)?
Aber ich kenne eine nicht-x86-CPU-Architektur die einen "Real-Mode" hat, ätsch bätsch. :-P

Die haben alle nur einen Modus.
Also das stimmt nicht ganz, zwischen einem User-Mode und einem System/Supervisor/..../Gott-Mode können die meisten CPUs unterscheiden (meine ja auch).


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

Programm Noob

  • Gast
Gespeichert
« Antwort #14 am: 20. October 2010, 19:26 »
Die haben alle nur einen Modus.
Also das stimmt nicht ganz, zwischen einem User-Mode und einem System/Supervisor/..../Gott-Mode können die meisten CPUs unterscheiden (meine ja auch).
Meine Auch

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 20. October 2010, 22:14 »
Haarespalter.

Das zwischen User- & Kernelmodus (oder Supervisor) unterschieden wird, ist klar. Das meinte ich auch nicht. Und ein x86-Emulator kennt natürlich auch Real & Protected Mode, aber das ist für mich ganz klar x86 und nicht Itanums x86-Emulation oder Qemu unter ARM.

bscreator

  • Gast
Gespeichert
« Antwort #16 am: 23. October 2010, 16:03 »
Hallo,

Wie gesagt, will ich immer noch meinen Bootloader selber schreiben und damit nichts anderes machen, als einen einfachen C-Kernel im REAL-Mode zu laden. Das tut mir leid, wenn ich vielen von euch mit dem
Zitat
Bootloader selber schreiben
und dem
Zitat
REAL-Mode
Kopfschmerzen bereite  :-(

Was ist das Problem :

- die verschiedenen Dateiformate (Bootloader: Binary und Kernel: Object

Muss ich das ganze mit einem Crosscompiler machen, oder gibt es einen anderen Weg ?
(z.B. C-Kernel an 2. Sektor schreiben und an die Adresse springen)

Wenn ihr mir Code schickt, bin ich euch sehr dankbar.

Wäre wirklich sehr nett, wenn ihr mir helfen könntet.
Ich danke euch wirklich sehr,  :-) :-)
bsc


AGGROStar1991

  • Beiträge: 29
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 23. October 2010, 16:27 »
Mit welchem Compiler arbeitest du denn um dein Ziel zu verwirklichen?
du brauchst einen der 16bit RM-Code ausspuckt.
sobald du den hast is das eig alles kein problem mehr, könnte man auch mit einem crosscompiler machen. die einfachste version wäre iwo MS dos zum laufen zu bringen(vllt geht das auch mit bochs oder so) und dir da so nen compiler drauf zu tun, gibt auch gleich viele gute assembler für DOS.
Musst dann aber drauf achten das du keinen DPMI compiler hast sondern einen der RM Code ausspuckt, mein Favorit ist Pacific C.

mfg

bscreator

  • Gast
Gespeichert
« Antwort #18 am: 23. October 2010, 20:08 »
Hallo AGGROStar1991,

Ich verwende Turbo C. Bin mir auch fast sicher, dass der 16-Bit-Code ausspuckt.
Aber mit dem bekomme ich eben nur ne *.Object Datei.

Muss ich dann die Binary von NASM und die Object-Datei des Turbo C mit dem Crosscompiler verlinken, oder funktioniert es auch, wenn ich aus dem Bootloader-Code statt ner Binary ne Object-Datei mach und dann beide Object-Dateien mit NASM verlinke ?

Unter DOS zum Laufen zu bringen ist auch kein Problem, kann ja ne virtuelle Maschine erstellen und dann mein altes MS-DOS drauf installieren.

Vielen Dank,
bsc
« Letzte Änderung: 23. October 2010, 20:17 von bscreator »

Programm Noob

  • Gast
Gespeichert
« Antwort #19 am: 23. October 2010, 21:56 »

also der Bootloader wird zu einer Flat Binary?
der C Kernel wird durch Turbao C zu ner .obj ?

Also verlinken nein.
.obj ist kein Dateiformat.
der crosscompiler hat mit deinem Problem erstmal nichts zu tun.
welches Dateiformat ist die .obj???
Wenn du das nicht selber herrausfinden kannst, lade die Datei mal irgednwo hoch.

PNoob

 

Einloggen