x86 Assembly Language Programming

The x86 architecture is the most popular architecture for desktop and laptop computers. Let’s see how we can program in assembly language for processors in this family.

Introduction

This document contains very brief examples of assembly language programs for the x86. The topic of x86 assembly language programming is messy because:

We’ll give examples written for NASM, MASM and gas for both Win32 and Linux. We will even include a section on DOS assembly language programs for historical interest. These notes are not intended to be a substitute for the documentation that accompanies the processor and the assemblers, nor is it intended to teach you assembly language. Its only purpose is to show how to assemble and link programs using different assemblers and linkers.

Assemblers and Linkers

Regardless of the assembler, object file format, linker or operating system you use, the programming process is always the same:

asmlink.gif

Each assembly language file is assembled into an object file and the object files are linked with other object files to form an executable. A "static library" is really nothing more than a collection of (probably related) object files. Application programmers generally make use of libraries for things like I/O and math.

Assemblers you should know about include

This document does not cover how to use all the different assemblers; you need to read the documentation that comes with them. We will, however, give step-by-step instructions and complete examples of all three of these assemblers for a few extremely simple programs.

There are many object file formats. Some you should know about include

The NASM documentation has great descriptions of these.

You’ll need to get a linker that (1) understands the object file formats you produce, and (2) can write executables for the operating systems you want to run code on. Some linkers out there include

Programming for Linux

Programming Using System Calls

64-bit Linux installations use the processor’s SYSCALL instruction to jump into the portion of memory where operating system services are stored. To use SYSCALL, first put the system call number in RAX, then the arguments, if any, in RDI, RSI, RDX, R10, R8, and R9, respectively. In our first example we will use system calls for writing to a file (call number 1) and exiting a process (call number 60). Here it is in the NASM assembly language:

hello.asm
; ----------------------------------------------------------------------------------------
; Writes "Hello, World" to the console using only system calls. Runs on 64-bit Linux only.
; To assemble and run:
;
;     nasm -felf64 hello.asm && ld hello.o && ./a.out
; ----------------------------------------------------------------------------------------

          global    _start

          section   .text
_start:   mov       rax, 1                  ; system call for write
          mov       rdi, 1                  ; file handle 1 is stdout
          mov       rsi, message            ; address of string to output
          mov       rdx, 13                 ; number of bytes
          syscall                           ; invoke operating system to do the write
          mov       rax, 60                 ; system call for exit
          xor       rdi, rdi                ; exit code 0
          syscall                           ; invoke operating system to exit

          section   .data
message:  db        "Hello, World", 10      ; note the newline at the end

Here’s the same program in gas:

hello.s
# ----------------------------------------------------------------------------------------
# Writes "Hello, World" to the console using only system calls. Runs on 64-bit Linux only.
# To assemble and run:
#
#     gcc -c hello.s && ld hello.o && ./a.out
#
# or
#
#     gcc -nostdlib hello.s && ./a.out
# ----------------------------------------------------------------------------------------

        .global _start

        .text
_start:
        # write(1, message, 13)
        mov     $1, %rax                # system call 1 is write
        mov     $1, %rdi                # file handle 1 is stdout
        mov     $message, %rsi          # address of string to output
        mov     $13, %rdx               # number of bytes
        syscall                         # invoke operating system to do the write

        # exit(0)
        mov     $60, %rax               # system call 60 is exit
        xor     %rdi, %rdi              # we want return code 0
        syscall                         # invoke operating system to exit
message:
        .ascii  "Hello, world\n"

Since gas is the "native" assembler under Linux, assembling and linking is automatic with gcc, as explained in the program’s comments. If you just enter "gcc hello.s" then gcc will assemble and then try to link with a C library. You can suppress the link step with the -c option to gcc, or do the assembly and linking in one step by telling the linker not to use the C library with -nostdlib.

System Calls in 32-bit Linux

There are some systems with 32-bit builds of Linux out there still. On these systems you invoke operating systems services through an INT instruction, and use different registers for system call arguments (specifically EAX for the call number and EBX, ECX, EDX, EDI, and ESI for the arguments). Although it might be interesting to show some examples for historical reasons, this introduction is probably better kept short.

Programming with a C Library

Sometimes you might like to use your favorite C library functions in your assembly code. This should be trivial because the C library functions are all stored in a C library, such as libc.a. Technically the code is probably in a dynamic library, like libc.so, and libc.a just has calls into the dynamic library. Still, all we have to do is place calls to C functions in our assembly language program, and link with the static C library and we are set.

Before looking at an example, note that the C library already defines _start, which does some initialization, calls a function named main, does some clean up, then calls the system function exit! So if we link with a C library, all we have to do is define main and end with a ret instruction! Here is a simple example in NASM, which illustrates calling puts.

hola.asm
; ----------------------------------------------------------------------------------------
; Writes "Hola, mundo" to the console using a C library. Runs on Linux.
;
;     nasm -felf64 hola.asm && gcc hola.o && ./a.out
; ----------------------------------------------------------------------------------------

          global    main
          extern    puts

          section   .text
main:                                       ; This is called by the C library startup code
          mov       rdi, message            ; First integer (or pointer) argument in rdi
          call      puts                    ; puts(message)
          ret                               ; Return from main back into C library wrapper
message:
          db        "Hola, mundo", 0        ; Note strings must be terminated with 0 in C

And the equivalent program in GAS:

hola.s
# ----------------------------------------------------------------------------------------
# Writes "Hola, mundo" to the console using a C library. Runs on Linux or any other system
# that does not use underscores for symbols in its C library. To assemble and run:
#
#     gcc hola.s && ./a.out
# ----------------------------------------------------------------------------------------

        .global main

        .text
main:                                   # This is called by C library's startup code
        mov     $message, %rdi          # First integer (or pointer) parameter in %rdi
        call    puts                    # puts(message)
        ret                             # Return to C library code
message:
        .asciz "Hola, mundo"            # asciz puts a 0 byte at the end

The previous example shows that the first argument to a C function, if it’s an integer or pointer, goes in register RDI. Subsequent arguments go in RSI, RDX, RCX, R8, R9, and then subsequent arguments (which no sane programmer would ever use) will go "on the stack" (more about this stack thing later). If you have floating point arguments, they’ll go in XMM0, XMM1, etc. There is even quite a bit more to calling functions; we’ll see this later.

Programming for macOS

Rather than getting into macOS system calls, let’s just show the simple hello program using the C library. We’ll assume a 64-bit OS, and we’ll also assume you’ve installed gcc (usually obtained via downloading xcode).

hola.asm
; ----------------------------------------------------------------------------------------
; This is an macOS console program that writes "Hola, mundo" on one line and then exits.
; It uses puts from the C library.  To assemble and run:
;
;     nasm -fmacho64 hola.asm && gcc hola.o && ./a.out
; ----------------------------------------------------------------------------------------

          global    _main
          extern    _puts

          section   .text
_main:    push      rbx                     ; Call stack must be aligned
          lea       rdi, [rel message]      ; First argument is address of message
          call      _puts                   ; puts(message)
          pop       rbx                     ; Fix up stack before returning
          ret

          section   .data
message:  db        "Hola, mundo", 0        ; C strings need a zero byte at the end

There are some differences here! C library functions have underscores, and we had to say default rel for some strange reason, which you can read about in the NASM documentation.

Programming for Win32

Win32 is the primary operating system API found in most of Microsoft’s 32-bit operating systems including Windows 9x, NT, 2000 and XP. We will follow the plan of the previous section and first look at programs that just use system calls and then programs that use a C library.

For historical reference only.

These notes are pretty old. I’ve never learned Win64.

Calling the Win32 API Directly

Win32 defines thousands of functions! The code for these functions is spread out in many different dynamic libraries, but the majority of them are in KERNEL32.DLL, USER32.DLL and GDI32.DLL (which exist on all Windows installations). The interrupt to execute system calls on the x86 processor is hex 2E, with EAX containing the system call number and EDX pointing to the parameter table in memory. However, according to z0mbie, the actually system call numbers are not consistent across different operating systems, so, to write portable code you should stick to the API calls in the various system DLLs.

