University of Virginia Computer Science CS216: Program and Data Representation, Spring 2006 | 04 January 2016 |
Creating a C/Assembly Project
The project we'll develop in this tutorial will consist of a main() function written in C. It will call an assembly function named clear()Create Windows-based applications by using Windows Presentation Foundation or by using Windows Forms. Also create web applications using the.NET Framework, and client applications for computers or devices that you make available through the Microsoft Store. Build your first.NET Core console application with C#. Download Visual Studio 2019 today for free: https://visualstudio.microsoft.com/vs/whatsnew/.
. Since Visual Studio does not recognize assembly code, Visual Studio will have to be told what program to call to compile the assembly code. In this section, we'll cover the basic steps of creating a project, adding assembly code to it, specifying the Custom Build instructions, and building the project.Visual Micro is an Arduino IDE compatible development tool that enables programming and debugging of many different types of microcontrollers. Arduino for Microsoft Visual Studio Community Edition and Above. Cost and confusion by using your Visual Studio Toolset and industry standard Version Control. Visual Studio Essential Training: 04 Surveying the Programming Languages with Walt Ritscher Survey the programming languages available in Visual Studio 2015, including C#, Visual Basic, C, and F#. Microsoft Visual Studio is an integrated development environment (IDE) from Microsoft. It is used to develop computer programs for Microsoft Windows. Visual Studio is one stop shop for all applications built on the.Net platform. One can develop, debug and run applications using Visual Studio.
Step 1 - Create Project
Create a standard Visual Studio .NET 2003 C++ project. You should do the same things you have been doing to create solutions: Create a new blank solution, a Visual C++ project, and scroll down to select a win32 console application. On application settings be sure to make it an empty project.Add a C source file with a main() function. For this tutorial, we will create a main() function that will call an assembler function named clear() of type void and requires no parameters. We will define clear() using assembly code in a separate file called clear.asm. Since it is in a separate file, clear() will need to be declared at the beginning of the file. Our main() function will look like this: C++ Compiler Note: If you are using a C++ compiler, it will mangle names of functions. To avoid this, use (Thanks to Gabriel Zabusek for this note.)
Step 2 - Add Assembly Code
You can add files you have created (both .c and .asm) to the source files by right clicking on the source files folder in the solution explorer and selecting add existing item. After adding both files to the source files the solution explorer should look like:Add the file that contains your assembly source code to the project. If this hasn't been created yet, you can do this by selecting FileView in the Project Window, right-clicking on the project's name and selecting 'Add files to project...' When the dialog box appears, type in the name you want the assembly code file to be saved as (in our case, clear.asm). VS will warn you that the file does not exist and ask if you want to create a reference to it in the project anyway. Select Yes. Expand the tree listing in the project window until you see the name of the assembly file (clear.asm). Double-click the file name. VS will ask if you want to create a new file with that name. Select Yes. A new file will be created and opened in the editor.
Enter your assembly code. For this tutorial, we will clear the EAX and EBX registers. To do this, we'll use this code:
Step 3 - Set Custom Build Commands
We now provide the commands that VS will use to compile the assembly code. VS does not compile assembly source code. It must call an external program named ml.exe to perform the compilation. The command line must be added to Custom Build options of the Project Settings. To do this, right-click on the assembly filename (in the picture below, this is factorial.asm) in the Project window. Select Properties... from the pop-up menu.Select the Custom Build Step folder and update the a) Command Line and b) Outputs fields:
The Command Line field. This is the actual command which will be executed to build the file factorial.asm. It requires running ml.exe (the assembler) on your input file. You need to be sure that the first part of the command actually is where you have downloaded the ml.exe file (you don't need to add the .exe extension). The following will work if you had the file ml.exe in the directory C:cs216x86: (Note that if your directory name includes any spaces, you need to enclose it in quotation marks.)After setting these two fields, hit OK and close the dialog box, and you should be ready to build.
The Outputs field. This proves the name of the file created by the build step. In this case it will be the name of the input file with an .obj file extension.
Step 4 - Compile and Link
The project may now be compiled, linked, and run like any other VS project. Press F7 to Build the project and F5 to execute the program.Debugging a C/Assembly Project
Debugging a program with assembly is a little more involved than debugging a pure C program. In particular, Step-Into (F11) will not descend into an assembly module. We must use the Disassembly Window to get around this limitation. To debug the assembly code, we will have to stop the program with a breakpoint, open the disassembly window to view the assembly code, open the register or the memory windows, and use F11 to step through the code in the disassembly window.Step 1 - Stop the Program
Place a breakpoint on the line of your code that calls the assembly routine. Run the main program by pressing F5 (Go). It will execute normally and stop when it hits the breakpoint.Step 2 - Open the Disassembly Window
Open the Disassembly Window by selecting Debug->Windows->Disassembly from the Debug menu (these menu options probably won't appear until you have run the program). You can also view the disassembly by right clicking on the C code and selecting Go To Disassembly. A new window will appear that should look like this:The Disassembly Window shows the object file assembly instructions. The actual C code we wrote is listed in black. The disassembled code is listed in grey after corresponding C statement. These are the actual assembly instructions which will be executed as the program is run. The yellow arrow, indicating the next instruction to be executed, is present in this window. The arrow, however, is not pointing to the C statement clear();, but rather to the assembly instruction 00401038 call @ILT+0(_clear) (00401005).
The Disassembly Window allows stepping through code one assembly instruction at a time.
Step 3 - Display Registers and Memory
You may want to open the Register and Memory Windows at this point. These windows provide a snapshot of what's in the CPU's registers and system's memory between execution of program instructions. Open the Register Window by selecting Debug->Windows->Registers from the Debug menu (these menu options probably won't appear until you have run the program). It should appear like this:You can see the register values for EAX, EBX, ECX, EDX, ESI, EDI, ESP, and EBP, as well as some other registers and status flags present in the processor (these registers are from a Pentium Pro; registers in other processors may be different although the 8 listed will be present). You can right click in the register window to select which registers (FP, MMX, etc.) will be displayed.
To examine memory, select Debug->Windows->Registers from the Debug menu (these menu options probably won't appear until you have run the program). It appears like this:
It provides a memory dump with the memory address on the left, the hexadecimal values of the memory contents on the right, and the ASCII representation of the hex values on the right. A particular memory location can be displayed by typing the address in the text box at the top of the window. The window shown above displays the beginning of our program. The first instruction is in memory location 0x00401020 and is 0x55. This is the hexadecimal encoding of 'push ebp'. The next six numbers on the line show subsequent memory locations. In this example, a total of seven memory locations is shown on each line in this window. Note that the window can be re-sized to change the number of bytes displayed per line. The final column is the ASCII characters for the memory locations. This will usually be garbage unless you are viewing a memory region that has text stored in it. You can right click in the memory window and adjust how the contents of memory are grouped (by 1, 2, 4, or 8 bytes) and displayed (as signed or unsigned integers, floating point numbers, hex, etc.).
Step 4 - Step through the Code
Single-step through the code using F10 (Step Over) and F11 (Step Into). The Disassembly Window will trace execution of assembly instructions with the yellow arrow pointing to the next instruction to be executed.Pressing F11 once executes the call instruction. We're now at a jmp instruction that will jump us to beginning of the clear() function. Pressing F11 again takes us to the first instruction of the clear() function. The Disassembly Window now looks like this:
Notice that the yellow arrow is pointing to the first of our two xor calls. The Registers window at this point is unchanged. Pressing the F11 key again executes the first xor statement, clearing the EAX register. The Registers window is now:
The EAX value is now 0x0. Pressing F11 again clears the EBX register. Pressing F11 again returns from the clear() function and places us below our C statement return 1;. Since we've finished debugging the crucial part of our code, we can press F5 to Go and quickly finish the program.
CS216: Program and Data Representation University of Virginia | David Evans evans@cs.virginia.edu Using these Materials |
MASM is maintained by Microsoft and is an x86 assembler that consumes Windows and Intel syntax to produce a COFF executable. It is compatible for both 16 bit and 32 bit sources. Fortunately, Microsoft’s Visual Studio IDE endorses MASM programming tasks just by making a couple of project property changes. The prime objective behind this article is to introduce the power of assembly code in terms of speed and full control over programs which are typically not seen in other programming languages. Even though there are numerous editors and software available to do such a task in a standalone way, the aspirant system or security programmers who are only limited to .NET software IDE so far can enter into the real system programming world by using none other than visual studio IDE.
Prerequisite
In this article, we would get an understanding about creating both EXE and DLL using MASM with Visual Studio. So, the newbies should to have a brief knowledge of these technologies:
- Visual Studio 2010 or Later Version
- Basic Assembly Coding Competency
[download]
Developing EXE using MASM
We shall demonstrate assembly programming by creating a simple Windows executable which typically shows “Hello World!” in a message box the moment it is initiated. It is very tricky to do such an implementation because Visual Studio 2010 IDE doesn’t offer any explicit templates for writing assembly code like C#, VC++ and VB.NET programming languages. It in fact has an in-built option to compile or run assembly programs.
Opening New Project
We shall have to create a VC++ project solution which later is accompanied with an assembly code file. Hence, open Visual Studio and choose an Empty Project of VC++ template type. There is no need to create a sub-directory for this empty solution, so uncheck the corresponding check box as follows:
Once the test_masm of VC++ type solution is created, go to the solution explorer and right click to choose Build Customization option as follows:
The Build Customization options open up the MASM compiler options which uncheck by default. This is the key option which must be enabled in order to edit and compile the native assembly code file.
Assembly Coding
As we have stated earlier, VS 2o1o doesn’t provide assembly file templates, however choose a project from the solution explorer and right click to add a text file which will be provided a *.ASM extension as follows:
Now, a blank text.asm file is added to our test_masm solution. Open it and paste the following assembly code, which is responsible for displaying a message box, as follows:
[c]
.386 ; Tells MASM to use Intel 80386 instruction set.
Visual Studio Programming Download
.model flat,stdcall ; Flat memory model
option casemap:none ; Treat labels as case-sensitive
include masm32includewindows.inc
include masm32includekernel32.inc
includelib masm32libkernel32.lib
include masm32includeuser32.inc
includelib masm32libuser32.lib
.data ; Begin initialized data segment
MsgBoxCaption db 'Win32 Assembly Programming',0
MsgBoxText db 'Hello World!!!Welcome to ASM Programming under CLR',0
.code ; Beginning of code
start: ; Entry point of the code
invoke MessageBox, NULL, addr MsgBoxText, addr MsgBoxCaption, MB_OK
invoke ExitProcess, NULL
end start
[/c]
The assembly code file is written, but keep patience, this is not ready to compile or execute because some of important project settings are still remaining.
Mandatory Project Configurations
C Programming Visual Studio Code
Successful execution of an assembly code file with Visual Studio IDE depends on an external library file, which will be available from MASM SDK. Hence, choose project Properties by right clicking it from the solution explorer. Here, choose General by expanding Linker and in the Additional Library Directories, insert the path of include, lib and macros directories as follows:
Next, come to the Input section in the Linker and mention the reference of masm32.lib file as additional dependencies:
It is not required to generate a manifest file for such manipulation, hence disable it as follows:
Now, come to System from the Linker and set Windows in the subsystem section as follows:
Finally configure the code entry point as the start from the Advanced option in the Linker, which determines the code execution flow. We can identify the entry point of the ASM file from the .code section.
Now come to the Microsoft Macro Assembly section from the solution properties which appears the moment when we add an assembly file in solution directory, otherwise it shall be hidden. Here, set the directory name where the MASM SDK was installed earlier as follows:
Finally, everything is ready and the solution is compiled. If the whole configuration is correct, then a test_masm.exe file is created in the Debug folder of the solution.
Testing and Debugging
It is time to test the executable. When the exe is clicked, a “Hello World!” message box would appear as follows:
We can even debug the assembly code by inserting a breaking point as a specific location, and through the Register window in the Debug menu, we can observe all the CPU registers with corresponding flags as follows:
We shall cover the advanced debugging of an application in later articles. The following image shows the assembly code in debug mode which helps us to understand what is happening behind the scenes.
Although this section is not relevant to this article, but just for knowledge point view, we can disassemble any C++ file to its corresponding ASM code. The Visual Studio IDE is inbuilt with a Disassembly option, which is very helpful to detect a run time bug such as buffer overflow in the code via converting the source code file to an assembly code file as follows:
Developing DLL using MASM
In the previous section, we have seen how to create an EXE file using MASM with VS 2o10. We can also develop a library (DLL) by using MASM programming much like other technologies such as C#, VB, and C++. Therefore, the method can be utilized in the other client application in that created DLL. The procedure of generating a DLL is almost the same as EXE but requires some subtle configuration. First of we have to set Configuration type as DLL in the General section because now we are dealing with DLL. Such modification can happen from solution properties as:
And as we all know, DLL files are libraries which contain method definitions. Entry point is typically absent in the DLL file. Hence we have to change this setting as follows:
Finally, add a text file as masmlib with ASM extension in the solution like earlier and place the following code, which typically contains a testing method which will show some alert during the load and unload of DLL in the client program as follows:
[plain]
include masm32includemasm32rt.inc
.data
dLoading BYTE 'HELLO ,DLL is Loading…..', 0
dUnloading BYTE 'DLL is un-loading.???????', 0
dOrdinal BYTE 'Good-Bye', 0
.data?
hInst DWORD ?
.code
testingMethod proc hInstDLL:DWORD, fdwReason:DWORD, lpvReserved:DWORD
.if fdwReason DLL_PROCESS_ATTACH
invoke MessageBox, HWND_DESKTOP, offset dLoading, NULL, MB_OK
push hInstDLL
pop hInst
mov eax, TRUE
ret
.elseif fdwReason DLL_PROCESS_DETACH
invoke MessageBox, HWND_DESKTOP, offset dUnloading, NULL, MB_OK
.elseif fdwReason DLL_THREAD_ATTACH
.elseif fdwReason DLL_THREAD_DETACH
.endif
Visual Studio Programming
ret
testingMethod endp
ProcByOrdinal proc
invoke MessageBox, NULL, offset dOrdinal, NULL, NULL
ret
ProcByOrdinal endp
end testingMethod
[/plain]
Finally, compile this program and test_masm_dll. The DLL file would be created in the Debug folder which can referenced in the C++ program or in the MASM client program itself.
Final Note
So, we have seen how to create both EXE and DLL files using MASM programming languages employed with visual studio IDE. In fact, such a task could be achieved by hard-core MASM SDK but .NET programmers typically fear assembly programming due to strange syntax and platforms. Assembly language programming opens a new horizon of advance coding in terms of faster code executing, exploit writing and shell-coding. Programmers are often comfortable with Visual Studio due to having numerous in-built features and functionality. Hence, this article is dedicated to those professionals who are planning to shift towards system programming without leaving the .NET framework.