'x86 Assembly Question - Can anyone determine what is happening below?

I downloaded a modification for a 20+ year old game I play, which is written in assembly code. It adds a fog effect, and then varies the grip levels based on that. However, the fog level is chosen seemingly at random.

Is it easy to see that happening below with trained eyes? I ran it through a disassembler, so not sure if it is actually displaying properly...

It is easy to spot the incrementing 0x33, 0x34, 0x35 etc so I have a feeling that is significant.

0x0000000000000000:  DD 35 00 00 00 00       fnsave dword ptr [0]
0x0000000000000006:  80 3D 00 00 00 00 B8    cmp    byte ptr [0], 0xb8
0x000000000000000d:  75 24                   jne    0x33
0x000000000000000f:  80 3D A8 11 55 00 02    cmp    byte ptr [0x5511a8], 2
0x0000000000000016:  0F 85 E6 00 00 00       jne    0x102
0x000000000000001c:  80 3D 00 00 00 00 00    cmp    byte ptr [0], 0
0x0000000000000023:  75 30                   jne    0x55
0x0000000000000025:  50                      push   eax
0x0000000000000026:  A1 04 B5 6C 00          mov    eax, dword ptr [0x6cb504]
0x000000000000002b:  A3 00 00 00 00          mov    dword ptr [0], eax
0x0000000000000030:  58                      pop    eax
0x0000000000000031:  EB 22                   jmp    0x55

0x0000000000000033:  80 3D B0 11 55 00 02    cmp    byte ptr [0x5511b0], 2
0x000000000000003a:  0F 85 C2 00 00 00       jne    0x102
0x0000000000000040:  80 3D 00 00 00 00 00    cmp    byte ptr [0], 0
0x0000000000000047:  75 0C                   jne    0x55
0x0000000000000049:  50                      push   eax
0x000000000000004a:  A1 0C B5 6C 00          mov    eax, dword ptr [0x6cb50c]
0x000000000000004f:  A3 00 00 00 00          mov    dword ptr [0], eax
0x0000000000000054:  58                      pop    eax
0x0000000000000055:  80 3D 00 00 00 00 33    cmp    byte ptr [0], 0x33
0x000000000000005c:  75 11                   jne    0x6f
0x000000000000005e:  D9 05 00 00 00 00       fld    dword ptr [0]
0x0000000000000064:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x000000000000006a:  E9 30 00 00 00          jmp    0x9f

0x000000000000006f:  80 3D 00 00 00 00 34    cmp    byte ptr [0], 0x34
0x0000000000000076:  75 11                   jne    0x89
0x0000000000000078:  D9 05 00 00 00 00       fld    dword ptr [0]
0x000000000000007e:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x0000000000000084:  E9 30 00 00 00          jmp    0xb9

0x0000000000000089:  80 3D 00 00 00 00 35    cmp    byte ptr [0], 0x35
0x0000000000000090:  75 11                   jne    0xa3
0x0000000000000092:  D9 05 00 00 00 00       fld    dword ptr [0]
0x0000000000000098:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x000000000000009e:  E9 30 00 00 00          jmp    0xd3

0x00000000000000a3:  80 3D 00 00 00 00 36    cmp    byte ptr [0], 0x36
0x00000000000000aa:  75 11                   jne    0xbd
0x00000000000000ac:  D9 05 00 00 00 00       fld    dword ptr [0]
0x00000000000000b2:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x00000000000000b8:  E9 30 00 00 00          jmp    0xed

0x00000000000000bd:  80 3D 00 00 00 00 37    cmp    byte ptr [0], 0x37
0x00000000000000c4:  75 11                   jne    0xd7
0x00000000000000c6:  D9 05 00 00 00 00       fld    dword ptr [0]
0x00000000000000cc:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x00000000000000d2:  E9 30 00 00 00          jmp    0x107

0x00000000000000d7:  80 3D 00 00 00 00 38    cmp    byte ptr [0], 0x38
0x00000000000000de:  75 11                   jne    0xf1
0x00000000000000e0:  D9 05 00 00 00 00       fld    dword ptr [0]
0x00000000000000e6:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x00000000000000ec:  E9 30 00 00 00          jmp    0x121

0x00000000000000f1:  D9 05 00 00 00 00       fld    dword ptr [0]
0x00000000000000f7:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x00000000000000fd:  E9 1F 00 00 00          jmp    0x121

