0

There is C++ code:

int16_t ** g_Meshes;
int32_t m_MeshPtrCount;
int16_t * g_MeshBase;
uint32_t *mesh_indices;

for (int i = 0; i < m_MeshPtrCount; i++)
{
        g_Meshes[i] = &g_MeshBase[mesh_indices[i] / 2];
}

And corresponding Assembler code from IDA:

cseg01:0001E958 For_Mesh_Ptr_Count:                     ; CODE XREF: Load_Objects+B9j
cseg01:0001E958                 mov     ebx, Mesh_Indices
cseg01:0001E95E                 mov     eax, [edi+ebx]
cseg01:0001E961                 mov     edx, eax
cseg01:0001E963                 sar     edx, 1Fh
cseg01:0001E966                 sub     eax, edx
cseg01:0001E968                 sar     eax, 1
cseg01:0001E96A                 lea     edx, ds:0[eax*2]
cseg01:0001E971                 mov     eax, g_MeshBase
cseg01:0001E976                 add     eax, edx
cseg01:0001E978                 mov     [edi+ebx], eax
cseg01:0001E97B                 inc     ecx
cseg01:0001E97C                 mov     ebx, [esp+28h+var_20] ; var_20 = m_MeshPtrCount
cseg01:0001E980                 add     edi, 4
cseg01:0001E983                 cmp     ecx, ebx
cseg01:0001E985                 jl      short For_Mesh_Ptr_Count

Please explain someone for what need this operations:

cseg01:0001E963                 sar     edx, 1Fh
cseg01:0001E966                 sub     eax, edx
1
  • 1
    sar edx, 1Fh is equivalent to edx >> 31 except it always preserves the sign bit. sub eax, edx is simply eax -= edx. It's hard to provide more info than that since we dont know the variable-register mapping here.
    – mimak
    Commented Apr 14 at 11:23

1 Answer 1

1

It corresponds to calculating mesh_indices[i] / 2. The formula it's implementing is f(v) = (v - (v >> 31)) >> 1, with the shifts being arithmetic (i.e. the most significant bit is preserved). Implementing the operation this way respects the signedness of the original value. What is quite surprising here is that this is a miscompilation, as mesh_indices[i] is unsigned - the formula being implemented should simply be f(v) = v >> 1 (logical shift). For example, msvc correctly implements it in such a manner: https://godbolt.org/z/MGsYqTG13

2
  • Suppose we have eax = 1000'0000'0000'0010b; then mov edx, eax; then after sar edx, 1Fh we get edx = 1b; then sub eax, edx is equivalent eax - 1b? i.e. 1000'0000'0000'0010b - 1b? And then (1000'0000'0000'0010b - 1b) >> 1. But what it get for us? I understand that shift in right >> 1 is division by 2. For what we need preserve sign bit?
    – black4
    Commented Apr 15 at 12:20
  • 1
    We need to preserve the sign bit if we want to treat the argument as signed. You can work through the formulas for e.g. eax=0xFFFFFFFF and see that the more complicated formula will return zero, while only shifting to the right will return 0x7FFFFFFF. But, as I said, this is a miscompilation. The argument (mesh_indices[I]) is unsigned, the compiler should've used the unsigned variant of the formula.
    – ynwarcs
    Commented Apr 15 at 15:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.