|
Introduction
Mixed-language programming allows you to combine the unique strengths of Visual C++ with your assembly-language routines. There are some cases where you want to achieve things using inline assembly, such as improving speed, reducing memory needs and getting more efficiency. However, inline assembler is not as powerful as MASM, it does not support macros or directives. This article explains how to write assembly routines that can be called from Visual C++ modules. But before proceeding, there are two terms you have to be familiar with:
Naming Convention
It specifies how the compiler alters the symbol name as it places the name in a .OBJ file. For example, a C function “void func(void)” is put as “_func@0” in the .OBJ file, whereas in C++, it is decorated to “?func@@YAXXZ” in the .OBJ file.
Calling Convention
It determines how a language implements a call to a procedure and how the procedure returns to the caller. In the C Calling Convention (__cdecl), arguments are pushed onto the stack from right to left, the called procedure returns without removing the arguments from the stack. It is the caller’s responsibility to clean the stack after the call.
In Standard Calling Convention (__stdcall), arguments are pushed onto the stack from right to left, the called procedure cleans the stack if it does not accept a variable number of arguments. In Fast Calling Convention (__fastcall), the first two parameters are loaded into ecx, edx registers, respectively. The other parameters are pushed onto the stack from right to left. The same function is responsible for cleaning the stack.
Here is a summary table for some calling and naming conventions with an example:
| Language, Calling Convention |
Name in .OBJ file |
void func (void) |
C, cdecl |
_name |
_func |
C, __stdcall |
_name@nn |
_func@0 |
C, __fastcall |
@name@nn |
@func@0 |
C++, cdecl |
?name@@decoration |
?func@@YAXXZ |
C++, __stdcall |
?name@@decoration |
?func@@YGXXZ |
C++, __fastcall |
?name@@decoration |
?func@@YIXXZ |
How to use MASM routines in Visual C++ modules:
The following assembly function (Addup) accepts three DWORD (32-bit) values as parameters, and then returns the sum of them. Whenever you write a routine make sure you don't choose it as entry point (i.e. END Addup).
.486
.model flat, stdcall
option casemap :none
.code
Addup PROC, Arg1:DWORD, Arg2:DWORD, Arg3:DWORD
mov eax, Arg1
add eax, Arg2
add eax, Arg3
ret
Addup ENDP
END
- Now copy the resultant .obj file (Addup.obj) into your VC++ application’s project folder.
- Add to the C++ source file (.cpp) that will use this routine, the following prototype:
extern “C” int __stdcall Addup (int, int, int);
Or you can put this prototype into a new header file and then add it to your project. The extern “C” indicates C naming convention since you are in a C++ environment. MASM uses C naming convention when you specify STDCALL. Finally, the __stdcall indicates that the routine uses standard calling convention.
- Now add the .OBJ file name (Addup.obj) into your linker commands window. Or you can add the file manually to your project. Otherwise, you will get an “unresolved external” error.
- Now you should compile the project fine without any errors.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 16 of 16 (Total in Forum: 16) (Refresh) | FirstPrevNext |
|
|
 |
|
|
Hi,
I'm wondering, if I have a simple array in C, e.g.
int a[] = {1,2,3}; And I want to load the address of 'a' into EAX, for example, with inline asm, the following doesn't work:
__asm {
mov eax, a // invalid mov eax, offset a // also invalid lea eax, a // this is OK
}
I'm wondering why only the last one works? Isn't 'a' treated like a label of some kind, which maps to some address?
Could someone explain why the LEA instruction is the only one that seems to work?
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
First of all, "mov eax, a" ALWAYS moves the first element into eax register which is 1.
if 'a' is global then "mov eax, offset a" works 100%.
* LEA means Load Effective Address.
When you use "mov eax, a" then you are evaluating 'a' as a variable (the assembler expects 'a' to have a value), and this instruction is converted to something like this "mov eax,dword ptr [ebp-10h]" (has indirect addressing). because the array is not more than a group of contigous bytes, this instruction simply returns the first element of the array which is 1.
Local variables are stored on the stack and referenced normally with the EBP register, the actual address of 'a' is in "ebp-10h", to evaluate the address of a, logically you might think like this "move eax, ebp-10h". But unfortunately, this is not a valid assembly instruction and it won't be assembled. To overcome this problem, LEA can be used, which simply copies the value of "ebp-10h" into eax.
I hope everything is clear now!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Ah! Thank you very much for the quick and clear reply.
I think I understand now 
(Consequently, the first instruction (mov eax,a) is indeed valid, just not the intended result -- don't know why I thought it gave an error before)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You say that the first two arguments are moved to ECX and EDX, which are 32 bits large on x86, but what happens if the arguments are structures which are bigger, and are not passed by pointer? For example:
struct A { int a, b, c; };
void func(struct A a) { } // passed by copy, onto the stack usually.
How does fastcall handle that?
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Actually, the fastcall covention has not been standardized and it has been implemented differently depending on the compiler.
For Microsoft Visual C++ (though not sure if for all versions is the same) The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed from right to left.
In this case, there is only one argument a, but its size is greater than one DWORD; it has 4 DWORD values. So it is pushed on the stack from right to left (c to a). It behaves like an STDCALL!
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Ah, I see. Thanks for the reply.
BTW, are you sure you didn't mean "3 DWORD values" instead of 4? (The struct has 3 ints). Unless perhaps it gets padded out to 4 dwords for some reason.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Great article, but one thing you forgot to mention was how values are returned from procedures. From your example, I can deduce that the value in EAX is considered the return value after the procedure calls 'ret', but is that based on STDCALL or what?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Return Values registers are based on the compiler. For example, in C/C++ under Windows, EAX register is always used to carry the return value; however, you can still create your own functions and use other registers.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Ah, thanks for the quick reply.
I see, so do all compilers under windows follow this convention, or is it specific to MS Visual C++?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Most of them YES (and maybe all of them I am not sure). But you can make sure that for STDCALL yes, this is because of Win32 API.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Ok cool. What about CDECL/FASTCALL and others? Do they still use EAX or something else (like push onto stack)?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
When I write in Visual Studio 2005 void main() {
char msg[] = "Hello World!"; _asm { lea eax, msg push eax call printf line 20: add esp,4 } }
I get exception "Unhandled exception at 0x004182bc in TEST.exe: 0xC000001E: An attempt was made to execute an invalid lock sequence." on line 20
I think this works in VS 2003 but not in VS 2005 Please help me to solve this.
By Arun
|
| Sign In·View Thread·PermaLink | 3.50/5 (2 votes) |
|
|
|
 |
|
|
Because printf here is evaluated as a pointer to the entry in the Import Table of the PE not a pointer to the the function itself. To solve this problem just use:
call dword ptr[printf]
*The PE maintains entries to functions/routines using a table called Import Address Table.
|
| Sign In·View Thread·PermaLink | 5.00/5 (3 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|