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]