Summary
In this blog post I’m going to demonstrate how to create an assembly language subroutine and call it from a C++ program.
Assembly Language
It’s been a few years since I’ve created any assembly language. In fact, the last time I wrote a real assembly language program the tool to use was Borland’s Turbo Assembler in DOS. Those were the good ol’ days.
So I was browsing the web looking for a subject to blog about and I stumbled across this article about writing assembly in Visual Studio. The web page is old (i.e. Visual Studio 2003 days) and it was setup for a computer science class at the University of Virginia. They probably forgot that the page exists and I’m betting that it doesn’t connect to their website. Google didn’t forget. So here’s the link: Guide to Using Assembly in Visual Studio .NET.
I ran into a couple of issues with the instructions. First, $(InputPath) has been deprecated. It’s now $(ProjectPath) and $(InputName) has been depricated and has been replaced by $(ProjectName). Even with these changes the build does not work. So I coded the name of the file since it is attached to the property of that file.
Here’s what my settings look like:
Assembly File Setup
Here are the step-by-step instructions for setting up an asm file in your c++ program.
Step 1: Create a C++ Project
I’m using Visual Studio 2013 in this example. Go to File -> New -> Project. Then you’ll need to go to “Other Languages” and open the “Visual C++” branch. Click on the Win32 branch and click on “WIn32 Console Application”:
Give your project a name and click the “OK” button.
Next, you’ll have to right-click on the source files directory and create a new CPP file (add -> new item -> C++ File), name it “main.cpp”.
Now paste this main program in the main.cpp file:
extern "C" { void clear(); } int main(int argc, char *argv[]) { clear(); return 1; }
We’re going to create an assembly program with a function named “clear”, which explains the “extern” directive. You can name your functions anything you like, but you’ll need to change the extern directive to match.
Step 2: Add Assembly Code
Right-click on the source files folder again and add a text file (you can add another cpp file and just change the filename). Name the file factorial.asm.
Copy and paste this assembly code from the University of Virginia example that clears the EAX and EBX registers:
.586 ;Target processor. Use instructions for Pentium class machines .MODEL FLAT, C ;Use the flat memory model. Use C calling conventions .STACK ;Define a stack segment of 1KB (Not required for this example) .DATA ;Create a near data segment. Local variables are declared after ;this directive (Not required for this example) .CODE ;Indicates the start of a code segment. clear PROC xor eax, eax xor ebx, ebx ret clear ENDP END
Step 3: Setup Custom Build Commands
Right-click on your asm file and select “properties”. You’ll see a Configuration Properties setup. Change the Item Type to “Custom Build Tool” and Content to “Yes”:
You’ll see a new tree branch created on the left side of the window that has a “Custom Build Tool” branch. Once that appears, you can click on it to enter your build parameters:
You can copy this line and paste it into the Command Line of your window:
"C:Program Files (x86)Microsoft Visual Studio 12.0VCbinml" /c /Cx /coff factorial.asm
That assumes that you installed Visual Studio 2013 with the default install settings. Make sure you set your “Outputs” to “factorial.obj” because that will be the name of the file that hte linker expects. Also, change “Link Objects” to “Yes”. Apply your changes.
Now you should be able to build and run your application.
Troubleshooting
As the University of Virginia article mentions, troubleshooting requires you to put a breakpoint on the clear(); command in the c++ main file. Then run your program to that point. Next open the disassembly window (Debug -> Windows -> Disassembly).
To see the CPU registers, you’ll need to open the Registers window (Debug -> WIndows -> Registers).
I shrunk the width of the registers window to force the registers to wrap vertically. When you’re viewing the disassembly window you can use F11 to step into your assembly function and F10 to step through each assembly instruction. Your Registers window will show changes to the CPU registers by turning them red:
Also, you can right-click inside the Registers window to add MMX registers and other data points.
You can also right-click on the disassembly window and show line numbers. This will show the line numbers that occur in the C++ program itself.
Here’s the actual assembly program which clears the EAX and EBX by Xoring each register with itself, followed by a return:
Summary
Intel has an introduction to x64 assembly language, click here.
For the assembly language reference, click here.
University of Virginia currently has a good intro for x86 assembly, click here.