 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
gibberishh Cheater
Reputation: 1
Joined: 30 Aug 2021 Posts: 45
|
Posted: Thu Aug 03, 2023 10:41 pm Post subject: Floating Point x Integer Multiplication |
|
|
Need help with multiplying an integer by a floating point value to return an integer. The integer is in ecx (say #100). The floating point value is entered by the user in the table [label/symbol Mult, say (float)0.5].
Having read as much as I could absorb about FP values, I understand that both numbers need to be loaded into the stack [st(0),st(1)]. However I'm not 100% on how to do that. And how to be sure that after fmul the number I get back is an integer. Do I need fabs? I don't care about precise rounding. Also, I don't wish to do a multiply-divide cycle instead of using FP because I'm trying to learn FP instructions. Finally, it doesn't matter to me whether the code is for signed or unsigned values -- I'll take whatever you can give me but all my values will be positive (memrec will be unsigned unless you instruct me otherwise).
Online sources are confusing as hell and none of them seem to give a working example of code that I can reference They just give slices that must be put together (in this case) by someone who has never written assembly for floating points.
I am currently not working with game code. I am doing all this in a newmem region that does not change game code (yes, I'm making sure it gets executed) to understand the instructions and concepts involved. I need 32-bit code. ecx will eventually be populated (and read) by game code.
Here's what I would like to do:
| Code: | // setup constants
label(Mult)
registersymbol(Mult)
Mult:
dd 0
mov ecx,#100
mov [Mult],float(0.5) // Mult is exposed to the table and can be changed by the user
// multiply the values // NEED HELP HERE
fild ecx
fld [Mult] // do I need to move [Mult] into a register before loading?
fmul st(0),st(1)
fist ecx // will this have the integer value from the resulting multiplication? or do I have to somehow convert it into integer first?
// how do I clear/pop st(0) and st(1) here? |
Thanks!
_________________
It's not cheating. It's playing by my rules. |
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4724
|
Posted: Thu Aug 03, 2023 11:19 pm Post subject: |
|
|
Don't use x87... unless you're working on a really old game.
Basically, convert the integer to a floating point number, do the multiplication using floating point arithmetic, then convert the result back to an integer.
| Code: | mult:
dq (double)1
code:
cvtsi2sd xmm0,ecx
mulsd xmm0,[mult]
cvttsd2si ecx,xmm0 |
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
gibberishh Cheater
Reputation: 1
Joined: 30 Aug 2021 Posts: 45
|
Posted: Fri Aug 04, 2023 12:09 am Post subject: |
|
|
Oh okay. I'll try this out. Online resources (apparently) gave me the wrong impression that xmm registers were for 64-bit.
Also, with this method, do I need to clear xmm0 in some particular way? Or will a simple push-pop work with xmm0 as it does with ecx?
Finally, I'll experiment with this but I'm assuming this will work with floats as well as doubles?
Yes, actually it is a new port of a very old game: The Hell 2, based on the original Hellfire code. That's why I want to work with floats and not doubles because of the 4-byte length of float values. Not sure if that will be pertinent: this whole part of the code will work independent of the game (only the part that reads and writes back to ecx will interact with game code) but I like to maintain consistent "data types" within a game's code.
Thanks again
Edit: It works perfectly with double values. Obviously, the instructions are working with dqwords so they don't work with qword floats. I got this to work with floats instead, but couldn't have done it without your nudge in the right direction:
| Code: | mov [Result],ecx
fild [Result] // apparently I cannot fild a register, only an address
fld [Mult]
fmulp st(1),st(0)
fistp [Result]
mov ecx,[Result] |
Yes, it's x87 but I don't know of a more 'modern' way to do this with floats. Sorry.
_________________
It's not cheating. It's playing by my rules. |
|
| Back to top |
|
 |
ParkourPenguin I post too much
Reputation: 152
Joined: 06 Jul 2014 Posts: 4724
|
Posted: Fri Aug 04, 2023 11:14 am Post subject: |
|
|
| gibberishh wrote: | | Online resources (apparently) gave me the wrong impression that xmm registers were for 64-bit. | 64-bit applications use SSE (xmm registers) by default. They can also be used in 32-bit code. I'd suggest using whatever the game is using.
| gibberishh wrote: | | Also, with this method, do I need to clear xmm0 in some particular way? Or will a simple push-pop work with xmm0 as it does with ecx? | If the game is using xmm0, then use some other xmm register. e.g. use xmm5 or something.
If you really want to make sure you're safe, add some space on the stack (`sub esp,10`), write the entire xmm register there (`movups [esp],xmm0`), restore it later (`movups xmm0,[esp]`), and clean up the stack (`add esp,10`). This is usually unnecessary.
| gibberishh wrote: | | Finally, I'll experiment with this but I'm assuming this will work with floats as well as doubles? | Sure. `cvtsi2ss`, `mulss`, and `cvttss2si` are the corresponding mnemonics. There's no good reason to use floats, however.
| gibberishh wrote: | | Obviously, the instructions are working with dqwords so they don't work with qword floats. | Word is 2 bytes, DWord is 4 bytes, QWord is 8 bytes, DQWord is 16 bytes.
Floats are DWords, doubles are QWords, and XMM registers are DQWords.
| gibberishh wrote: | | That's why I want to work with floats and not doubles because of the 4-byte length of float values. | x87 floating point arithmetic is done using neither floats nor doubles. It uses an 80-bit double-extended floating point format.
These 80-bit values get stored in memory as either floats or doubles. I'd guess doubles are used more often. Just because the code is 32-bit doesn't mean everything is 4 bytes.
From the other aspect, 64-bit code still uses 4-byte integers as the default. Pretty much all the 8-byte integer values you see being used are pointers.
| gibberishh wrote: | | I like to maintain consistent "data types" within a game's code. | Do that with the floating point arithmetic unit: either SSE or x87. Don't bother with floats or doubles- there's practically no point.
Floats are mostly used in graphics where throughput is more vital than anything else. For CPU-related calculations, doubles are the default.
| gibberishh wrote: | | Code: | mov [Result],ecx
fild [Result] // apparently I cannot fild a register, only an address
fld [Mult]
fmulp st(1),st(0)
fistp [Result]
mov ecx,[Result] |
| `fild` can load an integer from a 16, 32, or 64-bit memory location. You should explicitly specify it in this case.
The stack is more appropriate than some arbitrary "Result" memory location, but that's just a superficial formality.
There's no need for the `fld`. `fmul` can take a memory location. Again, this memory location should specify its size, as it could be a float (dword) or a double (qword).
| Code: | sub esp,4
mov [esp],ecx
fild dword ptr [esp]
fmul dword ptr [Mult]
fistp dword ptr [esp]
mov ecx,[esp]
add esp,4 |
Look at an instruction set reference when you need a more definitive answer as to what instructions do. There are plenty of accessible mirrors online:
https://www.felixcloutier.com/x86/
_________________
I don't know where I'm going, but I'll figure it out when I get there. |
|
| Back to top |
|
 |
gibberishh Cheater
Reputation: 1
Joined: 30 Aug 2021 Posts: 45
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|