Netwide Assembler

From Wikipedia, the free encyclopedia

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
Written inAssembly, C[2]
Operating systemUnix-like, Windows, OS/2, MS-DOS
Available inEnglish
Typex86 assembler
LicenseBSD 2-clause
Websitewww.nasm.us

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]

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]

External links[edit]