Autor Thema: C-Kernel laden  (Gelesen 12032 mal)

bscreator

  • Gast
Gespeichert
« am: 27. April 2010, 21:20 »
Hallo,
ich hab folgendes im Internet gefunden:

Der Bootloader :
[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]
int 13h

call _main
jmp $
 
;##Funktion zur Stringausgabe / Begrenzungszeichen: ASCII 0
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
kernel:

Der Kernel:
extern "C" void prnt(char *var);
extern char boot;
 
int main()
{
char *str;
str=&boot;
prnt(str);
return 0;
}

Aus beiden wird ne OBJ-Datei gemacht, mit JLOC verlinkt und dann mit RawWrite auf ne Disk geschrieben und funktioniert.

Ein paar Fragen dazu:
1. Befinden sich hier Kernel und Bootloader im selben Segment?
2. An welche Segment:Offset-Adresse wird der Kernel eigentlich geladen?
3. Was passiert bei lea bx,[kernel] ?

Gruss,
bsc

« Letzte Änderung: 27. April 2010, 21:26 von bscreator »

user94

  • Beiträge: 2
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 27. April 2010, 21:59 »
Zu 2:
Soweit ich weiß, wird der C-Kernel hinter den Bootloader geladen, also an 0x7D00.
Dies passiert mit lea bx,[kernel] (kernel ist die Adresse hinter dem Bootloader)
(zu 3)

Zu 1:
Ich denke schon, sonst müsste cs geändert werden.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 27. April 2010, 22:14 »
Zu 2:
Soweit ich weiß, wird der C-Kernel hinter den Bootloader geladen, also an 0x7D00.

Ich weiß nicht wie JLOC das genau anstellt, aber da es angeblich klappt, muss der Kernel wohl nach 0x07c0:0x0200 geladen sein.
Das ist dann die lineare Adresse 0x7e00. (da 512 = 0x200)
Dieser Text wird unter jedem Beitrag angezeigt.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #3 am: 28. April 2010, 07:56 »
Ich habe eher das Gefühl, dass beides Teil des Bootloaders ist (Symbol _main muss im Assemblerteil bekannt sein und Symbol _boot/_prnt im C-Teil). Es wird halt nur der zweite Sektor (des Bootloaders) nachgeladen. Meiner Einschätzung nach dürfte das nicht wirklich das sein, was du willst. :wink:
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

bscreator

  • Gast
Gespeichert
« Antwort #4 am: 28. April 2010, 08:32 »
Zitat
Ich habe eher das Gefühl, dass beides Teil des Bootloaders ist
Denk ich auch :-D

Zitat
Soweit ich weiß, wird der C-Kernel hinter den Bootloader geladen
Diese Einschätzung teil ich auch :-D


1. Wenn ich den Kernel an eine andere Stelle, z.B. nach 0x1000:0x0000 laden will, dann klappt ja kein CALL mehr, da anderes Segment. Kann ich dann mit JMP 0x1000:0x0000 oder mit JMP 0x1000:_main den C-Kernel starten ?

2. Wenn ich die C-Funktionen in NASM geschrieben hab, kann ich diese ASM-Datei dann irgendwie mit INCLUDE an den C-Kernel "festmachen" , bzw. in den C-Kernel inkludieren ?

Gruss und danke,
bsc

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 28. April 2010, 10:09 »
Wenn du Assemblercode in einer C-Datei #includest, wird dir der Compiler den Code um die Ohren hauen, weil Assembler kein gültiges C ist. #include macht ja nichts anderes, als einfach den Text der anderen Datei an dieser Stelle einzufügen. Umgekehrt gilt dasselbe.

Wenn du Assembler und C in eine Binary zusammenbringen willst, brauchst du kein Include, sondern einen Linker.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bscreator

  • Gast
