R
rkhb schrieb:
Wenn Du den vollständigen Quelltext Deines Programms postest, noch Betriebssystem und Compiler/Assembler mitteilst, dann könnte ich versuchen, Dir die Binärlogik mithilfe eines Programms näher zu bringen.
cpuid schrieb:
Assembler: MASM
OS: Windows XP
Nun denn, hier erstmal das Programm zur (späteren) Erklärung:
.686p
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
.DATA
lfd db "1) ";
hex db "0123456789ABCDEF"
buf db "-",10
.DATA?
hStdOut dd ?
bin db 40 DUP (?)
int32 dd ?
NumberOfBytesWritten dd ?
.CODE
int2bin PROC
int2bin ENDP
Int2Bin PROC ; http://dcla.rkhb.de/umwandlung/int2bin.html
pushad
mov edx,[int32] ; Integer
mov edi, OFFSET bin ; Binärzahl (Puffer muss jetzt 40 Bytes fassen können)
mov ecx,8 ; äußere Schleife: 8 Nibbles
Schleife1:
push ecx
mov ecx,4 ; innere Schleife: 4 Bits
Schleife2:
shl edx,1
setc al ; AL je nach herausgeschobenen Bit setzen
or al,30h ; ASCII
stosb ; und in bin abspeichern
loop Schleife2 ; innere Schleife
mov al,32 ; Leerzeichen
stosb
pop ecx ; äußere Schleife
loop Schleife1
mov byte ptr [edi-1],10 ; \n ersetzt letztes Leerzeichen
popad
ret
Int2Bin ENDP
WriteBin PROC
pushad
invoke WriteFile, DWORD PTR [hStdOut], ADDR lfd, 4, ADDR NumberOfBytesWritten, 0
add BYTE PTR [lfd], 1
invoke WriteFile, DWORD PTR [hStdOut], ADDR bin, 40, ADDR NumberOfBytesWritten, 0
popad
ret
WriteBin ENDP
WriteChar PROC
pushad
invoke WriteFile, DWORD PTR [hStdOut], ADDR lfd, 4, ADDR NumberOfBytesWritten, 0
invoke WriteFile, DWORD PTR [hStdOut], ADDR buf, 2, ADDR NumberOfBytesWritten, 0
popad
ret
WriteChar ENDP
main PROC
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov DWORD PTR [hStdOut], eax
mov eax,1 ; Funktionsnummer für CPUID
mov dword ptr [int32], eax
call Int2Bin
call WriteBin ; 1) binäre Ausgabe der Funktionsnummer
cpuid
mov dword ptr [int32], eax ; Ergebnis von CPUID
call Int2Bin
call WriteBin ; 2) binäre Ausgabe des Ergebnisses von CPUID
mov edx, 11110000b ; AND-Maske
mov dword ptr [int32], edx
call Int2Bin
call WriteBin ; 3) binäre Ausgabe der AND-Maske
and eax, 11110000b ; CPUID-Ergebnis undieren
mov dword ptr [int32], eax
call Int2Bin
call WriteBin ; 4) binäre Ausgabe des Ergebnisses der AND-Operation
shr eax,4 ; nach rechts, um es besser umwandeln zu können
mov dword ptr [int32], eax
call Int2Bin
call WriteBin ; 5) binäre Ausgabe des Ergebnisses der Shift-Operation
mov ebx, OFFSET hex
xlat ; in Hexziffer(ASCII) umwandeln
mov BYTE PTR [buf] ,al
call Int2Bin
call WriteChar ; 6) Ausgabe der Hexzahl
invoke ExitProcess,0 ; und tschüss.
main ENDP
END main
Die Ausgabe des Programms sieht bei mir folgendermaßen aus:
`
0000 0000 0000 0000 0000 0000 0000 0001
0000 0000 0000 0000 0000 0110 1111 1011
0000 0000 0000 0000 0000 0000 1111 0000
0000 0000 0000 0000 0000 0000 1111 0000
0000 0000 0000 0000 0000 0000 0000 1111
F
`
Zunächst ist wichtig, dass Du Dir ein Register (EAX, EBX, ECX, EDX) nur als ein Bündel von 32 Bits vorstellst. Ob diese 32 Bit nun ein Buchstabe, eine Zahl, eine Adresse oder was ganz anderes darstellen soll, bestimmt der Programmierer (manchmal ist seine Wahl ein bisschen eingeschränkt, aber das ist hier nicht wichtig). Als erstes füllst Du EAX mit einer Funktionsnummer für CPUID (mov eax,1). Wie die 32 Bits von EAX danach aussehen, erzählt Dir die Zeile 1) des Programms.
Die 32 Bits von EAX werden von rechts nach links durchnummeriert. Die '1' ganz rechts, trägt also die Bezeichnung Bit0 und die '0' ganz links heißt Bit31 (Bit0 bis Bit31 ergibt 32 Bits).
Nun wird CPUID aufgerufen. Die CPU guckt nach der Funktionsnummer und gibt ein Ergebnis in EAX aus. Wie das aussieht, erzählt Dir Zeile 2) des Programms. Nun musst Du in das Manual Deiner CPU gucken, um zu erfahren, was das bedeuten soll. Wenn Du einen Intel-Prozessor hast, guckst Du in das Intel-Manual, wenn Du einen AMD-Prozessor, guckst Du in das AMD-Manual. Das liegt daran, dass sich die CPUID-Ausgaben der verschiedenen Prozessoren unterscheiden können.
Das zuständige Intel-Manual heißt "Intel 64 and IA-32 Architectures Software Developer's Manual Combined Volumes 2A, 2B, and 2C: Instruction Set Reference, A-Z" (http://www.intel.de/content/www/de/de/processors/architectures-software-developer-manuals.html). Hier stehen alle Informationen in Kapitel 3.2 (Instructions A-L) unter "CPUID - CPU Identification". Auf Table 3.17 steht, dass bei einem Initial Value von EAX=01H in EAX "Type, Family, Model, and Stepping ID (see Figure 3-5)" ausgegeben wird. Figure 3-5 befindet sich recht viek weiter unten und teilt Dir mit, welche Informationen in welchen Bits von EAX landen. Die kleinen Zahlen oben sind die Bitnummerierung.
Dich interessiert die Information "Model", die sich nach Figure 3-5 an Bit4 bis Bit7 befindet. Wenn Du jetzt in Zeile 2) des Programms von rechts abzählst (mit Null beginnend), dann siehst Du, dass es sich um den zweiten Vier-Block von rechts handelt. Alles übrige interessiert Dich nicht. Dieses "übrige" wird jetzt brutal auf Null gesetzt, damit es keine Verwirrung stiften kann. Dazu dient der AND-Befehl. Nur wo in Zeile 3) eine '1' steht, wird der Inhalt von Zeile 2) durchgelassen und erscheint in Zeile 4).
In Zeile 4) hast Du nur noch einen Block mit Information, das ist der zweite von rechts. Alle anderen Blöcke mit jeweils 4 Bits sind auf Null gesetzt. Jetzt kommt das, was Intel beim besten Willen nicht wissen kann, nämlich was Du mit diesem Block anstellen willst. Du willst offenbar, dass der Inhalt des Blocks als Zahl ausgegeben wird. Mit vier Bits kann man eine Zahl von 0 bis 15 darstellen, einfacher zu programmieren ist eine Hex-Zahl von 0 bis F. Mit dem Befehl XLAT wird jeweils ein Buchstabe (ASCII) aus dem String hex="0123456789ABCDEF" geholt, und zwar jeweils die Stelle, die in AL steht (ab Null zählend). Steht also in AL eine 6, dann wird die 7. Ziffer geholt - das ist die '6' - und in AL gespeichert. Aber wie kommt man zu so einem Wert in AL, die Model-Nummer in EAX steht doch ganz woanders?
Die Modelnummer muss nach rechts. Das Ergebnis siehst Du in Zeile 5) des Programms. Nun haben wir in AL eine Bitfolge, die man als Zähler (Index) für XLAT gebrauchen kann.
Nach dem Shift-Befehl steht Model in AL und mit dem XLAT-Befehl wird der Wert in AL in eine ASCII-Hexadezimalziffer umgewandelt. Das Ergebnis wird in Zeile 6) ausgegeben.
viele grüße
ralph
P.S.: Da wir hier nicht in einem Chat sind (und ich deshalb auch für Lurker und Googler schreibe), wirst Du nicht aufschreien "Das habe ich doch schon längst alles seit Jahren gewusst!!!", sondern Dir überlegen, welchen Denkfehler Du auf Intel abschieben willst.