Basic Notation
The basic usage scheme for asm
or __asm__
or _asm
or __asm
in C \ C ++ is as follows (using GCC as reference ):
asm [volatile] ( "SEU CODIGO\n\t"
"EM\n\t"
"ASSEMBLY"
: OperadoresDeSaída
[ : OperadoresDeEntrada
[ : Clobbers ] ])
This notation changes depending on the compiler.
Examples
I find it easier to explain using some example. View on ideone.
Assuming you have the following variables:
// Criando variáveis para interagir com assembly:
int foo, bar, var;
You can interact with them using inline assembly
as follows:
// Em C, seria:
// foo = 1;
// bar = 2;
// var = 3;
asm volatile ("movl $1, %0;" // código assembly
"movl $2, %1;"
"movl $3, %2;"
: "=r" (foo), "=r" (bar), "=r" (var) // variáveis de saída
);
The =r
indicates to the compiler that the result of that statement must be sent via a register to the %N
variable, where N is the index. You can also use =g
by letting the compiler decide what medium to use to send the value. More details in the documentation.
// Em C, seria:
// bar = foo * 2;
asm volatile ("movl $2, %%eax;" // eax = 2
"imul %%ebx, %%eax;" // eax * ebx
"movl %%eax, %0;" // faz bar igual ao resultado.
: "=r" (bar) // variáveis de saída
: "b" (foo) // variáveis de entrada (ebx = foo)
);
In this case, the compiler passes the foo value to the EBX register, then uses it in the supplied assembly code.
// Em C, seria:
// var = bar;
asm volatile ("movl %0, %%eax;"
"movl %%eax, %1;"
: "=r" (var) // saída
: "b" (bar) // entrada
: "%eax" // clobbers
);
Make var
equal to bar
using the EAX register (note the use of indexes in% 0 and% 1). The third parameter (clobbers) is to tell the compiler that the EAX register will be used. That way, before running your assembly code, the compiler will save any EAX content that will be used after your code, releasing EAX for you.
To get the CPU manufacturer
So, you can use the following code to call get the CPU manufacturer. Using cpuid
:
asm volatile ("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
: "a" (op));
Where, eax
, ebx
, ecx
and edx
are the values of the registers and op
is the function of the cpuid that will be called. With this, eax
variables and etc will receive the cpuid return, which you will use to print the processor manufacturer.
On Windows, you can also call the above code using the following function:
int regs[4]; // recebe eax, ebx, ecx, edx
int op = 0; // código da função
__cpuid(regs, op);
For this, you must include intrin.h
Example on ideone :
#include <stdio.h>
#include <stdint.h>
#include <cpuid.h>
#include <string.h>
int main(int argc, char **argv)
{
// a função opcode CPUID:
int op;
// registradores:
int eax;
int ebx;
int ecx;
int edx;
// parâmetro zero para CPUID indica que você quer o fabricante.
op = 0;
__asm__ ("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
: "a" (op));
// Receberá os valores de EBX, ECX e EDX para sistemas 32bits:
char vendor[sizeof(int) * 3 + 1];
strncpy(vendor, (const char*) &ebx, sizeof(int));
strncpy(&vendor[8], (const char*) &ecx, sizeof(int));
strncpy(&vendor[4], (const char*) &edx, sizeof(int));
vendor[12] = '"AMDisbetter!" ou "AuthenticAMD" -> "AMD";
"GenuineIntel" -> "Intel"
"VIA VIA VIA " -> "VIA"
"CentaurHauls" -> "Centaur"
"CyrixInstead" -> "Cyrix"
"TransmetaCPU" ou "GenuineTMx86" -> "Transmeta"
"Geode by NSC" -> "National Semiconductor"
"NexGenDriven" -> "NexGen"
"RiseRiseRise" -> "Rise"
"SiS SiS SiS " -> "SiS"
"UMC UMC UMC " -> "UMC"
"Vortex86 SoC" -> "Vortex"
"KVMKVMKVMKVM" -> "KVM"
"Microsoft Hv" -> "Microsoft Hyper-V"
"VMwareVMware" -> "VMware"
"XenVMMXenVMM" -> "Xen HVM"
'; // terminador nulo
printf("CPU: %s", vendor);
return 0;
}
The return will depend on the CPU and will only show the manufacturer, using the following notation:
asm [volatile] ( "SEU CODIGO\n\t"
"EM\n\t"
"ASSEMBLY"
: OperadoresDeSaída
[ : OperadoresDeEntrada
[ : Clobbers ] ])
NOTE: This code is for x86. To know which CPU model is a larger work.
Reference: Playing with cpuid