banner



Can You Push Two Registers

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 changed from Intel to AT&T, the standard syntax on UNIX systems, and the HTML lawmaking was purified.

This guide describes the nuts of 32-chip x86 associates language programming, covering a small but useful subset of the available instructions and assembler directives. In that location are several dissimilar assembly languages for generating x86 machine code. The one we will use in CS421 is the GNU Assembler (gas) assembler. We will uses the standard AT&T syntax for writing x86 assembly code.

The total x86 education set is large and complex (Intel's x86 teaching set manuals incorporate over 2900 pages), and we do not embrace it all in this guide. For example, there is a 16-fleck subset of the x86 instruction set. Using the sixteen-bit programming model tin be quite complex. Information technology has a segmented memory model, more restrictions on register usage, and and so on. In this guide, we will limit our attention to more modern aspects of x86 programming, and delve into the educational activity set up simply in plenty detail to get a bones feel for x86 programming.

Registers

Modern (i.e 386 and beyond) x86 processors have eight 32-bit general purpose registers, as depicted in Figure 1. The register names are mostly historical. For example, EAX used to be called the accumulator since it was used by a number of arithmetics operations, and ECX was known equally the counter since it was used to hold a loop index. Whereas most of the registers have lost their special purposes in the mod instruction set, by convention, two are reserved for special purposes — the stack pointer (ESP) and the base of operations pointer (EBP).

For the EAX, EBX, ECX, and EDX registers, subsections may be used. For example, the to the lowest degree significant 2 bytes of EAX can be treated equally a 16-chip register chosen AX. The least significant byte of AX can exist used as a unmarried 8-chip register chosen AL, while the most significant byte of AX tin be used as a single 8-flake register chosen AH. These names refer to the same physical register. When a ii-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, sixteen-bit versions of the instruction ready. However, they are sometimes user-friendly when dealing with data that are smaller than 32-bits (e.g. 1-byte ASCII characters).


Effigy one. x86 Registers

Retentiveness 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. Information declarations should be preceded by the .data directive. Following this directive, the directives .byte, .short, and .long can be used to declare ane, two, and 4 byte data locations, respectively. To refer to the address of the information created, we can characterization them. Labels are very useful and versatile in associates, they requite names to retentivity locations that will exist figured out later by the assembler or the linker. This is like to declaring variables by name, merely abides by some lower level rules. For instance, locations declared in sequence will exist located in retention next to one another.

Example declarations:

.information
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:
.brusk 42 /* Declare a 2-byte value initialized to 42, referred to as location ten. */
y:
.long 30000 /* Declare a 4-byte value, referred to every bit location y, initialized to 30000. */

Different in high level languages where arrays can have many dimensions and are accessed by indices, arrays in x86 assembly language are only a number of cells located contiguously in memory. An array tin can exist alleged past but list the values, as in the get-go case below. For the special case of an array of bytes, cord literals tin can be used. In case a large expanse of memory is filled with zeroes the .cypher directive can exist used.

Some examples:

due south:
.long 1, 2, 3 /* Declare three iv-byte values, initialized to one, 2, and 3.
The value at location s + viii will be 3. */
barr:
.cypher 10 /* Declare ten bytes starting at location barr, initialized to 0. */
str:
.string "howdy" /* Declare 6 bytes starting at the accost str initialized to
the ASCII character values for howdy followed by a nul (0) byte. */

Addressing Retentiveness

Mod x86-compatible processors are capable of addressing up to 232 bytes of memory: memory addresses are 32-bits broad. In the examples above, where we used labels to refer to memory regions, these labels are actually replaced by the assembler with 32-bit quantities that specify addresses in memory. In addition to supporting referring to retentivity regions by labels (i.e. constant values), the x86 provides a flexible scheme for calculating and referring to memory addresses: up to ii of the 32-bit registers and a 32-bit signed constant can exist added together to compute a memory address. One of the registers can be optionally pre-multiplied by 2, 4, or 8.

The addressing modes tin exist used with many x86 instructions (we'll describe them in the next section). Here we illustrate some examples using the mov instruction that moves data betwixt registers and memory. This pedagogy has 2 operands: the starting time is the source and the second specifies the destination.

Some examples of mov instructions using address computations are:

mov (%ebx), %eax /* Load four bytes from the retentiveness address in EBX into EAX. */
mov %ebx, var(,ane) /* Move the contents of EBX into the iv bytes at memory address var.
(Note, var is a 32-bit constant). */
mov -4(%esi), %eax /* Motility 4 bytes at retentiveness address ESI + (-iv) into EAX. */
mov %cl, (%esi,%eax,ane) /* Motion the contents of CL into the byte at accost ESI+EAX. */
mov (%esi,%ebx,4), %edx /* Move the 4 bytes of data at address ESI+4*EBX into EDX. */

Some examples of invalid address calculations include:

mov (%ebx,%ecx,-one), %eax /* Can only add register values. */
mov %ebx, (%eax,%esi,%edi,ane) /* At well-nigh ii registers in address ciphering. */

Operation Suffixes

In full general, the intended size of the of the data item at a given retentiveness accost tin be inferred from the assembly lawmaking didactics in which it is referenced. For example, in all of the higher up instructions, the size of the retention regions could be inferred from the size of the register operand. When nosotros were loading a 32-bit register, the assembler could infer that the region of retentiveness nosotros were referring to was 4 bytes wide. When we were storing the value of a one byte register to retentivity, the assembler could infer that we wanted the address to refer to a single byte in memory.

However, in some cases the size of a referred-to retentivity region is ambiguous. Consider the educational activity mov $two, (%ebx). Should this instruction move the value 2 into the single byte at address EBX? Perhaps information technology should motility the 32-bit integer representation of two into the four-bytes starting at address EBX. Since either is a valid possible estimation, the assembler must exist explicitly directed as to which is correct. The size prefixes b, w, and l serve this purpose, indicating sizes of 1, 2, and 4 bytes respectively.

For example:

movb $2, (%ebx) /* Move 2 into the single byte at the address stored in EBX. */
movw $2, (%ebx) /* Move the 16-bit integer representation of 2 into the ii bytes starting at the address in EBX. */
movl $ii, (%ebx) /* Move the 32-scrap integer representation of 2 into the four bytes starting at the address in EBX. */

Instructions

Machine instructions generally autumn into iii categories: information movement, arithmetic/logic, and control-flow. In this section, we will look at important examples of x86 instructions from each category. This department should non be considered an exhaustive list of x86 instructions, but rather a useful subset. For a complete list, encounter Intel's instruction set reference.

Nosotros use the post-obit notation:

<reg32> Any 32-bit register (%eax, %ebx, %ecx, %edx, %esi, %edi, %esp, or %ebp)
<reg16> Any xvi-fleck register (%ax, %bx, %cx, or %dx)
<reg8> Any 8-chip register (%ah, %bh, %ch, %dh, %al, %bl, %cl, or %dl)
<reg> Any register
<mem> A retentivity accost (e.g., (%eax), 4+var(,ane), or (%eax,%ebx,1))
<con32> Any 32-bit firsthand
<con16> Whatever sixteen-bit immediate
<con8> Any 8-scrap immediate
<con> Any 8-, xvi-, or 32-bit immediate

In assembly language, all the labels and numeric constants used as immediate operands (i.e. non in an address adding like 3(%eax,%ebx,8)) are ever prefixed by a dollar sign. When needed, hexadecimal notation can be used with the 0x prefix (due east.g. $0xABC). Without the prefix, numbers are interpreted in the decimal basis.

Data Movement Instructions

mov — Move

The mov instruction copies the information item referred to by its first operand (i.e. annals contents, retention contents, or a constant value) into the location referred to by its 2d operand (i.eastward. a register or memory). While register-to-annals moves are possible, direct memory-to-memory moves are non. In cases where memory transfers are desired, the source memory contents must first be loaded into a annals, then tin be stored to the destination retentivity address.

Syntax
mov <reg>, <reg>
mov <reg>, <mem>
mov <mem>, <reg>
mov <con>, <reg>
mov <con>, <mem>

Examples
mov %ebx, %eax — re-create the value in EBX into EAX
movb $5, var(,1) — store the value 5 into the byte at location var

button — Push button on stack

The push education places its operand onto the acme of the hardware supported stack in memory. Specifically, push first decrements ESP by four, then places its operand into the contents of the 32-bit location at address (%esp). ESP (the stack arrow) is decremented by push button since the x86 stack grows down — i.e. the stack grows from loftier addresses to lower addresses.

Syntax
push button <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

pop — Popular from stack

The popular instruction removes the four-byte data element from the top of the hardware-supported stack into the specified operand (i.due east. register or retentiveness location). It beginning moves the four bytes located at retention location (%esp) into the specified annals or memory location, and and so increments ESP past iv.

Syntax
pop <reg32>
pop <mem>

Examples
popular %edi — pop the top element of the stack into EDI.
pop (%ebx) — pop the top element of the stack into retention at the four bytes starting at location EBX.

lea — Load effective address

The lea instruction places the address specified past its first operand into the register specified by its second operand. Note, the contents of the memory location are non loaded, only the constructive address is computed and placed into the register. This is useful for obtaining a arrow into a memory region or to perform simple arithmetic operations.

Syntax
lea <mem>, <reg32>

Examples
lea (%ebx,%esi,viii), %edi — the quantity EBX+8*ESI is placed in EDI.
lea val(,i), %eax — the value val is placed in EAX.

Arithmetic and Logic Instructions

add — Integer improver

The add instruction adds together its two operands, storing the outcome in its second operand. Annotation, whereas both operands may be registers, at most 1 operand may be a memory location.

Syntax
add <reg>, <reg>
add <mem>, <reg>
add <reg>, <mem>
add <con>, <reg>
add <con>, <mem>

Examples
add together $10, %eax — EAX is set to EAX + 10
addb $ten, (%eax) — add 10 to the single byte stored at memory address stored in EAX

sub — Integer subtraction

The sub teaching stores in the value of its 2d operand the result of subtracting the value of its first operand from the value of its 2d operand. As with add, whereas both operands may be registers, at most 1 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 fix 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 past ane. The dec teaching decrements the contents of its operand by one.

Syntax
inc <reg>
inc <mem>
dec <reg>
dec <mem>

Examples
dec %eax — subtract 1 from the contents of EAX
incl var(,i) — add together one to the 32-fleck integer stored at location var

imul — Integer multiplication

The imul instruction has two basic formats: two-operand (first two syntax listings above) and iii-operand (last two syntax listings higher up).

The two-operand form multiplies its 2 operands together and stores the result in the second operand. The upshot (i.e. 2d) operand must exist a register.

The iii operand form multiplies its second and 3rd operands together and stores the consequence in its last operand. Once more, the result operand must exist a register. Furthermore, the start operand is restricted to beingness a constant 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-flake contents of the retention at location EBX. Shop the upshot in EAX.

imul $25, %edi, %esi — ESI is set up to EDI * 25

idiv — Integer division

The idiv education divides the contents of the 64 fleck integer EDX:EAX (constructed by viewing EDX as the nearly significant iv bytes and EAX as the least significant four bytes) by the specified operand value. The quotient outcome of the partitioning is stored into EAX, while the residue is placed in EDX.

Syntax
idiv <reg32>
idiv <mem>

Examples

idiv %ebx — divide the contents of EDX:EAX past the contents of EBX. Place the quotient in EAX and the remainder in EDX.

idivw (%ebx) — carve up the contents of EDX:EAS by the 32-bit value stored at the memory location in EBX. Identify the quotient in EAX and the residual in EDX.

and, or, xor — Bitwise logical and, or, and exclusive or

These instructions perform the specified logical operation (logical bitwise and, or, and exclusive or, respectively) on their operands, placing the result in the first 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 last four bits 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
not <reg>
not <mem>

Example
not %eax — flip all the bits of EAX

neg — Negate

Performs the ii's complement negation of the operand contents.

Syntax
neg <reg>
neg <mem>

Case
neg %eax — EAX is set up to (- EAX)

shl, shr — Shift left and correct

These instructions shift the bits in their first operand's contents left and correct, padding the resulting empty bit positions with zeros. The shifted operand tin can exist shifted up to 31 places. The number of bits to shift is specified by the 2nd operand, which can be either an 8-chip abiding or the register 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 past 2 (if the near significant bit 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. Circumspection: for negative integers, information technology is different from the C semantics of division!

Command Catamenia Instructions

The x86 processor maintains an instruction pointer (EIP) register that is a 32-bit value indicating the location in retention where the electric current instruction starts. Commonly, it increments to bespeak to the next instruction in memory begins after execution an instruction. The EIP register cannot be manipulated directly, but is updated implicitly past provided control flow instructions.

We use the notation <label> to refer to labeled locations in the plan text. Labels tin exist inserted anywhere in x86 assembly code text by entering a label proper noun followed by a colon. For instance,

            mov 8(%ebp), %esi begin:        xor %ecx, %ecx        mov (%esi), %eax          

The 2nd educational activity in this code fragment is labeled begin. Elsewhere in the lawmaking, we can refer to the retentivity location that this instruction is located at in memory using the more than convenient symbolic name brainstorm. This label is just a convenient way of expressing the location instead of its 32-bit value.

jmp — Jump

Transfers plan control menstruation to the pedagogy at the retentivity location indicated past the operand.

Syntax
jmp <characterization>

Example
jmp brainstorm — Spring to the education labeled brainstorm.

jcondition — Conditional jump

These instructions are conditional jumps that are based on the condition of a ready of condition codes that are stored in a special register called the machine status give-and-take. The contents of the machine condition word include information near the last arithmetic functioning performed. For example, one bit of this discussion indicates if the terminal result was zero. Some other indicates if the last event was negative. Based on these condition codes, a number of conditional jumps tin can be performed. For example, the jz instruction performs a jump to the specified operand label if the consequence of the concluding arithmetic operation was cipher. Otherwise, control gain to the side by side instruction in sequence.

A number of the conditional branches are given names that are intuitively based on the last functioning performed being a special compare didactics, cmp (run across below). For case, provisional branches such every bit jle and jne are based on first performing a cmp operation on the desired operands.

Syntax
je <label> (jump when equal)
jne <characterization> (bound when not equal)
jz <label> (jump when concluding result was zippo)
jg <label> (jump when greater than)
jge <label> (leap when greater than or equal to)
jl <characterization> (jump when less than)
jle <label> (spring when less than or equal to)

Case

cmp %ebx, %eax jle done          

If the contents of EAX are less than or equal to the contents of EBX, jump to the label washed. Otherwise, continue to the adjacent instruction.

cmp — Compare

Compare the values of the ii specified operands, setting the condition codes in the auto status word appropriately. This instruction is equivalent to the sub didactics, except the result of the subtraction is discarded instead of replacing the showtime operand.

Syntax
cmp <reg>, <reg>
cmp <mem>, <reg>
cmp <reg>, <mem>
cmp <con>, <reg>

Case
cmpb $10, (%ebx)
jeq loop

If the byte stored at the memory location in EBX is equal to the integer constant 10, spring to the location labeled loop.

call, ret — Subroutine call and return

These instructions implement a subroutine call and render. The telephone call instruction first pushes the current code location onto the hardware supported stack in retentiveness (see the push instruction for details), and then performs an unconditional jump to the code location indicated by the label operand. Different the simple jump instructions, the phone call pedagogy saves the location to return to when the subroutine completes.

The ret instruction implements a subroutine return mechanism. This pedagogy start pops a code location off the hardware supported in-memory stack (see the pop pedagogy for details). Information technology then performs an unconditional jump to the retrieved code location.

Syntax
telephone call <label>
ret

Calling Convention

To permit split programmers to share lawmaking and develop libraries for use by many programs, and to simplify the utilize of subroutines in general, programmers typically adopt a common calling convention. The calling convention is a protocol nearly how to telephone call and render from routines. For example, given a set of calling convention rules, a programmer demand non examine the definition of a subroutine to determine how parameters should exist passed to that subroutine. Furthermore, given a ready of calling convention rules, high-level language compilers can exist made to follow the rules, thus allowing mitt-coded assembly linguistic communication routines and high-level language routines to call i another.

In practice, many calling conventions are possible. Nosotros will describe the widely used C language calling convention. Following this convention will allow you to write associates 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 lawmaking.

The C calling convention is based heavily on the use of the hardware-supported stack. It is based on the button, pop, call, and ret instructions. Subroutine parameters are passed on the stack. Registers are saved on the stack, and local variables used by subroutines are placed in retention on the stack. The vast majority of high-level procedural languages implemented on almost processors have used similar calling conventions.

The calling convention is broken into two sets of rules. The first set of rules is employed by the caller of the subroutine, and the second set 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 volition be left in an inconsistent state; thus meticulous care should be used when implementing the call convention in your own subroutines.


Stack during Subroutine Call

[Thanks to James Peterson for finding and fixing the issues in the original version of this figure!]

A adept way to visualize the operation of the calling convention is to depict 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 three parameters and three local variables. The cells depicted in the stack are 32-bit wide memory locations, thus the memory addresses of the cells are iv bytes apart. The first parameter resides at an offset of viii bytes from the base of operations pointer. Above the parameters on the stack (and below the base pointer), the phone call instruction placed the render accost, thus leading to an extra 4 bytes of offset from the base pointer to the outset parameter. When the ret didactics is used to render from the subroutine, it will jump to the return address stored on the stack.

Caller Rules

To make a subrouting telephone call, the caller should:

  1. Before calling a subroutine, the caller should save the contents of certain registers that are designated caller-saved. The caller-saved registers are EAX, ECX, EDX. Since the called subroutine is allowed to modify these registers, if the caller relies on their values afterward the subroutine returns, the caller must push the values in these registers onto the stack (then they can be restore after the subroutine returns.
  2. To pass parameters to the subroutine, push them onto the stack before the telephone call. The parameters should be pushed in inverted order (i.e. concluding parameter kickoff). Since the stack grows down, the starting time parameter volition be stored at the lowest address (this inversion of parameters was historically used to allow functions to exist passed a variable number of parameters).
  3. To call the subroutine, use the telephone call pedagogy. This teaching places the render address 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.

After the subroutine returns (immediately following the call didactics), the caller can look to find the return value of the subroutine in the register EAX. To restore the motorcar land, the caller should:

  1. Remove the parameters from stack. This restores the stack to its country before the telephone call was performed.
  2. 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 by the subroutine.

Example

The lawmaking below shows a function call that follows the caller rules. The caller is calling a function myFunc that takes three integer parameters. First parameter is in EAX, the 2d parameter is the abiding 216; the tertiary parameter is in the memory location stored in EBX.

push (%ebx)    /* Push last parameter offset */ push $216      /* Push the 2d parameter */ push %eax      /* Push starting time parameter terminal */  call myFunc    /* Call the function (assume C naming) */  add together $12, %esp          

Note that after the telephone call returns, the caller cleans up the stack using the add together teaching. We have 12 bytes (3 parameters * 4 bytes each) on the stack, and the stack grows down. Thus, to get rid of the parameters, we can simply add 12 to the stack pointer.

The result produced past myFunc is now bachelor for use in the register EAX. The values of the caller-saved registers (ECX and EDX), may have been inverse. If the caller uses them after the call, it would have needed to save them on the stack before the phone call and restore them afterward it.

Callee Rules

The definition of the subroutine should adhere to the following rules at the beginning of the subroutine:

  1. 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 arrow, EBP. The base arrow is used past convention as a point of reference for finding parameters and local variables on the stack. When a subroutine is executing, the base pointer holds a copy of the stack pointer value from when the subroutine started executing. Parameters and local variables volition always be located at known, constant offsets away from the base pointer value. Nosotros push button the former base pointer value at the beginning of the subroutine and so that we can later restore the appropriate base pointer value for the caller when the subroutine returns. Retrieve, the caller is non expecting the subroutine to change the value of the base pointer. We then motility the stack pointer into EBP to obtain our point of reference for accessing parameters and local variables.
  2. Adjacent, allocate local variables by making space on the stack. Recall, the stack grows down, and so to make space on the top of the stack, the stack pointer should be decremented. The corporeality by which the stack pointer is decremented depends on the number and size of local variables needed. For example, if iii local integers (4 bytes each) were required, the stack pointer would need to be decremented by 12 to make space for these local variables (i.east., sub $12, %esp). Every bit with parameters, local variables volition be located at known offsets from the base pointer.
  3. Next, save the values of the callee-saved registers that volition be used past the function. To save registers, push them onto the stack. The callee-saved registers are EBX, EDI, and ESI (ESP and EBP will also be preserved past the calling convention, but demand non exist pushed on the stack during this pace).

After these three actions are performed, the trunk of the subroutine may keep. When the subroutine is returns, it must follow these steps:

  1. Exit the return value in EAX.
  2. Restore the old values of any callee-saved registers (EDI and ESI) that were modified. The register contents are restored by popping them from the stack. The registers should be popped in the inverse gild that they were pushed.
  3. Deallocate local variables. The obvious style to do this might be to add the appropriate value to the stack arrow (since the infinite was allocated by subtracting the needed corporeality from the stack pointer). In practice, a less fault-prone fashion to deallocate the variables is to move the value in the base of operations pointer into the stack pointer: mov %ebp, %esp. This works considering the base pointer always contains the value that the stack arrow contained immediately prior to the allocation of the local variables.
  4. Immediately before returning, restore the caller'due south base arrow value by popping EBP off the stack. Remember that the offset matter we did on entry to the subroutine was to button the base arrow to salve its old value.
  5. Finally, render to the caller by executing a ret instruction. This instruction will find 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 another. The beginning half of the rules apply to the starting time of the role, and are commonly said to define the prologue to the function. The latter half of the rules apply to the terminate of the office, and are thus normally said to ascertain the epilogue of the function.

Example

Here is an example function definition that follows the callee rules:

            /* Start the code section */   .text    /* Ascertain myFunc equally a global (exported) function. */   .globl myFunc   .type myFunc, @part myFunc:    /* Subroutine Prologue */   push %ebp      /* Save the former base of operations pointer value. */   mov %esp, %ebp /* Set the new base pointer value. */   sub $iv, %esp   /* Make room for ane 4-byte local variable. */   push %edi      /* Relieve the values of registers that the role */   button %esi      /* will change. This function uses EDI and ESI. */   /* (no need to salve EBX, EBP, or ESP) */    /* Subroutine Body */   mov eight(%ebp), %eax   /* Movement value of parameter 1 into EAX. */   mov 12(%ebp), %esi  /* Move value of parameter two into ESI. */   mov 16(%ebp), %edi  /* Motility value of parameter 3 into EDI. */    mov %edi, -four(%ebp)  /* Move EDI into the local variable. */   add together %esi, -4(%ebp)  /* Add ESI into the local variable. */   add -4(%ebp), %eax  /* Add the contents of the local variable */                       /* into EAX (final result). */    /* Subroutine Epilogue */   popular %esi       /* Recover register values. */   pop %edi   mov %ebp, %esp /* Deallocate the local variable. */   pop %ebp       /* Restore the caller's base arrow value. */   ret          

The subroutine prologue performs the standard deportment of saving a snapshot of the stack pointer in EBP (the base pointer), allocating local variables by decrementing the stack pointer, and saving register values on the stack.

In the torso of the subroutine nosotros tin see the use of the base pointer. Both parameters and local variables are located at constant offsets from the base of operations pointer for the duration of the subroutines execution. In item, we notice that since parameters were placed onto the stack before the subroutine was called, they are always located beneath the base pointer (i.eastward. at college addresses) on the stack. The first parameter to the subroutine can always be plant at memory location (EBP+8), the second at (EBP+12), the third at (EBP+16). Similarly, since local variables are allocated later on the base arrow is set, they ever reside to a higher place the base pointer (i.e. at lower addresses) on the stack. In particular, the first local variable is e'er located at (EBP-4), the 2d at (EBP-eight), and and then on. This conventional use of the base pointer allows us to quickly identify the use of local variables and parameters within a role body.

The function epilogue is basically a mirror prototype of the office prologue. The caller's register values are recovered from the stack, the local variables are deallocated by resetting the stack pointer, the caller's base pointer value is recovered, and the ret instruction is used to return to the appropriate code 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 past David Evans.
It was finally modified by Quentin Carbonneaux to use the AT&T syntax for Yale'south CS421.

Can You Push Two Registers,

Source: https://flint.cs.yale.edu/cs421/papers/x86-asm/asm.html

Posted by: williamsbour1950.blogspot.com

0 Response to "Can You Push Two Registers"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel