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

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

• 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

• 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.

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:
• 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:
• 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:
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:
• 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.
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

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

• 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

• 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.

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.
