Division Terminology Let's review some basic division terminology. For some reason, I can never keep track of which one is which.
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. Previous Lesson: Sign Extension Next Lesson: TSC Hacking Table of Contents |