To create files with functions in Assembly 64 bits using Visual Studio 2015 (Community):
- Right-click your project, enter the menu
Build Dependencies
and then in Build Customizations...
. On the customization screen, select the option masm(.targets, .props)
:
- In your project, in the folder
Source Files
, add a new item Utility
of the kind Text File (.txt)
(text file). After adding, rename the file from .txt
for .asm
(example: funcao.txt
for funcao.asm
):
- Right-click on the file
funcao.asm
and select Properties
. In the properties dialog, change the Item Type
of Text
for Microsoft Macro Assembler
:
- In the source code
C
, declare the prototype of the functions as extern
. If the program is in C++
, declare as extern "C"
. In your example, the main file looks like this:
#include "stdafx.h"
// delcaração da função em assembly
extern "C" long long int formula(long long int a, long long int b, long long int *r2);
// Função em C que implementa o mesmo cálculo (apenas para teste)
long long int formula2(long long int a, long long int b, long long int *r2)
{
*r2 = (a*b) / (a*a / b + b*b / a);
return a*a + b*b;
}
int main(int argc, char *argv[])
{
long long int ret1;
long long int ret2;
printf("inicio\n");
// Execução em C
ret1 = formula2(12, 16, &ret2);
printf("Resultado C: ret1=%lld, ret2=%lld\n", ret1, ret2);
// Execução em Assembly
ret1 = formula(12, 16, &ret2);
printf("Resultado ASM: ret1=%lld, ret2=%lld\n", ret1, ret2);
printf("fim.\n");
getchar();
return 0;
}
The guy long long int
defines the variables ret1
and ret2
as 64bit integers.
According to the logic you want to implement, the type can change and the way the Assembly code will be developed, too.
- In the source code Assembly, declare the functions as
public
. For your example, the file funcao.asm
was like this:
.code
public formula
; formula(a,b,ret2) = a*a + b*b
; *ret2 = ( a*b )/( a*a/b + b*b/a )
formula proc
mov r11, rdx ; r11 <- b
xor rdx, rdx ; rdx = 0
mov rax, rcx
imul rax, rax
mov r9, rax ; r9 <- a^2
mov rax, r11
imul rax, rax
mov r10, rax ; r10 <- b^2
idiv rcx
mov r12, rax ; r12 <- b^2/a
xor rdx, rdx
mov rax, r9
idiv r11
add rax, r12
mov r13, rax ; r13 <- b^2/a + a^2/b
xor rdx, rdx
mov rax, rcx
imul rax, r11
idiv r13
mov qword ptr [r8], rax ; resultado em rax
mov rax, r9
add rax, r10
ret
formula endp
end
In Assembly 64 bits, the passing of parameters, declaration of local variables, return of functions, etc. are different from the Assembly 32-bit.
Here are some links (in English) that talk about the subject (for programming Windows
, the main is the first link):
The result, after the implementation of the programme:
inicio
Resultado C: ret1=400, ret2=6
Resultado ASM: ret1=400, ret2=6
fim.
Edit
In response to the comment, to compile a mixed code (32 and 64 bits), according to the target defined in VS2015:
- Right-click on the file
funcao.asm
and goes into Properties
. In the properties window, change (if necessary) the items: Configuration
for All Configurations
and Platform
for Win32
or Active(Win32)
(if this platform is already selected)
- Change the item
Excluded From Build
for Yes
With this change, the archive funcao.asm
will only be compiled when the platform is set to 64 bits.
In the source code, use the macro _WIN64
to define the prototype of the functions as extern
for 64bits, or with Assembly inline (for example) for 32bits.
The important point (if possible) is: maintain the prototype of identical functions for both 32 and 64bit.
After the changes, the source code in C
is as follows:
#include "stdafx.h"
#ifdef _WIN64
// Código 64 bits
// delcaração da função em assembly
extern "C" long long int formula(long long int a, long long int b, long long int *r2);
#else
// Código 32 bits
// Inline
long long int _cdecl formula(long long int a, long long int b, long long int *ret2) {
int sqa, sqb, dv;
int ret_local; // Acrescentei esta variável
__asm {
mov eax, dword ptr[a]
mul eax
mov dword ptr[sqa], eax
div dword ptr[b]
mov dword ptr[dv], eax
mov eax, dword ptr[b]
mul eax
mov dword ptr[sqb], eax
div dword ptr[a]
add dword ptr[dv], eax
mov eax, dword ptr[a]
mul dword ptr[b]
div dword ptr[dv]
mov [ret2], eax ; Aqui, o código estava incorreto
mov eax, dword ptr[sqa]
add eax, dword ptr[sqb]
mov [ret_local], eax ; Armazena o retorno
}
return (long long int) ret_local;
}
#endif // _WIN64
// Função em C que implementa o mesmo cálculo (apenas para teste)
long long int formula2(long long int a, long long int b, long long int *r2)
{
*r2 = (a*b) / (a*a / b + b*b / a);
return a*a + b*b;
}
int main(int argc, char *argv[])
{
long long int ret1;
long long int ret2;
printf("inicio\n");
// Execução em C
ret1 = formula2(12, 16, &ret2);
printf("Resultado C: ret1=%lld, ret2=%lld\n", ret1, ret2);
// Execução em Assembly
ret1 = formula(12, 16, &ret2);
printf("Resultado ASM: ret1=%lld, ret2=%lld\n", ret1, ret2);
printf("fim.\n");
getchar();
return 0;
}
Note: I just made a small correction in the code inline and added a local variable to return the function result.
The result of the execution is the same informed in the above answer.
Obs2: There are other, possibly better, ways to organize mixed code (32 and 64bits) within the Solution
VS2015. This answer is just a "starting point" to show how to compile mixed code.
Thank you. I’ll test it all out.
– RHER WOLF
It worked when compiling for x64, but not when I compiled for x86 (even putting "# ifdef _WIN64" conditional to decide whether to use "extern" or "include"). Have some way to make the compiler select which code will be used according to the architecture without giving several errors?
– RHER WOLF
Errors were (only) in compiling the file
funcao.asm
?– Gomiero
I edited the answer. Please check if it is ok :)
– Gomiero
The various errors have been associated with the "file. asm, "was probably interpreting it as C++ code because the first errors referred to post-point and comma comments.
– RHER WOLF
One thing I would like to do is use "# ifndef" in the file ". asm" and write the x86 and x64 codes there. It is possible?
– RHER WOLF
@RHERWOLF believes that it is not possible, because the formats of the objects generated for x86 and x64 are different and the pre-processor directive will only change the contents of the file and not its format. To analyze the generated format, try entering the directory where the file is
funcao.obj
and enter the commanddumpbin /all funcao.obj
. You will see that the file type is8664 machine (x64)
, therefore the Linker will not be able to connect the 64bit object with the other objects generated byC
(32bits).– Gomiero
Okay. Thanks for your help.
– RHER WOLF
@RHERWOLF You’re welcome :)
– Gomiero