Question about assembler commands in games on the Unity engine

Memory scanning, code injection, debugger internals and other gamemodding related discussion
Post Reply
AlexS
Expert Cheater
Expert Cheater
Posts: 305
Joined: Sun Apr 08, 2018 3:46 pm
Reputation: 187

Question about assembler commands in games on the Unity engine

Post by AlexS »

(Google translation)

Question for knowledgeable users.

In games using the Unity engine, I often come across sections of code that look incomprehensible to me, even meaningless.

For example, here is the code from the game RimWorld:

Image

Please explain the meaning of the instructions surrounded by a colored frame. There are more than a thousand such code sections in the game. Why is this double round-trip conversion necessary?

Or here are other examples on the same piece of code:

Image

6 sequential instructions are highlighted in green, although in this case only two instructions are sufficient. Why is such a long method used?
Above the first colored frame are two instructions: the first writes the value of a register into memory (movss [rbp-10],xmm0), and the second writes back from the same memory to the same register. Why is the second instruction needed?
Under the first colored frame is the instruction lea rbp,[rbp+00], which does not change anything. Why are these instructions here?
It is also very common to encounter comparison instructions where the flags set after the comparison are not used in any way. There are hundreds of such instructions in the code. What is the point of these “empty” comparisons?

User avatar
Metanoia
Noobzor
Noobzor
Posts: 12
Joined: Thu Mar 07, 2024 7:16 pm
Reputation: 24

Re: Question about assembler commands in games on the Unity engine

Post by Metanoia »

That’s a standard method/function found in all Unity games, not just a RimWorld thing. It calculates the absolute value of a given value, as the name suggests. Both pictures depict the exact same method, so I’m not sure what you mean by other examples. Some of those are just redundancies; they do absolutely nothing. The lea rbp,[rbp+00] is just Cheat Engine showing it wrong there should not be anything there.

User avatar
SunBeam
Administration
Administration
Posts: 4810
Joined: Sun Feb 04, 2018 7:16 pm
Reputation: 4432

Re: Question about assembler commands in games on the Unity engine

Post by SunBeam »

Metanoia wrote:
Fri May 10, 2024 6:03 am
The lea rbp,[rbp+00] is just Cheat Engine showing it wrong there should not be anything there.
CE isn't showing anything wrong. That's the mnemonic representation of the ASM bytes displayed on that line. Look for the same bytes in this snippet: [Link].

Code: Select all

00007FF6DF084D1E | 48 8D 65 00              | lea rsp,qword ptr ss:[rbp]              | ;test1.asm:82

User avatar
Metanoia
Noobzor
Noobzor
Posts: 12
Joined: Thu Mar 07, 2024 7:16 pm
Reputation: 24

Re: Question about assembler commands in games on the Unity engine

Post by Metanoia »

SunBeam wrote:
Sat May 11, 2024 10:46 pm
Metanoia wrote:
Fri May 10, 2024 6:03 am
The lea rbp,[rbp+00] is just Cheat Engine showing it wrong there should not be anything there.
CE isn't showing anything wrong. That's the mnemonic representation of the ASM bytes displayed on that line. Look for the same bytes in this snippet: [Link].

Code: Select all

00007FF6DF084D1E | 48 8D 65 00              | lea rsp,qword ptr ss:[rbp]              | ;test1.asm:82
Ahh my bad I had the idea it was the same thing as 00 00 coming out as

add [rax],al

Thank you for correcting me.

AlexS
Expert Cheater
Expert Cheater
Posts: 305
Joined: Sun Apr 08, 2018 3:46 pm
Reputation: 187

Re: Question about assembler commands in games on the Unity engine

Post by AlexS »

Metanoia wrote:
Fri May 10, 2024 6:03 am
That’s a standard method/function found in all Unity games, not just a RimWorld thing. It calculates the absolute value of a given value, as the name suggests. Both pictures depict the exact same method, so I’m not sure what you mean by other examples. Some of those are just redundancies; they do absolutely nothing. The lea rbp,[rbp+00] is just Cheat Engine showing it wrong there should not be anything there.
(Google translation)

I was not talking about the entire method, but about the sections of code I highlighted in the screenshot, the meaning of which is not clear to me. Probably because of my bad English they didn't understand me...

These instructions perform a double round-trip conversion, the contents of the xmm0 register are not changed (the tail in the high part of the register remains, but it is not used):

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
Why is there a round-trip conversion needed here?

The second instruction loads the value from memory back into the register it came from:

