Netwide Assembler

Summary

The Netwide Assembler (NASM) is an assembler and disassembler for the Intel x86 architecture. It can be used to write 16-bit, 32-bit (IA-32) and 64-bit (x86-64) programs. It is considered one of the most popular assemblers for Linux and x86 chips.[3]

NASM
Original author(s)Simon Tatham, Julian Hall
Developer(s)H. Peter Anvin, Chang Seok Bae, Jim Kukunas, Frank B. Kotler, Cyrill Gorcunov
Initial releaseOctober 1996; 27 years ago (1996-10)
Stable release
2.16.03[1] Edit this on Wikidata / 17 April 2024; 9 days ago (17 April 2024)
Repository
  • github.com/netwide-assembler/nasm Edit this at Wikidata
Written inAssembly, C[2]
Operating systemUnix-like, Windows, OS/2, MS-DOS
Available inEnglish
Typex86 assembler
LicenseBSD 2-clause
Websitewww.nasm.us

It was originally written by Simon Tatham with assistance from Julian Hall. As of 2016, it is maintained by a small team led by H. Peter Anvin.[4] It is open-source software released under the terms of a simplified (2-clause) BSD license.[5]

Features edit

NASM can output several binary formats, including COFF, OMF, a.out, Executable and Linkable Format (ELF), Mach-O and binary file (.bin, binary disk image, used to compile operating systems), though position-independent code is supported only for ELF object files. It also has its own binary format called RDOFF.[6]

The variety of output formats allows retargeting programs to virtually any x86 operating system (OS). It can also create flat binary files, usable to write boot loaders, read-only memory (ROM) images, and in various facets of OS development.[6] It can run on non-x86 platforms as a cross assembler, such as PowerPC and SPARC, though it cannot generate programs usable by those machines.

NASM uses a variant of Intel assembly syntax instead of AT&T syntax.[7] It also avoids features such as automatic generation of segment overrides (and the related ASSUME directive) used by MASM and compatible assemblers.[6]

Sample programs edit

A "Hello, world!" program for the DOS operating system:

section .text
org 0x100
	mov	ah, 0x9
	mov	dx, hello
	int	0x21

	mov	ax, 0x4c00
	int	0x21

section .data
hello:	db 'Hello, world!', 13, 10, '$'

An equivalent program for Linux:

global _start

section .text
_start:
	mov	eax, 4 ; write
	mov	ebx, 1 ; stdout
	mov	ecx, msg
	mov	edx, msg.len
	int	0x80   ; write(stdout, msg, strlen(msg));

	xor	eax, msg.len ; invert return value from write()
	xchg eax, ebx ; value for exit()
	mov	eax, 1 ; exit
	int	0x80   ; exit(...)

section .data
msg:	db	"Hello, world!", 10
.len:	equ	$ - msg

An example of a similar program for Microsoft Windows:

global _main
extern _MessageBoxA@16
extern _ExitProcess@4

section code use32 class=code
_main:
	push	dword 0      ; UINT uType = MB_OK
	push	dword title  ; LPCSTR lpCaption
	push	dword banner ; LPCSTR lpText
	push	dword 0      ; HWND hWnd = NULL
	call	_MessageBoxA@16

	push	dword 0      ; UINT uExitCode
	call	_ExitProcess@4

section data use32 class=data
	banner:	db 'Hello, world!', 0
	title:	db 'Hello', 0

A 64-bit program for Apple OS X that inputs a keystroke and shows it on the screen:

global _start

section .data

	query_string:		db	"Enter a character:  "
	query_string_len:	equ	$ - query_string
	out_string:			db	"You have input:  "
	out_string_len:		equ	$ - out_string

section .bss

	in_char:			resw 4

section .text

_start:

	mov	rax, 0x2000004	 	; put the write-system-call-code into register rax
	mov	rdi, 1				; tell kernel to use stdout
	mov	rsi, query_string	; rsi is where the kernel expects to find the address of the message
	mov	rdx, query_string_len	; and rdx is where the kernel expects to find the length of the message 
	syscall

	; read in the character
	mov	rax, 0x2000003		; read system call
	mov	rdi, 0				; stdin
	mov	rsi, in_char		; address for storage, declared in section .bss
	mov	rdx, 2				; get 2 bytes from the kernel's buffer (one for the carriage return)
	syscall

	; show user the output
	mov	rax, 0x2000004		; write system call
	mov	rdi, 1				; stdout
	mov	rsi, out_string
	mov	rdx, out_string_len
	syscall

	mov	rax, 0x2000004		; write system call
	mov	rdi, 1				; stdout
	mov	rsi, in_char
	mov	rdx, 2				; the second byte is to apply the carriage return expected in the string
	syscall

	; exit system call
	mov	rax, 0x2000001		; exit system call
	xor     rdi, rdi
	syscall

section .data

   vuid db "BC220425429", 0  ; Provided VUID: "BC220425429"
   numeric_array times 10 db 0 ; Array to store numeric digits
   largest_digit db 0  ; Variable to store the largest digit
   updated_array times 10 db 0 ; Array to store updated VUID
   temp_array times 10 db 0 ; Temporary array for sorting

section .text global _start

_start:

   ; Step 1: Store the numeric part of VUID in an array
   mov esi, vuid ; Point to the VUID string
   mov ecx, 10   ; Loop counter for 10 digits
   mov ebx, numeric_array ; Point to the numeric_array

extract_digits:

   mov al, [esi] ; Load character from VUID
   cmp al, 0     ; Check if end of string
   je end_extract ; If end of string, exit loop
   cmp al, '0'   ; Check if character is a digit
   jl next_char  ; If not a digit, skip to next character
   cmp al, '9'
   jg next_char
   sub al, '0'   ; Convert character to numeric value
   mov [ebx], al ; Store numeric value in array
   inc ebx       ; Move to next element in array

next_char:

   inc esi       ; Move to next character in VUID
   loop extract_digits ; Repeat until all 10 digits are extracted

end_extract:

   ; Step 2: Find the largest numeric digit
   mov ebx, numeric_array ; Point to the numeric_array
   mov al, [ebx] ; Load the first digit
   mov [largest_digit], al ; Assume it as the largest digit
   mov ecx, 9 ; Loop counter for remaining digits
   inc ebx ; Move to the next digit

compare_digits:

   mov al, [ebx] ; Load the digit
   cmp al, [largest_digit] ; Compare with largest digit found so far
   jle skip_update ; If less than or equal, skip update
   mov [largest_digit], al ; Update largest digit

skip_update:

   inc ebx ; Move to the next digit
   loop compare_digits ; Repeat until all digits are compared
   ; Step 3: Subtract each numeric digit from the largest digit
   mov ebx, numeric_array ; Point to the numeric_array
   mov edi, updated_array ; Point to the updated_array

subtract_digits:

   mov al, [ebx] ; Load numeric digit
   sub al, [largest_digit] ; Subtract from largest digit
   mov [edi], al ; Store the result in updated_array
   inc ebx ; Move to the next digit
   inc edi ; Move to the next element in updated_array
   loop subtract_digits ; Repeat for all digits
   ; Step 4: Sort and store updated VUID in ascending order
   ; (You can implement any sorting algorithm here, like bubble sort or insertion sort)
   ; Sort updated_array using bubble sort
   mov ecx, 10 ; Number of elements
   dec ecx     ; Outer loop counter

outer_loop:

   mov ebx, updated_array ; Reset pointer to the beginning of the array
   mov edx, 9 ; Inner loop counter

inner_loop:

   mov al, [ebx] ; Load current element
   mov ah, [ebx + 1] ; Load next element
   cmp al, ah ; Compare current and next element
   jg swap_elements ; If current element > next element, swap
   inc ebx ; Move to the next element
   dec edx ; Decrement inner loop counter
   jnz inner_loop ; Repeat inner loop until edx = 0
   loop outer_loop ; Repeat outer loop until ecx = 0
   ; Store sorted array back to updated_array
   mov ebx, updated_array ; Point to the updated_array
   mov edi, temp_array ; Point to the temporary array for sorting
   mov ecx, 10 ; Loop counter
   rep movsb ; Copy the sorted array back to updated_array
   ; Display the sorted array
   mov eax, 4 ; Syscall number for sys_write
   mov ebx, 1 ; File descriptor (stdout)
   mov ecx, updated_array ; Pointer to the array
   mov edx, 10 ; Number of bytes to write
   int 0x80 ; Call kernel
   ; Exit the program
   mov eax, 1 ; Syscall number for sys_exit
   xor ebx, ebx ; Exit code 0
   int 0x80 ; Call kernel

swap_elements:

   ; Swap elements in updated_array
   mov al, [ebx] ; Move current element to al
   mov ah, [ebx + 1] ; Move next element to ah
   mov [ebx], ah ; Move next element to current position
   mov [ebx + 1], al ; Move current element to next position
   jmp inner_loop ; Continue inner loop

Development edit

NASM version 0.90 was released in October 1996.[5]

Version 2.00 was released on 28 November 2007, adding support for x86-64 extensions.[4] The development versions are not uploaded to SourceForge.net, but are checked into GitHub with binary snapshots available from the project web page.

A search engine for NASM documentation is also available.[8]

In July 2009, as of version 2.07, NASM was released under the Simplified (2-clause) BSD license. Previously, because it was licensed under LGPL, it led to development of Yasm, a complete rewrite of under the New BSD License. Yasm offered support for x86-64 earlier than NASM. It also added support for GNU Assembler syntax.

RDOFF edit

Relocatable Dynamic Object File Format (RDOFF) is used by developers to test the integrity of NASM's object file output abilities. It is based heavily on the internal structure of NASM,[9] essentially consisting of a header containing a serialization of the output driver function calls followed by an array of sections containing executable code or data. Tools for using the format, including a linker and loader, are included in the NASM distribution.

Until version 0.90 was released in October 1996, NASM supported output of only flat-format executable files (e.g., DOS COM files). In version 0.90, Simon Tatham added support for an object-file output interface, and for DOS .OBJ files for 16-bit code only.[10]

NASM thus lacked a 32-bit object format. To address this lack, and as an exercise to learn the object-file interface, developer Julian Hall put together the first version of RDOFF, which was released in NASM version 0.91.[10]

Since this initial version, there has been one major update to the RDOFF format, which added a record-length indicator on each header record,[11] allowing programs to skip over records whose format they do not recognise, and support for multiple segments; RDOFF1 only supported three segments: text, data and bss (containing uninitialized data).[9]

The RDOFF format is strongly deprecated and has been disabled starting in NASM 2.15.04.[12]

See also edit

References edit

  1. ^ "Release 2.16.03". 17 April 2024. Retrieved 23 April 2024.
  2. ^ "NASM, the Netwide Assembler". GitHub. 25 October 2021.
  3. ^ Ram Narayan. "Linux assemblers: A comparison of GAS and NASM". IBM. Archived from the original on 3 October 2013. two of the most popular assemblers for Linux, GNU Assembler (GAS) and Netwide Assembler (NASM)
  4. ^ a b "The Netwide Assembler". Retrieved 27 June 2008.
  5. ^ a b "NASM Version History". Retrieved 3 August 2019.
  6. ^ a b c "NASM Manual". Archived from the original on 23 February 2009. Retrieved 15 August 2009.
  7. ^ Randall Hyde. "NASM: The Netwide Assembler". Archived from the original on 12 September 2010. Retrieved 27 June 2008.
  8. ^ "NASM Doc Search Engine". Archived from the original on 23 January 2010. Retrieved 14 September 2009.
  9. ^ a b "NASM Manual Ch. 6". Retrieved 27 June 2008.
  10. ^ a b "NASM CVS". 8 June 2008. Retrieved 27 June 2008.
  11. ^ "V1-V2.txt". 4 December 2002. Retrieved 27 June 2008.
  12. ^ "Relocatable Dynamic Object File Format (deprecated)".

Further reading edit

  • Jeff Duntemann (2000). Assembly Language Step by Step. J Wiley and Sons. ISBN 0-471-37523-3.

External links edit

  • Official website
  • Netwide Assembler on SourceForge
  • Special edition for Win32 and BeOS.
  • A comparison of GAS and NASM at IBM
  • "Netwide Assembler". Freecode.: a converter between the source format of the assemblers NASM and GAS