# Modify formula by adding a subtraction

I have the following Assembler Code in a x86 Program and I need to modify it as it is buggy:

``````fld     ds:(flt_203B8 - 29C48h)[ebx]
fdivr   dword ptr [esi+44h]
fmul    ds:(flt_203BC - 29C48h)[ebx]
fisttp  [ebp+var_334]
mov     eax, [ebp+var_334]
cmp     eax, 0Fh
jg      short greater

test    eax, eax
mov     edx, 0
cmovs   eax, edx
jmp     short valueWithinLimits

greater:
mov     eax, 0Fh

valueWithinLimits:
....
``````

In Pseudocode this is

``````v29 = (signed int)(*(float *)(v3 + 68) / 40.0 * 15.0);
if ( v29 > 15 )
{
v29 = 15;
}
else if ( v29 < 0 )
{
v29 = 0;
}
``````

I need to insert the following line as second line:

``````v29 = 15 - v29;
``````

Is there any way I can do that without needing any more space? I assume no but maybe someone has a smart Idea here what can be done in this case.

It's hard to say, since you didn't post the entire assembly related to the pseudocode. It seems however, that the "if" block is implemented via jumps. In that case, you may use conditional moves instead. For example, assuming that "if" block is implemented like this (uses 28 bytes):

``````  cmp eax, 0Fh
jg greater
cmp eax, 0
jl less
jmp continue
less:
mov [ebp+var_334], 0
jmp continue
greater:
mov [ebp+var_334], 0Fh
continue:
``````

You may implement it like below:

``````  mov ebx, 0Fh
cmp eax, 0Fh
cmovg eax, ebx
xor ebx, ebx
cmp eax, 0
cmovl eax, ebx
mov [ebp+var_334], eax
``````

This implementation uses 22 bytes, which is 6 bytes lower than the previous one - exactly the space you need to insert fsubr instruction to compute 15 - st(0) before storing the result in v29.

Consider this implementation:

``````  xor ebx, ebx    ; ebx = 0
mov bl, 15      ; ebx = 15
neg eax         ; eax = -eax
add eax, ebx    ; eax = 15 - eax
cmp eax, ebx
cmovg eax, ebx
xor ebx, ebx
test eax, eax
cmovs eax, ebx
``````

It's even shorter (occupies 20 bytes), does the whole job and doesn't require additional operations on floats.

• Correct me if I'm wrong, but in your implementation there is a problem whenever 0<=v29<=15 leading to overwriting v29 with whatever is stored in ecx before your function (undefined behaviour?) – Anonymous Anonymous Apr 2 at 21:28
• You are right. I’ve edited my answer. – bart1e Apr 3 at 4:52
• Sorry I didn't notice that I missed part of it, I have completed it now. Seems like I could bring it down to the lower size, however I can not put the 15 anywhere, which makes it impossible to use it I think. I tried to assemble "fsubr 15, %st" but it doesn't work – Roman Apr 3 at 15:57
• Well, you cannot use immediate values in fsubr (what I wrote was just a shortcut). You can, however, put a constant float equal to 15 if it is present somewhere in your program. If not, let me know and I will suggest you another solution. – bart1e Apr 3 at 16:03
• It must be present as we are multiplying with 15, however I can't get IDA to assemble with flt_203bc either which is what the fmul uses to multiply with 15 – Roman Apr 3 at 16:07

Actually your assembler code isn't complete. It matches to next pseodocode:

v29 = (signed int)(*(float *)(v3 + 68) / 40.0 * 15.0);
if ( v29 > 15 )

If 40.0 and 15.0 are constants, you could remove division and only do multiplication with 0.375. Not sure how much space would this save.

You have code which scales and offsets, you need to scale and offset. So you do not need to change the code at all, just the constants.

Work your new operation backwards into the existing math. Change the sign of one of the constants you multiply by, and work the offset back through the multiplication and sign change and combine it with the original offset.