Wie überprüfen ob eflags vorhanden?



  • Zu erst einmal wünsche ich allen Foren-Usern ein frohes neues Jahr!

    Ich habe auch nur eine kleine Frage: Und zwar brauche ich Code, mit dem ich prüfen kann, ob mir Instruktionen von MMX, SSE, SSE2 usw. zur Verfügung stehen. Dies ist alles kein Problem, jedoch muss ich zunächst einmal prüfen ob mir der Pefehl "cpuid" überhaupt zur Verfügung steht.
    Dies wiederum mache ich, in dem ich bit 21 (ID-Bit) der eflags überprüfe.

    Wie kann ich aber sicherstellen, dass die erweiterten Flags überhaupt existieren?



  • Auf die EFLAGS kannst du zugreifen, wenn du einen 386er oder neuer hast. Wenn du im 32-Bit-Modus (z.B. unter Windows, Linux, ...) bist, dann hast du definitiv einen 386er oder neuer. Wenn dir nicht sicher bist, ob du einen 386er oder neuer hast, dann solltest du dir http://www.intel.com/Assets/PDF/appnote/241618.pdf durchlesen. Kapitel 9 enthält einen sehr sehr sehr genauen Beispielcode inklusive Erklärungen...



  • Ja, dass sieht sehr gut aus, danke.

    Ich habe aber noch ein kleines Problem bei meinem restlichen Code, ich erhalte immer den Fehlern "unknown 0001", wenn ich meinen Code aus C heraus mit dem Visual Studio 2008 linke.
    MASM compiliert ohne Probleme (Parameter -c -coff)

    Hier der Code:

    TITLE sse checking - check for MMX, SSE, SSE2, SSE3, SSSE3 and SSE4.1 support
    
    		.MODEL SMALL
    		.8086
    
    .DATA
    ; --------- ;
    ; constants ;
    ; --------- ;
    ID_BIT 		 EQU 00200000h
    FEATURE_BYTE EQU 1
    MMX_BIT		 EQU 00800000h
    SSE_BIT		 EQU 02000000h
    SSE2_BIT	 EQU 04000000h
    SSE3_BIT	 EQU 00000001h
    SSSE3_BIT	 EQU 00000200h
    SSE41_BIT	 EQU 00080000h
    
    MMX   EQU 0								; MMX Technology Support
    SSE   EQU 1								; 
    SSE2  EQU 2								;
    SSE3  EQU 3								;
    SSSE3 EQU 4								;
    SSE41 EQU 5								;
    
    ; ---------------- ;
    ; global variables ;
    ; ---------------- ;
    _InstructionSetAvailable db 6 dup(0)	; set to "false" (0) by default
    _CPUID_Available	 	 db 0			;			  ""
    _EFLAGS_Available		 db 0			;			  ""
    
    ; --------------- ;
    ; global routines ;
    ; --------------- ;
    PUBLIC _Initialize
    
    .CODE
    _Initialize PROC	
    ;	mov  ax, @data
    ;	mov  ds, ax
    .386						
    	pushfd					; push eflags to stack
    	pop  eax				; load eflags to eax
    	mov  edx, eax			; save value in edx
    	xor  eax, ID_BIT		; not ID bit
    	push eax				; back to stack
    	popfd					; from stack to eflags with not ID bit
    	pushfd					; push eflags to stack (again)
    	pop  eax				; load it to eax
    	xor  eax, edx			; check for equality
    	jz	 SHORT done			; equals? if true cpuid is not available (pre Pentium+)
    	inc  BYTE PTR [ds:_CPUID_Available]
    
    .586						; enable Penium-Instructionset (f. CPUID)
    	mov  eax, FEATURE_BYTE	; check byte 1 (processor info and feature bits)
    	cpuid
    	test edx, MMX_BIT		; check for MMX Technology support
    	setnz BYTE PTR [ds:_InstructionSetAvailable + MMX]
    
    	test edx, SSE_BIT		; check for Streaming SIMD Extensions (SSE) support 
    	setnz BYTE PTR [ds:_InstructionSetAvailable + SSE]
    
    	test edx, SSE2_BIT		; check for SSE2 support 
    	setnz BYTE PTR [ds:_InstructionSetAvailable + SSE2]
    
    	test ecx, SSE3_BIT		; check for SSE3 support
    	setnz BYTE PTR [ds:_InstructionSetAvailable + SSE3]
    
    	test ecx, SSSE3_BIT		; check for Supplemental Streaming SIMD Extensions 3 support
    	setnz BYTE PTR [ds:_InstructionSetAvailable + SSSE3]
    
    	test ecx, SSE41_BIT		; check for SSE4.1 support
    	setnz BYTE PTR [ds:_InstructionSetAvailable + SSE41]
    
    done:
    	ret
    _Initialize ENDP
    
    END
    
    #include <stdio.h>
    
    #define BOOL unsigned char
    #define MMX   0
    #define SSE   1
    #define SSE2  2
    #define SSE3  3
    #define SSSE3 4
    #define SSE41 5
    
    extern BOOL InstructionSetAvailable[6];
    extern void Initialize();
    
    int main() 
    {
    	if( InstructionSetAvailable[SSE3] ) {
    		...
    	}
    
    	return 0;
    }
    


  • 😮
    Die Funktion ist nicht idiotensicher - ich blicke da nicht mehr durch 😉
    Vielleicht ein Vorschlag: Man könnte die Funktion auf das Ausführen von CPUID und Speichern der EAX...EDX Register vereinfachen, und die ganze Logik, ob MMX, SSE usw., in C implementieren. Ungefähr so

    // Irgendwie in Assember implementiert:
    extern int ExecuteCPUID(unsigned int FunctionID, unsigned int *pRegs)
    ...
    unsigned int Regs[4];
    int err = 0;
    bool flag_MMX = false;
    
    err = ExecuteCPUID(FEATURE_BYTE, &Regs[0]);
    
    if (err < 0)
    {
        // CPUID not supported
        ...
    }
    else
    {
        // Regs[0...3] contains EAX, EBX, ECX, EDX
        flag_MMX = (MMX_BIT == (Regs[EDX] & MMX_BIT));
        ...
    }
    


  • abc.w schrieb:

    😮
    Die Funktion ist nicht idiotensicher - ich blicke da nicht mehr durch 😉

    😮 meinerseits 😃
    Wo ist das Problem?

    Ich habe ein array aus 6 Byte, welche bool's entsprechen sollen. So kann ich (wie im C-Code gezeigt) einfach per "InstructionSetAvailable" und dem Offset prüfen, ob ein spezieller Befehlssatz verfügbar ist.

    Die Constanten (sowhol in C als auch asm) hab ich zur Vereinfachung gemacht.

    Was genau verstehst du da nicht? Rein aus Interesse.


  • Mod

    FrEEzE2046 schrieb:

    .MODEL SMALL
    		.8086
    

    Das sollte vermutlich eher so aussehen

    .386
    .model flat
    

    schließlich soll keine 16bit-Anwendung erstellt werden.



  • FrEEzE2046 schrieb:

    Was genau verstehst du da nicht? Rein aus Interesse.

    Ich glaube, ich verstehe die Funktion ganz gut. Finde nur, dass das Auswerten und Setzen der Flags zu viel des Guten ist und man sollte es in C/C++ machen. Ansonsten ist die Funktion gut und geradeaus geschrieben (noch). Ich glaube, man muss jetzt nur noch die Register ECX, EBX und EDX "retten" und wiederherstellen, weil CPUID sie ja überschreibt...



  • camper schrieb:

    FrEEzE2046 schrieb:

    .MODEL SMALL
    		.8086
    

    Das sollte vermutlich eher so aussehen

    .386
    .model flat
    

    schließlich soll keine 16bit-Anwendung erstellt werden.

    Ähm,

    ohne Scheiß. Das habe ich komplett übersehen. Kann dir aber auch sagen woran's liegt:

    Ich habe zuvor ein kleines Tool geschrieben, was beim Starten des Computers ausgefehrt werden kann, und da ich mich da im Real-Mode befinde ... 😃

    abc.w schrieb:

    Ich glaube, ich verstehe die Funktion ganz gut. Finde nur, dass das Auswerten und Setzen der Flags zu viel des Guten ist und man sollte es in C/C++ machen. Ansonsten ist die Funktion gut und geradeaus geschrieben (noch). Ich glaube, man muss jetzt nur noch die Register ECX, EBX und EDX "retten" und wiederherstellen, weil CPUID sie ja überschreibt...

    Ja, ich weiß was du meinst. Aber 1. hab ich mit der Funktion nichts weiter vor, als dieses Array zu setzen und 2. wird der Code in dem die Funktion "eigentlich" aufgerufen wird, auch in Assembler und nicht C sein.

    Warum willst du ECX und EDX retten?



  • FrEEzE2046 schrieb:

    Warum willst du ECX und EDX retten?

    ...ich glaube, dass man sie retten muss, weiss aber nicht genau...



  • abc.w schrieb:

    FrEEzE2046 schrieb:

    Warum willst du ECX und EDX retten?

    ...ich glaube, dass man sie retten muss, weiss aber nicht genau...

    Also normalerweiße rettet man nur das EBX-Register. Welchen speziellen Grund meinst du denn?



  • FrEEzE2046 schrieb:

    Also normalerweiße rettet man nur das EBX-Register. Welchen speziellen Grund meinst du denn?

    Mit fällt kein spezieller Grund auf. Wenn's läuft, dann läuft's 😉


Anmelden zum Antworten