Author Topic: Why simple cpuid code gives runtime error?  (Read 12272 times)

Offline aloha_arts

  • Jr. Member
  • *
  • Posts: 2
Why simple cpuid code gives runtime error?
« on: March 31, 2010, 08:41:13 PM »
Why does the following code give a runtime error?
It prints: "Vendor id: GenuineIntel" and then crashes.

compiled with: nams -fwin32 ...

Code: [Select]
    global  _main
    extern  _printf

    section .text
_main:
    push    ebx
    push    ebp


    xor     eax, eax
    cpuid

    mov     [vendor], ebx
    mov     [vendor + 4], edx
    mov     [vendor + 8], ecx

    push    vendor
    push    format
    call    _printf
    sub     esp, 4

    pop     ebp
    pop     ebx

    ret

    section .data
format      db      'Vendor id: %s', 10, 0
vendor      times   12  db  0

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Why simple cpuid code gives runtime error?
« Reply #1 on: March 31, 2010, 09:04:13 PM »
At a glance, you are making 8 bytes worth the stack pushes before calling printf, and then "adding" 4 more bytes to the stack after. Remember, the stack grows downwards, not upwards.

In short, esp is 12 bytes off of where it should be.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Why simple cpuid code gives runtime error?
« Reply #2 on: March 31, 2010, 09:13:45 PM »
I would also add a byte to "vendor" and zero-terminate it...

Best,
Frank


Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Why simple cpuid code gives runtime error?
« Reply #3 on: March 31, 2010, 11:01:52 PM »
I would also add a byte to "vendor" and zero-terminate it...

Most definitely. Good catch.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Why simple cpuid code gives runtime error?
« Reply #4 on: April 01, 2010, 01:35:23 AM »
Just for fun, here's a more verbose subfunction(?) of cpuid.

Code: [Select]
; nasm -f elf cpuname.asm
; ld -o cpuname cpuname.o

global _start

section .bss
    namestring resb 48

section .text
_start:

    mov eax, 80000000h
    cpuid
    cmp eax, 80000004h ; supported?
    jb exit
   
    mov edi, namestring

    mov eax, 80000002h
    cpuid
    call savestring

    mov eax, 80000003h
    cpuid
    call savestring

    mov eax, 80000004h
    cpuid
    call savestring

    mov ecx, namestring ; buffer
    mov edx, 48 ; length
    mov ebx, 1 ; stdout
    mov eax, 4 ; sys_write
    int 80h

exit:
    mov eax, 1
    int 80h
;-----------------------

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

The astute observer will note that I didn't leave a space for a zero terminator either. Well, I didn't need one, I know the length. I should have added another byte and stuffed a linefeed in there, though! Oh, well. :)

The conversion to Windows/_printf should be easy - don't forget to preserve the necessary registers if you're going to exit with "ret"! (sys_exit doesn't care).

Best,
Frank


Offline aloha_arts

  • Jr. Member
  • *
  • Posts: 2
Re: Why simple cpuid code gives runtime error?
« Reply #5 on: April 01, 2010, 01:56:30 PM »
Thank you. You where rigth about the esp line.
:)

Do you know where I can read through some NASM tutorials for windows programming and interrups?