Chapter 1 – Intel IA-32 Architecture
1.1 Introduction to the IA-32 Architecture
IA-32 refers to the family of Intel 80x86 processors beginning with the Intel 80386 and continuing up to the latest Intel multi-core offerings. IA-32 also refers to the assembly instruction set implemented by Intel and other vendors like AMD. The full 80x86 instruction set is very large and complex. Appendix B of the NASM manual lists all the assembly instructions supported by the NASM assembler.
Each evolving family of processors has added improvements in speed and functionality to the internal architecture. A hallmark of the IA-32 family of processors is that each new generation is designed to be backward compatible with its predecessor.
When referring to 32-bit Intel microprocessors, we are also including microprocessors manufactured by AMD, Cyrix, and to a lesser extent VIA Centaur Technologies, all based on the 80x86 architecture.
1.2 Scope and Purpose
This chapter provides an introduction to the registers and operating modes used by Intel-based 80x86 microprocessors employing the IA-32 architecture. Topics covered in this chapter include:
- Overview of the Intel IA-32 architecture structure
- General description of the general purpose registers, destination index and stack pointer, segment registers, EFLAGS, instruction pointer, 80-bit floating-point registers, 64-bit MMX registers, and 128-bit XMM registers
- Discussion of the three operating modes of Intel 80x86 microprocessors
1.3 Intel IA-32 Architecture
The 80x86 architecture includes general-purpose registers (GPRs), segment registers, internal bus lines, flag and control registers, arithmetic logic units (ALUs), floating-point units (FPUs), pipelines, and data and code caches. The latest 80x86 processors incorporate three-way superscalar design, 64-bit multimedia math extensions (MMX), 128-bit streaming SIMD extensions (SSE), and a second execution pipeline. Don’t worry; these subjects are covered soon enough.
In this introductory book, our focus is on the internal registers and memory architecture of the 80x86 processor. Figure 1-1 shows a representative 80x86 microprocessor system. This is a high-level view of the general 80x86 model referred to in our discussions. This model is as complex as we want to get for now. For a more in-depth review of the 80x86 architecture, read the manuals referenced in Appendix C.
The Intel IA-32 Software Developer’s Manual consists of five volumes: Basic Architecture, Instruction Set Reference A-M, Instruction Set Reference N-Z, System Programming Guide Part 1, and System Programming Guide Part 2. AMD has similar manuals on their website.
Figure 1-1 Representative Intel IA-32 Microprocessor System
1.3.1 Control Unit (CU)
The control unit directs the operation of the other components on the CPU by providing timing and control signals. The main function of the CPU is to execute programs stored in memory in the form of instructions and data. The control unit contains the necessary logic to interpret instructions and to generate the signals necessary for the execution of those instructions.
1.3.2 Control Bus
A bus is a group of parallel wires and connections that transfer signals from one part of the computer to another. The control bus is part of the internal and external bus lines. It is used to communicate commands to the various devices within the CPU and externally within the computer. Internal components and external devices also return status signals back through the control bus.
1.3.3 Address Bus
The latest Intel 80x86 processors have 36-bit address buses capable of connecting 64GB of memory. In 32-bit mode, the amount of addressable memory is limited to 4GB. The address bus is also part of the internal and external bus system. It is used to send signals that select a specific location in memory to either read or write data depending on which command signal is presented by the control bus.
1.3.4 Data Bus
The IA-32 microprocessor has two types of data buses: an internal data bus and an external data bus. The external data bus communicates with external devices, such as memory, and transfers data to the internal bus. The internal bus lines transfer data to and from the ALU, registers, and the control unit. Intel’s 32-bit 80x86 processors have 32-bit internal data paths.
1.3.5 Arithmetic Logic Unit (ALU)
The ALU is one of the most important components in a microprocessor. It performs arithmetic operations on integer values such as addition and subtraction, logical operations such as AND, OR, and XOR. The operation to be performed is specified by signals from the control unit. Data used in operations can come from either memory or an external input like a hard drive or USB device.
Typically, the EAX register acts as an accumulator for the ALU. The accumulator is the repository for successive results of arithmetic operations. Resulting data residing in the accumulator may then be transferred to memory or other output device.
The speed of successive 80x86 processors has increased, but the speed of main memory (RAM) has not kept pace. To minimize size and cost, RAM memory uses inexpensive Dynamic RAM (DRAM). Static RAM (SRAM) is much faster, but also more expensive, so it is used in small quantities as a temporary storage location for data on the microprocessor. This high-speed memory is referred to as cache memory. Current 80x86 microprocessors have cache memory in two levels: Level 1 (L1) and Level 2 (L2).
The instruction pipeline is a technique used to fill cache memory with instructions and data to increase the number of instructions that can be executed without waiting for memory access cycles. Pipelining doesn't reduce the time it takes to complete an instruction; it increases the number of instructions that can be processed at once and reduces the delay between completed instructions. Our representative microprocessor system presents a very simplistic view of pipelining and caching.
Sometimes assembly programmers make the assumption that each instruction they write is executed before execution of the next instruction starts. This assumption can result in what is called stalling as one instruction waits for its predecessor to complete or one instruction waits to gain memory access while another instruction is using the memory location. Various techniques for resolving pipeline stalls exist, but are beyond the scope of this book. The more pipeline stages a processor has, the more instructions it can work on at one time and the less of a delay there is between completed instructions. Most 80x86 microprocessor designs incorporate multiple pipeline stages for increased throughput.
1.3.7 Floating-point Unit (FPU)
The FPU, also known as the math coprocessor, performs arithmetic operations on floating-point numbers. They are integral components of the 80x86 CPU specially designed to carry out addition, subtraction, multiplication, division, and other algebraic and trigonometric functions on single-(32-bit), double-(64-bit), and extended-precision (80-bit) floating-point numbers. Like the ALU, the FPU has its algorithms hard coded inside the unit. Additionally, floating-point operations are often pipelined to increase throughput. Some modern processors may contain more than one FPU.
1.4 Microprocessor Registers
Registers are the main working areas within the processor and many of the registers are designed for special purposes. The key to learning assembly language is understanding how to move data into and out of registers, knowing how to work on the data once you get it inside a particular register, and then using the EFLAGS register to check the status of the work you performed in the target register.
Figure 1-2 depicts the major registers incorporated in IA-32-compatible processors running in 32-bit mode. Creating effective inline assembly code requires you to be familiar with the basic architecture of the processor family you are targeting.
Figure 1-2 Main IA-32 Registers and RAM Memory
1.4.1 General Purpose Registers
The eight general-purpose registers: EAX, EBX, ECX, EDX, ESI, EDI, EBP, and ESP are 32-bits wide (4 bytes). They are used to execute the basic instructions and perform integer arithmetic on byte, word, and doubleword integers; handle program flow; operate on bit and byte strings; and access memory.
These registers are used to store operands for logical and arithmetic operations, operands for address calculations, and pointers for accessing memory locations. Historically, each of the eight registers have been designed and used for the following purposes:
EAX – Accumulator for math calculations EDI – Destination Index pointer in the DS segment EBX – Base pointer to data in the DS segment ESI – Source Index pointer in the ES segment ECX – Counter for string and loop operations ESP – Stack Pointer in the SS segment EDX – Data I/O source pointer EBP – Base Pointer to data on the stack
Figure 1-3 shows how general purpose registers can be accessed at 8-bit, 16-bit, and 32-bit levels. However, access below the 32-bit level is seldom necessary in our programs except when conducting string operations on individual characters. For instance, the EAX, EBX, ECX, and EDX 32-bit registers can be accessed at the 16-bit level using the AX, BX, CX, and DX mnemonics respectively. They can be further accessed at the 8-bit level using the AH/AL, BH/BL, CH/CL, and DH/DL mnemonics respectively.
Figure 1-3 General Purpose Registers
The ESI register is typically used to point to a source string in memory while the EDI register is used to point to a destination string in memory. The EBP register is normally used to point to the base of the stack in the stack segment (SS) while the ESP register points to the top of the current stack frame in the stack.
The letter “E” in register names stands for “Extended”. Extended registers are always 32-bits wide. The letter “L” stands for “Low” byte while the letter “H” stands for “High” byte.
1.4.2 Source Index (ESI) and Destination Index (EDI) Registers
With the exception of I/O string instructions, all string operations use ESI as the source-operand pointer and EDI as the destination-operand pointer. I/O string instructions use EDX to specify the input-port or output-port number. For repeated string operations (those preceded with a repeat-instruction prefix), the ESI and EDI registers are incremented or decremented as the string elements are moved from the source location to the destination location. Incrementing or decrementing is designated by setting the direction bit (bit 10) in the EFLAGS register. Repeat-string operations also use ECX to hold the string length, and decrement it as data are moved from one location to the other.
Figure 1-4 is a general overview of how the ESI and EDI registers are used in a program. Note the zero (0) at the end of both strings. IWBASIC strings are “null terminated”. That is, the null (zero) is used to denote the end of a string in memory.
Figure 1-4 Source (ESI) and Destination (EDI) Index Registers
1.4.3 Segment Registers
The six 16-bit segment registers: CS, DS, SS, ES, FS, and GS are used to hold 16-bit segment offset indexes. Segment registers are special pointers that divide and point to various reserved areas in memory. In protected mode (flat memory model), the operating system (OS) sets each data segment register (DS, ES, FS, GS) with segment values that point to overlapping memory areas, each of which begins at address 0 of the linear address space for your program when it is loaded into memory.
Each segment is defined by a segment descriptor stored in a table known as the global descriptor table (GDT). We will not get into global descriptor tables as you have no direct control over them anyway.
Figure 1-5 shows how segments are defined. The value in the CS segment register is an indexed address that points to the base of the code area in memory. The processor fetches program instructions from the code segment pointed to by the combination of the EIP and CS registers. Data are stored in memory areas pointed to by the DS, ES, FS, and GS segment registers. The SS register contains the location in memory where the base of the program stack resides. The programmer can explicitly load the SS register with appropriate values in order to set up multiple stacks.
The DS, ES, FS, and GS registers allow four separate data segments to be accessed; however, in 32-bit operating mode, these four registers are typically loaded with the same data segment address. The segment registers are not directly accessible to you in 32-bit flat memory mode and because of this, there is little need to discuss the segment registers in detail. The operating system assigns values to segment registers at start up and the linker provides relative addresses into each segment using segment pointers like the EIP and EBP registers.
Figure 1-5 Segment Registers for the 32-Bit Flat Memory Model
1.4.4 Base Pointer (EBP) and Stack Pointer (ESP) Registers
A stack is a portion of the stack segment in memory that is used to hold parameters, local variables, and return addresses. Software conventions typically define stacks using a stack frame, which consists of two registers—a stack-frame base pointer (EBP) and a stack pointer (ESP). Generally, most programs contain multiple stack frames as shown in Figure 1-6. The stack is limited only by the amount of memory.
The stack-segment (SS) register, points to the base address of the stack segment. The stack pointers contain offsets from the base address of the current stack segment. All instructions that address memory using the EBP or ESP registers cause the processor to access the current stack segment.
In typical applications, EBP and ESP point to the same location in memory before a procedure is called. After data are pushed onto the stack, the stack frame base pointer remains where it was and the stack pointer advances to the next lower address after the pushed data, where it becomes the new top-of-stack.
Remember that the stack segment grows from higher memory to lower memory. Therefore, the base of the stack is at the bottom of the segment and the address of the top of the current stack frame is at the top of the stack at a lower memory location.
Notice in Figure 1-6 that the stack segment (SS) register points to the bottom of the stack in memory and that EBP points to the bottom of the current stack frame. ESP points to the top of the stack and current stack frame. Another convention is that stacks grow toward lower memory addresses. That is, from higher addresses at the bottom of memory to lower addresses at the top of the stack segment.
Figure 1-6 Base Pointer (EBP) and Stack Pointer (ESP) Registers
1.4.5 Instruction Pointer (EIP) Register
The instruction pointer (EIP) register contains a 32-bit offset address into the code segment for the next program instruction to be executed. The EIP register is used to keep track of the address of the next instruction to be fetched from the code section of memory. Keep in mind that with prefetching and pipelining, the next instruction to be fetched is not necessarily the next instruction to be executed.
As shown in Figure 1-7, the EIP register works in combination with the CS segment register to calculate the offset address needed to retrieve the next code instruction. The CS register contains an index that points to a table with the address of the base of the code segment and when combined with EIP, points to the next instruction in memory to be executed. EIP is moved ahead or backwards by a number of instructions when executing a jump, call, return, interrupt, etc. You have no direct access to the EIP register; only indirect access by modifying the value of a return instruction or performing a branch operation in your program.
With pipelining, an 80x86 microprocessor actually starts execution of an instruction before it finishes execution of prior instructions. This increases the effective speed of the processor.
Figure 1-7 EIP Register
1.4.6 EFLAGS Register
The EFLAGS register stores bit information related to the status of the program being executed and allows limited control over the processor. The EFLAGS register is 32-bits wide and contains six status flags, one control flag, and ten system flags. Some of the flags in the EFLAGS register can be modified directly using special-purpose instructions. There are no instructions that allow the whole register to be examined or modified directly by you.
The low 16 bits of the EFLAGS register are accessible by application software and hold the following flags:
- Six status flags (carry flag CF, parity flag PF, auxiliary carry flag AF, zero flag ZF, sign flag SF, and overflow flag OF)
- One control flag (the direction flag DF)
- Ten system flags of which 3 are reserved by Intel and cannot be controlled by you
In Figure 1-8, you can see the six status flags located at bits 0, 2, 4, 6, 7, and 11. Status flags indicate the results of any arithmetic instructions executed in your general purpose registers.
The remaining low 16-bits of the EFLAGS register represent system flags. The only flags we are interested in are the status and control flags.
Bits 31–16 of the EFLAGS register contain flags that are accessible only to system software. The highest 10 bits of EFLAGS are reserved. The system flags in the EFLAGS register control operating-system functions. These bit positions should never be modified by your code.
A flag is set when it equals 1 and is cleared (reset) when it equals 0.
Figure 1-8 EFLAGS Register
The status flags of the EFLAGS register allow the results of one instruction to influence other instructions. Each status flag is discussed next.
Carry Flag (CF). The carry flag (bit 0) is set to 1 by hardware if the last integer addition or subtraction operation resulted in a carry (for addition) or a borrow (for subtraction) out of the most-significant bit position of the result. Otherwise, hardware clears the flag to 0.
Software can also set or clear the carry flag with the set carry (STC) and clear carry (CLC) instructions, respectively. Software can complement the flag with the CMC instruction.
Parity Flag (PF). The parity flag (bit 2) is set to 1 by hardware if there is an even number of 1 bits in the least-significant byte of the last result of certain operations. Otherwise hardware clears the flag to 0 if there are an odd number of bits. Software can read the flag to implement parity checking.
Auxiliary Carry Flag (AF). The auxiliary carry flag (bit 4) is set by hardware if an arithmetic operation or a binary-coded decimal (BCD) operation generates a carry (in the case of an addition) or a borrow (in the case of a subtraction) out of bit 3 of the result. Otherwise, AF is cleared to zero.
The main application of this flag is to support decimal arithmetic operations. Most commonly, this flag is used internally by correction commands for decimal addition (AAA) and subtraction (AAS).
Zero Flag (ZF). The zero flag (bit 6) is set by hardware to 1 if the last arithmetic operation resulted in a value of zero. Otherwise (for a non-zero result), hardware clears the flag to 0. The compare and test instructions also affect the zero flag. The zero flag is typically used to test whether the result of an arithmetic or logical operation is zero, or to test whether two operands are equal.
Sign Flag (SF). The sign flag (bit 7) is set by hardware to 1 if the last arithmetic operation resulted in a negative value. Otherwise (for a positive-valued result), hardware clears the flag to 0. Thus, in such operations, the value of the sign flag is set equal to the value of the most-significant bit of the result. Depending on the size of operands, the most-significant bit is bit 7 (for bytes), bit 15 (for words), bit 31 (for doublewords), or bit 63 (for quadwords).
Overflow Flag (OF). The overflow flag (bit 11) is set by hardware to 1 to indicate that the most-significant (sign) bit of the result of the last signed integer operation differed from the signs of both source operands. Otherwise, hardware clears the flag to 0. A set overflow flag means that the magnitude of the positive or negative result is too big (overflow) or too small (underflow) to fit its defined data type.
The control flag (Direction Flag) is used in string operations to determine whether a string operation should scan strings in the forward or backward direction.
Direction Flag (DF). The direction flag (bit 10) determines the order in which strings are processed. The DF flag is modified by your program to automatically increment or decrement the count in the ECX/CX register. Putting a ‘1’ in this bit position causes string instructions to process strings from high addresses to low addresses. Clearing (putting a ‘0’) in this bit location causes string instructions to process strings from low addresses to high addresses.
The ten system flags control the operation of the processor. Of interest to you is the identification (ID) flag that indicates whether the processor supports the CPUID instruction. More on CPUID instructions in Chapter 17.
1.4.7 FPU Registers
The eight 80x86 FPU registers: ST0, ST1, ST2, ST3, ST4, ST5, ST6, and ST7 provide single-precision, double-precision, and extended-precision floating-point calculations. These registers operate on floating-point values, word integers, doubleword integers, quadword integers, and binary coded decimal (BCD) values. As shown in Figure 1-9, FPU registers are 80 bits wide.
Figure 1-9 Floating-Point Unit (FPU) Registers
1.4.8 MMX Registers
The eight MMX registers: MM0, MM1, MM2, MM3, MM4, MM5, MM6, and MM7 support execution of single-instruction multiple-data (SIMD) operations on 64-bit packed byte, word, and doubleword integers. Although MMX registers are defined in the IA-32 architecture by Intel as separate registers, they are aliased to the registers in the FPU data register stack (ST0-ST7). This is seen as a major drawback for two reasons. First, you cannot mix FPU and MMX operations at the same time. Second, you must reset the MMX registers with the exit MMX instruction EMMS before switching back to floating-point operations.
The MMX registers are primarily used for media, communications, and graphics applications. MMX registers are strictly data registers; they cannot be used to hold addresses nor are they suitable for calculations involving addresses.
Figure 1-10 shows how MMX registers are aliased onto the FPU registers. Aliasing was done back in the early days of microprocessor development when there was insufficient space on chips to add new registers. Also, aliasing allowed older 80x86 processors to remain compatible with Windows 95, NT, and Linux without having to change OS code.
Figure 1-10 MMX Register Set Overlaid on the FPU Registers
1.4.9 XMM Registers
The eight XMM data registers XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, and XMM7 support execution of single instruction multiple-data (SIMD) and Streaming SIMD Extensions (SSE) operations on 128-bit packed single-precision and double-precision floating-point values and on 128-bit packed byte, word, doubleword, and quadword integers. Single instruction, multiple-data (SIMD) is a method designed to operate on multiple data simultaneously.
XMM registers are not aliased to any floating-point or other registers; they are actually new storage registers added to newer 80x86 microprocessors. A single 128-bit XMM register can hold four 32-bit floating-point numbers. A typical SSE instruction can operate on four pairs of these floating-point numbers simultaneously. XMM registers are designed to accelerate media type instructions, but also can speed up regular integer and floating-point arithmetic operations. Figure 1-11 depicts the set of 128-bit XMM registers found in IA-32 type microprocessors.
Figure 1-11 XMM Registers
Memory for our purpose includes up to 4 gigabytes of addressable memory space. This is because programs running in 32-bit registers and address buses can contain addresses between 0 and 232-1. Generally, program memory is divided into at least three sections: an area for storing program code, an area for storing data, and an area for the stack. More about sections later.
1.6 Using Registers
In IWBASIC, you can use any general purpose register in your inline assembly code. If you write inline assembly language procedures the OS requires you to preserve the contents of the EBX, EDI, and ESI registers by pushing them on the stack and popping them off the stack before your procedure returns.
However, if your routine is simple and does not modify any of these three registers, then you may not need to preserve them. When in doubt, preserve and restore all used registers.
When writing functions in IWBASIC, it is safe to assume IWBASIC will save the EBX, ESI, and EDI registers upon entry into and exiting out of a IWBASIC function.
1.7 Modes of Operation
The Intel IA-32 architecture supports three operating modes: real-address mode, protected mode, and system management mode. Another mode called virtual-8086 mode is a special case of protected mode. The operating mode determines which assembly instructions are available to you when programming.
1.7.1 Protected Mode
The primary operating mode of interest to us is the 32-bit protected mode. Protected mode is the native state of the processor and executes using the flat memory model. The flat memory model appears to a program as a single, continuous address area located in memory. Intel refers to this space as linear address space and includes the code, data, and stack sections of your programs. In 32-bit programming, the operating system assigns your program up to 4 gigabytes of memory in which to store data and execute code.
Protected mode is designed to prevent programs from overwriting each other’s program code and data areas. However, the power and flexibility of inline assembly allows you to read and write data to almost any memory address in your program space. For this reason, it is imperative that you ensure your code behaves properly.
For the most part, when you write inline assembly code, you will be on your own. IWBASIC cannot save you from writing badly structured and poorly behaved assembly code. Even the underlying assembler can’t catch all your coding mistakes. Therefore, to write effective and stable inline assembly code, you should become familiar with the key aspects of 32-bit protected mode programming. You can supplement your knowledge by reading the Intel manuals as well as the NASM User’s Guide. Caution, these manuals are not light reading.
1.7.2 Real Address Mode
Real address mode implements the Intel 8086 processor environment. This mode was available in Windows 98 and used to run MS-DOS programs that required direct access to system memory and hardware devices. Programs running in this mode often crashed because they were able to write to each other’s allocated memory space as well as to the operating system program space.
When IA-32 processors operate in real address mode, they are limited to 1MB of memory space using 20-bit addresses in the range 0 to FFFFF hexadecimal. Real address mode also uses 16-bit segmented values that cause programmers to be concerned about programming segment registers. Unlike protected mode where the data, code, and stack areas are located in the same segment, real address mode puts the data, code, and stack in different segments addressed by the DS, CS, and SS registers.
1.7.3 System Management Mode
System management mode (SMM) provides an operating system with methods for implementing functions related to power management and system security. SMM is a standard architectural feature in all IA-32 processors. This mode is typically used by computer manufacturers to customize the processor for a particular system setup. In SMM, the processor switches to a separate address space while saving the context of the currently running task.
1.8 Putting it all Together
You are probably eager to try writing your first program using inline assembly. To help you become familiar with inline assembly coding, let’s look at a quick sample program. You might not understand everything you are typing at this point, but you should be able to determine how inline assembly is inserted into IWBASIC code.
Open IWBASIC and type the code in Listing 1-1 into a new editor window.
Listing 1-1 First Inline Assembly Program
INT myInt = 500 REM Declare IWBASIC global variable, REM use the quote (‘) or REM directive to indicate IWBASIC comments _asm ; Declare a block of inline assembly code, ; use semi-colons to indicate assembly comments mov eax, [myInt] ; Copy the contents of the IWBASIC global variable myInt ; into the EAX register add eax, 100 ; Add 100 to the contents of the EAX register, ; now EAX = EAX + 100 (i.e., EAX = 500 + 100) mov [myInt], eax ; Copy result in EAX back into the global variable myInt, ; note the brackets around myInt _endasm REM We are outside the assembly block, so now we are back to REM using quotes or REM to delineate IWBASIC comments PRINT myInt REM Write 600 to the screen DO: UNTIL INKEY$ <> “” REM Wait until a key is pressed END REM Close console window and exit program
Congratulations, you have just written your first program using inline assembly. When you compile and run this program, it should print the number 600 to your screen. Don’t worry about understanding this program just yet. Just note that “_asm” and “_endasm” tell IWBASIC that the instructions contained between these two directives represent inline assembly code. IWBASIC will ignore all instructions between “_asm” and “_endasm” and pass them on to the NASM assembler to be assembled. Since all statements contained within an assembly block are passed to NASM, they must conform to the syntax requirements found in the NASM User’s Manual.
1.9 Chapter Review
Chapter 1 introduced you to the Intel IA-32 microprocessor system. We discussed the key components of the 80x86 microprocessor of interest to novice inline assembly programmers. You also learned that the 80x86 architecture contains general purpose registers; index, stack, and instruction pointers; segment registers; EFLAGS register; 80-bit floating-point registers, 64-bit MMX registers, 128-bit XMM registers, and a set of assembly language instructions. Finally, you learned that the 80x86 processor has three operating modes and that each mode has memory access limits.
Chapter 1 Exercises:
- How much memory can be accessed by your program when running in 32-bit protected mode?
- What are the names of the general purpose registers and what are they used for?
- In combination with the CS segment register, what does the EIP register point to?
- Which direction does the stack expand in memory?
- What does each of the six status flags indicate?
- What are the three modes of operation for the Intel IA-32 family of microprocessors?
- What is a major drawback of the MMX registers?
- What are the memory sections used by your programs and what are they used for?
- Which general purpose registers can you use in your inline assembly code?
- Which registers must be saved if you intend on using them in your assembly code?