Here is the "Hello, World" program in NASM, using only Win32 calls.

hello.asm
; ----------------------------------------------------------------------------
; hello.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
; is very instructive to study since it does not make use of a C library.
; Because system calls from kernel32.dll are used, you need to link with
; an import library.  You also have to specify the starting address yourself.
;
; Assembler: NASM
; OS: Any Win32-based OS
; Other libraries: Use gcc's import library libkernel32.a
; Assemble with "nasm -fwin32 hello.asm"
; Link with "ld -e go hello.obj -lkernel32"
; ----------------------------------------------------------------------------

	global	go
	extern	_ExitProcess@4
	extern	_GetStdHandle@4
	extern	_WriteConsoleA@20

        section .data
msg:	db	'Hello, World', 10
handle: db	0
written:
	db	0

	section .text
go:
	; handle = GetStdHandle(-11)
	push	dword -11
	call	_GetStdHandle@4
	mov	[handle], eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
	push	dword 0
        push    written
	push	dword 13
	push	msg
	push	dword [handle]
	call	_WriteConsoleA@20

	; ExitProcess(0)
	push	dword 0
	call	_ExitProcess@4

Here you can see that the Win32 calls we are using are

GetStdHandle
WriteConsoleA
ExitProcess

and parameters are passed to these calls on the stack. The comments instruct us to assemble into an object format of "win32" (not "coff"!) then link with the linker ld. Of course you can use any linker you want, but ld comes with gcc and you can download a whole Win32 port of gcc for free. We pass the starting address to the linker, and specify the static library libkernel32.a to link with. This static library is part of the Win32 gcc distribution, and it contains the right calls into the system DLLs.

The gas version of this program looks very similar:

hello.s
/*****************************************************************************
* hello.s
*
* This is a Win32 console program that writes "Hello, World" on one line and
* then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
* is very instructive to study since it does not make use of a C library.
* Because system calls from kernel32.dll are used, you need to link with
* an import library.  You also have to specify the starting address yourself.
*
* Assembler: gas
* OS: Any Win32-based OS
* Other libraries: Use gcc s import library libkernel32.a
* Assemble with "gcc -c hello.s"
* Link with "ld -e go hello.o -lkernel32"
*****************************************************************************/

         .global go

         .data
msg:     .ascii  "Hello, World\n"
handle:  .int    0
written: .int    0

         .text
go:
         /* handle = GetStdHandle(-11) */
         pushl   $-11
         call    _GetStdHandle@4
         mov     %eax, handle

         /* WriteConsole(handle, &msg[0], 13, &written, 0) */
         pushl   $0
         pushl   $written
         pushl   $13
         pushl   $msg
         pushl   handle
         call    _WriteConsoleA@20

         /* ExitProcess(0) */
         pushl   $0
         call    _ExitProcess@4

In fact the differences between the two programs are really only syntactic. Another minor point is that gas doesn’t really care if you define external systems with some sort of "extern" directive or not.

As in the NASM version, we’ve specified our entry point, and will be passing it to the linker in the -e option. To assemble this code, do

gcc -c hello.s

The -c option is important! It tells gcc to assemble but not link. Without the -c option, gcc will try to link the object file with a C runtime library. Since we are not using a C runtime library, and in fact are specifying our own starting point, and cleaning up ourselves with ExitProcess we definitely want to link ourselves. The linking step is the same as the NASM example; the only difference is that gcc produces win32 object files with extension .o rather than .obj.

If you really want to pay a vendor for an assembler and linker you can use Microsoft’s MASM assembler. Anything less than version 6.14 will be extremely painful to use. Here is the version of the hello program in MASM

