Reversing
26 February 2011 6 Comments

Assembler Tutorial: Hello World with NASM and CL.EXE or LINK.EXE

Introduction

If learning assembler with the NASM.exe assembler peaks your interest, you might be interested in this extensive tutorial by Paul Carter. Annoyingly, finding a linker on Windows that plays nice with NASM took me a while. The tutorial by P. Carter is not very clear on this matter. I wanted to use the linker link.exe that comes with Visual Studio 2010, because the free DJGPP linker that is mentioned by Mr Carter generates badly formatted .exe files. In this post I will show how to compile and link a Hello World assembler program with nasm.exe and link.exe.

Compiling Assembly Code

Let’s compile and link this Hello World program (courtesy of Ray Toal) in a file named helloworld.asm.

; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
 
global  _main
extern  _printf
 
section .text
_main:
push    message
call    _printf
add     esp, 4
ret
message:
db      'Hello, World', 10, 0

As you can see we use the printf() function to print the text “Hello, World”. This function is marked as extern, because it is an imported function (it resides in the C Runtime Library).

The tutorial by Paul Carter provides a command for assembling example code in the file asm_io.asm:

; To assemble for Microsoft Visual Studio
 
; nasm -f win32 -d COFF_TYPE asm_io.asm

Unfortunately, this syntax is incorrect. The -d switch seems to be deprecated in my NASM version (2.09.04) : it does not do anything. The indicated filetype win32 does seem to be correct–it denotes the win32 object file format, which makes sense.

The correct command for compiling the helloworld.asm file is:

nasm -f win32 helloworld.asm

With this command NASM generates a file called helloworld.obj. Now we must use a linker to link the .obj file into a .exe file. Open the Visual Studio Command Prompt and type:

link.exe helloworld.obj libcmt.lib
 
// or
 
cl.exe helloworld.obj /link libcmt.lib

The printf() function is statically included through libcmt.lib, which contains the C Runtime Library. You get an error if you omit it: error LNK2001: unresolved external symbol _printf

Now you can run helloworld.exe to test your program.

Further Info

  • There are other ways to create an assembler program that prints to the screen: you can use the deprecated DOS API (using interrupts), or omit the C runtime library and directly call the Windows API. Read this stackoverflow thread for more info.
  • If you use Microsoft’s MASM assembler solution in VS2010 (ml.exe) to create an object file, you can just call link.exe helloworld.obj without mentioning libcmt.lib. How is this possible? The .obj file generated by MASM contains a .drective section, which contains linker directives. These directives reference libcmt.lib, and link.exe includes libcmt.lib as a result. So the file is still included by the linker, but you don’t have to worry about it!

6 Responses to “Assembler Tutorial: Hello World with NASM and CL.EXE or LINK.EXE”

  1. Fazliddin 16 June 2011 at 6:21 am #

    Hello Mr. Art0. Your tutorial is turned out to be very useful for me. I dug internet looking for usage of cl tool for two month, but could not find any precise tutorial. Microsoft’s official documentation do not describe matter properly.

    Thank you.

    With regards Fazliddin.

  2. troyknudson 9 August 2011 at 3:30 am #

    Great tutorial!!

    • tboerman 9 August 2011 at 10:37 am #

      Thank you!

  3. despatricio 21 September 2011 at 11:22 am #

    My apologies for this very amateur question.

    With win7 64 ultimate and Visual Studio 2010 (full package) installed, do I need to set a PATH to use cl.exe or link.exe with NASM from the command line?

    Your help is greatly appreciated.

    • tboerman 22 September 2011 at 10:22 pm #

      As you probably understand, if you want to call an EXE file without specifying its full path on the command line, then it has to be either in the current directory directory of cmd.exe, or the directory must be in the PATH environment variable.

      If you use the Visual Studio Command Prompt then the PATH will automatically contain the location of cl.exe. However, to call nasm.exe from any directory as well, you are correct that you need to add it to the PATH variable manually. Restart cmd.exe afterwards, and use the set command to look at your current environment variables and check that it worked!

  4. Ahmed 28 June 2012 at 8:47 am #

    I Just Want To Say Thank You Very Much