Search code examples
assemblyx86disassemblyexponentialfpu

logarithm and exponential, What does this assembly code do?


What is the result of the following assembly code?

fld qword ptr [address2]
fld qword ptr [address1]
fldl2e
fmulp   ST(1),ST
fld ST(0)
frndint
fxch    ST(1)
fsub    ST,ST(1)
f2xm1
fld1
faddp   ST(1),ST
fscale

Here, I don't understand what this code is doing. What I have interpreted is as following:

value[address2]^(2^(value[address1]*log2(e)-roundf(value[address1]*log2(e))))

Which does not make sense. Could someone please correct me?


Solution

  • Next time please post you attempted comments next to the disassembly. It's taking a long time to type everything out to see if I end up at the same place as you. Also, there's a whole stackexchange for reverse engineering. I don't usually look at it, but there are some good x86 experts there.

    let's say v1 = contents of addr1 and v2 = ... [addr2].

    fld qword ptr [address2]   ; st(0) = v2
    fld qword ptr [address1]   ; st(0) = v1, st(1) = v2
    fldl2e                     ; st0 = l2e = log_2(e); st1=v1 st2=v2
    fmulp   ST(1),ST           ; st0 = v1*l2e;  st2=v2
    fld ST(0)                  ; st0 = v1*l2e; st1=v1*l2e  st2=v2
    frndint                    ; st0 = round(v1*l2e); st1=v1*l2e  st2=v2
    fxch    ST(1)              ; st0 = v1*l2e; st1=round(v1*l2e)  st2=v2
    ; careful here, this is fsub, NOT fsubp
    fsub    ST,ST(1)           ; st0 = v1*l2e - round(v1*l2e) = fractional part of v1*l2e = v1l2efrac; st1=round(v1*l2e)  st2=v2
    f2xm1                      ; st0 = 2^(v1l2efrac)-1; st1=round(v1*l2e)  st2=v2
    fld1                       ; st0 = 1.0;  st1 = 2^(v1l2efrac)-1  st2=round(v1*l2e)  st3=v2
    faddp   ST(1),ST           ; st0 = 1.0 + 2^(v1l2efrac)-1 = 2^v1l2efrac; st1=round(v1*l2e)  st2=v2
      ; st0 = 2^v1l2efrac; st1=round(v1*l2e);  st2=v2
    fscale                 ; st0 = 2^v1l2efrac * 2^round(v1*l2e); st1=round(v1*l2e)  st2=v2
      ; st0 = 2^(v1l2efrac + round(v1*l2e));  st1=round(v1*l2e)  st2=v2
      ;  simplify: fractional part + integer part = whole
      ; st0 = 2^(v1*l2e);  st1=round(v1*l2e)  st2=v2 
      ;  simplify: x^y = 2^(y * log2(x))
      ; st0 = e^v1;        st1=round(v1*l2e)  st2=v2
    

    So in the end, st(0) = e^[address1], with 2 other values still on the FP stack. (The contents of the rest of the FP stack, and how deep it is, is a huge point which you left out of your analysis. FP stack pushes and pops have to balance (except for leaving a return value in st(0)), so that can act as a check on whether you've correctly traced a piece of code.)

    AFAICT, v2 is left on the FP stack at the end of this, and unused in the calculation. It looks like you had 2 extra pops in your tracing.