LOGBOOK

HELP

Quiz Entry - updated: 2026.07.07

Why does compiled x86-64 code for x * 24 contain shift and lea instructions but no multiply?

Shifts and adds are faster than a general multiply, so the compiler strength-reduces a constant multiply into them — e.g. x * 24 = (x + 2x) << 3.

x * 24 compiled to lea (3x) then sal $3 (times 8), no multiply instruction

* The compiler rewrites x * 24 as (x + 2x) << 3: one lea builds 3x, one sal $3 multiplies by 8 — no imul at all. *

Because v << k equals v · 2^k for both signed and unsigned values, any multiplication by a compile-time constant can be rebuilt from shifts, adds, and subtracts. For x * 24, note 24 = 3 · 8, so the compiler computes 3x then multiplies by 8 with a shift:

mul24:                        # x in %rdi, result in %rax
  leal  (%rdi,%rdi,2), %eax   # t = x + x*2 = 3x   (lea does the add+scale for free)
  sall  $3, %eax              # return t << 3 = 3x * 8 = 24x

Other constants decompose the same way, sometimes with subtraction:

x * 7  = (x << 3) - x        // 8x - x
x * 14 = (x << 4) - (x << 1) // 16x - 2x

Why it matters for reverse engineering: a tight cluster of lea / sal / add / sub with no imul is very often a multiply-by-constant in disguise. Read the shift amounts and adds back out and you can reconstruct the original constant — recognising this pattern is a staple of reading optimised disassembly.

Go deeper:

From Quiz: REVE1 / Number Representations | Updated: Jul 07, 2026