Combining C++ and Assembly jbwyatt.com

Why?
  1. speed
  2. size
  3. low-level access (registers)


.. First, a Word About C# and IL

Managed Code vs. Native Code
   IL
   CLR
   .NET class library
   
Use ILDASM to inspect C#  MANAGED code =>IL
   - Run the the Visual Studio command prompt
   - type in ILDASM
   - choose a C# exe file
   
References:   
msdn: ildasm
a nice IL C# tutor


.. HLL to Assembly Code

HLL compilers translate mathematical expressions into assembly language.

You can do it also.

For example in C++:
     
     int Rval;
     int Xval = 26;
     int Yval = 30;
     int Zval = 40;
   
     ...
   
     Rval = (Yval - – Zval) - Xval; // (30-40) - 26 = -36 
     

...and in assembly: mov eax, Xval neg eax ; EAX = -26 mov ebx, Yval sub ebx, Zval ; EBX = -10 add eax, ebx mov Rval, eax ; -36 ... Rval DWORD ? Xval DWORD 26 Yval DWORD 30 Zval DWORD 40
... and mixing it up: int Rval; int Xval = 26; int Yval = 30; int Zval = 40; __asm { mov eax, Xval neg eax ; EAX = -26 mov ebx, Yval sub ebx, Zval ; EBX = -10 add eax, ebx mov Rval, eax ; -36 } ** note that you can NOT define assembly data in mixed code - why??? note that you can NOT use the OFFSET operator in mixed code -- why??

.. Disassembly Code

DISASSEMBLY: C++ to Assembly - example...
 ===========================

 random code from a sudoku program...

 case 1:
        ////////////////////////////////////////////////////
        // generate & print simple grid WITH repetitions
        //
        ///////////////////////////////////////////////////
        timeStart = time(0); 
0044E4FA  push        0
0044E4FC  call        time (44EE00h)
0044E501  add         esp,4
0044E504  mov         dword ptr [ebp-68h],eax

        // allocate dynamic memory on the heap
        grid1=new int[SZp*SZp];
0044E507  mov         eax,dword ptr [ebp-80h]
0044E50A  imul        eax,dword ptr [ebp-80h]
0044E50E  xor         ecx,ecx
0044E510  mov         edx,4
0044E515  mul         eax,edx
0044E517  seto        cl
0044E51A  neg         ecx
0044E51C  or          ecx,eax
0044E51E  push        ecx
0044E51F  call        operator new[] (440ADCh)
0044E524  add         esp,4
0044E527  mov         dword ptr [ebp-248h],eax
0044E52D  mov         eax,dword ptr [ebp-248h]
0044E533  mov         dword ptr [ebp-14h],eax

        // init grids to all zeroes
        initGridP(grid1, SZp);
0044E536  mov         eax,dword ptr [ebp-80h]
0044E539  push        eax
0044E53A  mov         ecx,dword ptr [ebp-14h]
0044E53D  push        ecx
0044E53E  call        initGridP (440820h)
0044E543  add         esp,8

        // generate grid using random numbers(1 to gridsize)
        simpleGridP(grid1, SZp);
0044E546  mov         eax,dword ptr [ebp-80h]
0044E549  push        eax
0044E54A  mov         ecx,dword ptr [ebp-14h]
0044E54D  push        ecx
0044E54E  call        simpleGridP (4406DBh)
0044E553  add         esp,8
        printGridP(grid1, SZp);
0044E556  mov         eax,dword ptr [ebp-80h]
0044E559  push        eax
0044E55A  mov         ecx,dword ptr [ebp-14h]
0044E55D  push        ecx
0044E55E  call        printGridP (441ED7h)
0044E563  add         esp,8
        cout << "Simple random grid with NO CHECK for repetitions..." << endl;
0044E566  push        offset std::endl (44077Bh)
0044E56B  push        offset string "Simple random grid with NO CHECK"... (4C5EC0h)
0044E570  push        offset std::cout (4DEFE0h)
0044E575  call        std::operator<< > (441248h)
0044E57A  add         esp,8
0044E57D  mov         ecx,eax
0044E57F  call        std::basic_ostream >::operator<< (441284h)

        // release allocated memory
        delete []grid1;
0044E584  mov         eax,dword ptr [ebp-14h]
0044E587  mov         dword ptr [ebp-23Ch],eax
0044E58D  mov         ecx,dword ptr [ebp-23Ch]
0044E593  push        ecx
0044E594  call        operator delete[] (4401EAh)
0044E599  add         esp,4

        // time stamp
        cout << "Seconds used is " << time(0)-timeStart << endl;
0044E59C  push        offset std::endl (44077Bh)
0044E5A1  push        0
0044E5A3  call        time (44EE00h)
0044E5A8  add         esp,4
0044E5AB  mov         ecx,eax
0044E5AD  mov         esi,edx
0044E5AF  mov         eax,dword ptr [ebp-68h]
0044E5B2  cdq
0044E5B3  sub         ecx,eax
0044E5B5  sbb         esi,edx
0044E5B7  push        esi
0044E5B8  push        ecx
0044E5B9  push        offset string "Seconds used is " (4C5EACh)
0044E5BE  push        offset std::cout (4DEFE0h)
0044E5C3  call        std::operator<< > (441248h)
0044E5C8  add         esp,8
0044E5CB  mov         ecx,eax
0044E5CD  call        std::basic_ostream >::operator<< (441D29h)
0044E5D2  mov         ecx,eax
0044E5D4  call        std::basic_ostream >::operator<< (441284h)
         break;
0044E5D9  jmp         $LN4+62h (44EAECh)

.. C++ Code

Hello World Progression

Metric
Stick Figure (functions)

.. Mixed Code: __asm Blocks in C++

__asm
{
  assembly code
}

The __asm (2 underscores!!) keyword invokes the inline assembler and can appear wherever a C++ statement is legal and must be followed by an assembly instruction or a group of assembly instructions in braces. The inline assembler lets you embed assembly-language instructions in your C and C++ source programs. It's built into the compiler, so you don't need a separate assembler . Inline assembly code can use any C or C++ variable or function name that is in scope, so it's easy to integrate with your program's C and C++ code. Because the assembly code can be mixed with C and C++ statements, it can do tasks that are cumbersome or impossible in C or C++ alone. Example Code: ============= __asm { mov al, 2 mov dx, 0xD007 out dx, al } OR, you can put __asm before each assembly instruction: __asm mov al, 2 __asm mov dx, 0xD007 __asm out dx, al
Can NOT use assembler directives including data defintions. Can only use registers and variables declared in C++.
Example Program: ================ add 3 to 9 equals 12 (in EAX) subtract 2 getting 10 (in EAX) negate giving -10 (EAX) move into C++ variable, number print the variable (-10) #include <iostream> using namespace std; int main() { int number=3; __asm { mov EAX, 00000009h add EAX, number ; add 3 mov EBX, 2 sub EAX, EBX ; 12 - 2 = 10 neg EAX mov number, EAX } cout << number; ; -10 return 0; }
Example Program: ================ #include <iostream> using namespace std; int Sum(int, int); int main() { cout << "Hello \n\n"; int x = Sum( 3, 4 ); cout << x << endl; // 7 cout << Sum( 3, 2 ) << endl; // 5 cout << Sum( Sum( 1,2 ), x ) << endl; //10 return 0; } int Sum (int x, int y) { int s; __asm { mov eax, x mov ebx, y add eax, ebx mov s, eax } return s; }