How to run Assembly inline in a code with variables in C?

Asked

Viewed 2,785 times

8

From an example book, I was able to run the following Assembly (AT&T) code with gas, which returns a message with the processor name:

.section .data 
output:
    .asciz "The processor Vendor ID is '%s'\n"

.section .bss
    .lcomm tam, 12

.section .text
.global main
main:
    movl $0, %eax
    cpuid
    movl $tam, %edi
    movl %ebx, (%edi)
    movl %edx, 4(%edi)
    movl %ecx, 8(%edi)
    pushl $tam
    pushl $output
    call printf
    addl $8, %esp   

    pushl $0    
    call exit

Question: I’m trying to put the inline code in C, but I’m having difficulties. How do I define my variables in C so that they work properly? The code "try" below did not work, but it demonstrates a little my doubt:

#include <stdio.h> 

int main(void)
{   
    const int tam = 12;
    char *output = "The processor Vendor ID is '%s'\n";

    __asm__ (

            "movl $0, %eax;"
            "cpuid;"
            "movl tam, %edi;"
            "movl %ebx, (%edi);"
            "movl %edx, 4(%edi);"
            "movl %ecx, 8(%edi);"
            "pushl $tam;"
            "pushl $output;"
            "call printf;"
            "addl $8, %esp;"
    );

    return 0;
}

I would like to know how to make this inline code in C that returns the processor name. Simple commands (without .data or .bss) I can compile and execute, but whenever I have variables of . bss or even constants of . data I can’t compile. How do I get the above source to Compile and run similarly to Assembly ? Thanks for your attention.

1 answer

5


Basic Notation

The basic scheme of use of 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. Look at the 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 indicate to the compiler that the result of that instruction must be sent by means of a register for the variable %N, where N is the index. You can also use =g letting the compiler decide which way 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 value of foo to the EBX register, and then uses it in the informed Assembly code.


//    Em C, seria:
//        var = bar;
asm volatile ("movl %0, %%eax;"
              "movl %%eax, %1;"
              : "=r" (var) // saída
              : "b" (bar)  // entrada
              : "%eax"     // clobbers
              ); 

Makes var equal to bar using the EAX register (note the use of indexes in %0 and %1). The third parameter (Clobbers) serves to tell the compiler that the EAX register will be used. This way, before executing your Assembly code, the compiler will save any content present in EAX that will be used after your code, releasing the EAX for you.


To get the CPU manufacturer

Then, 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 cpuid function that will be called. With this, variables eax and etc will receive the cpuid return, which you will use to print the processor manufacturer.

In Windows, you can also call up 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 in 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] = '\0'; // terminador nulo

    printf("CPU: %s", vendor);

    return 0;
}

The return will depend on the CPU and will show only the manufacturer, using the following notation:

"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"

Note: this code is for x86. To know which CPU model is a larger job.

Reference: Playing with cpuid

  • Actually, I wanted to get your first paragraph straight. My main question is not to show the processor manufacturer, but rather the interaction between C code and Assembly. I tried to understand the first part, but I didn’t understand it very well.

  • @Rafaelbluhm I added some examples explaining better.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.