Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C# » How To » Revisions
 
Go to top

Mixing .NET and Assembly Language in a standalone 64-bit exe

, 14 Oct 2011
Rate this:
Please Sign up or sign in to vote.
This article deals with building a standalone 64-bit .NET .exe file that is statically linked with an Assembly Language compiled object file.
This is an old version of the currently published article.

Introduction  

The technique of building a standalone .Net executable when there is a mix of managed and unmanaged code has been first explained by Steve Teixeira in http://blogs.msdn.com/b/texblog/archive/2007/04/05/linking-native-c-into-c-applications.aspx, which you are strongly recommended to read if this is new for you.

Our article uses that technique, but we will be building a 64-bit only program. The reason is that we are going to statically link compiled 64-bit Assembly Language (or ASM) which is CPU dependent. You will have to take that into account when configuring the platform target on your .Net projects.

asmwnet1.jpg 

asmwnet2.jpg

Using the code

1) Assembly Language

 I developed two ASM routines that will be called from .Net. One performs a small Math calculation using SSE2 instructions. The other is a very fast encryption/decryption routine using the XXTEA alghorithm (http://en.wikipedia.org/wiki/XXTEA). The XXTEA alghorithm is a very strong encryption alghorithm, but not to be used when the security of a nation depends on it because a small number of people appear to know how to attack it. Anyway, we are not going to discuss cryptography here. 

The routine that performs the Math calculation sin(val1^2 / val2) is shown below, just small like this:  

; Calculates sin(val1^2 / val2)
;double AsmMathCalc (double val1, LONGLONG val2);
AsmMathCalc proc FRAME val1:MMWORD, val2:SQWORD
	mulsd xmm0, xmm0 ; val1^2
	cvtsi2sd xmm1, rdx
	divsd xmm0,xmm1        
	call sin
	ret ; result is returned in xmm0
AsmMathCalc endp
		

The routine that performs the encryption/decryption is not shown here due to its length, you  need to download to see it. It opens the file to be encrypted (or decrypted) and creates a file for the encrypted (decrypted) output. Then reads and encrypts (or decrypts) in chunks and writes to the new file. Encrypted files are saved with the extension ".enc" added to the full file name, decrypted files add the extension ".dec". Note that XXTEA works with 32-bit words, if the file length in bytes is not divisible by 4, we have to send more "4-filesize modulo 4" bytes to make up for the difference.  

 2) C++/CLR code to interop with the ASM 

My approach was to create a classe library C++ project. Then I placed the parts dealing with the managed code and unmanaged code in separate source code files.

Managed code: 

// CInterop.h

#pragma once
#include "native.h"

using namespace System;

namespace CInterop {

	//public ref class ASMCallingClass ; only for testing when compiling as library
	ref class ASMCallingClass
	{
		public :
		static double ASMMathCalc(double val1, LONGLONG val2)
		{
			return runAsmCalc(val1, val2);
		}
		static int ASMXXTea(LPWSTR fileName, LPDWORD Key, BOOL encode)
		{
			return runAsmXXTea(fileName, Key, encode);
		}
	};
}
		

Unmanaged code: 

//native.cpp

#include "Stdafx.h"

	extern "C"
	{
		double AsmMathCalc (double val1, LONGLONG val2);
		int AsmXXTEAEncDec(LPWSTR val1, LPDWORD val2, BOOL val3);
	}

	double runAsmCalc(double val1, LONGLONG val2)
	{
		return AsmMathCalc(val1, val2);
	}
	int runAsmXXTea(LPWSTR fileName, LPDWORD Key, BOOL encode)
	{
		return AsmXXTEAEncDec(fileName, Key, encode);
	}
		

Just for testing purposes you can add the ASM compiled object file to Properties\Linker\INput\Additional Dependencies, but this will not be used in the final building process because we will build all from the command line. 

3) C# Windows Forms Application

In this project add a "using" clause for the C++/CLR namespace. If you have built the C++/CLR class library, you can test now if all is working. If it does not, make public the class ASMCallingClass in the interop project and rebuild the library.

Building 

You have three projects in total: The ASM project, the C++/CLR interop project and the C# project.

To be able to build a single executable, you need to compile in dependency order. Native code first, second the interop code and finally the 100% managed code.

Open a console Window with the environment set for Visual Studio x64 compilations, (in the Start menu you may find Visual Studio x64 Win 64 Command Prompt, which is what we need). 

1) Compile the ASM with with the JWasm compiler:

 <path>\jwasm -c -win64 -Zp8 asmrotines.asm

