0% found this document useful (0 votes)
45 views2 pages

NASM Assembly Tutorial for Windows

This document is a quick tutorial on using the Netwide Assembler (NASM) for writing and disassembling assembly programs. It provides step-by-step instructions on writing assembly code, assembling it into machine code, and using tools like ndisasm and objdump for disassembly. The tutorial emphasizes the importance of using the correct directives and syntax for successful assembly and disassembly processes.

Uploaded by

nightmarepuma
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
45 views2 pages

NASM Assembly Tutorial for Windows

This document is a quick tutorial on using the Netwide Assembler (NASM) for writing and disassembling assembly programs. It provides step-by-step instructions on writing assembly code, assembling it into machine code, and using tools like ndisasm and objdump for disassembly. The tutorial emphasizes the importance of using the correct directives and syntax for successful assembly and disassembly processes.

Uploaded by

nightmarepuma
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

NASM Quick Tutorial

REVA

Introduction
It may be useful to write your own assembly programs, assemble them, and then inspect the
output as an aid when learning the (dis)assembly process. The Netwide Assembler (NASM) is
recommended as it’s cross-platform and freely available from the NASM site:
[Link]

Tutorial
1. Use your favorite text editor to start writing assembly. The top of your file should include
the directive [BITS 32] to let nasm know it should compile using 32-bit code.

2. Follow the BITS directive with a directive to indicate that the next section should be con-
sidered “text”, which indicates executable code in this context. Use the section .text
directive to indicate this. This is not entirely necessary, but it shows you how to move
data into different sections.

3. Begin writing valid assembly! See below for an example.

[BITS 32] ; BITS directive

section .text ; section directive to indicate executable 'code'

push ebp
mov ebp, esp
lea esi, [ string ]

string:
db 'hello world',0xd,0x0
end_string:
Figure 1: View of the assembly that was hand-written

4. (Assuming Linux but Windows is similar). To assemble your newly created assembly to
machine code, run the following:
nasm ex2.S -o ex2

5. Assuming your syntax was correct, a new file named ex2 should be created. It is also
created in a format that your disassembler will be able to handle.
6. You can then use the ndisasm utility to disassemble your code to see what it looks like.
You can use the -u or -b 32 to force 32-bit disassembly. See below for an example.
Notice that the disassembly from address 0x00000009 and beyond is jibberish. This is
because ndisasm is a linear sweep disassembler and it is trying to disassemble the string
“hello world”.

user@reva:~/$ ndisasm -u ex2


00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 8D3509000000 lea esi,[dword 0x9]
00000009 68656C6C6F push dword 0x6f6c6c65
0000000E 20776F and [edi+0x6f],dh
00000011 726C jc 0x7f
00000013 64 fs
00000014 0D db 0x0d
00000015 00 db 0x00
Figure 2: Output of ex2 disassembled by ndisasm

7. With binutils installed (e.g. sudo apt-get install binutils), you can use
objdump to have it disassemble the code for you so you can compare your disassembly
with a known good disassembler engine. Note by default objdump uses AT&T syntax,
whereas we will be using Intel syntax. To force objdump to use Intel syntax, use the
-M intel option. Use the -D option to indicate you want to disassemble all. Since
there is no header information, we must tell objdump this is a binary file. To do so, use
the -b binary option. Again, without the header, we need to inform objdump of the
processor. In this case, we want the Intel x86 processor so we supply -mi386.

user@reva:~/$ objdump -M intel -D -b binary -mi386 ex2

ex2: file format binary

Disassembly of section .data:

00000000 <.data>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 8d 35 09 00 00 00 lea esi,ds:0x9
9: 68 65 6c 6c 6f push 0x6f6c6c65
e: 20 77 6f and BYTE PTR [edi+0x6f],dh
11: 72 6c jb 0x7f
13: 64 fs
14: 0d .byte 0xd
Figure 3: Output of ex2 disassembled by objdump

Common questions

Powered by AI

The outputs of ndisasm and objdump might differ even for the same assembly code due to differences in disassembly methodology and syntax. ndisasm uses a linear sweep disassembly approach, which can erroneously interpret data as code, leading to incorrect output resembling gibberish when it misinterprets non-instruction bytes. In contrast, objdump, when supplied with the right options, correctly interprets sections of code and uses Intel syntax, resulting in more accurate disassembly. The document shows that ndisasm misinterprets the string 'hello world', while objdump correctly identifies the executable instructions .

Specifying different syntax options, such as -M intel in objdump, affects the disassembly output by altering the assembly language syntax used in the disassembled code. Intel syntax, which arranges operands differently from AT&T syntax (such as the order of source and destination), can be more familiar to those with experience in high-level programming languages or previous exposure to Intel-based assembly language resources. This choice of syntax not only facilitates easier understanding and verification but also ensures compatibility with code styles of existing projects .

To start writing an assembly program using NASM, begin with a text editor and include the directive [BITS 32] at the top of your file to indicate that the assembly should compile as 32-bit code. Follow this with a section .text directive to indicate the executable code section. Then, proceed to write your assembly code .

Disassembly output can appear as gibberish in a linear sweep disassembler like ndisasm because it disassembles sequentially without understanding the instruction context or boundaries. In the example, disassembly from address 0x00000009 appears as gibberish because ndisasm attempts to disassemble the binary data representing the string 'hello world', mistaking it for instructions, which leads to incorrect interpretations like 'push dword 0x6f6c6c65' .

Failing to inform objdump that the file is binary and not providing processor-specific options can lead to incorrect disassembly outputs. Without knowing the file's format, objdump may default to inappropriate settings, resulting in misinterpretation of the binary data. Moreover, without processor-specific options such as -mi386, objdump may use a generic or incorrect instruction set decoding, causing further discrepancies in the disassembly, potentially producing results incompatible with actual code execution on the intended processor .

Using a known good disassembler engine like objdump is crucial when learning assembly language because it provides a reliable reference for verifying the correctness of disassembled code. It helps learners identify and rectify mistakes in their assembly syntax and understand the relationship between high-level representations and machine code. Moreover, objdump's ability to represent code in Intel or AT&T syntax improves comprehension by aligning instruction representation with learning preferences or existing knowledge from other programming languages .

To correctly disassemble an assembly file without header information using objdump, the following options should be used: -M intel to use Intel syntax, -D to disassemble all sections, -b binary to indicate the file format is binary, and -mi386 to specify the Intel x86 processor. In the document example, these options were used to disassemble the 'ex2' file, resulting in a correctly disassembled output that looks similar to the one provided by the assembler, despite the absence of the header .

The directive [BITS 32] is essential when writing assembly programs for NASM because it instructs the assembler to compile the code for a 32-bit architecture. This dictates the word size for registers and other offsets, ensuring the generated machine code operates correctly on 32-bit processors. Omitting this directive might result in a misalignment between the written assembly code and the processor's expected instruction set, leading to potential runtime errors or incorrect executions .

The 'section .text' directive in NASM specifies that the code following it should be considered executable code. This helps in organizing the assembly program by clearly defining different sections, such as data and text, which aids in instructing the assembler on how to treat the program parts during compilation .

Binutils plays a significant role in the assembly program development process by providing a suite of tools, including objdump, which assist in the translation and analysis of assembly code. For NASM users, binutils complement assembly and disassembly processes by enabling detailed inspection of binary outputs, facilitating debugging and optimization. Objdump, part of binutils, allows developers to convert binary back to assemble instructions with options for various syntax styles, thus serving both as an educational tool for learning and as a practical aid for ensuring assembly code correctness and efficiency .

You might also like