Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Pk3 am 19. August 2009, 17:39
-
Hallo, ich versuche schon seit Stunden meinen C Kernel zum laufen zu bringen.
Einen Bootloader habe ich schon gemacht, der in den ProtectMode schaltet, wenn ich aber dann in den Kernel springen will passiert garnichts.
Hier mal der Bootloader:
[BITS 16]
org 0x7c00
%define STACKSEGMENT 0x9000 ; lineare Adresse des Stacks : 0x90000
%define STACKSIZE 0x200 ; Größe des Stacks : 512Byte
%define KERNELSEGMENT 0x10000 ; lineare Adresse des Kernels : 0x40000
jmp START
GDTR:
limit dw (GDT_END - GDT - 1)
base dd (0)
GDT:
NULL_DESCRIPTOR EQU $-GDT
dd 0
dd 0
CODE_DESCRIPTOR EQU $-GDT
dw 0ffffh
dw 0
db 0
db 09ah
db 0cfh
db 0
DATA_DESCRIPTOR EQU $-GDT
dw 0ffffh
dw 0
db 0
db 092h
db 0cfh
db 0
GDT_END:
START:
cli ; keine Interrupts
mov ax, STACKSEGMENT
mov ss, ax ; Stacksegment setzen
mov sp, STACKSIZE ; Größe des Stacks festlegen
xor ax, ax ; ax = 0
mov ds, ax ; Datensegment auf 0 setzen
sti
xor bx, bx ; Ziel-Offset : 0x0
mov ax, KERNELSEGMENT ; Ziel-Segment : 0x4000
mov es, ax
mov ah, 0x2 ; Funktion 0x2 : Sektor lesen
mov al, 1 ; Anzahl der Sektoren : 1
mov ch, 0 ; Track : 0
mov cl, 2 ; LSN : 2
mov dh, 0 ; Head : 0
mov dl, 0 ; Laufwerk : A
int 0x13 ; Interrupt : 0x13
cli ; keine Interrupts
mov ax, cs ; Code-Segment holen
mov ds, ax ; Daten-Segment gleichsetzen
xor eax, eax ; ax = 0
mov es, ax ; Extra-Segment auf Null setzen
mov si, GDT ; Quelle : GDT
xor di, di ; Ziel : 0x0000
mov cx, 6 ; 6 DoubleWords kopieren (ganze GDT)
rep movsd
lgdt [GDTR]
mov eax, cr0
or eax, 1 ; Bit0 setzen (PE-Bit enabled)
mov cr0, eax
db 0xea ; FAR-JUMP zum Codesegment
dw (PMODE)
dw 0x8
[BITS 32] ; 32 Bit-Code erstellen
PMODE:
xor eax, eax
mov eax, 2 ; Selektor für das Datensegment erstellen
shl eax, 3
mov ds, ax ; Daten-, Stack- und Extrasegment mit
mov ss, ax ; Datensegmentdeskriptor laden
mov es, ax
xor ax, ax
mov fs, ax ; fs und gs mit Nulldeskriptor laden
mov gs, ax
mov esp, 09000h ; Stack setzen
jmp 08h:010000h
stop:
jmp stop
times 512-($-$$)-2 db 0
dw 0x0AA55
Der Kernel (*.c)
int begin()
{
char *Text = "Welcome to Protected Mode";
char *VideoMem = (char*)0xA8000;
while(*Text)
{
*VideoMem = *Text;
*VideoMem++;
*VideoMem = 7;
*VideoMem++;
*Text++;
}
return(0);
}
Linker-Script (*.ld)
OUTPUT_FORMAT("binary")
INPUT("kernel.o")
ENTRY(_begin)
SECTIONS
{
.text 0x10000 :
{
*(.text)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
Und so mach ich das ganze zu einer IMG-Datei.
nasm -f bin -o boot.bin boot.asm
gcc -ffreestanding -c -o kernel.o kernel.c
ld link.ld -o kernel.bin
copy /b boot.bin + kernel.bin os.img
Weiß jemand woran das liegt das der Kernel nicht geladen wird?
Hab schon viel rumprobiert, z.B. die Addresse dess Kernels,
hat alles nichts geholfen :-(.
Bitte um Hilfe!
-
Ich glaube, das ist jetzt nicht alles, was falsch ist, aber da kann sicher jemand mit mehr Ahnung weiterhelfen (Kein Plan vom Linken :-D), aber:
Dein größter Fehler besteht zuerst einmal darin, dass dein Bootloader den Kernel aufrufen muss. Nur weil du Bootloader und Kernel im/auf dem Image hast, tut sich da nix. Dein Bootloader muss halt einen call oder einen jmp (Ja gut, es gibt auch andere Möglichkeiten) machen, damit dein Kernel auch überhaupt aufgerufen wird. Dafür sollte dem Bootloader auch der Einstiegspunkt des Kernels bekannt sein.
Eventuell solltest du dir nochmal ganz genau visualisieren, wie der Programmfluss denn abläuft, dann klappt das auch ;-)
PS: Bevor ichs vergesse und irgendjemand Anderes es loswerden will: Wir empfehlen GRUB als Bootloader.
Uppala, da hab ich doch glatt was überlesen...
-
Hi,
%define KERNELSEGMENT 0x10000
Das soll wohl 0x1000 sein, wenn ich mir den Rest des Codes anschaue. Mein NASM 2.02 hat mir deswegen auch eine Warnung gegeben.
char *VideoMem = (char*)0xA8000;
Der Videospeicher ist bei 0xB8000. Der Wert 0xA8000 stammt aus einem total verkorkstem Tutorial.
An das Ende von begin() muss außerdem eine Endlosschleife, weil du aus der Funktion nicht zurückkehren darfst. Du bist ja mit jmp dahin gesprungen.
ld link.ld -o kernel.bin
Da muss ein -T vor das link.ld.
-
Der Videospeicher ist bei 0xB8000. Der Wert 0xA8000 stammt aus einem total verkorkstem Tutorial.
Achso, na dann kein Wunder das nix auf dem Bildschirm kommt :).
An das Ende von begin() muss außerdem eine Endlosschleife, weil du aus der Funktion nicht zurückkehren darfst. Du bist ja mit jmp dahin gesprungen.
Ich hab nach diesem Jump zum Kernel ein "Endlossjump" gemacht also
stop:
jmp stop
Funktioniert doch auch, oder?
Da muss ein -T vor das link.ld.
Wenn ich das mache, bekomme ich folgende Fehlermeldung:
ld: cannot perform PE operations on non PE out put file 'kernel.bin'.
Den rest werde ich verbessern und mal schaun obs geht.
Danke für die Antworten :wink:!
-
Ich hab nach diesem Jump zum Kernel ein "Endlossjump" gemacht also
stop:
jmp stop
Funktioniert doch auch, oder?
Nein, da du den Kernel mit "jmp" aufgerufen hast, er weiß also nicht, wohin er zurückkehren soll. Um das zu korrigieren, müsstest du "call" verwenden. :wink:
-
Ich hab nach diesem Jump zum Kernel ein "Endlossjump" gemacht also
stop:
jmp stop
Funktioniert doch auch, oder?
In diesem Fall nicht, weil du ja nie dahinkommst. Du springst mit jmp 0x08:0x10000 zum Kernel, aber der Kernel weiß nicht, wie er zurückkommt. Du könntest mit call statt jmp zum Kernel springen, dann funktioniert das.
Da muss ein -T vor das link.ld.
Wenn ich das mache, bekomme ich folgende Fehlermeldung:
ld: cannot perform PE operations on non PE out put file 'kernel.bin'.
Ohne -T sieht der ld das Linker-Skript nicht als das primäre Linkerskript an und erzeugt eine .exe-Datei. (Davon kannst du dich mittels objdump -p kernel.bin überzeugen.)
Es gibt zwei Möglichkeiten, um doch eine Binärdatei zu bekommen: Entweder nimmst du einen Cross Compiler (z.B. einen (http://lowlevel.brainsware.org/wiki/index.php/Crosscompiler_f%C3%BCr_Windows), den ich erstellt habe, oder machst dir einen selbst (http://lowlevel.brainsware.org/wiki/index.php/Cross-Compiler)) oder du baust deinen Build-Prozess um: Aus link.ld entfernst du die Zeile OUTPUT_FORMAT("binary") und rufst nach dem Linken noch objcopy auf um die Datei ins Binärformat zu wandeln: objcopy -O binary kernel.bin
-
So, habe jetzt alles verbessert. Jedoch passiert wieder nichts :(.
Liegt das vielleicht an der Addresse dess Kernels? Der Kernel is im moment
auf 0x1000 und aufrufen tu ich ihn mit jmp 08h:01000h , eine Endlosschleife
ist auch am Ende dess Kernels.
Ich versteh nicht warum das nicht geht.... :(.
-
Warum hast du ihn jetzt an diese Adresse gelegt?
-
Wenn ich ihn an eine Addresse tu, die größer als 0x10000 ist, dann meldet mir nasm.exe das die Addresse zu groß ist.
Achja, das objcopy funktioniert bei mir nicht. Da kommt immer eine
Meldung, in der steht, das das Dateiformat *.bin nicht bekannt ist.
-
Also das Zusammenfassen von Fehlermeldungen ist immer so eine Sache ...
Wo gibt dir NASM die Fehlermeldung? Was sagt der genau? Was ist die genaue Fehlermeldung von objcopy?
-
Das gebe ich ein:
objcopy -O binary kernel.bin
Und das kommt:
objcopy:kernel.bin: File format not recognized
-
Kommt die Meldung immer? Auch wenn du vorher kernel.bin löschst, und sie mit ld erneut erstellst?
-
Die Meldung kommt immer, oder kann das sein das ich eine alte Version
von objcopy.exe habe? Wenn ja, kannst du mir bitte einen Downloadlink
schicken wo man die neue findet? Ich hab bei Google lange gesucht
bis ich die gefunden habe.
Hier die Batch - Datei:
ECHO OFF
nasmw -f bin -o boot.bin boot.asm
D:\Programme\CodeBlocks\MinGW\Bin\gcc -ffreestanding -c -o kernel.o kernel.c
D:\Programme\CodeBlocks\MinGW\Bin\ld -T link.ld -o kernel.bin
objcopy -O binary kernel.bin
copy /b boot.bin + kernel.bin os.img
pause
rawwritewin.exe C:\Users\Pk3\Desktop\C_Kernel\os.img a:
Edit:
objcopy.exe ist bei mir 676kb groß.
-
In diesem Fall ist sowohl Eingabe wie Ausgabe. Wenn du objcopy -O binary kernel.bin kernel-output.bin schreibst, dann ist kernel-output.bin die Ausgabe.
Ich kann mir nicht erklären, warum das so nicht funktioniert.
-
Versteh ich auch nicht.... wie gesagt, vielleicht liegt das an der Version von objcopy.exe. Bei mir ist die 676kb groß. Das Linke - Script sieht jetzt so aus:
INPUT("kernel.o")
ENTRY(_begin)
SECTIONS
{
.text 0x1000 :
{
*(.text)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
-
objcopy -O binary --input-target binary kernel.bin kernel-output.bin
Mit --input-target binary funktionierts ohne Meldung.
Aber so ist es doch sinnlos, weiß jemand wie der richtige
input-target heißt?
-
Die Version kannst du mit objcopy -V feststellen.
Das Problem an MinGW ist, dass es halt stark auf Windows spezialisiert ist. Eventuell solltest du wie ich bereits oben vorgeschlagen habe auf einen Cross Compiler umsteigen.
-
Habe mir jetzt einen CrossCompiler heruntergeladen und es damit probiert.
Das objcopy geht jetzt endlich :). Die größe der IMG Datei hat sich auch verändert (von 5kb auf 1kb).
Und wenn ich das Image auf eine Diskette schreibe, und darauf boote, dann
rebootet sich der PC von alleine, ohne das ich irgentwas mache.
Ich weiß nicht wo der Fehler liegt.... hab schon so viel rumprobiert
und nichts klappt.... :-(.
-
Hi,
für den Anfang solltest du zum Testen Bochs oder Qemu benutzen. Die können dir meistens auch Hinweise geben, was schief gelaufen ist.
Zum Beispiel erstellt Bochs ein Log, in dem die Instruktion bei der das Problem aufgetreten ist, sowie der Zustand der CPU (Register, etc.) stehen.
Ich benutze meistens diese Konfigurationsdatei für Bochs:
floppya: 1_44="os.img", status=inserted
boot: floppy
romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xe0000
cpu: count=1, ips=10000000, reset_on_triple_fault=1
megs: 8
vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
vga: extension=vbe
log: bochs.log
logprefix: %t-%e-@%i-%d
In einer Datei namens bochs.bxrc oder so speichern, und in das Verzeichnis mit deinem os.img kopieren und dann per Doppelklick starten.
-
Danke für den Tipp, hab das jetzt mal gemacht und folgende Log-Datei
bekommen.
http://xyross.de/bochs.log
Darin fällt mir nur auf, das der Protect-Mode eingeschaltet wurde (Zeile 756)
00065895575-i-@006f0018-[CPU0 ] protected mode
und das er beendet
00065895575-e-@006f0018-[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
nachdem
00065895575-i-@006f0018-[CPU0 ] >> add dword ptr ds:[eax], eax : 0100
ausgeführt wurde. Also muss da der Fehler sein.
Jedoch finde ich im Assembler-Code (boot.asm) kein
"add", aber den Register "eax". Die 0100 ähnelt der Addresse
dess Kernels, fehlt halt eine Null, die habe ich anschließend rangehängt
also beim jmp, jetzt siehts so aus:
jmp 08h:010000h
Dann habe ich das ganze nochmal gemacht und jetzt sagt Bochs das:
00002609039-i-@00010006-[CPU0 ] >> and byte ptr gs:[edi+ebp*2+0x20], dh : 6520746F20
00002609039-e-@00010006-[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
(Hier die Log-Datei: http://xyross.de/bochs2.log)
Da weiß ich nicht was ich machen soll, damits funktioniert.
Es passiert aber aufjedenfall nach dem Jump zum Kernel.
Edit:
Ich habe den Fehler gefunden, er liegt im C - Code:
char *Text = "Welcome to Protected Mode";
char *VideoMem = (char*)0xB8000;
while(*Text)
{
*VideoMem = *Text;
*VideoMem++;
*VideoMem = 7;
*VideoMem++;
*Text++;
}
Ich habe mal alles aus der begin() - Funtkion raus, auser die
Endlosschleife ( for(;;); ), jetzt sagt Bochs folgendes:
00141710000-i-@00010004-[CPU0 ] >> jmp .+0xfffffffe (0x00010004) : EBFE
Hab dann mal bei Google nach einer printf - Funktion gesucht und diese
verwendet:
void printf(char *text)
{
char *ptr;
for ( ptr = (char *)0xB8000; *text != 0; text++ )
{
*(ptr++) = *text;
*(ptr++) = 0xe;
}
}
int begin()
{
printf("Test");
for(;;);
}
als Fehler bekomme ich:
00026099052-i-@00000008-[CPU0 ] >> (invalid) : FFFF
-
Hi,
00065895575-i-@006f0018-[CPU0 ] >> add dword ptr ds:[eax], eax : 0100
ausgeführt wurde. Also muss da der Fehler sein.
Jedoch finde ich im Assembler-Code (boot.asm) kein
"add", aber den Register "eax".
Wenn du den Code nicht als deinen erkennst, dann heißt das, dass dein Bootloader/Kernel irgendwo ins Nirvana springt, oder dass sich dein Kernel nicht an der Stelle befindet, wo der Bootloader hinspringt. Ich vermute letzteres.
Die 0100 ähnelt der Addresse
dess Kernels, fehlt halt eine Null, die habe ich anschließend rangehängt
also beim jmp, jetzt siehts so aus:
Hinter dem Assemblerbefehl steht immer der Maschinencode in Hexadezimaldarstellung. Die Ähnlichkeit mit irgendwelchen Adressen hat an dieser Stelle nichts zu bedeuten. Wenn dein Programmfluss irgendwo im Nirvana landet, dann ist dieser Speicher einfach mit zufälligen Werten, je nach Art des Speichers auch mit Nullen (0x00) oder Einsen (0xFF) gefüllt.
Das Interessante hier ist nicht der Befehl selbst, sondern der Zustand der CPU. Der Wert des Befehlszählers (RIP bzw. EIP) ist 00000000006f0018, was weit ab von deinem Programm ist.
00002609039-i-@00010006-[CPU0 ] >> and byte ptr gs:[edi+ebp*2+0x20], dh : 6520746F20
00002609039-e-@00010006-[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Dies mal ist der Maschinencode wesentlich interessanter. 6520746F20 sieht aus wie ASCII Code und zwar entspricht der genau dem "e to " aus deinem "Welcome to Protected Mode". Das heißt die CPU versucht die Daten auszuführen, weil die Daten in deiner Binärdatei vor dem Code liegen.
Als du die Ausgabe entfernt hast, hast du auch diesen String aus deinem Programm entfernt. Dann war der Datenbereich deines Programms leer und wieder der Code das erste in deinem Progamm. Das Fehler liegt also in dem Prozess, wie du den Kernel erstellst, nicht am Code des Kernels.
Der String landet in der *(.rodata) oder *(.rdata) Sektion je nach Compiler. Änder mal dein Linkerskript so, dass du die Sektionen erwähnst:
INPUT("kernel.o")
ENTRY(_begin)
SECTIONS
{
.text 0x10000 :
{
*(.text)
*(.rdata)
*(.rodata)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
Außerdem würde ich dir mal empfehlen, dich mehr mit den Werkzeugen auseinander zu setzen. objdump kann dir viele Informationen über deine Objekt-Dateien (und über deinen Kernel solange er nicht eine Binärdatei ist) liefern, mit ndisasm, welches bei NASM dabei ist, kannst du den Kernel, wenn er eine flache Binärdatei ist, disassemblieren. Außerdem könntest du dich mal mit dem Debugger von Bochs auseinander setzen. Mit lb 0x7c00 kannst du da einen Breakpoint an den Anfang des Bootloaders setzen, mit c kommst du dann bis zu diesem Breakpoint, mit s kannst du single steppen und mit n kannst du einen step over (z.B. über BIOS Interrupts) machen.
All diese Programme haben außerdem Handbücher, die online verfügbar sind.
-
Ich habs jetzt, der Fehler war im C Code, ich habe das ausprobiert:
int begin() {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
while(i < (80*25*2)) {
vidmem[i]='G';
i++;
vidmem[i]=0x06;
i++;
};
for(;;);
}
Da wird der Bildschirm mit "G" gefüllt.
Aber wenn ich eine Funktion aufrufen will, in dem man ein
char übergeben muss, wird die Funktion net ausgeführt.
z.B.:
void printf(char *text);
int begin() {
printf("TEST");
while(1);
}
void printf(char *text) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
while(i < (80*25*2))
{
vidmem[i]='G';
i++;
vidmem[i]=0x06;
i++;
};
};
-
Aber wenn ich eine Funktion aufrufen will, in dem man ein
char übergeben muss, wird die Funktion net ausgeführt.
z.B.:
void printf(char *text);
int begin() {
printf("TEST");
while(1);
}
Hast du den Code genau so ausprobiert? In dem Fall sollte gcc keine Optimierung vornehmen. Ansonsten optimiert gcc an so nem printf scheinbar manchmal. Siehe dazu das Zitat aus einem anderen Thread:
Der GCC optimiert ein printf("foo\n") zu einem puts("foo"), weil ein standardkonformes puts automatisch ein \n ausgibt.
Ich schätze da gibts es mindestens folgende Möglichkeiten:
- printf nicht printf nennen
- oder standardkonformes puts implementieren
- oder angeblich soll da -fno-builtin oder -fno-builtin-printf helfen.
-> http://www.ciselant.de/projects/gcc_printf/gcc_printf.html
-
Hmm..... ich kann nur char´s übergeben, die net mehr als 2 Zeichen enthalten,
also z.B. printf("hi"); , das geht, aber printf("hih"); geht nicht.
-
@MNemo
Ich habe die Funktion auch schon unbenannt in "v_print", hilft aber auch nix :-(.
void v_print(char *msg);
int begin() {
v_print("Die");
while(1);
}
void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
unsigned int s=0;
while(s < sizeof(msg) - 1) {
vidmem[i]=msg[s];
i++;
vidmem[i]=0x06;
i++;
s++;
}
}
-
void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
unsigned int s=0;
while(s < sizeof(msg) - 1) {
vidmem[i]=msg[s];
i++;
vidmem[i]=0x06;
i++;
s++;
}
}
Emm… Ja…
Deine C Kenntnisse sind ja nicht gerade berauschend.
sizeof(msg) wird dir immer 4(bzw. bei 64-Bit CPUs 8 ) liefern. weil msg nur mal ein Pointer ist. und die sind 4 bzw. 8 Byte groß.
du solltest dir bei der String Ausgabe eher von nutzen machen, dass c-strings ein Null-Byte am ende haben.
BTW: ein char ist _ein_ Zeichen. ein string ist ein array aus chars mit einem 0-Byte(char) am ende
-
Das Problem liegt da woanders, wie gesagt, wenn ich an eine Funktion ein Char-Array übergebe und deren inhalt länger als 2 Zeichen ist dann wird die Funktion nichmal aufgerufen.
-
was sagt den
$ objdump -d kernel.o
dazu?
-
Hi,
versuch doch mal folgendes:
void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
int i = 0;
int j = 0;
while ((byte)msg[i] != 0)
{
vidmem[j] = msg[i];
j++;
vidmem[j] = (char)0x07
j++;
i++;
}
}
Für Syntaxfehler übernehme ich keine Haftung. Bin kein C-ler :-D
-
file format pe-i386
Disassembly of section .text:
00000000 <.text>:
0: 44 inc %esp
1: 65 72 00 jb 4 <_begin>
00000004 <_begin>:
4: 55 push %ebp
5: 89 e5 mov %esp,%ebp
7: 68 00 00 00 00 push $0x0
c: e8 13 00 00 00 call 24 <_v_print>
11: 83 c4 04 add $0x4,%esp
14: eb 02 jmp 18 <_begin+0x14>
16: eb 08 jmp 20 <_begin+0x1c>
18: eb fa jmp 14 <_begin+0x10>
1a: 8d b6 00 00 00 lea 0x0(%esi),%esi
1f: 00
20: 89 ec mov %ebp,%esp
22: 5d pop %ebp
23: c3 ret
00000024 <_v_print>:
24: 55 push %ebp
25: 89 e5 mov %esp,%ebp
27: 83 ec 10 sub $0x10,%esp
2a: c7 45 fc 00 80 movl $0xb8000,0xfffffffc(%ebp)
2f: 0b 00
31: c7 45 f8 00 00 movl $0x0,0xfffffff8(%ebp)
36: 00 00
38: c7 45 f4 00 00 movl $0x0,0xfffffff4(%ebp)
3d: 00 00
3f: 90 nop
40: 8b 45 08 mov 0x8(%ebp),%eax
43: 8b 55 f4 mov 0xfffffff4(%ebp),%edx
46: 01 d0 add %edx,%eax
48: 80 38 00 cmpb $0x0,(%eax)
4b: 75 03 jne 50 <_v_print+0x2c>
4d: eb 31 jmp 80 <_v_print+0x5c>
4f: 90 nop
50: 8b 45 fc mov 0xfffffffc(%ebp),%eax
53: 8b 55 f8 mov 0xfffffff8(%ebp),%edx
56: 01 d0 add %edx,%eax
58: 8b 55 08 mov 0x8(%ebp),%edx
5b: 8b 4d f4 mov 0xfffffff4(%ebp),%ecx
5e: 01 ca add %ecx,%edx
60: 8a 0a mov (%edx),%cl
62: 88 08 mov %cl,(%eax)
64: ff 45 f8 incl 0xfffffff8(%ebp)
67: 8b 45 fc mov 0xfffffffc(%ebp),%eax
6a: 8b 55 f8 mov 0xfffffff8(%ebp),%edx
6d: 01 d0 add %edx,%eax
6f: c6 00 06 movb $0x6,(%eax)
72: ff 45 f8 incl 0xfffffff8(%ebp)
75: ff 45 f4 incl 0xfffffff4(%ebp)
78: eb c6 jmp 40 <_v_print+0x1c>
7a: 8d b6 00 00 00 lea 0x0(%esi),%esi
7f: 00
80: 89 ec mov %ebp,%esp
82: 5d pop %ebp
83: c3 ret
00000084 <_v_clear>:
84: 55 push %ebp
85: 89 e5 mov %esp,%ebp
87: 83 ec 10 sub $0x10,%esp
8a: c7 45 fc 00 80 movl $0xb8000,0xfffffffc(%ebp)
8f: 0b 00
91: c7 45 f8 00 00 movl $0x0,0xfffffff8(%ebp)
96: 00 00
98: 81 7d f8 9f 0f cmpl $0xf9f,0xfffffff8(%ebp)
9d: 00 00
9f: 76 02 jbe a3 <_v_clear+0x1f>
a1: eb 1e jmp c1 <_v_clear+0x3d>
a3: 8b 45 fc mov 0xfffffffc(%ebp),%eax
a6: 8b 55 f8 mov 0xfffffff8(%ebp),%edx
a9: 01 d0 add %edx,%eax
ab: c6 00 20 movb $0x20,(%eax)
ae: ff 45 f8 incl 0xfffffff8(%ebp)
b1: 8b 45 fc mov 0xfffffffc(%ebp),%eax
b4: 8b 55 f8 mov 0xfffffff8(%ebp),%edx
b7: 01 d0 add %edx,%eax
b9: c6 00 07 movb $0x7,(%eax)
bc: ff 45 f8 incl 0xfffffff8(%ebp)
bf: eb d7 jmp 98 <_v_clear+0x14>
c1: 89 ec mov %ebp,%esp
c3: 5d pop %ebp
c4: c3 ret
-
c: e8 13 00 00 00 call 24 <_v_print>
also der Aufruf findet eindeutig statt.
ändere mal diese Zeile in deinem linkscript
*(.rodata)
zu
*(.rodata*)
gcc steckt strings AFAIK in sections mit namen wie
.rodata-str-XY
vielleicht ist dein string ja einfach nicht mit gelinkt.
-
Jetzt kann ich maximal ne 3-Zeichen-Char-Array an eine Funktion übergeben :-D. Mehr geht nich....
Link.ld
INPUT("C:\Users\Pk3\Desktop\C_Kernel\kernel.o")
ENTRY(_begin)
SECTIONS
{
.text 0x10000 :
{
*(.text)
*(.rdata)
*(.rodata*)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
kernel.c
void v_print(char *msg);
void v_clear();
int begin() {
v_print("Derd");
while(1);
}
void v_print(char *msg) {
char *vidmem = (char *) 0xB8000;
unsigned int i=0;
unsigned int s=0;
while(msg[s] != 0) {
vidmem[i]=msg[s];
i++;
vidmem[i]=0x06;
i++;
s++;
}
}
void v_clear() {
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
while(i < (80*25*2)) {
vidmem[i]=' ';
i++;
vidmem[i]=0x07;
i++;
}
}
boot.asm
[BITS 16]
org 0x7c00
%define STACKSEGMENT 0x9000 ; lineare Adresse des Stacks : 0x90000
%define STACKSIZE 0x200 ; Größe des Stacks : 512Byte
%define KERNELSEGMENT 0x1000 ; lineare Adresse des Kernels : 0x10000
jmp START
GDTR:
limit dw (GDT_END - GDT - 1)
base dd (0)
GDT:
NULL_DESCRIPTOR EQU $-GDT
dd 0
dd 0
CODE_DESCRIPTOR EQU $-GDT
dw 0ffffh
dw 0
db 0
db 09ah
db 0cfh
db 0
DATA_DESCRIPTOR EQU $-GDT
dw 0ffffh
dw 0
db 0
db 092h
db 0cfh
db 0
GDT_END:
START:
cli ; keine Interrupts
mov ax, STACKSEGMENT
mov ss, ax ; Stacksegment setzen
mov sp, STACKSIZE ; Größe des Stacks festlegen
xor ax, ax ; ax = 0
mov ds, ax ; Datensegment auf 0 setzen
sti
xor bx, bx ; Ziel-Offset : 0x0
mov ax, KERNELSEGMENT ; Ziel-Segment : 0x1000
mov es, ax
mov ah, 0x2 ; Funktion 0x2 : Sektor lesen
mov al, 1 ; Anzahl der Sektoren : 1
mov ch, 0 ; Track : 0
mov cl, 2 ; LSN : 2
mov dh, 0 ; Head : 0
mov dl, 0 ; Laufwerk : A
int 0x13 ; Interrupt : 0x13
cli ; keine Interrupts
mov ax, cs ; Code-Segment holen
mov ds, ax ; Daten-Segment gleichsetzen
xor eax, eax ; ax = 0
mov es, ax ; Extra-Segment auf Null setzen
mov si, GDT ; Quelle : GDT
xor di, di ; Ziel : 0x0000
mov cx, 6 ; 6 DoubleWords kopieren (ganze GDT)
rep movsd
lgdt [GDTR]
mov eax, cr0
or eax, 1 ; Bit0 setzen (PE-Bit enabled)
mov cr0, eax
db 0xea ; FAR-JUMP zum Codesegment
dw (PMODE)
dw 0x8
[BITS 32] ; 32 Bit-Code erstellen
PMODE:
xor eax, eax
mov eax, 2 ; Selektor für das Datensegment erstellen
shl eax, 3
mov ds, ax ; Daten-, Stack- und Extrasegment mit
mov ss, ax ; Datensegmentdeskriptor laden
mov es, ax
xor ax, ax
mov fs, ax ; fs und gs mit Nulldeskriptor laden
mov gs, ax
mov esp, 09000h ; Stack setzen
jmp 08h:010000h
times 512-($-$$)-2 db 0
dw 0x0AA55
-
Mach aus dem char* vidmem mal bitte ein unsigned long *vidmem = (unsigned long *)0xB8000
-
Dein code tut bei mir ohne Probleme.
$ nasm -f bin boot.asm
$ gcc -m32 -ffreestanding -fleading-underscore -c kernel.c
$ ld -melf_i386 -T link.ld -o kernel.bin kernel.o
$ dd if=/dev/zero of=floppy.img bs=512 count=2880
$ cat boot kernel.bin | dd of=floppy.img conv=notrunc
$ qemu -fda floppy.img
Ich spare mir das objcopy mit
OUTPUT_FORMAT( "binary" )
im linkerscript
@hartmut: warum denn das?
[edit]ich kann mir nicht vorstellen das es tut wenn man alle 4 bzw. 8 byte abwechselnd ein Daten- und Attribut-Byte in den RAM schreibt.[/edit]
-
Weil ich es so gemacht habe *G*
-
@MNemo
-m32 -fleading-underscore
So funktionierts, jetzt geht alles, danke an alle :-D!