1

I am just learning about how code actually works. I am a beginner in assembly, mediocre in C and that's all. I read that instructions exist for addition, subtraction, multiplication & division. I got curious and did some simple arithmetic C and converted to assembly. I was blown away by the results.

Addition and subtraction converted directly. But for multiplication, whenever multiplier is a power of 2, it just shifted to left 'power' times. For example x*4 -> sal x, 2 (understandable as shifting is much more fast). On some other occasion, for x*y, it just added x effectively y times!

The confusing bit(reason for this post) is division. I did in C, val/5(val=45). The compiler converted it as

    mov ecx, DWORD PTR v[rip]
    mov edx, 1717986919
    mov eax, ecx
    imul    edx
    sar edx
    mov eax, ecx
    sar eax, 31
    sub edx, eax
    mov eax, edx

I patiently went through it manually and yes, it will produce 9 as the result on eax.(I assumed sar edx as sar edx, 1). But what is it doing? How is it getting 1717986919? When both of values are unknown, compiler have to and does it in normal way. But what kind of optimization is this?(My compiler is gcc-7.5.0)

  • 3
    I recommend reading Chapter 10 of Hacker's Delight https://doc.lagout.org/security/Hackers%20Delight.pdf . It is about doing division by a constant value and optimizations. Effectively your division has been converted into a faster form by doing multiplication by a magic number. Hint it is better to look at the decimal value `1717986919` in hex which is `0x66666667` – Michael Petch Sep 19 '20 at 16:31
  • 1
    The linked duplicate doesn't really cover signed division; the `sar eax,31` creates a 0 or -1, which is used to correct the rounding for negative inputs. (toward 0 instead of what arithmetic shifts normally do, toward -inf) – Peter Cordes Sep 19 '20 at 16:50

0 Answers0