Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Programm Noob am 19. November 2009, 00:11
-
Moin
Ich hab mit hilfe des Wiki´s mir eine schöne CPUID Funktion gebastelt, doch irgenwie haut das vorn und hinten nicht hin.
Hir mein Code.
#include ".\include\video.h"
/**
* cpuid_check prüft, ob cpuid auf diesem PC funktioniert,
* wenn nicht dann als rückgabewert eine 0,
* wenn ja dann als rückgabewert eine 1
* und wenn es nicht überprüft erden kann ob nun ja oder nein eine 3.
*/
char cpuid_check()
{
char EAX;
char ECX;
asm volatile("pushfd"
"pushfd"
"pop ecx"
"mov eax, ecx"
"xor eax, 0x200000"
"push eax"
"popfd"
"pushfd"
"pop eax"
"mov %0, eax"
"mov %1, ecx"::"%0"(EAX), "%1" (ECX));
if (EAX == ECX)
{
return 0;
}
else if (EAX != ECX)
{
return 1;
}
else
{
return 3;
}
}
/**
* cpuid ruft die cpuid funktion des Prozessors auf und vergleicht
* die Vendor-ID mit gespeichteten werten und gibt den Prozessorhersteller Namen aus.
*/
int cpuid()
{
char EAX;
char EBX;
char ECX;
char EDX;
int cpuid_check_ret;
cpuid_check_ret = cpuid_check();
if (cpuid_check_ret == 0)
{
//gebe Meldung aus, dass CPUID nicht unterstützt wird!
}
else if (cpuid_check_ret == 1) // führe CPUID aus.
{
asm volatile("mov eax, 0x00000000"
"cpuid"
"mov %0, eax"
"mov %1, ebx"
"mov %2, ecx"
"mov %3, edx"::"%0"(EAX), "%1" (EBX), "%2" (ECX), "%3" (EDX));
if (EBX == "Auth" && EDX == "enti" %% ECX == "cAMD") // ist er von AMD?
{
printf("Der Prozessor ist von AMD.", 2, 0xA); // Gebe "Der prozessor ist von AMD" aus
}
else if (EBX == "Cent" && EDX == "aurH" %% ECX == "auls") // ist er von Centaur?
{
printf("Der Prozessor ist von Centaur.", 2, 0xA); // Gebe "Der prozessor ist von Centaur" aus
}
else if (EBX == "Cyri" && EDX == "xIns" %% ECX == "tead") // ist er von Cyrix?
{
printf("Der Prozessor ist von Cyrix.", 2, 0xA); // Gebe "Der prozessor ist von Cyrix" aus
}
else if (EBX == "Genu" && EDX == "eneI" %% ECX == "ntel") // ist er von Intel?
{
printf("Der Prozessor ist von Intel.", 2, 0xA); // Gebe "Der prozessor ist von Intel" aus
}
else if (EBX == "NexG" && EDX == "enDr" %% ECX == "iven") // ist er von NexGen ?
{
printf("Der Prozessor ist von NexGen.", 2, 0xA); // Gebe "Der prozessor ist von NexGen" aus
}
else if (EBX == "Geod" && EDX == "e by" %% ECX == " NSC") // ist er von National Semiconductor ?
{
printf("Der Prozessor ist von National Semiconductor.", 2, 0xA); // Gebe "Der prozessor ist von National Semiconductor " aus
}
else if (EBX == "Rise" && EDX == "Rise" %% ECX == "Rise") // ist er von Rise?
{
printf("Der Prozessor ist von Rise.", 2, 0xA); // Gebe "Der prozessor ist von Rise" aus
}
else if (EBX == "SiS " && EDX == "SiS " %% ECX == "SiS ") // ist er von SiS?
{
printf("Der Prozessor ist von SiS.", 2, 0xA); // Gebe "Der prozessor ist von SiS" aus
}
else if (EBX == "Genu" && EDX == "ineT" %% ECX == "Mx86") // ist er von Transmeta?
{
printf("Der Prozessor ist von Transmeta.", 2, 0xA); // Gebe "Der prozessor ist von Transmeta" aus
}
else if (EBX == "UMC " && EDX == "UMC " %% ECX == "UMC ") // ist er von UMC?
{
printf("Der Prozessor ist von UMC.", 2, 0xA); // Gebe "Der prozessor ist von UMC" aus
}
else if (EBX == "VIA " && EDX == "VIA " %% ECX == "VIA ") // ist er von VIA?
{
printf("Der Prozessor ist von VIA.", 2, 0xA); // Gebe "Der prozessor ist von VIA" aus
}
}
else
{
printf("Es ist ein Fehler aufgetreten..", 2, 0xA); // ein Fehler ist aufgetreten.
}
}
Ich hoffe ihr könnt mir helfen.
Programm Noob
-
Könnte es sein, dass du die Ein- und Ausgabeparameter von asm() vertauscht hast? Anscheinend compilst du ja mit Intelsyntax, weiß nicht, ob das da anders ist ^^
-
Ich gehe einfach mal davon aus, dass das C ist, evtl. C++. :roll:
Was sollen die ganzen '%%' in den IF-Abfragen? Sollten das denn nicht auch '&&' sein? Des Weiteren würde ich mal sagen, dass man in C Strings nicht per "==" vergleichen kann.
Was du machen könntest, wäre alles zu einem String zusammen zu kopieren, damit quase "AuthenticAMD" an einem Stück ist.
Bei den Variablen bin ich mir nicht ganz sicher, aber diese müssten (denke ich mir mal so) alles Arrays mit 4 Feldern sein, da EAX, EBX sowie ECX immer 4 Buchstaben enthalten. (*EDIT* Bsp.: char EAX[4]; *EDIT*)
Gruß Christian
PS: Es würde helfen, wenn du Grob sagen kannst, was funktioniert und was nicht. z.B. cpuid_check funktioniert oder so...
-
Ui, stimmt. %% geht nicht, ebenso wie == bei Strings. Zudem willst du EAX, EBX, ECX und EDX wohl eher zu char* oder int machen. Und für cpuid_check_ret brauchst du auch keinen int, wenn eh nur ein char zurückgegeben wird ;-)
-
Als kleine Verbesserung noch könnte man folgendes im cpuid_check ändern...
Lass das "else if" weg, EAX und ECX können ja entweder nur gleich oder ungleich sein (kleiner gleich würde z.B. keinen Sinn machen). Alternativ kannst du auch das gesetzte eflags-bit extrahieren und einmal vorher und einmal nachher vergleichen. :)
Somit würde auch das else in der anderen Funktion wegfallen.
-
Ich hoffe ihr könnt mir helfen.
Das hoffe ich auch. Allerdings müsstest du dazu erstmal dein Problem beschreiben. "Tut nicht" ist keine angemessene Problembeschreibung. Anhaltspunkte, die du immer beantworten solltest: Was versuchst du zu tun? Was erwartest du, dass rauskommt? Was passiert wirklich? Ist der Code den du zeigst, wirklich der minimal nötige, um das Problem zu provozieren?
Was mir im Moment auffällt ist, dass da ein pushfd zu viel ist, oder? Aber mit dem %% dürfte das gar nicht erst kompiliert haben...
-
Das pushfd ist warscheinlich nicht zuviel, aber es fehlt ein popfd ganz am Ende.
-
Meinetwegen auch sorum (aber ist es wirklich nötig?). Auf jeden Fall mehr push als pop und das ist nicht gut.
-
Assemblersyntax ist falschrum (GCC verwendet den GAS, der AT&T-Syntax nutzt), die Register nicht mittels %0 bis %3 sondern über die richtigen Constraints übergeben.
CPUID für Funktion 0x00000000 sollte so aussehen:
unsigned int eax, ebx, ecx, edx;
__asm__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x00000000));
Den Code in cpuid_check solltest du analog ändern.
-
Die Assemblersyntax muss nicht falschrum sein. Wenn er -masm=intel in der Kommandozeile verwendet, ist die hier vollkommen korrekt (wenn man von persönlichen Vorlieben absieht :-) ), da der GAS nicht nur AT&T, sondern auch Intel unterstützt.
Wenn Programm Noob diese Option allerdings nicht verwendet, ist das natürlich falschrum.
-
Ich glaube mittlerweile haben wir genug Probleme entdeckt, warum der Code überhaupt nicht kompilieren kann, dass Programmer Noob vielleicht erstmal sein Problem näher spezifizieren sollte. ;)
-
Moin
Oh, da habe ich doch glatt vergessen zu sagen das der code in c geschrieben ist, und das ich ihn wie folg aufrufe:
i586-elf-gcc -m32 -ffreestanding -o .\obj\cpuid.o -c .\src\cpuid.c -Wall -Werror -nostdinc -masm=intel
und das es nicht compilieren lässt.
Diese hier "%%" sollten natürlich auch"&&" sein. habe mich wohl vertippt. Danke.
Habe jetzt alles so wie ihr gesagt habt abgeändert:
#include ".\include\video.h"
/**
* cpuid_check prüft, ob cpuid auf diesem PC funktioniert,
* wenn nicht dann als rückgabewert eine 0,
* wenn ja dann als rückgabewert eine 1
* und wenn es nicht überprüft erden kann ob nun ja oder nein eine 3.
*/
int cpuid_check()
{
int EAX;
char ECX;
__asm__("pushfd"
"pushfd"
"pop ecx"
"mov eax, ecx"
"xor eax, 0x200000"
"push eax"
"popfd"
"pushfd"
"pop eax" : "=a"(EAX), "=c"(ECX));
if (EAX == ECX)
{
return 0;
}
else
{
return 1;
}
}
/**
* cpuid ruft die cpuid funktion des Prozessors auf und vergleicht
* die Vendor-ID mit gespeichteten werten und gibt den Prozessorhersteller Namen aus.
*/
int cpuid()
{
unsigned int EAX, EBX, ECX, EDX;
int cpuid_check_ret;
cpuid_check_ret = cpuid_check();
if (cpuid_check_ret == 0)
{
//gebe Meldung aus, dass CPUID nicht unterstützt wird!
}
else if (cpuid_check_ret == 1) // führe CPUID aus.
{
__asm__("cpuid" : "=a"(EAX), "=b"(EBX), "=c"(ECX), "=d"(EDX) : "a"(0x00000000));
if (EBX == "Auth" && EDX == "enti" && ECX == "cAMD") // ist er von AMD?
{
printf("Der Prozessor ist von AMD.", 2, 0xA); // Gebe "Der prozessor ist von AMD" aus
}
else if (EBX == "Cent" && EDX == "aurH" && ECX == "auls") // ist er von Centaur?
{
printf("Der Prozessor ist von Centaur.", 2, 0xA); // Gebe "Der prozessor ist von Centaur" aus
}
else if (EBX == "Cyri" && EDX == "xIns" && ECX == "tead") // ist er von Cyrix?
{
printf("Der Prozessor ist von Cyrix.", 2, 0xA); // Gebe "Der prozessor ist von Cyrix" aus
}
else if (EBX == "Genu" && EDX == "eneI" && ECX == "ntel") // ist er von Intel?
{
printf("Der Prozessor ist von Intel.", 2, 0xA); // Gebe "Der prozessor ist von Intel" aus
}
else if (EBX == "NexG" && EDX == "enDr" && ECX == "iven") // ist er von NexGen ?
{
printf("Der Prozessor ist von NexGen.", 2, 0xA); // Gebe "Der prozessor ist von NexGen" aus
}
else if (EBX == "Geod" && EDX == "e by" && ECX == " NSC") // ist er von National Semiconductor ?
{
printf("Der Prozessor ist von National Semiconductor.", 2, 0xA); // Gebe "Der prozessor ist von National Semiconductor " aus
}
else if (EBX == "Rise" && EDX == "Rise" && ECX == "Rise") // ist er von Rise?
{
printf("Der Prozessor ist von Rise.", 2, 0xA); // Gebe "Der prozessor ist von Rise" aus
}
else if (EBX == "SiS " && EDX == "SiS " && ECX == "SiS ") // ist er von SiS?
{
printf("Der Prozessor ist von SiS.", 2, 0xA); // Gebe "Der prozessor ist von SiS" aus
}
else if (EBX == "Genu" && EDX == "ineT" && ECX == "Mx86") // ist er von Transmeta?
{
printf("Der Prozessor ist von Transmeta.", 2, 0xA); // Gebe "Der prozessor ist von Transmeta" aus
}
else if (EBX == "UMC " && EDX == "UMC " && ECX == "UMC ") // ist er von UMC?
{
printf("Der Prozessor ist von UMC.", 2, 0xA); // Gebe "Der prozessor ist von UMC" aus
}
else if (EBX == "VIA " && EDX == "VIA " && ECX == "VIA ") // ist er von VIA?
{
printf("Der Prozessor ist von VIA.", 2, 0xA); // Gebe "Der prozessor ist von VIA" aus
}
}
else
{
printf("Es ist ein Fehler aufgetreten..", 2, 0xA); // ein Fehler ist aufgetreten.
}
}
Trotzdem kann ich es nicht compilieren.
cpuid.c:93: error: comparison between pointer and integer
cpuid.c:93: error: comparison with string literal results in unspecified behavior
Wisst ihr vileicht woran das liegt??
Programm Noob
-
So dan großer Hilfe von JanDing ausm IRC habe ich jetzt fast alle fehler beseitigen können. Doch ein neuer ist aufgetaucht den ich nicht weg bekomme:
cpuid.c:19: error expected ´(´ before ´:´ token
Mein Jetztiger Code ist der:
#include ".\include\video.h"
/**
* cpuid_check prüft, ob cpuid auf diesem PC funktioniert,
* wenn nicht dann als rückgabewert eine 0,
* wenn ja dann als rückgabewert eine 1
* und wenn es nicht überprüft erden kann ob nun ja oder nein eine 3.
*/
int cpuid_check()
{
int EAX;
char ECX;
__asm__("pushfd" : "pushfd" : "pop ecx" : "mov eax, ecx" : "xor eax, 0x200000" : "push eax" : "popfd" : "pushfd" : "pop eax" : "=a"(EAX), "=c"(ECX));
if (EAX == ECX)
{
return 0;
}
else
{
return 1;
}
}
/**
* cpuid ruft die cpuid funktion des Prozessors auf und vergleicht
* die Vendor-ID mit gespeichteten werten und gibt den Prozessorhersteller Namen aus.
*/
void cpuid()
{
unsigned int EAX, EBX, ECX, EDX;
int cpuid_check_ret;
cpuid_check_ret = cpuid_check();
if (cpuid_check_ret == 0)
{
//gebe Meldung aus, dass CPUID nicht unterstützt wird!
}
else if (cpuid_check_ret == 1) // führe CPUID aus.
{
__asm__("cpuid" : "=a"(EAX), "=b"(EBX), "=c"(ECX), "=d"(EDX) : "a"(0x00000000));
if (EBX == 0x68747541 && EDX == 0x69746D65 && ECX == 0x444D4163) // ist er von AMD?
{
printf("Der Prozessor ist von AMD.", 2, 0xA); // Gebe "Der prozessor ist von AMD" aus
}
/*else if (EBX == "Cent" && EDX == "aurH" && ECX == "auls") // ist er von Centaur?
{
printf("Der Prozessor ist von Centaur.", 2, 0xA); // Gebe "Der prozessor ist von Centaur" aus
}
else if (EBX == "Cyri" && EDX == "xIns" && ECX == "tead") // ist er von Cyrix?
{
printf("Der Prozessor ist von Cyrix.", 2, 0xA); // Gebe "Der prozessor ist von Cyrix" aus
}*/
else if (EBX == 0x756E6547 && EDX == 0x49656E65 && ECX == 0x6C65746E) // ist er von Intel?
{
printf("Der Prozessor ist von Intel.", 2, 0xA); // Gebe "Der prozessor ist von Intel" aus
}
/*else if (EBX == "NexG" && EDX == "enDr" && ECX == "iven") // ist er von NexGen ?
{
printf("Der Prozessor ist von NexGen.", 2, 0xA); // Gebe "Der prozessor ist von NexGen" aus
}
else if (EBX == "Geod" && EDX == "e by" && ECX == " NSC") // ist er von National Semiconductor ?
{
printf("Der Prozessor ist von National Semiconductor.", 2, 0xA); // Gebe "Der prozessor ist von National Semiconductor " aus
}
else if (EBX == "Rise" && EDX == "Rise" && ECX == "Rise") // ist er von Rise?
{
printf("Der Prozessor ist von Rise.", 2, 0xA); // Gebe "Der prozessor ist von Rise" aus
}
else if (EBX == "SiS " && EDX == "SiS " && ECX == "SiS ") // ist er von SiS?
{
printf("Der Prozessor ist von SiS.", 2, 0xA); // Gebe "Der prozessor ist von SiS" aus
}
else if (EBX == "Genu" && EDX == "ineT" && ECX == "Mx86") // ist er von Transmeta?
{
printf("Der Prozessor ist von Transmeta.", 2, 0xA); // Gebe "Der prozessor ist von Transmeta" aus
}
else if (EBX == "UMC " && EDX == "UMC " && ECX == "UMC ") // ist er von UMC?
{
printf("Der Prozessor ist von UMC.", 2, 0xA); // Gebe "Der prozessor ist von UMC" aus
}
else if (EBX == "VIA " && EDX == "VIA " && ECX == "VIA ") // ist er von VIA?
{
printf("Der Prozessor ist von VIA.", 2, 0xA); // Gebe "Der prozessor ist von VIA" aus
}*/
}
else
{
printf("Es ist ein Fehler aufgetreten..", 2, 0xA); // ein Fehler ist aufgetreten.
}
}
Wisst ihr was gcc von mir möchte :?
Programm Noob
-
Wenn mich nicht alles täuscht, dürfte dein Fehler beim Inline Assembler sein, quasi hier:
__asm__("pushfd" : "pushfd" : "pop ecx" : "mov eax, ecx" : "xor eax, 0x200000" : "push eax" : "popfd" : "pushfd" : "pop eax" : "=a"(EAX), "=c"(ECX));
Wenn du mehrere Assembleranweisungen aneinander hängen möchtest, dann geht das so nicht. Was möglcih wäre, wäre ein Konstrukt der folgenden Art:
__asm__("pushfd; pushfd; pop ecx ..." : "=a"(EAX), "=c"(ECX));
// Alternativ auch so:
__asm__("pushfd\npushfd\npop ecx ..." : "=a"(EAX), "=c"(ECX));
Die Instruktionen müssen also entweder per Semikolon oder per Newline von einander getrennt werden...
-
Moin
Ich habe zwar den Code gerade nicht da, aber das mit dem inline-Assembler klingt mir Logisch.
Ich melde mich nacher
Programm Noob
-
Habe es geradde ausprobiert der Fehler ist der gleiche.
Programm Noob
-
es könnte nützlich sein wenn du die fehlerhafte Zeile mal markierst. Zeile 19 in deinem geposteten Code enthält nämlich überhaupt gar keinen ':'.
-
Die fehlerhafte Zeile 19 ist bei mir folgende:
__asm__("pushfd" : "pushfd" : "pop ecx" : "mov eax, ecx" : "xor eax, 0x200000" : "push eax" : "popfd" : "pushfd" : "pop eax" : "=a"(EAX), "=c"(ECX));
Es fehlt ganz am anfang ein Komentar für doxygen, der aber unwichtig ist.
Programm Noob
-
Und diese Zeile müsste eben
__asm__ __volatile__ ("pushfd; pushfd; pop ecx; mov eax, ecx; xor eax,0x200000; push eax; popfd; pushfd; pop eax; popfd" : "=a"(EAX), "=c"(ECX));
lauten. Wobei man das __volatile__ wohl auch weglassen kann, aber ich mache es aus Gewohnheit eben immer hin.
-
Wenn ich die Zeile ersetze , dann erhalte ich folgende Fehler:
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s: Assembler messages:
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: no such instruction:
`pushfd'
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: no such instruction:
`pushfd'
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: too many memory refer
ences for `mov'
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: too many memory refer
ences for `xor'
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: no such instruction:
`popfd'
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: no such instruction:
`pushfd'
C:\Users\PROGRA~1\AppData\Local\Temp\ccGKNcnp.s:12: Error: no such instruction:
`popfd'
Kann man vielleicht gcc sagen, dass er mit nasm arbeiten soll?
weil anscheinend kennt gas die Befehle nicht.
Programm Noob
-
da hast du beim compilieren wohl
'-masm intel' '-masm=intel' vergessen.
Edit: Im AT/T-Syntax sieht das ungefähr so aus
__asm__("pushf;"
"pushf;"
"pop %1;"
"mov %1, %0;"
"xor $0x200000, %0;"
"push %0;"
"popf;"
"pushf;"
"pop %0;"
"popf" : "=a"(EAX), "=c"(ECX));
-
heißt das nicht :
-masm=intel :?
Programm Noob
-
doch :oops:
-masm=intel
ist korrekt, aber das hat bei dir wohl gefehlt. Zumindest gibt's bei mir die Fehlermeldung nur wenn ich es weglasse.
-
Es könnte sein, dass gas pushfd und popfd nicht kennt, probiers einfach mal mit pushf und popf.
-
@MNemo mit welchem Compiler arbeitest du?
weil bei cross gcc mit -masm=intel gibts den Fehler nämlich trotzdem
programm Noob
-
ich nutzte:
gcc (Debian 4.3.4-5) 4.3.4
GNU assembler (GNU Binutils for Debian) 2.20
alles 64bit, daher compiliere ich mit '-m32'
-
Compilieren kann ich es jetzt, doch wenn ich das ganze in bochs testen will startet sobald die Funkion ausgeführt wird der "PC" in Bochs neu.
Programm Noob
-
Hänge bei deinen CFLAGS den Switch -masm=intel an. Damit kompilliert er nicht mehr in AT&T-Syntax sondern in Intel-Syntax ;)
-
Compilieren kann ich es jetzt, doch wenn ich das ganze in bochs testen will startet sobald die Funkion ausgeführt wird der "PC" in Bochs neu.
XanClic und ich haben bei den Codebeispielen jeweils das fehlende 'popf' am Ende ergänzt(ohne es nochmal zu erwähnen). hast du das in deinem Code auch? Alternativ kannst du auch das erste pushf weglassen.
-
Hänge bei deinen CFLAGS den Switch -masm=intel an. Damit kompilliert er nicht mehr in AT&T-Syntax sondern in Intel-Syntax ;)
weil bei cross gcc mit -masm=intel gibts den Fehler nämlich trotzdem
Ich glaube, da muss man nix an eine Umgebungsvariable anhängen, denn afaik nutzt gcc diese an sich nicht. Sie wird nur standardmäßig in Makefiles genutzt, dann eben in der Form $(CC) $(CFLAGS). Aber an sich sollte die das nicht beeinflussen.
Und offenbar hat er ja -masm=intel als Parameter benutzt.
Wobei ich hoffe, dass ich jetzt keinen Mist erzählt hab und gcc CFLAGS doch direkt nutzt. :-D
-
Moin
@MNemo ja das zweite popf habe ich auch angefügt.
@XanClic ich arbeite nicht mit makefiles oder zumindest noch nicht sondern nutze .bat Dateien
Der Fehler ist noch nicht behoben, ich wede mal gucken was der Bochs debugger ausspuckt.
Danke für eure Hilfe bis jetzt, sollte trotzden noch irgendjemanden etwas einfallen, dann bitte posten.
Programm Noob
-
@XanClic ich arbeite nicht mit makefiles oder zumindest noch nicht sondern nutze .bat Dateien
Das dachte ich mir und deshalb hat dich CFLAGS afaik nicht zu interessieren. :wink: