C + + embedded assembly tutorial 1

Posted by kevin7 on Thu, 20 Jan 2022 14:01:05 +0100

Note:
All the code in this article is tested in my own VS2008. Due to different environments, it can not be guaranteed to run on all compilers.

1. Introduction to embedded assembly

In C + +, you can use__ asm keyword to embed assembly language.
for example

int main(){
  __asm{//Assembly!
    mov eax,0
  }
  return 0;
}

 

2. Compilation version Hello, World!

As we know, in C + +, you can use the printf function to output. (if you use cout, you need to use techniques such as operator overloading, which is inconvenient here.)

Tips:
In assembly, the instruction to call function is called CALL.
The parameters of the function are stored on the stack.

Then we can start writing. First, let's take a look at the normal version of C + +:

#include<stdio.h>
#include<stdlib.h>

const char *s1="Hello, World\n",*s2="pause";
int main(){
    printf(s1);
    system(s2);
    
    return 0;
}

 

For convenience, we first disassemble the normal version. The result is:

printf(s1);
00BD13CE  mov         esi,esp 
00BD13D0  mov         eax,dword ptr [s1 (0BD7038h)] 
00BD13D5  push        eax  
00BD13D6  call        dword ptr [__imp__printf (0BD82C4h)] 
00BD13DC  add         esp,4 
00BD13DF  cmp         esi,esp 
00BD13E1  call        @ILT+315(__RTC_CheckEsp) (0BD1140h) 

In the first sentence, MOV, ESI and ESP are used to check whether the stack is working normally
In the second sentence, mov eax,dword ptr[s1], 0BD7038h in parentheses is the address. Don't worry about it. It means to put the address in eax
In the third sentence, push eax puts the address just put into eax on the stack, which is actually putting the parameters on the stack

The fourth sentence, call DWORD PTR [_imp__printf]
__ imp__printf is the compiled result of the printf function. The beginning of the underscore indicates that this is a function
We usually write printf directly when we write inline assembly

Fifth sentence, add esp,4
In fact, it is manual stack leveling. Previously, 4 bytes of s1 were placed in the stack. Now move the esp pointer, that is, the pointer at the top of the stack down (the stack moves from high address to low address), and level the stack

Regardless of the last two sentences, it is to ensure that esi and esp are equal, because the stack was manually flattened before. Combined with the first sentence, it should be equal here. It should be all right if you don't write

 

 

The final inline assembly should look like this:

#include<stdio.h>
#include<stdlib.h>

const char *s1="Hello, World\n",*s2="pause";
int main(){
    _asm{
        mov eax,dword ptr [s1]
        push eax
        call dword ptr [printf]
        add esp,4
        mov eax,dword ptr[s2]
        push eax
        call dword ptr [system]
        add esp,4
    }
    return 0;
}

The operation results are normal.

 

3. Inline assembly A+B

The A+B problem requires both scanf and printf

First of all, note that the parameters of the function are stored upside down in the stack. (Note: this C standard does not specify, but the assembly language itself is a thing that depends very much on the environment, so leave it alone for the time being)

for example

scanf("%d %d",&a,&b);

If translated into assembly, it should be like this (the following is pseudo code)

push &b
push &a
push "%d %d"
call scanf

 

Then we can start writing.

For the scanf part, pay attention to the first two parameters. Since the address is put in, the MOV instruction cannot be used, but the LEA instruction should be used

lea eax,[a]

Means to put the address of a into eax.

There is no difficulty in other parts. Pay attention to how much add esp is added when the stack is finally flattened, and the size of each parameter is added.

For example, scanf, each address is 4 bytes, and the total is 12 bytes.

 

Complete code

#include<stdio.h>
#include<stdlib.h>

const char *s1="%d%d",*s2="%d\n",*s3="pause";
int a,b;
int main(){
    _asm{
        lea eax,[b]
        push eax
        lea eax,[a]
        push eax
        mov eax,dword ptr [s1]
        push eax
        call dword ptr [scanf]
        add esp,12

        mov eax,[a]
        add eax,[b]
        push eax
        mov eax,dword ptr [s2]
        push eax
        call dword ptr [printf]
        add esp,8


        mov eax,dword ptr [s3]
        push eax
        call dword ptr [system]
        add esp,4
    }
    return 0;
}