0

I'm learning x86-64 assembly using online exercises on OST2's website.

All the exercise questions in regards to multiplication are confusing me.

mov rax, 0x89204E764CB58DF0
mov esp, 0xF627BAE4
mul esp

Question: What value is stored in edx:eax after the code is ran? Answer: The correct value in edx:eax after this code executes was 0x49C25E0D7A62C9C0

I can't understand how they have this result. My attempt was to just do the obvious of taking 0x89204E764CB58DF0 and multiplying it by 0xF627BAE4, then only accounting for the 32 right bits (as I believe edx:eax is for 32 bit).

My result was 0x7A62C9C0, which is half right - that's supposed to be the other half of the correct answer. So I thought.. maybe I should account for the entire 64 bits? No - that makes my result 0x3B83FB257A62C9C0 - the first 32 bits are wrong.

How can I better understand multiplication (signed and unsigned) in ASM? The site provides answers for the questions, but I don't want to be spoonfed but rather understand what's going on instead.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 3
    That's a pretty weird example, using `esp` like that. Anyway, your mistake seems to be not looking at the entire 64-bit result (i.e. `edx:eax`), and not disregarding the upper 32 bits of `rax` which are irrelevant for the multiplication. `4CB58DF0 * F627BAE4 = 49C25E0D7A62C9C0` – Michael Jan 25 '22 at 18:32
  • 1
    @Michael I agree - the example is weird (and the usage of `esp` rather than using `r9`-`r16` or even a stack variable rather than this.. questionable code), but indeed it caught me off-guard. Thanks for answering my question! – Nicole Erel Jan 25 '22 at 18:37
  • 2
    `edx:eax` is two consecutive 32-bit dwords which form a 64-bit qword. Using `esp` for arbitrary arithmetic is really unusual. – ecm Jan 25 '22 at 18:40
  • 1
    `edx:eax` is a pair of 64-bit regs, but the *inputs* to `imul r/m32` are both 32-bit; that's *why* the output is only 64-bit (sum of the input bit-widths). Also, when you say *the first 32 bits are wrong*, perhaps you're talking about this *high* 32 bits? Since x86 is little-endian (and if you were doing to store edx:eax into memory, you'd normally put eax first, at a lower address), my first reading of "first 32" was the low half. But the low N bits of a multiply don't depend on input bits outside the low N, so the low 32 of your result should be right. Best to just say high / low, IMO. – Peter Cordes Jan 25 '22 at 20:59
  • 1
    Anyway, the key point here is that the inputs to `mul` *aren't* different sizes. RAX just has some high garbage in this question, to make sure you understand that. The manual makes this pretty clear: https://www.felixcloutier.com/x86/mul – Peter Cordes Jan 25 '22 at 21:04
  • Not an exact duplicate: [imul assembly instruction - one operand?](https://stackoverflow.com/q/3818755) answers the question by explaining how `mul` and `imul` work, but doesn't explicitly mention that the high part of RAX is still irrelevant with 32-bit operand-size in 64-bit mode. That's the confusion here. Maybe [The advantages of using 32bit registers/instructions in x86-64](https://stackoverflow.com/q/38303333) / [When and why do we sign extend and use cdq with mul/div?](https://stackoverflow.com/q/36464879) – Peter Cordes Jan 25 '22 at 22:09
  • Loosely related: but [Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?](https://stackoverflow.com/q/34377711) - but you're *not* doing a wider operation with garbage in high bits, you're using a 32-bit operation. The real comparison would be against `mov ecx, eax` (zero extend into RCX) / `imul rcx, rsp` to get the 64-bit result in RCX. Also [Why is imul used for multiplying unsigned numbers?](https://stackoverflow.com/q/42587607) – Peter Cordes Jan 25 '22 at 22:14

0 Answers0