Lowlevel
Lowlevel => Softwareentwicklung => Thema gestartet von: OS_3000 am 31. March 2012, 22:48
-
Ich habe das Problem, dass ich einige Methoden eines Headers einfach nicht aufrufen kann. :cry:
Zb. in meiner "AsmAcess.h":
#ifndef ASMACCESS
#define ASMACCESS
#include <stdint.h>
inline uint8_t inb(uint16_t Port)
{
unsigned char Data = 0;
asm volatile ("inb %1, %0" : : "a" (Data), "Nd" (Port));
return Data;
}
inline void outb(uint16_t Port, uint8_t Data)
{
asm volatile ("outb %0, %1" : : "a" (Data), "Nd" (Port));
}
inline void halt()
{
StopPoint:
asm volatile ("cli");
asm volatile ("hlt");
goto StopPoint;
}
#endif
Diese Datei binde ich dann zb. in meinem Kernel ein:
#include "kernel\console.h"
#include "kernel\asmaccess.h"
void main()
{
Console_ClearScreen();
Console_WriteLine("Hallo!");
Console_WriteLine("Ich heiße Compi!");
Console_WriteLine("Ich bin ein Computer");
Console_WriteLine("und lasse hier diesen sinnfreien Text anzeigen.");
halt();
}
Wenn ich das Ganze dann mit folgendem Code kompilieren will:
del obj\*.o
SET C_COMPILE=i586-elf-gcc -m32 -ffreestanding -Wall -nostdinc -std=gnu99 -I stdlib
SET ASM_COMPILE=nasm -f elf
%ASM_COMPILE% -o obj\start_S.o start.S
%C_COMPILE% -o obj\kernel_c.o -c kernel.c
%C_COMPILE% -o obj\beep_c.o -c kernel\beep.c
%C_COMPILE% -o obj\console_c.o -c kernel\console.c
%C_COMPILE% -o obj\rand_c.o -c stdlib\rand.c
i586-elf-ld -T linkconf.ld -o obj\kernel.bin obj\*.o -Ttext=0x100000
copy obj\kernel.bin cd\kernel.bin
mkisofs -R -J -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o cdrom.iso cd/
Kommt beim Linken immer diese Fehlermeldung:
obj\kernel.o: In Funktion "[i]main[/i]":
kernel.c(.text+0x57): undefined reference to "halt"
Ich bin absolut ratlos, was das Problem auslöst.
Eigentlich müsste der Präprozessor "#include "kernel\asmaccess.h"" mit dem Code in der Datei ersetzen und abschliessend das Ganze inlinen.
Doch weshalb tut er das nicht? :-o
Ich hoffe ihr könnt mir helfen. :-)
-
Der Fehler ist komisch, aber nimm besser mal das goto raus. Du hast den Punkt nirgendwo definiert und hlt; stoppt die CPU.
-
Hat leider nicht geholfen. :cry:
Der Fehler tritt übrigens auch bei dem Aufruf der In\Out-Funktion auf.
Die "MoveCurser"-Funktion der "Console"-Datei verursacht so sogar 8 Linkerfehler.
void Console_MoveCurser()
{
if (Console_ShowCurser)
{
//Curser auf Position setzen
outb(0x3D4, 14);
outb(0x3D5, (uint8_t)(Console_Curser >> 8));
outb(0x3D4, 15);
outb(0x3D5, (uint8_t)Console_Curser);
}
else
{
//Curser aus dem Bildschirm setzen
outb(0x3D4, 14);
outb(0x3D5, (uint8_t)(Console_CharCount >> 8));
outb(0x3D4, 15);
outb(0x3D5, (uint8_t)Console_CharCount);
}
}
-
Hi,
einbinden tut der die header aber, oder? Das würde ich mal nachprüfen.
Schrein einfach mal ein "#error bla" in einen der header, dann können wir das schonmal ausschließen.
Grüße, LittleFox
--
Handy ..
-
Diese Datei binde ich dann zb. in meinem Kernel ein:
#include "kernel\console.h"
#include "kernel\asmaccess.h"
void main()
{
Console_ClearScreen();
Console_WriteLine("Hallo!");
Console_WriteLine("Ich heiße Compi!");
Console_WriteLine("Ich bin ein Computer");
Console_WriteLine("und lasse hier diesen sinnfreien Text anzeigen.");
halt();
}
Liegt das vielleicht in deinem Kernelverzeichnis?
du solltest dann das nehmen:
#include "console.h"
#include "asmaccess.h"
statt dem:
#include "kernel\console.h"
#include "kernel\asmaccess.h"
-
Bei "#Error Ich funktioniere nicht" kommt der Fehler beim kompilieren von "Console.c" und "Kernel.c" wie es sein soll.
Das das wegen dem Kernelverzeichnis streikt, schliess ich mal aus, da "kernel\Console.h" problemlos eingebunden werden kann.
Ich hab mal das Ganze angehängt, vielleicht hilfts bei der Fehlersuche. :-)
(Die Datei, ist eine 7z-Datei, da ich solche aber leider nicht hochladen darf, habe ich noch ein ".txt" drangehängt. Zum entpacken einfach wieder ".7z" daraus machen. :wink:)
-
ich kann dir leider nicht sagen warum es so nicht funktioniert, aber static inline hilft.
-
Ah, tausend Dank!
Kannst du mir auch noch sagen, was dieses "static" jetzt eigentlich bewirkt, also wozu es gut ist?
Bedauerlicherweiße kommt jetzt beim kompilieren von "Console.c" ein anderer Fehler:
Temp\cckJeKaN.s: Assembler messages:
Temp\cckJeKaN.s:30: Error suffix or operands invalid for "out"
Was stimmt denn jetzt schonwieder nicht?
Meine Funktionen heißen schliesslich immer "outb".
-
static sagt das eine funktion nur in der aktuellen datei benutzt wird. Wenn du zwei Dateien hast die asmaccess.h includen hättest du ohne static die halt funktion zweimal definiert und es käme zu konfliketen beim linken. Static behebt das.
@Assembeler error messages
Es scheint als wäre dein uint8_t kein echter 8-Bit integer. So dass dir gcc z.B.
outb %eax, %dx
statt
outb %al, %dx
baut. Dann passt b (= 8bit) nicht zu eax (=32bit).
-
Ich verstehe zwar nicht, weshalb das jetzt kein echter Integer sein soll,
aber auf jedenfall geht es jetzt. :-D
Noch mal vielen Dank. :-)
-
Ein integer ist es schon, nur scheint er größer als 8-Bit zu sein.
if (sizeof(uint8_t) != 1) {
puts("uint8_t hält _nicht_ was er verspricht!");
}
Edit: Ich hab mal nachgeguckt. Dein uint8_t ist OK. aber dein uint16_t nicht. Es lag also an %edx statt %dx. Da du "Nd" hast ist es übrigens nicht ratsam das als "%%dx" hart zu codieren sondern uint16_t zu fixen. (short statt int) bzw. ich nehme:
typedef unsigned uint8_t __attribute__((__mode__(__QI__)));
typedef unsigned uint16_t __attribute__((__mode__(__HI__)));
typedef unsigned uint32_t __attribute__((__mode__(__SI__)));
typedef unsigned uint64_t __attribute__((__mode__(__DI__)));
-
nochmal zu dem outb:
deine funktionen in asmaccess.h sind falsch. Sie könnten (sollten) so aussehen:
static inline void outb(uint16_t port, uint8_t data){
asm("outb %0, %1" : : "a" (data), "Nd" (port));
}
static inline uint8_t inb(uint16_t port){
unsigned char result = 0;
asm("inb %1, %0" : "=a" (result) : "Nd" (port));
return result;
}
-
Ja, stimmt, hab Blödsinn geschrieben.
Meinte natürlich, dass es eben kein 8-Bit Integer ist. :roll:
Das mit dem "short" hab ich jetzt bereits selbst bemerkt, als die "Console.c" nicht so recht funktioniert hat.
Diese Definition hatte ich aus dem Internet.
Konnte ja nicht wissen, dass sie noch aus der 16-Bit-Zeit stammt. :-o
typedef unsigned uint8_t __attribute__((__mode__(__QI__)));
typedef unsigned uint16_t __attribute__((__mode__(__HI__)));
typedef unsigned uint32_t __attribute__((__mode__(__SI__)));
typedef unsigned uint64_t __attribute__((__mode__(__DI__)));
Wenn das besser ist, mach ichs so.
EDIT:
Wo ist jetzt der Fehler in "outb"?
Der einzige Unterschied ist in "inb" das Istgleichzeichen vor dem "a".
-
Dein outb ist korrekt.
Ich benutzte diese (u)intNN_t Definitionen weil C mir z.B. nicht garantiert das long 32-bit ist. Es ist halt gcc-only (und auch nur neuere). Aber ich glaub es geht auch irgendwie die stdint.h von gcc zu nehmen, das wäre dann noch besser.
-
ich meinte ja eingentlich auch nur das inb.
Der Assembler hat mir nur Angezeit: Suffix or operands invalid for out
mit den Funktionen kommt das nicht
deshalb hab ich dir funktionierende Funktionen :wink: nochmal geschrieben
-
Eigentlich dachte ich, jetzt gehts endlich, als das heute wieder los ging. :x
Jetzt kommt dauernd "undefined Reference to __moddi3", "undefined Reference to __divdi3", "undefined Reference to __umoddi3" und "undefined Reference to __udivdi3".
-
wenn ich mich richtig erinnere haben die Funktionen etwas mit uint64/int64 zu tun.
Ist vielleicht schonmal ein Ansatzpunkt.
Grüße
-
Hm...
Könnte gut sein, da der Fehler in "Console_WriteInt64" auftritt.
Mal noch der Quellcode:
void Console_WriteInt64(sint64_t Number)
{
char String[21];
//Negative Zahlen extra behandeln
bool Negative = Number < 0;
if (Negative)
{
String[0] = '-';
Number = 0 - Number;
}
//Nummer in Ziffern aufteilen
char TempDigits[10];
int Index = 0;
while(Number > 0)
{
TempDigits[Index++] = Number % 10;
Number /= 10;
}
//String zusammenbauen
int StringIndex = Negative ? 1 : 0;
for (Index--; Index >= 0; Index--)
{
String[StringIndex] = TempDigits[Index] + 0x30;
StringIndex++;
}
String[StringIndex] = 0;
Console_Write(String);
}
EDIT: Weshalb gibts hier eigentlich kein Syntaxhighlighting?
So ist Quellcode fast unleserlich.
-
Du musst die libgcc dazulinken.
-
Wo finde ich das bzw. wie linke ich das?
Hab eben ein wenig im Internet rumgeschaut, aber nichts dazu gefunden.
-
-lgcc an den Compileraufruf anhängen
-
Leider kommt dann "i586-elf-gcc: cannot find -lgcc".
-
äh - sorry
Linkeraufruf - hoff ich :D
Edit: Kommt davon wenn man auf Arbeit irgendwas postet :D
-
gcc -m 32 -print-libgcc-file-name sagt dir, wo sie liegt (falls sie installiert ist - ansonsten kann es sein, dass er dir die 64-Bit-Variante unterschieben will, die natürlich nicht funktioniert!). Diese .a-Datei übergibst du einfach mit an ld.
-
Ihr seit echt super, jetzt gehts! :-D
Bläht aber ein bisschen den Kernel auf. (8kb -> 40kb)
Gibt es eine Möglichkeit nicht immer den Pfad "C:\Programm Ordner\MinGW\OSprogramming\lib\gcc\i586-elf\4.4.0\libgcc.a" angeben zu müssen? Der ist nämlich höllisch lang und wenn ich das auf einen anderen Computer kompilieren will, muss er auch angepasst werden.
Sowas wie von LittleFox wäre gut.
Und ja, dass hab ich natürlich beim Linker angegeben. :wink:
-
die Regeln bezüglich "inline" soweit ich es gerade im kopf habe:
1) niemals inline alleine verwenden, da die Sichtbarkeit (im Objectfile) von Funktionen dann abhängt vom Compiler und vom Optimierungslevel.
2) static inline sagt dem Compiler (genauso wie static alleine) das diese Funktion nicht sichtbar sein soll ausserhalb des generierten Objectfiles. Damit wird diese Funktion entweder geinlined, oder als eigene Funktion generiert, die aber nicht sichtbar ist nach aussen. Nachteil ist das wenn der Compiler in mehreren Objectfiles sich entscheidet die Funktion nicht zu inlinen, die Funktion mehrfach erzeugt wird (pro objectfile bis zu einmal) und dann auch mehrfach im executable ist.
3) extern static sagt dem Compiler dass er die Funktion entweder inlinen soll, oder sie als extern betrachten soll. Wenn man es so organisiert dass in allen C-Dateien als extern inline verwendet wird und in einer einzige als normale Funktion, wird genau in einem Objectfile die Funktion sichtbar sein (immer), und in allen anderen entweder geinlined oder als externe reference.
Beispiel zu 3:
inlineit.h:#ifdef INLINEIT_C
#define INLINEIT_INLINE
#else
#define INLINEIT_INLINE extern inline
#endif
INLINEIT_INLINE foobar() {
...
}
inlineit.c:#define INLINEIT_C
#include "inlineit.h"
anotherfile.c:#include "inlineit.h"
/*use foobar here*/
-
Gibt es eine Möglichkeit nicht immer den Pfad "C:\Programm Ordner\MinGW\OSprogramming\lib\gcc\i586-elf\4.4.0\libgcc.a" angeben zu müssen? Der ist nämlich höllisch lang und wenn ich das auf einen anderen Computer kompilieren will, muss er auch angepasst werden.
Ein Skript, das gcc -m32 -print-libgcc-file-name ausführt, zum Beispiel?
-
Ich wüsste nicht, wie ich das in einem Script machen soll.
Wahrscheinlich bist du Linuxumgebungen gewöhnt, da geht sowas wahrscheinlich. :roll:
Zu Case23:
Dieses Problem hat sich eigentlich bereits geklärt. :wink:
Was ich noch nicht so ganz verstanden hab ist, warum "extern static" immer geinlined wird.
-
Wenn du unter Windows bist ... was ich einfach mal dem Pfad aufbau entnehme ... dann kannst du einfach Batch nehmen, das ist auch eine scriptsprache ... ;)
-
Natürlich, kann ich Batchdateien erstellen.
Doch darin kann man meines Wissens nicht die Ausgabe eine Programmes in eine MSDOS-Variable umleiten.
-
Hast du nicht eh MSYS installiert? Das hat doch eine bash?
-
Makefile? Makefail! So setzt man unter Windows die Variable LIBGCC_FILE_NAME mit dem Dateinamen:
FOR /F "usebackq" %%I IN (`gcc -print-libgcc-file-name`) DO SET LIBGCC_FILE_NAME=%%I
Ich unterwandere hier mal wieder alle Versuche die Leute zu guten Praktiken zu bewegen. :evil:
-
MSYS? Nein
FOR /F "usebackq" %%I IN (`gcc -print-libgcc-file-name`) DO SET LIBGCC_FILE_NAME=%%I
Funktioniert fast.
Bloß wenn ein Leerzeichen im Pfad ist(wie bei mir :cry:) dann bricht es ab.
Es liefert bei mir ledeglich "C:\Programm" zurück.
Wusste gar nicht, dass man sowas in MSDOS machen kann. :wink:
-
Zu meinen Zeiten, als die Gummistiefel noch aus Holz waren, hatte for noch keine so komischen Parameter.
-
Nach ein bisschen rumprobieren, hab ich es jetzt hingekriegt. :-D
FOR /F "usebackq tokens=*" %%I IN (`i586-elf-gcc -print-libgcc-file-name`) DO SET LIBGCC_FILE_NAME=%%I
Hätte nie gedacht, dass das mit der MSDOS-Stapelverarbeitung geht.
Nochmal vielen Dank für den genialen Tipp. :-D
-
Viel Spaß damit. ;) Übrigens ist das nicht für DOS sondern Windows NT.
-
Die Stapelverarbeitung läuft aber in einem MSDOS-Subsystem. :wink:
-
@OS_3000
static inline muss nicht inlinen, aber durch das static wird es auf jedenfall nicht sichtbar nach aussen
-
Upps...
Das ist dann wohl weniger für Standardlibs und Betriebssystemcalls geeignet. :oops:
Also dann verwende ich "extern static".
EDIT: Ne auch nicht:
Bei "extern static" motzt der Compiler.
EDIT2: "extern inline" geht auch nicht.
Da motzt der Linker.
-
Die Stapelverarbeitung läuft aber in einem MSDOS-Subsystem. :wink:
Nein, da Kommandozeile != DOS.
Du meinst COMMAND.COM, aber der kennt so fancy parameters nicht. Dafür brauchst du cmd.exe, eine echte WinNT-Anwendung.
PS: Beschaff dir eine UNIX-Umgebung. Bevorzugt mit einer unixoiden Basis. Das macht vieles einfacher. ;-)
So, nachdem die Haare hinreichend gespalten sind, geh ich schlafen. :P
-
Du meinst COMMAND.COM
Ne, hab ich noch nie gehört\benutzt.
-
COMMAND.COM ist die Befehlszeile von DOS und damit ein 16Bit Programm.
cmd.exe ist ein 32Bit Programm für Windows NT und bildet einige Befehle von COMMAND.COM nach. Das heißt aber nicht das cmd.exe ein DOS ist - ist es nämlich nicht.
Die Stapelverarbeitung läuft mit der cmd.exe, also auch nicht in einem MSDOS-Subsystem.
Das einzige im MSDOS Subsystem sind 16Bit Programme (alte Spiele etc.).
In den 64Bit Versionen von Windoof gibt es AFAIK gar kein DOS-Subsystem mehr und ab Vista ist das auch in der 32Bit Version eingeschränkt (z.B. geht der Vollbildmodus nicht mehr).
Bei XP gibt es COMMAND.COM AFAIK übrigens noch - frag mich aber jetzt bitte nicht wo :D
Edit: gib in cmd.exe mal COMMAND.COM ein ;)
Grüße,
LittleFox
-
Der Vollständigkeit halber: Der DOS-Kram von NT hieß "ntvdm" (NT Virtual DOS Machine). Und er war furchtbar. Leider wird häufig cmd.exe immer noch fälschlicherweise als "DOS-Box" oder ähnlichem bezeichnet. Außer dem halbwegs ähnlichen Äußeren und der konzeptbedingt ähnlichen Bedienung haben cmd.exe und echtes DOS jedoch herzlich wenig gemeinsam.
-
Eine DosBox gibts wirklich (nur ist das nicht die Windows Konsole :wink:)
http://www.dosbox.com/ (http://www.dosbox.com/)
http://de.wikipedia.org/wiki/DOSBox (http://de.wikipedia.org/wiki/DOSBox)
-
Exakt, DOSBox sorgt nämlich für eine echte DOS-Umgebung, was cmd nicht tut und ntvdm eher schlecht getan hat. Und als DOS-Box (meistens mit Bindestrich dazwischen) bezeichnen viele Menschen cmd.exe, was ja falsch ist ;)
Ich merke, das wird gerade ein bisschen OT hier ;)
-
Was war denn an NTVDM so falsch? Unter XP konnte ich zumindestens noch Siedler II spielen :D
-
Die NTVDM von XP war schon wesentlich besser als die von Windows 2000, die konnte immerhin schon SB16 emulieren. Ansonsten sind Vollbild(grafik)modi im NTVDM eine Sache des Grafik-BIOS bzw. des Grafiktreibers und damit mehr ein Glücksspiel.
An die Kompatiblität von Windows 95 kommt das alles nicht ran, aber das ist der Unterschied zwischen einer Emulation und dem Original.
Auf:
Ne, hab ich noch nie gehört\benutzt.
habe ich nicht geantwortet, weil ich das für Ironie gehalten hatte.
Schöne Grüße,
Svenska
-
@OS_3000
wenn du extern inline verwenden willst brauchst du ein schema ähnlich meinem beispiel oben damit der linker sich nicht beschwert.