© Jo Van Hoey 2019
J. Van HoeyBeginning x64 Assembly Programminghttps://doi.org/10.1007/978-1-4842-5076-1_25

25. Got Some ID?

Jo Van Hoey1 
(1)
Hamme, Belgium
 

Sometimes it is necessary to find out the functionality available in a processor. In your program, you can, for example, look for the presence or absence of a certain version of SSE. In the next chapter, we will use programs with SSE instructions, so we need to find out first which version of SSE is supported by our processor. There is an instruction for checking the CPU characteristics: cpuid.

Using cpuid

You first put a specific parameter in eax, then execute the instruction cpuid, and finally check the returned value in ecx and edx. Indeed, cpuid uses 32-bit registers.

The amount of information you can find out with cpuid is staggering. Go to the Intel manuals ( https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf ) and look up the cpuid instruction in Volume 2A. You will find several tables that show what is returned in ecx when you start cpuid with certain value in eax. This is only part of the information you can retrieve; another table shows the information returned in edx. Browse the Intel manual to see the possibilities.

Let’s see an example of looking for SSE functionality that we will need in the next chapter. In the Intel manual, you find that you can use ecx bits 0, 19, and 20 and ecx bits 25 and 26 to find out which version of SSE is implemented in a processor.

Listing 25-1 shows the example program.
; cpu.asm
extern printf
section .data
        fmt_no_sse db "This cpu does not support SSE",10,0
        fmt_sse42 db "This cpu supports SSE 4.2",10,0
        fmt_sse41 db "This cpu supports SSE 4.1",10,0
        fmt_ssse3 db "This cpu supports SSSE 3",10,0
        fmt_sse3 db "This cpu supports SSE 3",10,0
        fmt_sse2 db "This cpu supports SSE 2",10,0
        fmt_sse db "This cpu supports SSE",10,0
section .bss
section .text
      global main
main:
push rbp
mov   rbp,rsp
    call cpu_sse    ;returns 1 in rax if sse support, otherwise 0
leave
ret
cpu_sse:
      push rbp
      mov rbp,rsp
      xor r12,r12         ;flag SSE available
      mov eax,1           ;request CPU feature flags
      cpuid
;test for SSE
    test edx,2000000h           ;test bit 25 (SSE)
    jz sse2                     ;SSE available
    mov r12,1
    xor rax,rax
    mov rdi,fmt_sse
    push rcx                    ;modified by printf
    push rdx                    ;preserve result of cpuid
    call printf
    pop rdx
    pop rcx
sse2:
    test edx,4000000h           ;test bit 26 (SSE 2)
    jz sse3                     ;SSE 2 available
    mov r12,1
    xor rax,rax
    mov rdi,fmt_sse2
    push rcx                    ;modified by printf
    push rdx                    ;preserve result of cpuid
    call printf
    pop rdx
    pop rcx
sse3:
    test ecx,1                  ;test bit 0 (SSE 3)
    jz ssse3                    ;SSE 3 available
    mov r12,1
    xor rax,rax
    mov rdi,fmt_sse3
    push rcx                    ;modified by printf
    call printf
    pop rcx
ssse3:
    test ecx,9h                 ;test bit 0 (SSE 3)
    jz sse41                    ;SSE 3 available
    mov r12,1
    xor rax,rax
    mov rdi,fmt_ssse3
    push rcx                    ;modified by printf
    call printf
    pop rcx
sse41:
    test ecx,80000h             ;test bit 19 (SSE 4.1)
    jz sse42                    ;SSE 4.1 available
    mov r12,1
    xor rax,rax
    mov rdi,fmt_sse41
    push rcx                    ;modified by printf
    call printf
    pop rcx
sse42:
   test ecx,100000h             ;test bit 20 (SSE 4.2)
   jz wrapup                    ;SSE 4.2 available
   mov r12,1
   xor rax,rax
   mov rdi,fmt_sse42
   push rcx                     ;modified by printf
   call printf
   pop rcx
wrapup:
    cmp r12,1
    je sse_ok
    mov rdi,fmt_no_sse
    xor rax,rax
    call printf                 ;displays message if SSE not available
    jmp the_exit
sse_ok:
    mov rax,r12                 ;returns 1, sse supported
the_exit:
leave
ret
Listing 25-1

cpu.asm

The main program calls only one function, cpu_sse, and if the return value is 1, the processor supports some version of SSE. If the return value is 0, you can forget about using SSE on that computer. In the function cpu_sse, we find out which SSE versions are supported. Put 1 in eax and execute the instruction cupid; as mentioned, the results will be returned in ecx and edx.

Using the test Instruction

The ecx and edx registers will be evaluated with a test instruction, which is a bit-wise logical and of the two operands. We could have used the cmp instruction, but test has a performance advantage. Of course, you can also use the instruction bt (see Chapter 17).

The test instruction sets the flags SF, ZF, and PF according to the test result. In the Intel manual, you will find the operation of the test instruction, as follows:
TEMP ← SRC1 AND SRC2;
SF ← MSB(TEMP);
IF TEMP = 0
     THEN ZF ← 1;
     ELSE ZF ← 0;
FI:
PF ← BitwiseXNOR(TEMP[0:7]);
CF ← 0;
OF ← 0;
(∗ AF is undefined *)

The important flag in our case is ZF. If ZF=0, then the result is nonzero; the SSE bit is 1, and the CPU supports that version of SSE. The instruction jz evaluates if ZF=1, and if so, the SSE version is not supported, and the execution jumps to the next part. Otherwise, the program prints a confirmation message.

In our example, after cpuid is executed, we test edx. The register edx has 32 bits, and we want to know if bit 25 is set, meaning that the CPU supports SSE (version 1). So, we need the second operand in the test instruction to have 1 in bit 25, with the other bits all 0. Remember that the lowest bit has index 0, and the highest has index 31. In binary, it looks like this:
0000 0010 0000 0000 0000 0000 0000 0000
In hexadecimal, it looks like this:
2000000

Remember, you can find plenty of binary to hexadecimal conversion tools on the Internet.

The execution “cascades” through the program, and if no SSE is supported, r12 will remain 0. We did not use the return value, but you could check rax, the return value, to conclude whether any SSE is supported. Or you could modify the program to return the highest version of SSE.

Figure 25-1 shows the output.
../images/483996_1_En_25_Chapter/483996_1_En_25_Fig1_HTML.jpg
Figure 25-1

cpu_sse.asm output

You could build a similar function to find out other CPU information and, depending on the returned result, choose to use certain functionality on this CPU and other functionality on another CPU.

In a later chapter, when we discuss AVX, we will again have to find out whether the CPU supports AVX.

Summary

In this chapter, you learned about the following:
  • How to find out what functionality is supported by the CPU with cpuid

  • How to use bits with the test instruction

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.137.38