hello.asm
; ----------------------------------------------------------------------------
; hello.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It uses only plain Win32 system calls from kernel32.dll, so it
; is very instructive to study since it does not make use of a C library.
; Because system calls from kernel32.dll are used, you need to link with
; an import library.
;
; Processor: 386 or later
; Assembler: MASM
; OS: Any Win32-based OS
; Other libraries: Use Microsoft's import library kernel32.lib
; Assemble with "ml hello.asm /c"
; Link with "link hello kernel32.lib /subsystem:console /entry:go"
; ----------------------------------------------------------------------------

        .386P
        .model    flat
        extern    _ExitProcess@4:near
        extern    _GetStdHandle@4:near
        extern    _WriteConsoleA@20:near
        public    _go

        .data
msg     byte      'Hello, World', 10
handle  dword     ?
written dword     ?

        .stack

        .code
_go:        
        ; handle = GetStdHandle(-11)
        push      -11
        call      _GetStdHandle@4
        mov       handle, eax

        ; WriteConsole(handle, &msg[0], 13, &written, 0)
        push      0
        push      offset written
        push      13
        push      offset msg
        push      handle
        call      _WriteConsoleA@20

        ; ExitProcess(0)
        push      0
        call      _ExitProcess@4

        end

The processor (.386P) and model (.model) directives are an annoyance, but they have to be there and the processor directive must precede the model directive or the assembler will think the processor is running in 16-bit mode (*sigh*). As before we have to specify an entry point and pass it to the linker. Assemble with

    ml hello.asm /c

The /c option is required since ml will try to link. Not only is the MASM assembler, ml, not free, but neither is Microsoft’s linker, link.exe, nor are static versions of the Win32 libraries, such as kernel32.lib. After you buy those you link your code with

    link hello.obj kernel32.lib /subsystem:console /entry:go

To get this to work, kernel32.lib needs to be in a known library path or additional options must be passed to the linker. You might find the /subsystem option interesting; leave it out to see a ridiculous error message when running the linked executable (at least under Win9x).

Most of MASM’s syntactic weirdness, like using the "offset" keyword to get the address of a variable are not present in NASM. While NASM is probably gaining popularity, there is far more MASM code out there, and it is a good idea to have at least a passing acquaintance with MASM, since most publications use it. It is the closest thing to a "standard" x86 assembly language there is.

Using a C Runtime Library for Win32 Programming

As under Linux, using a C runtime library makes it very easy to write simple assembly language programs. Here is one in NASM:

powers.asm
; ----------------------------------------------------------------------------
; powers.asm
;
; Displays powers of 2 from 2^0 to 2^31, one per line, to standard output.
;
; Assembler: NASM
; OS: Any Win32-based OS
; Other libraries: Use gcc's C runtime library
; Assemble with "nasm -fwin32 powers.asm"
; Link with "gcc powers.obj" (C runtime library linked automatically)
; ----------------------------------------------------------------------------

        extern _printf
	global _main

	section .text
_main:
	push	esi			; callee-save registers
	push	edi

        mov     esi, 1                  ; current value
        mov     edi, 31                 ; counter
L1:
	push	esi			; push value to print
        push    format			; push address of format string
	call	_printf
	add	esp, 8			; pop off parameters passed to printf
	add	esi, esi		; double value
	dec	edi			; keep counting
	jne	L1

	pop	edi
	pop	esi
	ret

format:	db	'%d', 10, 0

The same program in gas looks like this:

powers.s
/*****************************************************************************
* powers.s
*
* Displays powers of 2 from 2^0 to 2^31, one per line.  It should be linked
* with a C runtime library.  The C runtime library contains startup code
* so you do not have to specify a starting label.  The startup code in
* the C library eventually calls main.
*
* Assembler: gas
* OS: Any Win32-based OS
* Other libraries: Use the gccs C runtime library
* Assemble and link: "gcc powers.s" (gcc links the C library automatically)
*****************************************************************************/

        .global   _main

        .text
format: .asciz    "%d\n"

_main:
        pushl     %esi                  /* callee save registers */
        pushl     %edi
        
        movl      $1, %esi              /* current value */
        movl      $31, %edi             /* counter */
L1:
        pushl     %esi                  /* push value of number to print */
        pushl     $format               /* push address of format */
        call      _printf
        addl      $8, %esp

        addl      %esi, %esi            /* double value */
        decl      %edi                  /* keep counting */
        jnz       L1
        
        popl      %edi
        popl      %esi
        ret

