CPUID


When we set EAX to 0, and call the CPUID instruction, the processor fills the ECX, EBX, EDX registers with parts of the string containing the name of the processor, e.g. AuthenticAMD or GenuineIntel . But the PUSH instruction on the x86-64 instruction set pushes the 64-bit versions of the registers. We need to concatenate the strings in the 3 registers and print them on screen, using the write() system call. So what we do is shift the lower 32-bit part of RDX (i.e. EDX ) to the upper 32-bit part of RDX , and move the lower 32-bit part of RBX (i.e. EBX ) into the lower 32-bit part of RDX , thus placing the two of the parts of the string into the RDX register. The remaining part of the string is in the lower 32-bit part of RCX , which when gets pushed connects to the remaining string in the RDX register. Then we push both the registers on the stack, and then call the write() system call.

For doing a write() system call, we place the number of the system call as given in unistd.h into RAX , and then place the arguments into RDI, RSI & RDX. RDI is the file descriptor where we want to write to. RSI holds the address of the string and RDX holds the length of the string. If the value of RDI is 0x1 , the string obtained from the CPUID call will be printed on screen ( stdout ).

We then do an exit() system call to exit the program. This program does not use the C library and uses the kernel interface directly. Hence we do not have to define a main() function. We can directly use the _start symbol that the operating system uses to invoke every application. We have to declare it global so that it is noted as a symbol in the application's final binary that has been created and can be called by the operating system.


section .text
    global _start

    _start:
        xor eax,eax       ; place 0x0 in EAX for getting the name of the processor 
        cpuid
        shl  rdx,0x20     ; shifting lower 32-bits into upper 32-bit of RDX
        xor  rdx,rbx      ; moving EBX into EDX
        push rcx          ; push the string on the stack
        push rdx
        mov  rdx, 0x10    ; since we are pushing 2 registers, the length is not more than 16 bytes.
        mov  rsi, rsp     ; The address of the string is RSP because the string is on the stack
        push 0x1          ; The system call write() has the value 0x1 in the sytem call table
        pop  rax
        mov  rdi, rax     ; Since we are printing to stdout, the value of the file descriptor is also 0x1
        syscall           ; make the system call
        mov  rax, 0x3c    ; We now make the exit() system call here.
        xor  rdi, rdi     ; the argument is 0x0
        syscall           ; this exits the application and gives control back to the shell or the Operating system

				

The command to compile the above code is as follows:
$ yasm -f elf64 cpuid.asm 
$ ld -o cpuid.out cpuid.o  
				



Tweet


Follow @_vicash_