Note: There are a number of programs able to compile source code Assembly Language, they are called Assemblers. The most popular is MASM from Microsoft. I have not used ML64 (64-bit MASM) though, because it does not support the "invoke" directive in 64-bit mode (and "invoke" speeds up the coding process quite a bit) but JWasm is backward compatible with MASM, so it is easy to make this code compile with ML64 by replacing the "invoke" directives. 

You must test the ASM rotines while you code them, because it is very easy to insert bugs in ASM. There are various ways of doing that. For my demo program, I just linked the asmrotines.obj with a test program written in C, under Visual Studio. The reason is that Visual Studio C++ IDE has a built-in disassembler and you can single step the ASM instructions.

2) Copy the compiled ASM file, asmrotines.obj, to the folder where are the source files of your C++/CLR interop project and change your console window to that folder.

3) Compile the native code source file, which has the "native.cpp" name in our project. The command line is:

cl /c /MD native.cpp

The C/C++ compiler will generate the object file "native.obj" 

4) Now, compile the managed file, "CInterop.cpp" in our project with the following command line:

cl /clr /LN /MD CInterop.cpp native.obj asmrotines.obj

The /clr switch generates mixed mode code, /LN creates a .netmodule and /MD links with MSVCRT.LIB. Because this module contains a reference to the native code, we also need to pass native.obj and asmrotines.obj so that this file can be passed through to the link line when the compiler invokes the linker to produce the .netmodule. This is basically the explanation given by Mr. Steve Teixeira. 

5) Now, copy to the folder where the C# files are, asmrotines.obj, CInterop.obj, native.obj, and CInterop.netmodule and change the console window to that folder.

6) Run the C# compiler with the following command line:

csc /target:module /unsafe /addmodule:cinterop.netmodule Program.cs Form1.cs Form1.Designer.cs  Properties\AssemblyInfo.cs

7) Finally, run the Microsoft Linker to link together all the parts we have been building along the way.

link /LTCG /CLRIMAGETYPE:IJW /ENTRY:Charp.Program.Main /SUBSYSTEM:WINDOWS /ASSEMBLYMODULE:cinterop.netmodule /OUT:NetAndAsm.exe cinterop.obj native.obj asmrotines.obj program.netmodule 

And that's all about it! 

FAQ 

Q: Any sample but for Mixing .NET and Assembly Language in a standalone 32-bit exe ?

A: The same sample, but for 32-bit is in my websiste at: http://www.atelierweb.com/articles/NetAndAsm32.htm 

History 

Initial release, 11th October 2011
12th October, fixed a bug (the  standalone was asking for the .netmodule). Not anymore
14th October, fixed bug in ASM at CreateFileW (error returns INVALID_HANDLE_VALUE, not zero).    

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Jose A Pascoa
AtelierWeb Software
Portugal Portugal
Jose Pascoa is the owner of AtelierWeb Software (http://www.atelierweb.com) and Open Source Penguindow Valley (http://www.ospv.com). We produce security and network software and mixed utilities since 1999. The first program I published (in a BBS) was a MS-DOS utility, had the size of 21 KB and was done in Assembly Language. Nowadays, my low level languages are more likely to be "C", "C++" and "Delphi" rather than Assembly Language but I still like it. I have nothing against more fashionable languages like C# and technologies like WPF, actually I have played with them and published software with them.
Follow on   Twitter

Comments and Discussions


Discussions posted for the Published version of this article. Posting a message here will take you to the publicly available article in order to continue your conversation in public.
 
QuestionMy Vote of 5 PinmemberRaviRanjankr20-Nov-11 4:20 
AnswerRe: My Vote of 5 PinmemberJose A Pascoa20-Nov-11 9:32 
GeneralMy vote of 4 PinmemberMario Majcica14-Oct-11 7:00 
GeneralRe: My vote of 4 PinmemberJose A Pascoa14-Oct-11 7:37 
GeneralMy vote of 5 PinmemberOliver Mantl DSc12-Oct-11 5:59 
GeneralRe: My vote of 5 PinmemberJose A Pascoa12-Oct-11 10:26 
GeneralMy vote of 5 PinmemberSergio Andrés Gutiérrez Rojas11-Oct-11 6:42 
GeneralRe: My vote of 5 PinmemberJose A Pascoa11-Oct-11 10:11 
GeneralMy vote of 5 PinmemberUSABebopKid11-Oct-11 5:49 
GeneralRe: My vote of 5 PinmemberJose A Pascoa11-Oct-11 10:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 14 Oct 2011
Article Copyright 2011 by Jose A Pascoa
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid