Springen naar inhoud


Tutorial info

  • Toegevoegd op: 12 jul 2011 12:31
  • Bekeken: 2458
 


* * * * *
0 Beoordeling

Mix Assembly with Managed.

Geplaatst door pascalbianca op12 jul 2011 12:31
Contributed by : Vozzie op 09-01-2010

Achtergrond

Onlangs begon ik opnieuw te spelen in assembly.
Ik botste tegen Microsoft C voorbeelden hoe assembly te mixen met C.
Nu heb ik geprobeerd of dit ook werkt voor Managed C++.
Nou, dat doet het! Deze tutorial toont het instellen van een minimale project dat beide Managed(.Net) en Unmanaged(Assembly) code.
Zo'n project kan om verschillende redenen nuttig zijn, zoals het toevoegen van een bestaande assembly procedure aan een project of sommige delen te beschermen tegen .net decompilers zoals ildasm, Reflector enz…
Mijn reden was om iets te leren.

Introductie

Een geweldig hulpmiddel om te leren van één of andere assembly is MASM32 SDK.
Er is zoveel te ontdekken en ik ontdekte dat MASM32 SDK met behulp van een Linker(ml.exe) van Microsoft (versie 6.14.8444) werkt.
Nu verstuurd Visual Studio ml.exe mee.
Dit zijn de versies die ik ontdekt had op mijn computer…
• Visual Studio 2002
Versie: Microsoft ® Macro Assembler Version 7.00.9466
Locatie: C:\Program Files\Microsoft Visual Studio .NET\Vc7\bin
• Visual Studio 2003
Versie: Microsoft ® Macro Assembler Version 7.10.3077
Locatie: C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin
• Visual Studio 2005
Versie: Microsoft ® Macro Assembler Version 8.00.50727.762
Locatie: C:\Program Files\Microsoft Visual Studio 8\VC\bin
• Visual Studio 2008
Versie: Microsoft ® Macro Assembler Version 9.00.30729.01
Locatie: C:\Program Files\Microsoft Visual Studio .NET\Vc7\bin
Op zoek naar een manier om MASM te gebruiken in Visual Studio heb ik voorbeelden gevonden van microsoft (location: C:\Program Files\Microsoft Visual Studio 9.0\Samples\1033\)
Deze tutorial is gedaan zowel voor Visual Studio 2005 en 2008.
Geen bevestiging als het werkt met 2010 maar is wel welkom.

Maken van het project.

• Open Visual Studio, Menu File-> Click New-> Click Project
• Selecteer  “Visual C++” -> Selecteer  CLR -> Selecteer  CLR Console Application
• Geef een naam aan het  project( ik gebruik  MixMasMan), Selecteer  de locatie en klik OK

Geplaatste afbeelding

Het assembly-bestand toevoegen.

• Het is mogelijk om een aangepaste sjabloon "projectitem" te maken maar een gemakkelijke manier om een Assembly-bestand toe te voegen is het creëren van een assembly-bestand in de project...
• In de solution explorer onder het project rechtermuis klik op Source Files -> Add ->klik New Item -> in het dialog selecteer Text File(.txt) -> voor naam geef in MasmProcs.asm -> klik OK
• In de solution explorer onder het project met de rechtermuisknop op bronbestanden-> toevoegen-> klik op nieuw Item-> in het dialoogvenster Selecteer tekst File(.txt)-> voor naam invoeren MasmProcs.asm-> Klik op OK

Geplaatste afbeelding

• Klik met de rechtermuisknop op de MasmProcs.asm file in the solution explorer -> klik Exclude from project
• Klik met de rechtermuisknop op Source Files -> Add -> klik Existing Item -> selecteer de MasmProcs.asm bestand -> klik OK
• Een Matching Custom Build Rules dialoog verschijnt(als men niet  configuring the build rules manually ziet) -> selecteer MASM -> klik OK

Geplaatste afbeelding

• Om te zien als alles goed ging, klik met de rechtermuisknop de MasmProcs.asm bestand opnieuw, klik op Eigenschappen, er moet een configuratiesectie Microsoft Macro Assembler zijn.

Geplaatste afbeelding

Als die sectie er is, dan is het bestand klaar om te compilen, maar als dit zou mislukken is het mogelijk om de build rules manueel te configureren.

Configureer de build rules manueel

