
#include <stdio.h>

int main(){
    
    // Notes:
    // "%" placeholder for a variable
    // "%%" Actual CPU position, like pointer.
    
    // movb = 1 byte, movw = 2 bytes, movl = 4 bytes, movq = 8 bytes.
    
    // 1st register IN, 2nd ... are OUT.
    
    // xmm0, xmm1 ... xmm15 = 16 bytes
    // rax, rbx, rcx, rdx   = 8 bytes (long) 
    // eax, ebx, ecx, edx   = 4 bytes (int)
    // ax, bx, cx, dx       = 2 bytes
    // al, bl, cl, dl       = 1 byte (char)
    // r                    = general register
    
    int number = 6, target = 0;
    // target = number
    // MOVE -> B register TO a (=a)
    asm(
        "movl %%ebx, %%eax"
        : "=a"(target)
        : "b"(number)
    );
    printf("Target is now: %d\n", target);
    
    
    // Swap 2 numbers.
    int a = 5, b = 2;
    printf("a = %d, b = %d OLD\n", a, b);
    asm(
        "xchg %0, %1" // eXCHanGe
        : "+r"(a), "+r"(b)
    );
    printf("a = %d, b = %d NEW\n", a, b);
    
    
    int * i_p2;
    i_p2 =(int*)&i_p2;
    printf("**i_p2   = %p\n", **(void***)i_p2);
    
    int * i_p = NULL;
    asm(
        "movq %1, %0\n\t"   // i_p = &i_p
        "movq %1, (%1)\n\t" // *i_p = &i_p
        : "=r"(i_p)
        : "r"(&i_p)
    );
    printf("****i_p  = %p\n", ****(void*****)i_p);


    int num1 = 4, num2 = 2, r;
    // r = num1 + num2;
    // ADD -> B + A INTO "=A"
    asm(
        "addl %%ebx, %%eax" // THIS LINE ORDER MATTERS!
        : "=a"(r)
        : "a"(num1), "b"(num2) // REGISTERS eax and ebx
    );
    printf("add: %d\n", r);
    
    // SUB -> B + A INTO "=A"
    asm(
        "subl %%ebx, %%eax"
        : "=a"(r)               
        : "a"(num1), "b"(num2)
    );
    printf("add: %d\n", r);
    
    
    // CPU vendor
    unsigned int ebx, ecx, edx;
    char vendor[13];
    
    // Get CPUID and keep commands in THIS ORDER.
    asm volatile(
        "cpuid"
        : "=b"(ebx), "=d"(edx), "=c"(ecx)
        : "a"(0)
    );
    
    *(unsigned int*)&vendor[0] = ebx;
    *(unsigned int*)&vendor[4] = edx;
    *(unsigned int*)&vendor[8] = ecx;
    vendor[12] = '\0';
    
    printf("CPU vendor: %s\n", vendor);
    
    

    return 0;
}