The Eip Register Can Be the Destination Operand of a Mov, Add, or Sub Instruction.
x86 Associates Guide
Contents: Registers | Retention and Addressing | Instructions | Calling Convention
This is a version adapted by Quentin Carbonneaux from David Evans' original document. The syntax was inverse from Intel to AT&T, the standard syntax on UNIX systems, and the HTML lawmaking was purified.
This guide describes the nuts of 32-bit x86 associates linguistic communication programming, covering a small but useful subset of the available instructions and assembler directives. There are several dissimilar associates languages for generating x86 car code. The one nosotros volition use in CS421 is the GNU Assembler (gas) assembler. We will uses the standard AT&T syntax for writing x86 associates code.
The full x86 instruction set is big and complex (Intel's x86 educational activity fix manuals comprise over 2900 pages), and nosotros do non embrace it all in this guide. For case, there is a 16-scrap subset of the x86 instruction set. Using the sixteen-bit programming model tin can be quite complex. It has a segmented retentivity model, more restrictions on register usage, and then on. In this guide, we will limit our attention to more modern aspects of x86 programming, and delve into the instruction fix only in enough detail to become a basic feel for x86 programming.
Registers
Modern (i.e 386 and beyond) x86 processors have viii 32-scrap full general purpose registers, equally depicted in Figure 1. The register names are mostly historical. For instance, EAX used to be called the accumulator since information technology was used by a number of arithmetic operations, and ECX was known as the counter since it was used to hold a loop index. Whereas near of the registers accept lost their special purposes in the modern instruction set, by convention, two are reserved for special purposes — the stack pointer (ESP) and the base arrow (EBP).
For the EAX, EBX, ECX, and EDX registers, subsections may be used. For example, the to the lowest degree pregnant 2 bytes of EAX tin can exist treated as a 16-bit annals called AX. The least significant byte of AX can be used as a single 8-bit register called AL, while the almost significant byte of AX tin can be used as a single eight-flake register called AH. These names refer to the aforementioned physical register. When a 2-byte quantity is placed into DX, the update affects the value of DH, DL, and EDX. These sub-registers are mainly hold-overs from older, 16-bit versions of the teaching set. All the same, they are sometimes convenient when dealing with data that are smaller than 32-bits (eastward.g. 1-byte ASCII characters).
Figure i. x86 Registers
Retention and Addressing Modes
Declaring Static Data Regions
You can declare static information regions (analogous to global variables) in x86 assembly using special assembler directives for this purpose. Data declarations should be preceded by the .data directive. Following this directive, the directives .byte, .short, and .long can exist used to declare 1, ii, and 4 byte data locations, respectively. To refer to the address of the information created, nosotros can characterization them. Labels are very useful and versatile in assembly, they requite names to memory locations that will be figured out later by the assembler or the linker. This is similar to declaring variables past proper noun, only abides past some lower level rules. For example, locations declared in sequence volition exist located in memory next to one some other.
Instance declarations:
.data var: .byte 64 /* Declare a byte, referred to as location var, containing the value 64. */ .byte 10 /* Declare a byte with no label, containing the value 10. Its location is var + 1. */ x: .curt 42 /* Declare a 2-byte value initialized to 42, referred to equally location x. */ y: .long 30000 /* Declare a 4-byte value, referred to every bit location y, initialized to 30000. */
Unlike in high level languages where arrays can have many dimensions and are accessed by indices, arrays in x86 assembly linguistic communication are simply a number of cells located contiguously in memory. An array can exist alleged by just listing the values, every bit in the first example below. For the special case of an array of bytes, string literals can be used. In instance a large area of memory is filled with zeroes the .nil directive tin be used.
Some examples:
due south: .long 1, 2, 3 /* Declare three 4-byte values, initialized to ane, 2, and 3.
The value at location s + eight will be 3. */barr: .zero 10 /* Declare 10 bytes starting at location barr, initialized to 0. */ str: .string "hi" /* Declare 6 bytes starting at the accost str initialized to
the ASCII character values for hello followed by a nul (0) byte. */
Addressing Retentivity
Modern x86-compatible processors are capable of addressing up to two32 bytes of retentivity: memory addresses are 32-bits broad. In the examples above, where we used labels to refer to memory regions, these labels are really replaced by the assembler with 32-bit quantities that specify addresses in memory. In addition to supporting referring to memory regions by labels (i.e. constant values), the x86 provides a flexible scheme for computing and referring to memory addresses: up to 2 of the 32-bit registers and a 32-flake signed constant can exist added together to compute a memory address. 1 of the registers can be optionally pre-multiplied by 2, 4, or 8.
The addressing modes can be used with many x86 instructions (we'll draw them in the next section). Hither nosotros illustrate some examples using the mov teaching that moves data between registers and retentiveness. This instruction has two operands: the first is the source and the second specifies the destination.
Some examples of mov instructions using address computations are:
mov (%ebx), %eax /* Load 4 bytes from the memory address in EBX into EAX. */ mov %ebx, var(,one) /* Move the contents of EBX into the 4 bytes at memory address var.
(Annotation, var is a 32-bit abiding). */mov -4(%esi), %eax /* Move iv bytes at memory accost ESI + (-4) into EAX. */ mov %cl, (%esi,%eax,1) /* Motion the contents of CL into the byte at address ESI+EAX. */ mov (%esi,%ebx,iv), %edx /* Motion the 4 bytes of information at address ESI+4*EBX into EDX. */
Some examples of invalid address calculations include:
mov (%ebx,%ecx,-i), %eax /* Tin only add register values. */ mov %ebx, (%eax,%esi,%edi,1) /* At well-nigh ii registers in address computation. */
Operation Suffixes
In general, the intended size of the of the data item at a given memory address can exist inferred from the associates code teaching in which it is referenced. For instance, in all of the above instructions, the size of the memory regions could be inferred from the size of the register operand. When we were loading a 32-chip annals, the assembler could infer that the region of memory we were referring to was 4 bytes wide. When we were storing the value of a 1 byte register to retention, the assembler could infer that we wanted the accost to refer to a unmarried byte in memory.
However, in some cases the size of a referred-to retentivity region is ambiguous. Consider the instruction mov $2, (%ebx). Should this pedagogy move the value 2 into the single byte at accost EBX? Perhaps information technology should move the 32-bit integer representation of ii into the 4-bytes starting at address EBX. Since either is a valid possible interpretation, the assembler must be explicitly directed as to which is correct. The size prefixes b, w, and l serve this purpose, indicating sizes of one, 2, and 4 bytes respectively.
For example:
movb $ii, (%ebx) /* Motility 2 into the single byte at the address stored in EBX. */ movw $2, (%ebx) /* Move the xvi-bit integer representation of 2 into the 2 bytes starting at the address in EBX. */ movl $ii, (%ebx) /* Move the 32-bit integer representation of two into the 4 bytes starting at the address in EBX. */
Instructions
Machine instructions generally fall into three categories: data movement, arithmetics/logic, and control-catamenia. In this section, we will look at of import examples of x86 instructions from each category. This section should not exist considered an exhaustive list of x86 instructions, but rather a useful subset. For a complete list, see Intel's instruction set reference.
Nosotros utilise the following notation:
<reg32> Any 32-bit register (%eax, %ebx, %ecx, %edx, %esi, %edi, %esp, or %ebp) <reg16> Whatever 16-flake annals (%ax, %bx, %cx, or %dx) <reg8> Whatsoever 8-scrap register (%ah, %bh, %ch, %dh, %al, %bl, %cl, or %dl) <reg> Any annals <mem> A memory address (east.thousand., (%eax), iv+var(,ane), or (%eax,%ebx,1)) <con32> Any 32-bit immediate <con16> Any xvi-fleck immediate <con8> Any 8-flake immediate <con> Whatever 8-, 16-, or 32-bit firsthand
In associates language, all the labels and numeric constants used every bit immediate operands (i.e. not in an accost calculation similar 3(%eax,%ebx,viii)) are always prefixed by a dollar sign. When needed, hexadecimal notation can be used with the 0x prefix (east.one thousand. $0xABC). Without the prefix, numbers are interpreted in the decimal basis.
Information Movement Instructions
mov — Move
The mov instruction copies the data particular referred to past its kickoff operand (i.e. register contents, memory contents, or a constant value) into the location referred to past its second operand (i.e. a register or memory). While annals-to-register moves are possible, straight memory-to-memory moves are not. In cases where memory transfers are desired, the source memory contents must first exist loaded into a register, and so tin can be stored to the destination memory address.Syntax
mov <reg>, <reg>
mov <reg>, <mem>
mov <mem>, <reg>
mov <con>, <reg>
mov <con>, <mem>
Examples
mov %ebx, %eax — copy the value in EBX into EAX
movb $5, var(,1) — store the value v into the byte at location var
push — Push on stack
The push button instruction places its operand onto the top of the hardware supported stack in retention. Specifically, push button first decrements ESP past four, so places its operand into the contents of the 32-scrap location at address (%esp). ESP (the stack pointer) is decremented by push since the x86 stack grows downwards — i.eastward. the stack grows from high addresses to lower addresses.Syntax
push <reg32>
push <mem>
push <con32>Examples
push %eax — push eax on the stack
push var(,1) — push button the 4 bytes at address var onto the stack
popular — Popular from stack
The pop instruction removes the 4-byte data element from the top of the hardware-supported stack into the specified operand (i.east. register or retentiveness location). It showtime moves the 4 bytes located at memory location (%esp) into the specified register or memory location, and then increments ESP by 4.Syntax
Examples
pop <reg32>
pop <mem>
pop %edi — pop the top chemical element of the stack into EDI.
pop (%ebx) — pop the meridian chemical element of the stack into retentivity at the 4 bytes starting at location EBX.
lea — Load constructive address
The lea instruction places the address specified past its kickoff operand into the register specified by its second operand. Note, the contents of the memory location are non loaded, just the effective address is computed and placed into the annals. This is useful for obtaining a pointer into a memory region or to perform uncomplicated arithmetics operations.Syntax
lea <mem>, <reg32>
Examples
lea (%ebx,%esi,8), %edi — the quantity EBX+eight*ESI is placed in EDI.
lea val(,one), %eax — the value val is placed in EAX.
Arithmetic and Logic Instructions
add — Integer addition
The add instruction adds together its ii operands, storing the issue in its second operand. Note, whereas both operands may be registers, at most one operand may be a retentiveness location.Syntax
add <reg>, <reg>
add together <mem>, <reg>
add <reg>, <mem>
add <con>, <reg>
add together <con>, <mem>
Examples
add $10, %eax — EAX is fix to EAX + x
addb $ten, (%eax) — add ten to the single byte stored at memory accost stored in EAX
sub — Integer subtraction
The sub instruction stores in the value of its second operand the outcome of subtracting the value of its beginning operand from the value of its second operand. As with add, whereas both operands may exist registers, at most one operand may be a memory location.Syntax
sub <reg>, <reg>
sub <mem>, <reg>
sub <reg>, <mem>
sub <con>, <reg>
sub <con>, <mem>
Examples
sub %ah, %al — AL is ready to AL - AH
sub $216, %eax — subtract 216 from the value stored in EAX
inc, dec — Increment, Decrement
The inc education increments the contents of its operand by one. The dec didactics decrements the contents of its operand by one.Syntax
inc <reg>
inc <mem>
dec <reg>
december <mem>Examples
dec %eax — decrease one from the contents of EAX
incl var(,1) — add ane to the 32-bit integer stored at location var
imul — Integer multiplication
The imul instruction has two bones formats: two-operand (first two syntax listings in a higher place) and 3-operand (last two syntax listings above).The two-operand form multiplies its two operands together and stores the effect in the second operand. The event (i.e. 2d) operand must exist a register.
The three operand grade multiplies its second and third operands together and stores the issue in its last operand. Once more, the result operand must be a register. Furthermore, the start operand is restricted to being a abiding value.
Syntax
imul <reg32>, <reg32>
imul <mem>, <reg32>
imul <con>, <reg32>, <reg32>
imul <con>, <mem>, <reg32>Examples
imul (%ebx), %eax — multiply the contents of EAX past the 32-bit contents of the memory at location EBX. Store the outcome in EAX.
imul $25, %edi, %esi — ESI is set to EDI * 25
idiv — Integer partition
The idiv educational activity divides the contents of the 64 bit integer EDX:EAX (synthetic by viewing EDX every bit the most significant four bytes and EAX as the least pregnant four bytes) by the specified operand value. The quotient event of the division is stored into EAX, while the remainder is placed in EDX.Syntax
idiv <reg32>
idiv <mem>Examples
idiv %ebx — divide the contents of EDX:EAX by the contents of EBX. Identify the quotient in EAX and the rest in EDX.
idivw (%ebx) — divide the contents of EDX:EAS past the 32-scrap value stored at the retention location in EBX. Place the caliber in EAX and the remainder in EDX.
and, or, xor — Bitwise logical and, or, and exclusive or
These instructions perform the specified logical functioning (logical bitwise and, or, and exclusive or, respectively) on their operands, placing the result in the kickoff operand location.Syntax
and <reg>, <reg>
and <mem>, <reg>
and <reg>, <mem>
and <con>, <reg>
and <con>, <mem>
or <reg>, <reg>
or <mem>, <reg>
or <reg>, <mem>
or <con>, <reg>
or <con>, <mem>
xor <reg>, <reg>
xor <mem>, <reg>
xor <reg>, <mem>
xor <con>, <reg>
xor <con>, <mem>
Examples
and $0x0f, %eax — clear all but the concluding 4 $.25 of EAX.
xor %edx, %edx — set the contents of EDX to zero.
not — Bitwise logical non
Logically negates the operand contents (that is, flips all bit values in the operand).Syntax
non <reg>
not <mem>Instance
not %eax — flip all the bits of EAX
neg — Negate
Performs the two'southward complement negation of the operand contents.Syntax
neg <reg>
neg <mem>Example
neg %eax — EAX is gear up to (- EAX)
shl, shr — Shift left and right
These instructions shift the bits in their first operand's contents left and right, padding the resulting empty fleck positions with zeros. The shifted operand can exist shifted upwardly to 31 places. The number of bits to shift is specified by the second operand, which can be either an 8-bit constant or the annals CL. In either case, shifts counts of greater then 31 are performed modulo 32.Syntax
shl <con8>, <reg>
shl <con8>, <mem>
shl %cl, <reg>
shl %cl, <mem>shr <con8>, <reg>
shr <con8>, <mem>
shr %cl, <reg>
shr %cl, <mem>Examples
shl $1, eax — Multiply the value of EAX by two (if the most significant fleck is 0)
shr %cl, %ebx — Store in EBX the floor of result of dividing the value of EBX by 2 n where due north is the value in CL. Caution: for negative integers, it is different from the C semantics of division!
Command Flow Instructions
The x86 processor maintains an instruction pointer (EIP) annals that is a 32-fleck value indicating the location in retention where the current instruction starts. Normally, it increments to signal to the adjacent teaching in memory begins subsequently execution an instruction. The EIP register cannot be manipulated straight, only is updated implicitly past provided control flow instructions.
We use the notation <label> to refer to labeled locations in the program text. Labels tin be inserted anywhere in x86 assembly code text by entering a label proper name followed by a colon. For instance,
mov eight(%ebp), %esi brainstorm: xor %ecx, %ecx mov (%esi), %eax
The second education in this lawmaking fragment is labeled begin. Elsewhere in the lawmaking, we tin refer to the memory location that this didactics is located at in memory using the more convenient symbolic proper name begin. This label is merely a convenient way of expressing the location instead of its 32-bit value.
jmp — Spring
Transfers program control flow to the instruction at the retentiveness location indicated by the operand.Syntax
jmp <characterization>Example
jmp begin — Spring to the instruction labeled begin.
jcondition — Conditional jump
These instructions are conditional jumps that are based on the status of a prepare of condition codes that are stored in a special annals called the auto condition word. The contents of the machine status discussion include data most the last arithmetic operation performed. For example, i bit of this discussion indicates if the concluding result was zero. Another indicates if the concluding result was negative. Based on these condition codes, a number of conditional jumps tin can exist performed. For example, the jz instruction performs a jump to the specified operand label if the result of the final arithmetic operation was zero. Otherwise, control gain to the next instruction in sequence.A number of the provisional branches are given names that are intuitively based on the final performance performed being a special compare teaching, cmp (see below). For example, conditional branches such as jle and jne are based on get-go performing a cmp performance on the desired operands.
Syntax
je <characterization> (jump when equal)
jne <label> (bound when not equal)
jz <label> (jump when last result was zippo)
jg <label> (jump when greater than)
jge <characterization> (jump when greater than or equal to)
jl <characterization> (jump when less than)
jle <label> (jump when less than or equal to)Example
cmp %ebx, %eax jle doneIf the contents of EAX are less than or equal to the contents of EBX, spring to the characterization done. Otherwise, continue to the next didactics.
cmp — Compare
Compare the values of the ii specified operands, setting the condition codes in the machine status word accordingly. This education is equivalent to the sub instruction, except the outcome of the subtraction is discarded instead of replacing the offset operand.Syntax
cmp <reg>, <reg>
cmp <mem>, <reg>
cmp <reg>, <mem>
cmp <con>, <reg>Example
cmpb $10, (%ebx)
jeq loopIf the byte stored at the memory location in EBX is equal to the integer constant 10, jump to the location labeled loop.
call, ret — Subroutine phone call and render
These instructions implement a subroutine call and return. The phone call educational activity first pushes the current code location onto the hardware supported stack in memory (see the push education for details), and and then performs an unconditional jump to the code location indicated by the label operand. Dissimilar the simple spring instructions, the call instruction saves the location to render to when the subroutine completes.The ret instruction implements a subroutine return mechanism. This educational activity first pops a lawmaking location off the hardware supported in-memory stack (run into the pop education for details). It then performs an unconditional jump to the retrieved lawmaking location.
Syntax
call <label>
ret
Calling Convention
To permit separate programmers to share code and develop libraries for utilise by many programs, and to simplify the use of subroutines in general, programmers typically prefer a mutual calling convention. The calling convention is a protocol well-nigh how to call and render from routines. For case, given a set of calling convention rules, a developer demand not examine the definition of a subroutine to determine how parameters should be passed to that subroutine. Furthermore, given a set of calling convention rules, high-level language compilers can exist made to follow the rules, thus allowing paw-coded assembly language routines and high-level language routines to phone call one some other.
In practice, many calling conventions are possible. Nosotros volition describe the widely used C language calling convention. Following this convention volition permit yous to write assembly language subroutines that are safely callable from C (and C++) lawmaking, and will also enable you lot to phone call C library functions from your assembly language code.
The C calling convention is based heavily on the employ of the hardware-supported stack. Information technology is based on the push, pop, call, and ret instructions. Subroutine parameters are passed on the stack. Registers are saved on the stack, and local variables used past subroutines are placed in retentiveness on the stack. The vast majority of high-level procedural languages implemented on most processors have used similar calling conventions.
The calling convention is cleaved into 2 sets of rules. The first fix of rules is employed by the caller of the subroutine, and the 2nd gear up of rules is observed by the writer of the subroutine (the callee). It should be emphasized that mistakes in the observance of these rules quickly result in fatal program errors since the stack will be left in an inconsistent state; thus meticulous care should be used when implementing the call convention in your own subroutines.
Stack during Subroutine Phone call
[Cheers to James Peterson for finding and fixing the bug in the original version of this figure!]
A good mode to visualize the operation of the calling convention is to describe the contents of the nearby region of the stack during subroutine execution. The image above depicts the contents of the stack during the execution of a subroutine with iii parameters and three local variables. The cells depicted in the stack are 32-bit wide memory locations, thus the retentivity addresses of the cells are four bytes apart. The first parameter resides at an offset of 8 bytes from the base of operations pointer. Above the parameters on the stack (and beneath the base pointer), the call instruction placed the return address, thus leading to an extra four bytes of offset from the base of operations arrow to the outset parameter. When the ret instruction is used to return from the subroutine, information technology volition jump to the render address stored on the stack.
Caller Rules
To make a subrouting call, the caller should:
- Before calling a subroutine, the caller should salvage the contents of sure registers that are designated caller-saved. The caller-saved registers are EAX, ECX, EDX. Since the called subroutine is allowed to change these registers, if the caller relies on their values afterwards the subroutine returns, the caller must push the values in these registers onto the stack (so they can be restore after the subroutine returns.
- To pass parameters to the subroutine, push them onto the stack before the call. The parameters should be pushed in inverted order (i.e. concluding parameter first). Since the stack grows down, the first parameter will be stored at the lowest address (this inversion of parameters was historically used to allow functions to be passed a variable number of parameters).
- To call the subroutine, employ the call instruction. This education places the return accost on top of the parameters on the stack, and branches to the subroutine code. This invokes the subroutine, which should follow the callee rules below.
Subsequently the subroutine returns (immediately following the call pedagogy), the caller can expect to find the return value of the subroutine in the register EAX. To restore the machine state, the caller should:
- Remove the parameters from stack. This restores the stack to its state earlier the telephone call was performed.
- Restore the contents of caller-saved registers (EAX, ECX, EDX) by popping them off of the stack. The caller can assume that no other registers were modified past the subroutine.
Instance
The lawmaking beneath shows a office call that follows the caller rules. The caller is calling a function myFunc that takes three integer parameters. First parameter is in EAX, the second parameter is the constant 216; the 3rd parameter is in the memory location stored in EBX.
push (%ebx) /* Push last parameter first */ push $216 /* Push button the second parameter */ button %eax /* Push button showtime parameter terminal */ call myFunc /* Call the function (assume C naming) */ add $12, %esp
Note that after the call returns, the caller cleans up the stack using the add instruction. We have 12 bytes (3 parameters * iv bytes each) on the stack, and the stack grows down. Thus, to get rid of the parameters, we can merely add 12 to the stack pointer.
The effect produced by myFunc is now available for use in the annals EAX. The values of the caller-saved registers (ECX and EDX), may take been inverse. If the caller uses them after the call, it would have needed to save them on the stack before the call and restore them after it.
Callee Rules
The definition of the subroutine should attach to the following rules at the offset of the subroutine:
- Push the value of EBP onto the stack, and then copy the value of ESP into EBP using the following instructions:
push %ebp mov %esp, %ebp
This initial action maintains the base of operations pointer, EBP. The base pointer is used by convention equally a point of reference for finding parameters and local variables on the stack. When a subroutine is executing, the base arrow holds a re-create of the stack pointer value from when the subroutine started executing. Parameters and local variables will always exist located at known, constant offsets away from the base arrow value. We push the one-time base pointer value at the outset of the subroutine so that we tin can afterward restore the appropriate base pointer value for the caller when the subroutine returns. Remember, the caller is not expecting the subroutine to modify the value of the base pointer. We then motion the stack pointer into EBP to obtain our point of reference for accessing parameters and local variables. - Next, classify local variables by making space on the stack. Recall, the stack grows down, so to brand space on the height of the stack, the stack pointer should be decremented. The amount past which the stack arrow is decremented depends on the number and size of local variables needed. For example, if 3 local integers (4 bytes each) were required, the stack pointer would need to be decremented by 12 to brand space for these local variables (i.e., sub $12, %esp). Every bit with parameters, local variables volition be located at known offsets from the base pointer.
- Next, salve the values of the callee-saved registers that will be used by the part. To relieve registers, push them onto the stack. The callee-saved registers are EBX, EDI, and ESI (ESP and EBP will also exist preserved by the calling convention, but demand not exist pushed on the stack during this step).
After these three actions are performed, the body of the subroutine may proceed. When the subroutine is returns, it must follow these steps:
- Leave the render value in EAX.
- Restore the old values of any callee-saved registers (EDI and ESI) that were modified. The register contents are restored past popping them from the stack. The registers should be popped in the inverse order that they were pushed.
- Deallocate local variables. The obvious mode to practise this might be to add together the appropriate value to the stack arrow (since the space was allocated by subtracting the needed amount from the stack pointer). In exercise, a less error-prone way to deallocate the variables is to move the value in the base pointer into the stack arrow: mov %ebp, %esp. This works because the base pointer always contains the value that the stack arrow contained immediately prior to the allocation of the local variables.
- Immediately before returning, restore the caller's base arrow value past popping EBP off the stack. Recall that the first thing we did on entry to the subroutine was to push button the base pointer to save its onetime value.
- Finally, render to the caller by executing a ret teaching. This instruction will notice and remove the advisable return address from the stack.
Note that the callee's rules fall cleanly into two halves that are basically mirror images of one some other. The first half of the rules apply to the beginning of the function, and are unremarkably said to define the prologue to the function. The latter half of the rules use to the terminate of the function, and are thus commonly said to ascertain the epilogue of the part.
Example
Here is an example function definition that follows the callee rules:
/* Start the code section */ .text /* Ascertain myFunc as a global (exported) function. */ .globl myFunc .blazon myFunc, @role myFunc: /* Subroutine Prologue */ push %ebp /* Salve the old base arrow value. */ mov %esp, %ebp /* Set the new base pointer value. */ sub $iv, %esp /* Make room for i 4-byte local variable. */ push %edi /* Salvage the values of registers that the role */ push %esi /* volition modify. This function uses EDI and ESI. */ /* (no need to save EBX, EBP, or ESP) */ /* Subroutine Torso */ mov viii(%ebp), %eax /* Move value of parameter 1 into EAX. */ mov 12(%ebp), %esi /* Motility value of parameter 2 into ESI. */ mov 16(%ebp), %edi /* Move value of parameter 3 into EDI. */ mov %edi, -4(%ebp) /* Move EDI into the local variable. */ add together %esi, -4(%ebp) /* Add ESI into the local variable. */ add -iv(%ebp), %eax /* Add the contents of the local variable */ /* into EAX (terminal result). */ /* Subroutine Epilogue */ pop %esi /* Recover register values. */ pop %edi mov %ebp, %esp /* Deallocate the local variable. */ pop %ebp /* Restore the caller's base of operations pointer value. */ ret
The subroutine prologue performs the standard actions of saving a snapshot of the stack pointer in EBP (the base pointer), allocating local variables by decrementing the stack arrow, and saving register values on the stack.
In the body of the subroutine we can see the use of the base pointer. Both parameters and local variables are located at constant offsets from the base pointer for the elapsing of the subroutines execution. In item, nosotros notice that since parameters were placed onto the stack earlier the subroutine was called, they are e'er located below the base pointer (i.e. at higher addresses) on the stack. The first parameter to the subroutine can e'er be found at memory location (EBP+8), the second at (EBP+12), the third at (EBP+xvi). Similarly, since local variables are allocated later the base pointer is set, they ever reside above the base arrow (i.due east. at lower addresses) on the stack. In particular, the first local variable is always located at (EBP-4), the second at (EBP-8), then on. This conventional use of the base of operations pointer allows us to apace identify the use of local variables and parameters inside a function torso.
The function epilogue is basically a mirror image of the role prologue. The caller'southward register values are recovered from the stack, the local variables are deallocated by resetting the stack pointer, the caller'southward base arrow value is recovered, and the ret instruction is used to return to the appropriate lawmaking location in the caller.
Credits: This guide was originally created by Adam Ferrari many years ago,
and since updated past Alan Batson, Mike Lack, and Anita Jones.
It was revised for 216 Spring 2006 by David Evans.
It was finally modified by Quentin Carbonneaux to use the AT&T syntax for Yale'south CS421.
Source: https://flint.cs.yale.edu/cs421/papers/x86-asm/asm.html
0 Response to "The Eip Register Can Be the Destination Operand of a Mov, Add, or Sub Instruction."
Postar um comentário