Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 13

Redefining IMUL and IDIV

Division Terminology
Let's review some basic division terminology. For some reason, I can never keep track of which one is
which.

 The dividend is the number that gets divided.


 The divisor is the number that you divide by.
 The quotient is the answer to the division problem.

In the statement: "6 divided by 2 is 3", 6 is the dividend, 2 is the divisor, and 3 is the quotient.

More about IDIV


IDIV's form will change depending on the data size of the first operand.

IDIV A = Assuming that A is a 32-bit operand, this command divides register-pair EDX:EAX by A and
stores quotient to EAX. Remainder is stored to EDX.
IDIV A = Assuming that A is a 16-bit operand, this command divides register-pair DX:AX by A and
stores quotient to AX. Remainder is stored to DX.
IDIV A = Assuming that A is an 8-bit operand, this command divides register AX by A and stores
quotient to AL. Remainder is stored to AH.

Here are some examples:


IDIV ECX ;Divides EDX:EAX by ECX. Answer goes into EAX.
IDIV DWORD [49E6D0] ;Divides EDX:EAX by the DWORD located at address 49E6D0. Answer
goes into EAX.
IDIV CX ;Divides DX:AX by CX. Answer goes into AX.
IDIV DH ;Divides AX by DH. Answer goes into AL.
Notice that dividing by an 8-bit operand means you never have to worry about register-pairs. If you have
a WORD-sized number that you'd like to divide by a BYTE-sized number, it's not that hard since you can
simply use AX.
MOV AX,7A3
MOV CL,17
IDIV CL ;Divides 7A3 by 17. Answer goes to AL.
Negatives and IDIV
Sometimes you do need to work with register pairs. But there's a problem that we need to take care of.
The way that assembly stores negative numbers brings up an issue with IDIV and register-pairs. 

Recall our old friend, the register pair EDX:EAX.

Scenario A
EDX = 00000000
EAX = 00030000
Therefore, EDX:EAX = 0000000000030000 = 30000

Let's say you wanted to divide 30,000 (hex) by 5 using IDIV. Just do this:
MOV EDX,0 ;The first part of EDX:EAX
MOV EAX,30000 ;Second part. Now EDX:EAX holds 30000.
MOV ECX,5
IDIV ECX ;Divide 30000 by 5. Stores answer to EAX.
But what if you wanted to divide -30000 by 5? Let's try the same thing.

Scenario B
EDX = 00000000
EAX = -00030000
Therefore, EDX:EAX = -30000
You might think this is okay, but it's completely wrong. If EDX holds 0, and EAX holds -30000, it does
NOT mean that EDX:EAX is holding -30000. This is because the negative sign prevents us from pairing
the two numbers together in the regular fashion.

If EAX holds -30000 (signed notation), it actually holds FFFD0000 (unsigned notation).
Since EDX holds 0, then EDX:EAX holds 00000000FFFD0000 (hex). That fails. The correct way to write
-30000 in 64-bits is FFFFFFFFFFFD0000.

In fact, your calculations will not work correctly if you simply try putting 0 into EDX. You would instead
need to put FFFFFFFF into EDX when you want IDIV to work with negative dividends, but 0 into EDX if
you're working with positive dividends.

A Solution: Sign Extension


Now, clearly the negative numbers have totally screwed up our ability to use IDIV easily. But of course,
the people who designed this stuff weren't idiots. They have an automatic system for converting a
DWORD (32-bit) value into a QWORD (64-bit) value, which will take into account whether or not the
DWORD was negative.

CDQ = Convert DWORD to QWORD. This will sign extend EAX to EDX:EAX. In other words, this will store
EAX to EDX:EAX, and will set EDX to the right value even if EAX is negative.

What if we want to IDIV by a 16-bit register or memory location? Don't we have to sign extend AX to
DX:AX?
That's right. So there's also a second instruction that does a similar thing for 16-bit registers:

CWD = Convert WORD to DWORD. This will sign extend AX to DX:AX. In other words, this will store AX
to DX:AX, and will set DX to the right value even if AX is negative.

Using the Solution


