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