Gespeichert
« Antwort #6 am: 28. April 2010, 12:16 »
[
Zitat
Wenn du Assemblercode in einer C-Datei #includest, wird dir der Compiler den Code um die Ohren hauen, weil Assembler kein gültiges C ist
Ach mist, du hast ja sooooooo recht

1. Aber ich könnt ja immer noch z.B. eine eigene Datei nur für in C geschriebene C-Funktionen erstellen und die Datei dann in den Kernel includieren, oder ?

2. 1. Wenn ich den Kernel an eine andere Stelle, z.B. nach 0x1000:0x0000 laden will, dann klappt ja kein CALL mehr, da anderes Segment. Kann ich dann mit JMP 0x1000:0x0000 oder mit JMP 0x1000:_main den C-Kernel starten ?

Gruss,
bsc

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 28. April 2010, 20:08 »
Hallo,


2. 1. Wenn ich den Kernel an eine andere Stelle, z.B. nach 0x1000:0x0000 laden will, dann klappt ja kein CALL mehr, da anderes Segment. Kann ich dann mit JMP 0x1000:0x0000 oder mit JMP 0x1000:_main den C-Kernel starten ?
Die CALLs innerhab der zusammengelinkten flachen Executable sind entweder NEAR und funktionieren in jedem Segment oder die sind FAR und Du musst sie vor der ersten Benutzung relozieren. Falls Du in Assembler und C die selbe Code-Sektion benutzt kannst Du von NEAR ausgehen, außerdem sollte der Linker eine nackte Binary nur dann erzeugen wenn keine unaufgelösten Relozierungen übrig bleiben.
Der Sprung von Deinem Assembler-Code, nachdem Du die Executable im Speicher umkopiert hast sollte IMHO 'JMP 0x1000:_main' sein.
Probiere das einfach mal aus.


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

bscreator

  • Gast
Gespeichert
« Antwort #8 am: 28. April 2010, 21:43 »
Zitat
Der Sprung von Deinem Assembler-Code, nachdem Du die Executable im Speicher umkopiert hast sollte IMHO 'JMP 0x1000:_main' sein.
Aha, vielen dank.

Zitat
Probiere das einfach mal aus.
Das werd ich. 

Vielen Dank euch allen,
bsc

bscreator

  • Gast
Gespeichert
« Antwort #9 am: 29. April 2010, 09:14 »
Nochne Frage:

Wenn ich meinem C-Kernel Funktionen zur Verfügung stellen will, muss ich ja diese erst in C oder Assembler schreiben.

Frage:
1. Wenn ich diese C-Funktionen in Assembler schreibe, diese Funktionsdatei in ein anderes Segment als Kernel geladen wird, die Funktionen aber als GLOBAL und im C-Kernel als EXTERN deklariert werden, kann ich diese verwenden, auch wenn sie sich in einem anderen Segment befinden, stimmts ?  

2. Wie kann ich einen C-Kernel exakt 512 Bytes gross machen? Gibts da auch so ne times-Funktion wie in NASM oder stellt der Inline-Assembler von C auch die times-Funktion zur Verfügung ? 

Gruss und danke,  :-D
bsc
« Letzte Änderung: 29. April 2010, 09:24 von bscreator »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 29. April 2010, 09:19 »
Der Compiler sollte halt wissen, dass er einen Far-Call erzeugen muss, nehme ich an. Und das klingt compilerspezifisch. Welchen Compiler benutzt du denn? Das Internet weiß da sicher was dazu.

Ich frage mich nur, warum du dir den ganzen Real-Mode-Quatsch überhaupt antust. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bscreator

  • Gast
Gespeichert
« Antwort #11 am: 29. April 2010, 09:29 »
Zitat
Ich frage mich nur, warum du dir den ganzen Real-Mode-Quatsch überhaupt antust.
Das fragen sich viele

Zitat
Der Compiler sollte halt wissen, dass er einen Far-Call erzeugen muss
Jo, da hast recht

Als Compiler nur den Turbo C 3.0, aber wie der das handhabt, hab ich keine Ahnung.

Wie immer ein paar Fragen: :?
1. Aber falls ich das mit dem Far-Call nicht hinkrieg, kann ich ja immer noch eine C-Datei (die in C geschriebene Funktionen enthält) in den Kernel inkludieren, oder ?

2. Wie kann ich einen C-Kernel exakt 512 Bytes gross machen? Gibts da auch so ne times-Funktion wie in NASM oder stellt der Inline-Assembler von C auch die times-Funktion zur Verfügung ? 

Gruss,
bsc

« Letzte Änderung: 29. April 2010, 15:12 von bscreator »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 29. April 2010, 16:28 »
Hallo,

was du möchtest, ist, Funktionen und Symbole einer Datei in einer anderen Datei nutzen. Das ist compiler- und linkerspezifisch, da musst du dich mit deinem Linker (TLINK) prügeln, nicht mit Compiler oder Assembler. Ob die Funktionen selbst nun ASM oder C sind, spielt nämlich keine Rolle - solange das Objectformat stimmt und die Symbole vorhanden sind.

Im laufenden Betrieb kannst du mit einem FAR CALL auch Code in anderen Segmenten ausführen, aber du musst dem Compiler sagen, dass er auch einen solchen Sprung erzeugen muss, auch das ist compilerspezifisch.

Eventuell solltest du als Assembler den TASM nutzen, da der wahrscheinlich besser mit TC und TLINK zusammenarbeitet als NASM. Ist aber nur so 'ne Vermutung.

Um eine Datei auf 512 Bytes zu padden, kannst du "dd" benutzen:
dd if=eingabe of=ausgabe bs=512 count=1 conv=sync
Und "dd" gibt es auch für Win32, wahrscheinlich auch für DOS. Ansonsten baust du dir halt in C schnell selbst ein solches Programm.

Die "times"-Anweisung in C ist mir nicht bekannt und ist - sofern vorhanden - auch compilerspezifisch. Sowas braucht man in C auch nicht...

Gruß,
Svenska

bscreator

  • Gast
Gespeichert
« Antwort #13 am: 29. April 2010, 21:24 »
Ah, ok

Also dass der ganze "Sch..." compilerspezifisch ist, ist nicht in meinem Sinn. Also werd ich am besten den ganzen Mist über 16-Bit-C-Kernel wieder vergessen.

Zitat
Ansonsten baust du dir halt in C schnell selbst ein solches Programm.
Oh man Svenska, du hast echt die besten Ideen.

Und da der ganze Mist compilerspezifisch ist, werd ich, da ich im Real-Mode bleiben will, mein OS in Assembler fertigstellen und in C ein paar "Hilfsprogramme", wie z.B. das 512-Byte padden, schreiben.

Im Real-Mode regiert also Assembler.

Jedenfalls danke euch allen! :-D

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 29. April 2010, 21:26 »
Hallo,


@bscreator:
FAR CALLs haben den Nachteil das sie immer absolute Adressen benutzen (zumindest im RM) und die stehen zur Compile-/Link-Zeit noch nicht fest sondern werden erst beim laden des Executables reloziert. Normalerweise macht dass das OS aber in Deinem Fall müsste es der Assembler-Teil des Boot-Loaders erledigen.
Kennst Du den Unterschied zwischen .COM und .EXE bei DOS?
Einen Loader für das DOS-EXE-Format zu schreiben sollte nicht allzu schwer sein (denke ich zumindest, genau weiß ich es nicht). Willst Du das wirklich tun? Wenn Du im RM mal mehr als 64 kBytes Speicher nutzen willst dann kommst Du da definitiv nicht drum herum (oder Du baust ein eigenes Format, was aber sicher noch komplizierter ist weil Du dann noch mindestens nen eigenen Linker brauchst, glaube mir ich weiß wovon ich da schreibe, ich mach das gerade). Vielleicht lässt Du dich mal von den Sourcen von Free-DOS inspirieren.


Zitat
Ich frage mich nur, warum du dir den ganzen Real-Mode-Quatsch überhaupt antust.
Das fragen sich viele
Ich mich auch. Ich hab oft genug RM-Programme entwickelt (das meiste in C/C++ aber auch einiges in Assembler) und dieser Kram macht IMHO echt keinen Spaß.


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 #15 am: 30. April 2010, 01:08 »
Hallo,

ein kleines Programm in C zu schreiben, welches eine Datei öffnet, die aktuelle Dateigröße ermittelt, auf ganze 512er addiert und den Inhalt (plus viele Nullbytes) wieder in eine Datei schreibt, sollte wirklich nicht zu schwer sein (fopen, fclose, read und write?). Außerdem gibt es "dd".

MS-DOS ist in Assembler geschrieben, die meisten anderen Programme für den Real-Mode in einer Hochsprache. Assembler hat den Nachteil der Unportabilität und Unlesbarkeit - es sei denn, die Kommentare machen den Gutteil des Codes aus - und Hochsprachen haben Vorteile.

Was ich bereits vorher zur Overlay- und damit indirekt auch zur Segment-Technik geschrieben habe, gilt auch weiterhin - die meisten Compiler können damit nichts anfangen und produzieren langsamen Code. Das ist dem primitiv-segmentbasierten Speichermodell geschuldet, welches einfach überholt ist. Die Compilertechnologie hat sich weiterentwickelt, diese Architektur halt nicht so recht.

Was die compilerspezifischen Sachen angeht, das betrifft den Zwischencode - den Binärcode zwischen Endergebnis und Quelltext. Der ist halt nicht universell, damit musst du leben. Das ganze gibt es dann auch noch in groß, wenn man versucht, Visual C nach gcc zu portieren oder umgekehrt. Oder Code für mein STM8-Board auf den PC. Der ist nicht nur hochgradig compilerabhängig, sondern dazu auch noch hardwarespezifisch...

Entweder, du baust dir ein vernünftiges Executable-Format, welches dir die Zerstückelung in Segmente erlaubt, oder aber du baust deinen Kernel in maximal 64K auf. Die Gedanken sind die gleichen, ob du nun ASM schreibst (und es selbst machen musst) oder ob du C nutzt (und damit den TLINK für eine EXE nutzen kannst, aber den EXE-Loader brauchst du selbst).

Ich wiederhole Erik, glaube ihm, er weiß, was er schreibt. Setz dich mit dem Linker deiner Wahl tiefgründig auseinander und informier dich über Executables verschiedener Formate.

Gruß,
Svenska

bscreator

  • Gast
Gespeichert
« Antwort #16 am: 30. April 2010, 08:10 »
Mein Hauptproblem ist, dass ich keine Ahnung hab, wie man in Turbo C einen FAR-CALL erzeugt.
In Assembler ist das ganze ja kein Problem, aber Turbo C keine Ahnung.

Zitat
FAR CALLs haben den Nachteil das sie immer absolute Adressen benutzen (zumindest im RM) und die stehen zur Compile-/Link-Zeit noch nicht fest sondern werden erst beim laden des Executables reloziert. Normalerweise macht dass das OS aber in Deinem Fall müsste es der Assembler-Teil des Boot-Loaders erledigen.
Meinst Du, dass ich eine (als GLOBAL deklarierte) ASM-Funktion für FAR-JUMPS im Bootloader schreiben soll? Wenn sich mein OS in nem anderen Segment befindet, kann ich damit aber trotzdem nix anfangen.

Zitat
Kennst Du den Unterschied zwischen .COM und .EXE bei DOS?
Den kenn ich. COM hat Daten- und Code im selben Segment, EXE bekommt verschiedene Segmente.

Zitat
ein kleines Programm in C zu schreiben, welches eine Datei öffnet, die aktuelle Dateigröße ermittelt, auf ganze 512er addiert und den Inhalt (plus viele Nullbytes) wieder in eine Datei schreibt, sollte wirklich nicht zu schwer sein
Das ist einfach. Bin ja in Visual C++ kein Anfänger mehr.

Zitat
Setz dich mit dem Linker deiner Wahl tiefgründig auseinander und informier dich über Executables verschiedener Formate.
Es geht nicht darum, dass mein OS Executables ausführen soll. Die Programme für mein OS schreib ich alle selber.

Aber vielleicht könnt ihr mir noch hier helfen:
Mein OS soll nur eine FAT12-Diskette auslesen können. Nicht auf Disk schreiben, keine Dateien öffnen können, nur den Inhalt der Disk anzeigen. Hab keine Ahnung wie, und das Tutorial von glaube PHIL oder TeeJay helfen mir auch nicht.
Könnt ihr mir da helfen ?

Viele Grüße,
bsc

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 30. April 2010, 08:52 »
Und da der ganze Mist compilerspezifisch ist, werd ich, da ich im Real-Mode bleiben will, mein OS in Assembler fertigstellen und in C ein paar "Hilfsprogramme", wie z.B. das 512-Byte padden, schreiben.

Im Real-Mode regiert also Assembler.
Da sind dann nicht nur Far Calls, sondern die gesame Syntax assemblerspezifisch. Bin mir nicht sicher, ob das in dieser Hinsicht eine Verbesserung ist. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 30. April 2010, 08:54 »
Aber vielleicht könnt ihr mir noch hier helfen:
Mein OS soll nur eine FAT12-Diskette auslesen können. Nicht auf Disk schreiben, keine Dateien öffnen können, nur den Inhalt der Disk anzeigen. Hab keine Ahnung wie, und das Tutorial von glaube PHIL oder TeeJay helfen mir auch nicht.
Könnt ihr mir da helfen ?
Das kriegst du in 64k locker unter, hast also gar keinen Bedarf, mehrere Segmente zu verwenden. Die bräuchtest du erst, wenn du was ernsthafteres machen wolltest.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bscreator

  • Gast
Gespeichert
« Antwort #19 am: 30. April 2010, 09:19 »
Zitat
Da sind dann nicht nur Far Calls, sondern die gesame Syntax assemblerspezifisch. Bin mir nicht sicher, ob das in dieser Hinsicht eine Verbesserung ist.
Ja schon, aber wenn du mir sagen kannst, wie ich FAR-CALLs in Turbo C machen kann, dann gehts in C weiter. Und ohne FAR-Calls keine Chance.

Zitat
Das kriegst du in 64k locker unter, hast also gar keinen Bedarf, mehrere Segmente zu verwenden. Die bräuchtest du erst, wenn du was ernsthafteres machen wolltest.
Ich will mal klein anfangen, also nur die Dateien auf einer FAT12-Diskette auslesen. Aber ich weiß nicht, wie und wo ich anfangen soll.

Also nochmal:
Wie die Syntax in Turbo C für FAR-CALLs lautet, das steht im LINKER-Tutorial, oder ?
« Letzte Änderung: 30. April 2010, 09:28 von bscreator »

 

Einloggen