If you saw my presentation at DevConf you may have gotten curious and want to play with assembly language yourself. Setting up Visual Studio for compiling and debugging Intel assembly is not hard, but not straightforward. Hence, this short tutorial. I’ll show you simple setup with C file as an entry point and small assembly “library”.
Project setup
1. Create new project – C++ Win32 Console Application
2. On a first screen click Next, as we want into pick some custom settings. On the second mark “Console Application” and “Empty Project”. For this simple example, we won’t need any default Windows headers. Click “Finish”.
3. Right-click on the project, “Add” -> “New Item…”. Pick C++ file, but rename it to .c, for example “source.c”.
4. Add another file in a similar way and also rename it – to “lib.asm”. What names you pick doesn’t really matter, as long as C and ASM file have different. Add also header file. Name it for example “header.h”. Your project should have a similar structure to this:
5. Right-click on the project, “Build Dependencies” -> “Build Customizations…”. Mark “masm” as selected. This adds Microsoft Macro Assembler into the build.
6. Right-click the assembly file (lib.asm), “Properties”. Item type most likely says “Does not participate in build”. Change it to Microsoft Macro Assembler.
Code
Now let’s add simplest possible code to make it run. First assembly file. This code declares simple multiplication function that takes two arguments.
;;lib.asm .386 PUBLIC _multiply _CODE SEGMENT dword public 'CODE' use32 ASSUME CS:_CODE _multiply PROC near push ebp mov ebp, esp push ebx mov eax, [ebp+12] ;; second argument mov ebx, [ebp+8] ;; first argument imul eax, ebx ;; multiplying; lower 32 bits -> eax; ;; higher -> edx pop ebx pop ebp ret _multiply ENDP _CODE ENDS END
Then let’s add the header, so we can use this function:
#pragma once int multiply(int a, int b);
And for the finish, the C file that will call our function:
#include "header.h" int main(int argc, char *argv[]) { int a = 3; int b = 2; int mult = multiply(a, b); return 0; }
Debugging
Now you’ll be able to debug it like every other application in visual studio. You can set breakpoints and even Watches to see what’s in registers:
One problem, that I’ve noticed happening quite often, is that Visual Studio doesn’t notice changes made in the .asm file and do not recompile the project. I found that a good way to force it is to change target CPU for something different, build, change back to our preferred settings and rebuild again.
Resources
Intel® 64 and IA-32 Architectures Software Developer’s Manual
This x86 Assembly guide at University of Virginia CS
Good luck with your experiments and exploring your computer’s architecture!
Thanks very much! Easy and quick to setup!
#pragma once
extern “C” int multiply(int a, int b); //add more keyword extern “C” to fix LNK2019 unresolved external symbol “int __cdecl multiply(int,int)” (?multiply@@YAHHH@Z) referenced in function _main