Code: Select all

movss [rbp-10],xmm0
movss xmm0,[rbp-10]
Why is the second instruction needed here?

After this instruction, the contents of the rbp register do not change:

Code: Select all

lea rbp,[rbp+00]
Why is this instruction needed here?

There are 6 instructions circled in green in the screenshot:

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
cvtss2sd xmm0,xmm0
cvtsd2ss xmm5,xmm0
movss [rbp-04],xmm5
movss xmm0,[rbp-04]
Instead, it is enough to use only 2 instructions, for example like this:

Code: Select all

movss [rbp-04],xmm0
movss xmm5,xmm0
Why was it necessary to use 6(!) instructions?

User avatar
Metanoia
Noobzor
Noobzor
Posts: 12
Joined: Thu Mar 07, 2024 7:16 pm
Reputation: 24

Re: Question about assembler commands in games on the Unity engine

Post by Metanoia »

AlexS wrote:
Sun May 12, 2024 10:28 am
Metanoia wrote:
Fri May 10, 2024 6:03 am
That’s a standard method/function found in all Unity games, not just a RimWorld thing. It calculates the absolute value of a given value, as the name suggests. Both pictures depict the exact same method, so I’m not sure what you mean by other examples. Some of those are just redundancies; they do absolutely nothing. The lea rbp,[rbp+00] is just Cheat Engine showing it wrong there should not be anything there.
(Google translation)

I was not talking about the entire method, but about the sections of code I highlighted in the screenshot, the meaning of which is not clear to me. Probably because of my bad English they didn't understand me...

These instructions perform a double round-trip conversion, the contents of the xmm0 register are not changed (the tail in the high part of the register remains, but it is not used):

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
Why is there a round-trip conversion needed here?

The second instruction loads the value from memory back into the register it came from:

Code: Select all

movss [rbp-10],xmm0
movss xmm0,[rbp-10]
Why is the second instruction needed here?

After this instruction, the contents of the rbp register do not change:

Code: Select all

lea rbp,[rbp+00]
Why is this instruction needed here?

There are 6 instructions circled in green in the screenshot:

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
cvtss2sd xmm0,xmm0
cvtsd2ss xmm5,xmm0
movss [rbp-04],xmm5
movss xmm0,[rbp-04]
Instead, it is enough to use only 2 instructions, for example like this:

Code: Select all

movss [rbp-04],xmm0
movss xmm5,xmm0
Why was it necessary to use 6(!) instructions?
After some research here. SunBeam can correct me if I got anything wrong.

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
These are effectively performing a rounding operation on the single precision floating point value in xmm0.

Code: Select all

movss [rbp-10],xmm0
movss xmm0,[rbp-10]
This is just a kind of of like a NOP or at least that’s what I’ve narrowed it down to.

Code: Select all

lea rbp,[rbp+00]
This is just the way the compiler picked to align/setup for the call right after.



"Why was it necessary to use 6(!) instructions?" No one can tell you why a compiler does its black magic it just does.

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
cvtss2sd xmm0,xmm0
cvtsd2ss xmm5,xmm0[code]

Just rounding. I think...

AlexS
Expert Cheater
Expert Cheater
Posts: 305
Joined: Sun Apr 08, 2018 3:46 pm
Reputation: 187

Re: Question about assembler commands in games on the Unity engine

Post by AlexS »

Metanoia wrote:
Mon May 13, 2024 2:21 am
These are effectively performing a rounding operation on the single precision floating point value in xmm0.
This is wrong. In this case, no rounding occurs because the lower precision is converted to the higher precision first. The value in the lower part of the register does not change after these two conversions (you can check).

For the experiment, I tried to remove all sections of the code:

Code: Select all

cvtss2sd xmm0,xmm0
cvtsd2ss xmm0,xmm0
I simply replaced more than two thousand (!) of such sections with “nop”. Same with the rest of the xmm registers. There were no crashes, the behavior of the game did not change in any way, except for the fact that performance increased slightly.
Did I understand correctly that all these sections of code are a consequence of the “strange” work of the compiler, and not the programmer’s intention?

ajiun
What is cheating?
What is cheating?
Posts: 1
Joined: Mon Oct 31, 2022 12:02 pm
Reputation: 0

Re: Question about assembler commands in games on the Unity engine

Post by ajiun »

This is for code alignment, as it is JIT compiled, and the same will be true for games made by Flash

Post Reply

Who is online

Users browsing this forum: No registered users