Note you can assemble and link with

    gcc powers.s

For the MASM version of this program, you can go purchase C Runtime Libraries from Microsoft as well. There are many versions of the library, but for single threaded programs, libc.lib is fine. Here is the powers program in MASM:

powers.asm
; ----------------------------------------------------------------------------
; powers.asm
;
; Displays powers of 2 from 2^0 to 2^31, one per line, to standard output.
;
; Processor: 386 or later
; Assembler: MASM
; OS: Any Win32-based OS
; Other libraries: Use a Microsoft-compatible C library (e.g. libc.lib).
; Assemble with "ml powers.asm /c"
; Link with "link powers libc.lib"
;
; By default, the linker uses "/subsystem:console /entry:mainCRTStartup".
; The function "mainCRTStartup" is inside libc.lib.  It does some
; initialization, calls a function "_main" (which will end up in powers.obj)
; then does more work and finally calls ExitProcess.
; ----------------------------------------------------------------------------

        .386P
        .model    flat
        extern    _printf:near
        public    _main

        .code
_main:
        push      esi                  ; callee-save registers
        push      edi
        
        mov       esi, 1               ; current value
        mov       edi, 31              ; counter                
L1:
        push      esi                  ; push value to print
        push      offset format        ; push address of format string
        call      _printf
        add       esp, 8               ; pop off parameters passed to printf
        add       esi, esi             ; double value
        dec       edi                  ; keep counting
        jnz       L1

        pop       edi
        pop       esi
        ret
        
format: byte      '%d', 10, 0

        end

When linking with libc.lib you get nice linker defaults. To assemble and link:

    ml powers.asm /c
    link powers.obj libc.lib

You’ll have to make sure the linker knows where to find libc.lib by setting some environment variables, of course, but you get the idea.

OpenGL Programming in NASM for Win32

For fun, here is a complete assembly language program that implements an OpenGL application running under GLUT on Windows systems:

triangle.asm
; ----------------------------------------------------------------------------
; triangle.asm
;
; A very simple *Windows* OpenGL application using the GLUT library.  It
; draws a nicely colored triangle in a top-level application window.  One
; interesting thing is that the Windows GL and GLUT functions do NOT use the
; C calling convention; instead they use the "stdcall" convention which is
; like C except that the callee pops the parameters.
; ----------------------------------------------------------------------------

	global	_main
	extern	_glClear@4
	extern	_glBegin@4
	extern	_glEnd@0
	extern	_glColor3f@12
	extern	_glVertex3f@12
	extern	_glFlush@0
	extern	_glutInit@8
	extern	_glutInitDisplayMode@4
	extern	_glutInitWindowPosition@8
	extern	_glutInitWindowSize@8
	extern	_glutCreateWindow@4
	extern	_glutDisplayFunc@4
	extern	_glutMainLoop@0

	section	.text
title:	db	'A Simple Triangle', 0
zero:	dd	0.0
one:	dd	1.0
half:	dd	0.5
neghalf:dd	-0.5

display:
	push	dword 16384
	call	_glClear@4		; glClear(GL_COLOR_BUFFER_BIT)
	push	dword 9
	call	_glBegin@4		; glBegin(GL_POLYGON)
	push	dword 0
	push	dword 0
	push	dword [one]
	call	_glColor3f@12		; glColor3f(1, 0, 0)
	push	dword 0
	push	dword [neghalf]
	push	dword [neghalf]
	call	_glVertex3f@12		; glVertex(-.5, -.5, 0)
	push	dword 0
	push    dword [one]
	push	dword 0
	call	_glColor3f@12		; glColor3f(0, 1, 0)
	push	dword 0
	push	dword [neghalf]
	push	dword [half]
	call	_glVertex3f@12		; glVertex(.5, -.5, 0)
	push	dword [one]
	push	dword 0
	push	dword 0
	call	_glColor3f@12		; glColor3f(0, 0, 1)
	push	dword 0
	push	dword [half]
	push	dword 0
	call	_glVertex3f@12		; glVertex(0, .5, 0)
	call	_glEnd@0		; glEnd()
	call	_glFlush@0		; glFlush()
	ret