0x0000000000000102:  E8 00 00 00 00          call   0x107
0x0000000000000107:  D9 05 00 00 00 00       fld    dword ptr [0]
0x000000000000010d:  D8 25 00 00 00 00       fsub   dword ptr [0]
0x0000000000000113:  D8 C9                   fmul   st(1)
0x0000000000000115:  D8 05 00 00 00 00       fadd   dword ptr [0]
0x000000000000011b:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x0000000000000121:  50                      push   eax
0x0000000000000122:  B8 01 00 00 00          mov    eax, 1
0x0000000000000127:  A3 00 00 00 00          mov    dword ptr [0], eax
0x000000000000012c:  B8 BE 00 00 00          mov    eax, 0xbe
0x0000000000000131:  A3 00 00 00 00          mov    dword ptr [0], eax
0x0000000000000136:  A3 00 00 00 00          mov    dword ptr [0], eax
0x000000000000013b:  A3 00 00 00 00          mov    dword ptr [0], eax
0x0000000000000140:  58                      pop    eax
0x0000000000000141:  E8 00 00 00 00          call   0x146
0x0000000000000146:  83 3D 00 00 00 00 00    cmp    dword ptr [0], 0
0x000000000000014d:  75 20                   jne    0x16f
0x000000000000014f:  50                      push   eax
0x0000000000000150:  A1 00 00 00 00          mov    eax, dword ptr [0]
0x0000000000000155:  A3 00 00 00 00          mov    dword ptr [0], eax
0x000000000000015a:  A1 00 00 00 00          mov    eax, dword ptr [0]
0x000000000000015f:  A3 00 00 00 00          mov    dword ptr [0], eax
0x0000000000000164:  A1 00 00 00 00          mov    eax, dword ptr [0]
0x0000000000000169:  A3 00 00 00 00          mov    dword ptr [0], eax
0x000000000000016e:  58                      pop    eax
0x000000000000016f:  D9 05 00 00 00 00       fld    dword ptr [0]
0x0000000000000175:  D8 35 00 00 00 00       fdiv   dword ptr [0]
0x000000000000017b:  D8 0D 00 00 00 00       fmul   dword ptr [0]
0x0000000000000181:  D9 E0                   fchs   
0x0000000000000183:  D8 05 00 00 00 00       fadd   dword ptr [0]
0x0000000000000189:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x000000000000018f:  D9 05 00 00 00 00       fld    dword ptr [0]
0x0000000000000195:  D8 35 00 00 00 00       fdiv   dword ptr [0]
0x000000000000019b:  D8 0D 00 00 00 00       fmul   dword ptr [0]
0x00000000000001a1:  D9 E0                   fchs   
0x00000000000001a3:  D8 05 00 00 00 00       fadd   dword ptr [0]
0x00000000000001a9:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x00000000000001af:  D9 EE                   fldz   
0x00000000000001b1:  D8 1D 00 00 00 00       fcomp  dword ptr [0]
0x00000000000001b7:  9B                      wait   
0x00000000000001b8:  DF E0                   fnstsw ax
0x00000000000001ba:  9E                      sahf   
0x00000000000001bb:  74 1E                   je     0x1db
0x00000000000001bd:  D9 05 00 00 00 00       fld    dword ptr [0]
0x00000000000001c3:  D8 35 00 00 00 00       fdiv   dword ptr [0]
0x00000000000001c9:  D8 0D 00 00 00 00       fmul   dword ptr [0]
0x00000000000001cf:  D8 05 00 00 00 00       fadd   dword ptr [0]
0x00000000000001d5:  D9 1D 00 00 00 00       fstp   dword ptr [0]
0x00000000000001db:  DD 25 00 00 00 00       frstor dword ptr [0]
0x00000000000001e1:  E9 00 00 00 00          jmp    0x1e6


Solution 1:[1]

Using absolute address 0 is very weird, presumably there's some kind of relocation to fixup those addresses. But your disassembly doesn't show it. If it's in a standard object-file format, you could use objdump -dr -Mintel foo.o to include relocation metadata.

But anyway, it uses fnsave to dump the x87 FPU state.

Probably the later addresses have different relocation fixup metadata, even though they're all [0] in the code you dumped. The start of the fsave area gets the FPUControlWord, and it makes no sense to fld / fstp 4 bytes from that location.

Almost certainly fld dword ptr [0] / fstp dword ptr [0] is copying a float value between 2 other locations, not loading / storing the FPU control and status words in place, as a 4-byte single-precision float. (Possibly munging the data if it represents a NaN.) So we must conclude that each [0] addressing mode could actually be any address, either within the fsave area or not. (The floats in the fsave area will be in 80-bit x87 format, not 32-bit (dword) single precision, so the fld dword is unlikely to be operating on them.)

The cmp with 0x33 .. 0x38 probably are looking at a byte of the x87 status word, maybe to figure out which slot in the save-area is the current top-of-stack? No, the status-word bits are not at the bottom of a byte. But the compare-result (C2, C1, C0) are at the bottom of the high byte of the status word (http://www.ray.masmcode.com/tutorial/fpuchap1.htm), and the exception-status bits in the bottom of the low byte.

So it's possible this chain of compare/branch is looking for something in the fsave area. Or more likely it's just checking for one of a few possible values for some byte of the game's data. Notice how on not-equal it jumps to the next cmp/jne. So this is an if/else chain, or one way of implementing a switch/case 0x33: / case 0x34: / ... statement.

The fnsave / frstor around the whole thing might be a red herring, it might not be poking around in that data at all. Instead it might just be saving/restoring the FPU state so it can use x87 instructions itself without messing up the main program. I initially thought it was reading the save-area because of the [0] address, but it seems clear that relocations might point that address at other parts of the program's data, not just this patch's own private storage.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Cordes