1
mov rax, 6
mov rbx, 2
div rbx       ; rax = 6/2 = 3 - FLOATING POINT EXCEPTION

Error: Floating Point Exception.

As I suppose, I think it's because instead of going to the ALU (Arithmetical Logical Unit) it goes to the FPU (Floating Point Unit) which means it returns a float instead of an integer. Am I right?

Which would mean, that the FPU wouldn't handle the two Integers I provided so it produces a Floating Point Exception.

But how do I divide two integers then? Or if my guess is wrong, what's my mistake?

  • The division takes the 128 value in rdx:rax and divides it by _rbx_ with when you do `div`. I suspect there is data in _RDX_ that is causing the division to overflow. For unsigned division you can simply set _RDX_ to 0. This question is related: https://stackoverflow.com/questions/38416593/why-should-edx-be-0-before-using-the-div-instruction/38416896#38416896 . The overflow of the itneger division is being reported to you with a generic "Floating Point Exception". It should be interpreted as "Arithmetic Exception" – Michael Petch Nov 27 '17 at 22:23
  • 2
    Use shifts to divide by powers of 2, [it's **much** faster](https://stackoverflow.com/questions/40354978/why-is-this-c-code-faster-than-my-hand-written-assembly-for-testing-the-collat), especially for 64-bit operand-size. – Peter Cordes Nov 28 '17 at 11:51
  • I'm well aware of that, although a very nice advice. Thanks. – Apostolis Anastasiou Nov 29 '17 at 07:04

1 Answers1

3

Linux maps the #DE (division by zero exception) generated by the CPU to the SIGFPE signal, which is then translated to the human-readable error message "Floating point exception"; unfortunately, it's quite misleading, as no floating point at all is involved into the process.

Now, given that rbx is 2, of course you are not dividing by zero. Still, there's another case when x86 generates a #DE exception: if the result is too big to fit into the target register.

In your code you are using the 64 bit form of the instruction (you wrote rbx - a 64 bit register - as divisor) which means that you are asking to divide rdx:rax (i.e. the 128 bit value obtained by joining rdx and rax) by rbx, and to put the result into rax (quotient) and rdx (remainder).

Since you are not zeroing out rdx, most probably it contains some big garbage value (residual from some previous computation?), and the division by two results in a quotient too big for rax. Hence, the #DE exception.

Long story short: zero out rdx before the div and everything will work out smoothly.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • Question: But doesn't `mov` set the whole register to a whole different value? Reply: Tried your request via setting it to 0 first with `xor rbx, rbx` and `mov rbx, 0` but didn't work, still same exception – Apostolis Anastasiou Nov 27 '17 at 22:41
  • @ApostolisAnastasiou: `mov` does set the whole register, the problem is that a `div` with a 64-bit divisor operand operates on `rdx:rax` (a *pair* of registers) as a source, and you only assigned to `rax`. As for your reply, you have to zero out `rdx`, not `rbx`! – Matteo Italia Nov 27 '17 at 22:47
  • It's [this exact situation](https://stackoverflow.com/questions/8649180/assembly-divisions-and-floating-points), only with the 64-bit version of `div` (which works on the larger registers). – Matteo Italia Nov 27 '17 at 22:50
  • Oh! Now I see! I didn't even know that division op actually saved the remainder somewhere. So each division should be followed by a rdx=0? – Apostolis Anastasiou Nov 27 '17 at 23:12
  • 1
    Each division should be *preceded* by a `rdx=0` - it's not just division that clobbers `rdx`! – Matteo Italia Nov 27 '17 at 23:32