Divide -30000 by 5:
MOV EAX,-30000 ;Store -30000 to EAX.
CDQ ;EDX:EAX holds -30000 now.
MOV ECX,5
IDIV ECX ;Divide -30000 by 5. Stores answer to EAX.
Divide 30000 by 5:
MOV EAX,30000 ;Store 30000 to EAX.
CDQ ;EDX:EAX holds 30000 now.
MOV ECX,5
IDIV ECX ;Divide 30000 by 5. Stores answer to EAX.
Divide -2E8D by 11 (using 16-bit registers):
MOV AX,-2E8D ;Store -2E8D to AX.
CWD ;DX:AX holds -2E8D now.
MOV CX,11
IDIV CX ;Divide -2E8D by 11. Stores answer to AX.
So just use CDQ before using IDIV with 32-bit registers. Or, just use CWD before an IDIV with 16-bit
registers. If you do that, then IDIV will work properly with positive and negative numbers. You shouldn't
have any worries about that. 

More about IMUL


There are 3 forms of IMUL that we already learned. They include...

IMUL A,B = Multiply A by B. Store the result to A. A must be a register, but B can be a register or
memory location.
IMUL A,B,C = Multiply B by C. Stores the result to register A. B can be a memory location or register. C
must be a hex number.
IMUL A = Assuming A is a 32-bit operand, this multiplies EAX by A. Stores the result to the register-pair
EDX:EAX. A can be a memory location or register.
I'll give you two more forms of IMUL.

IMUL A = Assuming A is a 16-bit operand, this multiplies AX by A. Stores the result to the register-pair
DX:AX.
IMUL A = Assuming A is an 8-bit operand, this multiplies AL by A. Stores the result to AX. 

As well as some example code: 


IMUL CX ;Calculates AX times CX, stores answer to DX:AX.
IMUL DL ;Calculates AL times DL, stores answer to AX.
Unsigned Multiplication and Division
IDIV and IMUL always treat their numbers as signed numbers. If you want to use unsigned numbers,
then you should use the instructions MUL and DIV (notice the lack of the letter "I" in the beginning).

MUL A = Assuming A is a 32-bit operand, this multiplies EAX by A and stores result to EDX:EAX. Treats
EAX and A as unsigned numbers.
MUL A = Assuming A is a 16-bit operand, this multiplies AX by A and stores result to DX:AX. Treats AX
and A as unsigned numbers.
MUL A = Assuming A is an 8-bit operand, this multiplies AL by A and stores result to AX. Treats AL and A
as unsigned numbers.

DIV A = Assuming A is a 32-bit operand, this divides EDX:EAX by A. Quotient goes to EAX, remainder
goes to EDX. Treats EDX:EAX and A as unsigned numbers.
DIV A = Assuming A is a 16-bit operand, this divides DX:AX by A. Quotient goes to AX, remainder goes
to DX. Treats DX:AX and A as unsigned numbers. 
DIV A = Assuming A is an 8-bit operand, this divides AX by A. Quotient goes to AL, remainder goes to
AH. Treats AX and A as unsigned numbers.

DIV and MUL can accept a register or a memory location as their first operand. 

[Chapter Nine][Previous] [Next] [Art of Assembly][Randall Hyde]

Art of Assembly: Chapter Nine

9.5 - Machine and Arithmetic Idioms


9.5.1 - Multiplying Without MUL and IMUL
9.5.2 - Division Without DIV and IDIV
9.5.3 - Using AND to Compute Remainders
9.5.4 - Implementing Modulo-n Counters with AND
9.5.5 - Testing an Extended Precision Value for 0FFFF..FFh
9.5.6 - TEST Operations
9.5.7 - Testing Signs with the XOR Instruction 

9.5 Machine and Arithmetic Idioms

An idiom is an idiosyncrasy. Several arithmetic operations and 80x86 instructions have idiosyncracies that you can take
advantage of when writing assembly language code. Some people refer to the use of machine and arithmetic idioms as "tricky
programming" that you should always avoid in well written programs. While it is wise to avoid tricks just for the sake of
tricks, many machine and arithmetic idioms are well-known and commonly found in assembly language programs. Some of
them can be really tricky, but a good number of them are simply "tricks of the trade." This text cannot even begin to present
all of the idioms in common use today; they are too numerous and the list is constantly changing. Nevertheless, there are
some very important idioms that you will see all the time, so it makes sense to discuss those.
9.5.1 Multiplying Without MUL and IMUL

If you take a quick look at the timing for the multiply instruction, you'll notice that the execution time for this instruction is
rather long. Only the div and idiv instructions take longer on the 8086. When multiplying by a constant, you can avoid
the performance penalty of the mul and imul instructions by using shifts, additions, and subtractions to perform the
multiplication. 

Remember, a shl operation performs the same operation as multiplying the specified operand by two. Shifting to the left
two bit positions multiplies the operand by four. Shifting to the left three bit positions multiplies the operand by eight. In
general, shifting an operand to the left n bits multiplies it by 2n. Any value can be multiplied by some constant using a series
of shifts and adds or shifts and subtractions. For example, to multiply the ax register by ten, you need only multiply it by
eight and then add in two times the original value. That is, 10*ax = 8*ax + 2*ax. The code to accomplish this is
shl ax, 1 ;Multiply AX by two
mov bx, ax ;Save 2*AX for later
shl ax, 1 ;Multiply AX by four
shl ax, 1 ;Multiply AX by eight
add ax, bx ;Add in 2*AX to get 10*AX
The ax register (or just about any register, for that matter) can be multiplied by most constant values much faster
using shl than by using the mul instruction. This may seem hard to believe since it only takes two instructions to compute
this product:
mov bx, 10
mul bx
However, if you look at the timings, the shift and add example above requires fewer clock cycles on most processors in the
80x86 family than the mul instruction. Of course, the code is somewhat larger (by a few bytes), but the performance
improvement is usually worth it. Of course, on the later 80x86 processors, the mul instruction is quite a bit faster than the
earlier processors, but the shift and add scheme is generally faster on these processors as well.

You can also use subtraction with shifts to perform a multiplication operation. Consider the following multiplication by
seven:
mov bx, ax ;Save AX*1
shl ax, 1 ;AX := AX*2
shl ax, 1 ;AX := AX*4
shl ax, 1 ;AX := AX*8
sub ax, bx ;AX := AX*7
This follows directly from the fact that ax*7 = (ax*8)-ax.

A common error made by beginning assembly language students is subtracting or adding one or two rather
than ax*1 or ax*2. The following does not compute ax*7:
shl ax, 1
shl ax, 1
shl ax, 1
sub ax, 1
It computes (8*ax)-1, something entirely different (unless, of course, ax = 1). Beware of this pitfall when using shifts,
additions, and subtractions to perform multiplication operations.

You can also use the lea instruction to compute certain products on 80386 and later processors. The trick is to use the 80386
scaled index mode. The following examples demonstrate some simple cases:
lea eax, [ecx][ecx] ;EAX := ECX * 2
lea eax, [eax]eax*2] ;EAX := EAX * 3
lea eax, [eax*4] ;EAX := EAX * 4
lea eax, [ebx][ebx*4] ;EAX := EBX * 5
lea eax, [eax*8] ;EAX := EAX * 8
lea eax, [edx][edx*8] ;EAX := EDX * 9

9.5.2 Division Without DIV and IDIV

Much as the shl instruction can be used for simulating a multiplication by some power of two,
the shr and sar instructions can be used to simulate a division by a power of two. Unfortunately, you cannot use shifts,
additions, and subtractions to perform a division by an arbitrary constant as easily as you can use these instructions to
perform a multiplication operation. 

Another way to perform division is to use the multiply instructions. You can divide by some value by multiplying by its
reciprocal. The multiply instruction is marginally faster than the divide instruction; multiplying by a reciprocal is almost
always faster than division.

Now you're probably wondering "how does one multiply by a reciprocal when the values we're dealing with are all integers?"
The answer, of course, is that we must cheat to do this. If you want to multiply by one tenth, there is no way you can load the
value 1/10th into an 80x86 register prior to performing the division. However, we could multiply 1/10th by 10, perform the
multiplication, and then divide the result by ten to get the final result. Of course, this wouldn't buy you anything at all, in fact
it would make things worse since you're now doing a multiplication by ten as well as a division by ten. However, suppose
you multiply 1/10th by 65,536 (6553), perform the multiplication, and then divide by 65,536. This would still perform the
correct operation and, as it turns out, if you set up the problem correctly, you can get the division operation for free. Consider
the following code that divides ax by ten:
mov dx, 6554 ;Round (65,536/10)
mul dx
This code leaves ax/10 in the dx register. 

To understand how this works, consider what happens when you multiply ax by 65,536 (10000h). This simply
moves ax into dx and sets ax to zero. Multiplying by 6,554 (65,536 divided by ten) puts ax divided by ten into
the dx register. Since mul is marginally faster than div , this technique runs a little faster than using a straight division.

Multiplying by the reciprocal works well when you need to divide by a constant. You could even use it to divide by a
variable, but the overhead to compute the reciprocal only pays off if you perform the division many, many times (by the same
value).

9.5.3 Using AND to Compute Remainders

The and instruction can be used to quickly compute remainders of the form:


dest := dest MOD 2n
To compute a remainder using the and instruction, simply and the operand with the value 2n-1. For example, to
compute ax = ax mod 8 simply use the instruction:
and ax, 7
Additional examples:
and ax, 3 ;AX := AX mod 4
and ax, 0Fh ;AX := AX mod 16
and ax, 1Fh ;AX := AX mod 32
and ax, 3Fh ;AX := AX mod 64
and ax, 7Fh ;AX := AX mod 128
mov ah, 0 ;AX := AX mod 256
; (Same as ax and 0FFh)

9.5.4 Implementing Modulo-n Counters with AND

If you want to implement a counter variable that counts up to 2n-1 and then resets to zero, simply using the following code:
inc CounterVar
and CounterVar, nBits
where nBits is a binary value containing n one bits right justified in the number. For example, to create a counter that cycles
between zero and fifteen, you could use the following:
inc CounterVar
and CounterVar, 00001111b

9.5.5 Testing an Extended Precision Value for 0FFFF..FFh

The and instruction can be used to quickly check a multi-word value to see if it contains ones in all its bit positions. Simply
load the first word into the ax register and then logically and the axregister with all the remaining words in the data
structure. When the and operation is complete, the ax register will contain 0FFFFh if and only if all the words in that
structure contained 0FFFFh. E.g.,
mov ax, word ptr var
and ax, word ptr var+2
and ax, word ptr var+4
.
.
.
and ax, word ptr var+n
cmp ax, 0FFFFh
je Is0FFFFh

9.5.6 TEST Operations

Remember, the test instruction is an and instruction that doesn't retain the results of the and operation (other than the
flag settings). Therefore, many of the comments concerning the and operation (particularly with respect to the way it affects
the flags) also hold for the test instruction. However, since the test instruction doesn't affect the destination operand,
multiple bit tests may be performed on the same value. Consider the following code:
test ax, 1
jnz Bit0
test ax, 2
jnz Bit1
test ax, 4
jnz Bit3
etc.
This code can be used to successively test each bit in the ax register (or any other operand for that matter). Note that you
cannot use the test/cmp instruction pair to test for a specific value within a string of bits (as you can with
the and/cmp instructions). Since test doesn't strip out any unwanted bits, the cmp instruction would actually be
comparing the original value rather than the stripped value. For this reason, you'll normally use the test instruction to see
if a single bit is set or if one or more bits out of a group of bits are set. Of course, if you have an 80386 or later processor, you
can also use the bt instruction to test individual bits in an operand.

Another important use of the test instruction is to efficiently compare a register against zero. The following test
instruction sets the zero flag if and only if ax contains zero (anything anded with itself produces its original value; this sets
the zero flag only if that value is zero):
test ax, ax
The test instruction is shorter than
cmp ax, 0
or
cmp eax, 0
though it is no better than
cmp al, 0
Note that you can use the and and or instructions to test for zero in a fashion identical to test. However, on pipelined
processors like the 80486 and Pentium chips, the test instruction is less likely to create a hazard since it does not store a
result back into its destination register.

9.5.7 Testing Signs with the XOR Instruction

Remember the pain associated with a multi-precision signed multiplication operation? You need to determine the sign of the
result, take the absolute value of the operands, multiply them, and then adjust the sign of the result as determined before the
multiplication operation. The sign of the product of two numbers is simply the exclusive-or of their signs before performing
the multiplication. Therefore, you can use the xor instruction to determine the sign of the product of two extended precision
numbers. E.g.,
32x32 Multiply:
mov al, byte ptr Oprnd1+3
xor al, byte ptr Oprnd2+3
mov cl, al ;Save sign

; Do the multiplication here (don't forget to take the absolute


; value of the two operands before performing the multiply).

.
.
.

; Now fix the sign.

cmp cl, 0 ;Check sign bit


jns ResultIsPos

; Negate the product here.

.
.
.

ResultIsPos:
#1) First of all, this is a homework assignment. I was told to create a sorting function with these
parameters using push and pop. They are passed in the function like this, and I don't know how to
access the elements in it with "int *list". I'm in the middle of the process

int sorter (int* list, int count, int opcode)


{
__asm
{
mov eax, 0; zero out the result
mov ebx, opcode; move opcode to ebx for comparison
; fill in your code here
mov ecx, 0; set the counter to 0
cmp ebx, 0x01; check ascendant or descendant
je ASCENDANT
jne DESCENDANT
ASCENDANT:
loop_start :
cmp ecx, count; condition for the outer loop
jge loop_end
push ecx
mov eax,
}
}

loop_start:
cmp ecx, count ; condition for the outer loop
jge loop_end ; jump if end of array
mov esi, list ; move pointer to esi
mov eax, [esi + 4 * ecx] ; move data that current index to eax
push ecx ; push ecx to the stack to save the index
inner_loop:
inc ecx ; increment eax
cmp eax, [esi + 4 * ecx]; compare eax with the next element in the array
jle swap ; if it is less than the current value than jump to swap
cmp ecx, count ; check if ecx reaches the end of array
jle inner_loop ; if not than go back to inner loop
pop ecx ; it ecx reaches the end than pop eax to go back to the old index of
outer loop
mov[esi + 4 * ecx], eax ; exchange the value of current eax to the element that is
compared
inc ecx ; increment ecx for outer loop
jmp loop_start ; jump back to loop start
swap: ; swap the smaller value with the current value
mov eax, [esi + 4 * ecx] ; swapping
jmp inner_loop ; jump back to inner loop
loop_end:
ret
    jle inner_loop looks suspicious. If ecx equals count and you jump back to inner_loop, the first thing
you'll do is increment ecx and compare against something that is outside of the array, –  Michael Jul 6 at
6:46
    but if I dont increase ecx, it would compare its current element with itself for the first time. I tried to increase
eax after checking "jle swap" and I ran into an infinite loop –  bao pham Jul 6 at 7:03
Place the value of list (i.e. the address of the ints) in a register, and use register-indirect
addressing:
mov esi, list
mov eax, [esi] ; read the first element
mov eax, [esi+4] ; read the second element
add esi, 8 ; move 2 elements ahead
mov eax, [esi] ; read the third element
; etc...
If you want to swap two elements in the array specified by indices in ecx and edx you could do:
mov eax, [esi + ecx*4] ; eax = elem1
xchg eax, [esi + edx*4] ; swap eax and elem2
mov [esi + ecx*4], eax ; elem2 = old elem1
Thank you so much, but how do I
swap the smaller value in the
array with a value of a certain
index in the array? –  bao
pham Jul 6 at 5:57

    Thank you so much again! I have a question. If I push ecx (the counter) to the
stack, will the data of ecx still remain on it? Because I want to keep the index
for my outer loop, and get it back after ecx finish the inner loop? Also, are
there any ways that I can contact you? –  bao pham Jul 6 at 6:14 

    Pushing ecx doesn't modify ecx. –  Michael Jul 6 at 6:20

    I finished my bubble sorting, but it keeps crashing, can you take a look at it
and help me with it please? Sorry, I'm very new to Assembly. –  bao pham Jul
6 at 6:36

    Now I have an array of structures with each element is (int ID, char name[20]).
I'm given a pointer 'char* list'. I passed it to esi. How can I read each character
of the name. I tried to do this: 'mov esi, list' -> 'add esi, 4' -> mov al, byte
ptr[esi+ ecx]-> 'inc ecx' -> 'add esi, 24'. Is it a right way to appoarch?
Thanks –  bao phamyesterday 

    Separate questions should be posted as new questions rather than as


comments. –  Michael yesterday

    At first, I was afraid of doing that because it's assignment and it's due yet, so
there are several reasons why I did not do it. However, I decided to do so.
Please help link –  bao pham 6 hours ago

x86 CPUs support index addressing like:

mov edx, list ;edx is a list ptr


mov ecx, index ;ecx ia an array index
mov eax, dword ptr[edx + ecx * 4] ;Load result to eax
if I find a smaller value , how can I swap it with the value of a current index? Thanks a lot –  bao pham Jul 6
  at 6:00
    Keep the index of both in a register, and then simply load the value into eax (or some other convenient
register) and store it at the other address: mov eax,[esi + ecx*4] : mov ebx,[esi + edx*4] : mov
[esi + edx*4],eax : mov [esi + ecx*4],ebx or similar. –  Rudy Velthuis Jul 6 at 14:31 
#2) I have an array of structures with each element is a number and street name

struct house
{
int number;
char streetName[20];
}
I want to search it with a token passed in. Here is my code, and I don't know why it does not work.

mov eax, 0 ; zero out the result


mov esi, list ; move the list pointer to ESI
mov edi, token ; move the pointer of token string to edi
mov edx, 0 ; reset edx counter
mov ecx, 0 ; reset ecx counter
L1:
mov eax, [esi+4] ; read number of street into eax
add esi, 4 ; move pointer 4 bytes to start reading street name
L2:
mov al, byte ptr[esi + ecx]; mov each char of street name from array to al
mov bl, byte ptr[edi + ecx]; mov each char of search token to bl
or al, 20h ; convert al (case insensitive)
or bl, 20h ; convert bl (case insensitive)
inc ecx ; prepare next char
cmp al, bl ; cmp al and bl
jne DIFFERENT ; jump to DIFFERENT if different
cmp bl, 0 ; check if bl reaches to the end of the string
je done ; jump if all match to done
jmp L2 ; jump back to L2 to check the next char
DIFFERENT:
add esi, 24 ; add esi 24 bytes to move the pointer to the next item of structure array
mov ecx, 0 ; reset the counter ecx
inc edx ; inc the edx counter for structure array
cmp edx, count ; check if it reaches the end of array
je not_found ; if reaching the end but found nothing then jmp to not found
jmp L1 ; jump back to L1
not_found:
mov eax, 0 ; set eax to 0 to indicate not found
done:

You don't say what assembler, but since you


use ptr you may also
need offset (on list and token?). –  Frank
Kotler 5 hours ago

    when you do cmp bl, 0 you have already OR-ed bl with 20h.
That condition is always false and the check go past the end of
the token and street name string. Also set an upper bound on
the inner cycle (i.e. onecx) to 20. –  knm241 4 hours ago

    I put info on using gdb for asm


into stackoverflow.com/tags/x86/info the other day. The idea
was so questions like this could be answered with just that
link. –  Peter Cordes 2 hours ago

    @knm241. I did move the codes so that it checks bl first


before it converts the case, but it still does not work. Do you
have any ideas? Thanks –  bao pham 2 hours ago
The x86 tag wiki page has info on using a debugger, as well as guides and other resources. This is exactly the kind of problem
that's ideal for solving yourself with a debugger. You would see your branch not branching when you expected, due to the bug
that knm241 pointed out.
#3) I
am trying to acces values from an array of integers and have been trying for hours with no
luck. Here is my code so far:

All I am trying to do is acces the values in the array "arr", i have seen how to do it with characters
but not with integers.

int binarySearch (int* arr, int arrSize, int key, int* count)
{
int result=-1;
int tempCount=0;
__asm
{
push esi;
push edi;
push eax;
push ebx;
push ecx;
push edx;

// START CODING HERE


mov edx, dword ptr arr[1] ;

// move the value of appropriate registers into result and tempCount;


// END CODING HERE

pop edx;
pop ecx;
pop ebx;
pop eax;
pop edi;
pop esi;
}
*count = tempCount;
return result;
}
Let's assume the index of the item you want is in eax, you would write

lea edx, [arr+eax*4]


mov edx, [edx]
This is equivalent to

edx = arr[eax]

Edit:

Sorry but I forgot that this is inline asm. lea edx, [arr] will load the effective address of the
parameter arr on the stack, not the pointer itself. Try this:

mov eax, 1; //index you want to access


mov ebx, arr;
lea edx, [ebx+eax*4];
mov edx, [edx];
int binarySearch (int* arr)
{
int test;

__asm
{
push eax;
push ebx;
push edx;

mov eax, 2;
mov ebx, arr;
lea edx, [ebx+eax*4];
mov edx, [edx];
mov test, edx

pop edx;
pop ebx;
pop eax;
}

return test;
}

int main(void)
{
int a[5];

a[0] = 0;
a[1] = 1;
a[2] = 21;

int t = binarySearch(a);

return 0;
}
t == 21 after this program executes. I believe that is what you are looking for.

You might also like