Voer deze stappen uit wanneer de configuratiesectie Microsoft Macro Assembler niet zichtbaar onder de bestandseigenschappen is, anders ga verder met het "toevoegen van code."
Een van de twee stappen is genoeg, de tweede stap is alleen wanneer bronbrowser informatie is gewenst.
• Klik met de rechtermuisknop op MasmProcs.asm bestand, klik op Eigenschappen, selecteer custom build step.
1. Om alleen een Object file (.obj bestand) te hebben.
Voor Debug:
CommandLine: ml -c -Zi “-Fl$(IntDir)\$(InputName).lst” “-Fo$(IntDir)\$(InputName).obj” “$(InputPath)”
Omschrijving: Assembling “$(InputPath)”
Outputs: $(IntDir)\$(InputName).obj
Voor Release:
CommandLine: ml -c “-Fl$(IntDir)\$(InputName).lst” “-Fo$(IntDir)\$(InputName).obj” “$(InputPath)”
Omschrijving: Assembling “$(InputPath)”
Outputs: $(IntDir)\$(InputName).obj
2. Om ook de “Source Browser information” (.sbr file) te hebben.
Voor Debug:
CommandLine: ml -c -Zi “-Fl$(IntDir)\$(InputName).lst” “-FR$(IntDir)\$(InputName).sbr” “-Fo$(IntDir)\$(InputName).obj” “$(InputPath)”
Outputs:
$(IntDir)\$(InputName).obj
$(IntDir)\$(InputName).sbr
Voor Release:
CommandLine: ml -c “-Fl$(IntDir)\$(InputName).lst” “-FR$(IntDir)\$(InputName).sbr” “-Fo$(IntDir)\$(InputName).obj” “$(InputPath)”
Outputs:
$(IntDir)\$(InputName).obj
$(IntDir)\$(InputName).sbr
Als u wilt meer weten over de commandline argument, gebruik "ml /?" in een MS-DOS-prompt.

Toevoegen van code

• Dubbel klik op het bestand MasmProcs.asm, en plak onderstaande code.
Code:
;File: MasmProcs.asm
 .386
.MODEL FLAT
 
.CODE
 
masm_add PROC STDCALL PUBLIC i1:DWORD, i2:DWORD
	; move i1 into eax
	mov eax, i1
	; add i2 to eax
	add eax, i2
	; return
	ret
masm_add ENDP
 
masm_enc PROC STDCALL PUBLIC s:DWORD,x:DWORD
	; xor eax to zero
	xor eax, eax
	; put string ptr in ecx
	mov ecx, s
	; put xor char in edx
	mov edx, x
@@:
	; end of string?
	cmp WORD PTR[ecx], 0
	; if end, jump forward to @@
	jz @F
	; xor one char(2 bytes)
	xor WORD PTR [ecx], dx
	; increment eax
	inc eax;
	; add 2 to ecx, point to next char
	add ecx, 2
	; jump back to @@
	jmp @B
@@:
	RET
masm_enc ENDP
 
masm_dec PROC STDCALL PUBLIC s:DWORD,x:DWORD,l:DWORD
	; put length in eax
	mov eax, l
	; put string ptr in ecx
	mov ecx, s
	; put xor char in edx
	mov edx, x
@@:
	; if eax is zero, jump to @@ forward
	or eax, eax
	jz @F
	; xor one char
	xor WORD PTR [ecx], dx
	; decrement eax
	dec eax
	; add 2 to ecx, point to next char
	add ecx, 2
	; jump back to @@
	jmp @B
@@:
	ret
masm_dec ENDP
 
masm_call PROC STDCALL PUBLIC pCallback:DWORD
	; set eax to 1
	mov eax, 1
@@:
	; push eax on stack, to remember it
	push eax
	; push eax on stack, as argument
	push eax
	; call the callback
	call pCallback
	; get our value stored on the stack
	pop eax
	; increment it
	inc eax
	; compare it with 11
	cmp eax, 11
	; if it's not equal, jump to first @@ label back
	jne @B
	ret
masm_call ENDP
 
END

• Voeg een header met prototypes toe om de andere modules te laten weten over de functies.
Om dit te doen, klik met de rechtermuisknop Header Files -> klik  Add ->klik  New Item -> selecteer Header File(.h) -> noem het MasmProcs.h -> klik OK
• PLaats onderstaande code in MasmProcs.h

Code:
//File: MasmProcs.h
// only include once
#pragma once 
 
// prototypes
int __stdcall masm_add(int,int);
int __stdcall masm_call(int);
int __stdcall masm_enc(wchar_t*,int);
int __stdcall masm_dec(wchar_t*,int,int);

• Nu voeg  MasmProcs.h toe in het stdafx.h bestand, di tom de andere modules te laten weten over de functies.
Nu voeg stdafx.h in iedere cpp bestand wat we willen gebruiken om voor assembly procedures(Dit wordt gedaan door visual studio automatisch wanneer een cpp-bestand word toe gevoegd.)
Om stdafx.h bestand aan te passen, dubbel klik het, en plaats onderstaande code erin.
Code:
//File: modify stdafx.h
// include only once
#pragma once
 
// included for PtrToStringChars
#include <vcclr.h>
 
extern "C" {
	#include "MasmProcs.h"
	//#include <windows.h>
}
Opmerking het extern "C" blok waar de MasmProcs.h opgenomen is.
Dit is om te controleren of er geen naam decoration is en kan worden genoemd als een normale api.
Dat is waarom windows.h in dergelijke extern "C" blok moet om de header in een beheerde project te kunnen gebruiken.
• De laatste stap is het wijzigen van de toepassing ingangspunt "MixMasMan.cpp".
Om te  wijzigen, dubbelklik erop in het project en zet de code hieronder in.

Code:
//File MixMasMan.cpp
#include "stdafx.h"
 
using namespace System;
using namespace System::Runtime::InteropServices;
 
// A Managed class holding a managed method that will be called from assembly
ref class CallbackWrapper
{
public:
	CallbackWrapper(void)
	{
	}
 
	System::Int32 MyCallback(System::Int32 i)
	{
		Console::WriteLine(String::Format("Callback: {0}", i));
		return 0;
	}
};
 
// A managed delegate type (callback), to convert into a unmanaged ptr
public delegate System::Int32 ManagedCallback(int); 
 
int main(array<System::String ^>^ args)
{
	// Call the masm_add procedure
	System::Int32 i1 = 10;
	System::Int32 i2 = 20;
	System::Int32 iResult = masm_add(i1, i2);
	Console::WriteLine(String::Format("Result: {0}", iResult));
 
	// Ask the user to enter some text
	System::String^ sResult = "";
	while(sResult == String::Empty){
		Console::Write("Please enter some text: ");
		sResult = Console::ReadLine();
	}
 
	// Call the masm encode and decode procedures,...
	// Pin our string so it doesn't get garbage collected
	pin_ptr<const wchar_t> pVal = PtrToStringChars(sResult);
	System::Int32 iSize = masm_enc((wchar_t*)pVal, 31);
	Console::WriteLine(String::Format("Encoded string: {0}", sResult));
	Console::WriteLine(String::Format("String length: {0}", iSize));
	masm_dec((wchar_t*)pVal, 31, iSize);
	Console::WriteLine(String::Format("Decoded string: {0}", sResult));
 
	// Create a instance of a managed class that holds the callback
	// This could be a VB.Net class too
	CallbackWrapper ^cw = gcnew CallbackWrapper();
	// Prevent our delegate from being garbage collected
	GCHandle gch = GCHandle::Alloc(cw);
	// Make a instance of the ManagedCallback delegate and pass it our callback method
	ManagedCallback ^mc = gcnew ManagedCallback(cw, &CallbackWrapper::MyCallback);
	// Get a pointer to the delegate
	IntPtr umc = Marshal::GetFunctionPointerForDelegate(mc); 
	// call the assembly procedure
	masm_call(umc.ToInt32());
	// Free the delegate
	gch.Free();
 
	Console::WriteLine("Press a key to quit...");
	Console::ReadKey();
	return 0;}

• Het project is nu klaar.

Wanneer we hem nu starten, lijkt het erop dat het zelfs mogelijk versterkt door middel van de assembly -code in Visual Studio.
Het programma roept eerst een eenvoudige routine die 2 gehele getallen resultaat toont.
Vervolgens een tekenreeks om te coderen en de lengte van de tekenreeks als een retourwaarde krijgt.
De tekenreeks wordt vervolgens gedecodeerd.
De codering en decodering routines zijn vrij eenvoudig.
Eindelijk een functiepointer naar een beheerde functie wordt doorgegeven aan de procedure van de assembly en die procedure roept de managed methode.

Geplaatste afbeelding

Inloggen


Untitled 1

Met dank aan Jürgen voor de jarenlange inzet van visualbasic.be (anno dec 2000)
Met dank aan Mike en Ronneke voor de jarenlange inzet van vbib.be (anno dec 2010)
Met dank aan PascalBianca voor de jarenlange inzet van vbib.be (anno dec 2016)