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.odazu?
- 
				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!