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; }