News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

cpuid proc that returns brand string crash

Started by aloha_arts, April 22, 2010, 11:02:27 PM

Previous topic - Next topic

aloha_arts

I've got this function that gets the brand string by means of the cpuid instruction.
The function stores the string into the local pszBuffer and then returns it.

On ret the debugger tells me that the program can't continue because
"the memory address at 6574... is not readable. Try to change EIP or pass exception to program."

Any ideas why this happens?
Thank you.



CpuBrand PROC STDCALL
   
    local pszBuffer[48] : BYTE

    push    ebx
    push    edi
    push    ebp
   
    ; determine if CPUID supported
    .IF cpufeature (CPUID) == 0
        jmp     finish
    .ENDIF
   
    ; determine if Brand String supported
    _cpuid  80000000h
    cmp     eax, 80000004h
    jb      not_supported
   
    mov     pszBuffer[47], 0
    lea     edi, pszBuffer
   
    _cpuid  80000002h
    call    storestring
    _cpuid  80000003h
    call    storestring
    _cpuid  80000004h
    call    storestring

   

    jmp finish

not_supported:
   
    _cpuid  1h  ; eax := cpu signature
                ; ebx.bl := cpu brand id

finish:

    lea     eax, pszBuffer
   
    pop     edi
    pop     ebx

    ret

storestring:

    stosd
    mov     ebx, eax
    stosd
    mov     ecx, eax
    stosd
    mov     edx, eax
    stosd
   
    ret

CpuBrand ENDP


dedndave

the buffer is local to the routine
it is assigned as space on the stack and lost when the routine exits
if you want to return the string, create a global buffer for it and pass the buffer address to the routine

clive

You also need to add a POP EBP, or remove the PUSH EBP, at the moment the stack is not balanced. This alone will cause it to crash

finish:

    lea     eax, pszBuffer

    POP EBP
   
    pop     edi
    pop     ebx

    ret


Define the buffer globally, per Dave. Make it big enough


    .DATA

pszBuffer  db  49 dup(?) ; 3 x 4 x 4 + 1 for NUL


Put the NUL in the right place


mov     pszBuffer[48], 0


The not supported path needs work.
It could be a random act of randomness. Those happen a lot as well.

joemc

Another fairly simple solution is to pass a pointer into the function:
CpuBrand PROC STDCALL pszBufer:DWORD
   
and put the string  in the caller's stack frame.  i.e. move local pszBuffer[48] : BYTE to the function that is calling CpuBrand.

hutch--

Here is a quick scruffy that shows the intel string and the extended brand info. Dave is the guy who has done the work on this stuff with CPUID so he may have a bit more to add for you.

This is the result I get with this Core2 Quad.


GenuineIntel
Intel(R) Core(TM)2 Quad CPU    Q9650  @ 3.00GHz
Press any key to continue ...



IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    Get_ID_String    PROTO :DWORD
    Get_Brand_String PROTO :DWORD

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL pbuf  :DWORD                  ; pointer
    LOCAL buffer[128]:BYTE              ; buffer

    mov pbuf, ptr$(buffer)

    invoke Get_ID_String,pbuf
    print pbuf,13,10

    invoke Get_Brand_String,pbuf
    print pbuf,13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

Get_ID_String proc pBuffer:DWORD

    push ebx
   
    mov eax, 0                          ; set ID string for Intel
    cpuid

    mov eax, [esp+4][4]                 ; (pBuffer) load buffer address into ESI

    mov [eax],    ebx                   ; write results to buffer
    mov [eax+4],  edx
    mov [eax+8],  ecx
    mov [eax+12], DWORD PTR 0           ; terminate result

    pop ebx
   
    ret 4

Get_ID_String endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

Get_Brand_String proc pBuffer:DWORD

    push ebx
    push esi
   
    mov eax, 80000002h                  ; extended function 2
    cpuid

    mov esi, [esp+4][8]                 ; (pBuffer) load buffer address into ESI

    mov [esi],   eax                    ; write results to buffer
    mov [esi+4],  ebx
    mov [esi+8],  ecx
    mov [esi+12], edx

    mov eax, 80000003h                  ; extended function 3
    cpuid

    mov [esi+16], eax                   ; write results to buffer
    mov [esi+20], ebx
    mov [esi+24], ecx
    mov [esi+28], edx

    mov eax, 80000004h                  ; extended function 4
    cpuid

    mov [esi+32], eax                   ; write results to buffer
    mov [esi+36], ebx
    mov [esi+40], ecx
    mov [esi+44], edx

    mov [esi+48], DWORD PTR 0           ; terminate result

    pop esi
    pop ebx
   
    ret 4

Get_Brand_String endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dedndave

well - couple things
it is a good idea to affinitize to a single core while using CPUID
before you do that, test to see if SetProcessAffinityMask is supported by using GetProcAddress
then, test to insure CPUID is supported prior to using it - toggle EFLAGS bit 21
at the same time, you may also toggle bit 18 and differentiate 386s from 486s (possible under older windows versions)

there are a few Cyrix CPUs that may have the CPUID instruction disabled
a ring 0 kernel mode driver is required to enable it
i am trying to figure out a way to identify Cyrix CPUs and their capabilities without using CPUID
there are only a few Cyrix models and there is a division test that does part of it for you
i forget the exact details - lost all that stuff when a hard drive failed
but you divide 5 by 2 and test the flags change