_main:
	push	dword [esp+8]		; push argv
	lea	eax, [esp+8]		; get addr of argc (offset changed :-)
	push	eax
	call	_glutInit@8		; glutInit(&argc, argv)
	push	dword 0
	call	_glutInitDisplayMode@4
	push	dword 80
	push	dword 80
	call	_glutInitWindowPosition@8
	push	dword 300
	push	dword 400
	call	_glutInitWindowSize@8
	push	title
	call	_glutCreateWindow@4
	push	display
	call	_glutDisplayFunc@4
	call	_glutMainLoop@0
	ret

Programming for DOS

Both MASM and NASM can create DOS executables. DOS is a primitive operating system (indeed, many people, perhaps correctly, refuse to call it an operating system), which runs in real mode only. Real mode addresses are 20-bit values written in the form SEGMENT:OFFSET where the segment and offset are each 16-bits wide and the physical address is SEGMENT * 16 + OFFSET.

A DOS program is a collection of segments. When the program is loaded, DS:0 and ES:0 points to a 256-byte section of memory called the program segment prefix and this is immediately followed by the segments of the program. CS:0 will point to the code segment and SS:0 to the stack segment. SP will be loaded with the size of the stack specified by the programmer, which is perfect because on the x86 a PUSH instruction decrements the stack pointer and then moves the pushed value into the memory addressed by SS:SP. The length of the command line argument string is placed in the byte at offset 80h of the prefix and the actual argument string begins at offset 81h.

Here is a simple DOS program to echo the command line argument string:

echo.asm
; ----------------------------------------------------------------------------
; echo.asm
;
; Echoes the command line to standard output.  Illustrates DOS system calls
; 40h = write to file, and 4ch = exit process.
;
; Processor: 386 or later
; Assembler: MASM
; OS: DOS 2.0 or later only
; Assemble and link with "ml echo.asm"
; ----------------------------------------------------------------------------

        .model  small
        .stack  64                      ; 64 byte stack
        .386
        .code
start:  movzx   cx,byte ptr ds:[80h]    ; size of parameter string
        mov     ah, 40h                 ; write
        mov     bx, 1                   ; ... to standard output
        mov     dx, 81h                 ; ... the parameter string
        int     21h                     ; ... by calling DOS
        mov     ah, 4ch
        int     21h
        end     start             

Note with the MASM assembler you have to place the .model directive before the processor directive to make the processor use 16-bit mode required for DOS.

Note that all "operating system services" such as input/output are accessible through the processor’s interrupt instruction so there is no need to link your program to a special library. Of course if you wanted to link to a 16-bit C runtime library you certainly can.

The echo program defines only a code and stack segment; an example of a program with a programmer-defined data segment is:

hello1.asm
; ----------------------------------------------------------------------------
; hello1.asm
;
; Displays a silly message to standard output.  Illustrates user-defined data.
; The easiest way to do this is to put the data in a data segment, separate 
; from the code, and access it via the ds register.  Note that you must have
; ds:0 pointing to your data segment (technically to your segment's GROUP) 
; before you reference your data.  The predefined symbol @data referes to 
; the group containing the segments created by .data, .data?, .const, 
; .fardata, and .fardata?.
;
; Processor: 386 or later
; Assembler: MASM
; OS: DOS 2.0 or later only
; Assemble and link with "ml hello1.asm"
; ----------------------------------------------------------------------------

	.model	small

        .stack  128

        .code
start:  mov     ax, @data
        mov     ds, ax
        mov     ah, 9
        lea     dx, Msg
        int     21h
	mov	ah, 4ch
	int	21h

        .data
Msg     byte    'Hello, there.', 13, 10, '$'

	end	start

Although DOS has been obsolete for many years, a brief study of DOS systems and the x86 real-addressing mode is somewhat interesting. First, real-mode addresses correspond to real, physical memory, so one can watch exactly what is happening in the machine very easily with a good debugger. In fact, most embedded microprocessors work in a kind of "real mode." Less than 1% of microprocessors run desktop PCs, servers and workstations; most are simple embedded processors. Finally a lot of DOS applications still exist, so it might be useful to know what kind of technology underlies it all.

Writing Optimized Code

Assembly language programmers and compiler writers should take great care in producing efficient code. This requires a fairly deep understanding of the x86 architecture, especially the behavior of the cache(s), pipelines and alignment bias. These specifics are well beyond the scope of this little document, but an excellent place to begin your study of this material is Agner Fog’s Optimization Guide or even Intel’s.

Differences between NASM, MASM, and GAS

The complete syntactic specification of each assembly language can be found elsewhere, but you can learn 99% of what you need to know by looking at a comparison table:

Operation NASM MASM GAS
Move contents of esi into ebx mov ebx, esi movl %esi, %ebx
Move contents of si into dx mov dx, si movw %si, %dx
Clear the eax register xor eax, eax xorl %eax, %eax
Move immediate value 10 into register al mov al, 10 movb $10, %al
Move contents of address 10 into register ecx mov ecx, [10] I DON’T KNOW movl 10, %ecx
Move contents of variable dog into register eax mov eax, [dog] mov eax, dog movl dog, %eax
Move address of variable dog into register eax mov eax, dog I DON’T KNOW movl $dog, %eax
Move immediate byte value 10 into memory pointed to by edx mov byte [edx], 10 mov byte ptr [edx], 10 movb $10, (%edx)
Move immediate 16-bit value 10 into memory pointed to by edx mov word [edx], 10 mov word ptr [edx], 10 movw $10, (%edx)
Move immediate 32-bit value 10 into memory pointed to by edx mov dword [edx], 10 mov dword ptr [edx], 10 movl $10, (%edx)
Compare eax to the contents of memory 8 bytes past the cell pointed to by ebp cmp eax, [ebp+8] cmpl $8(%ebp), %eax
Add into esi the value in memory ecx quadwords past the cell pointed to by eax add esi, [eax+ecx*8] addl (%eax,%ecx,8), %esi
Add into esi the value in memory ecx doublewords past 128 bytes past the cell pointed to by eax add esi, [eax+ecx*4+128] addl $128(%eax,%ecx,4), %esi
Add into esi the value in memory ecx doublewords past eax bytes past the beginning of the variable named array add esi, [eax+ecx*4+array] addl array(%eax,%ecx,4), %esi
Add into esi the value in memory ecx words past the beginning of the variable named array add esi, [ecx*2+array] addl array(,%ecx,2), %esi
Move the immediate value 4 into the memory cell pointed to by eax using selector fs mov byte [fs:eax], 4 mov byte ptr fs:eax, 4 movb $4, %fs:(%eax)
Jump into another segment ? jump far S:O ljmp $S, $O
Call to another segment ? call far S:O lcall $S, $O
Return from an intersegment call retf V ret far V lret $V
Sign-extend al into ax cbw cbtw
Sign-extend ax into eax cwde cwtl
Sign-extend ax into dx:ax cwd cwtd
Sign-extend eax into edx:eax cdq cltd
Sign-extend bh into si movsx si, bh movsbw %bh, %si
Sign-extend bh into esi movsx esi, bh movsbl %bh, %esi
Sign-extend cx into esi movsx esi, cx movswl %cx, %esi
Zero-extend bh into si movzx si, bh movzbw %bh, %si
Zero-extend bh into esi movzx esi, bh movzbl %bh, %esi
Zero-extend cx into esi movzx esi, cx movzwl %cx, %esi
100 doublewords, all initialized to 8192 times 100 dd 8192 dd 100 dup (8192) I DON’T KNOW
Reserve 64 bytes of storage resb 64 db 64 dup (?) .space 64
Hello World db 'Hello, World' .ascii "Hello, World"
Hello World with a newline, and zero-terminated db 'Hello, World', 10, 0 .asciz "Hello, World\n"

Good to know: