80 likes | 211 Vues
This guide provides an in-depth explanation of how to use the multiplication (MUL) and division (DIV) instructions in x86 CPUs. It discusses the importance of carry flags in addition, potential overflow issues, and strategies for adding larger numbers with the ADC instruction. Furthermore, it illustrates the intricacies of 8-bit multiplication, showing how numbers can exceed register capacity, requiring a 128-bit product for larger operands. Detailed examples explain the use of the RAX and RDX registers, along with practical implementation tips for using these arithmetic instructions effectively in programming.
E N D
MUL and DIV How to use the x86 CPU’s multiplication and division instructions
A comment about addition • When two register-values are added add %al, %bl their total can sometimes be “too large” to fit in the destination register: Example: 150 + 160 = 310 • Both numbers 150 and 160 can be expressed as 8-bit binary values: 150 as 10010110 (base 2) 160 as 10100000 (base 2) • But not their sum: 310 is 100110110 (base 2)
The Carry-Flag • The “extra” bit becomes the CF-bit (i.e., the ‘Carry’ Flag) in the RFLAGS register • Programs can “branch” if a carry occurs: jc toobig • Or branch elsewhere if no-carry occurs: jnc sumok • Special instruction exists to handle adding of large numbers: ADC (Add-with-Carry)
A Big Number example .section .data x: .short 150 y: .short 160 .section .text mov x, %al add y, %al mov x+1, %ah adc y+1, %ah
“worst-cases” add vs multiply • Adding two n-bit numbers never requires more than (n+1)-bits for their total, so the carry-flag bit suffices for holding the result • But multiplication is another story! • Biggest 8-bit number is 255 (= 11111111) • 255x255 = 65025 (= 1111111000000001) • So this product requires 16-bits: 0xFE01
MUL • Using MUL to multiply two 64-bit operands • Put the 64-bit ‘multiplicand’ into RAX • Put the 64-bit ‘multiplier’ into a general register • The CPU will produce a 128-bit ‘product’ • The product will be in the (RDX:RAX) register-pair • (You can also put the 64-bit ‘multiplier’ in a memory-variable if you then use ‘MULQ’)
DIV • If you put your 128-bit ‘dividend’ into the RDX:RAX register-pair, then you can put your 64-bit divisor into a general-register • The ‘quotient’ will appear in RAX and the remainder will appear in RDX – unless the quotient is too large to fit in register RAX • (You can also put your 64-bit ‘divisor’ in a memory variable if you then use DIVQ)