esp used as general purpose register

51 views
Skip to first unread message

Palo Marton

unread,
Dec 18, 2013, 9:18:54 AM12/18/13
to asmji...@googlegroups.com
I got this code emmited:

056C0577 B8 E8 25 0F 07       mov         eax,70F25E8h  
056C057C 89 5D 0C             mov         dword ptr [ebp+0Ch],ebx  
056C057F BB 90 EB C1 04       mov         ebx,4C1EB90h  
056C0584 89 4C 24 14          mov         dword ptr [esp+14h],ecx  
056C0588 89 1C 24             mov         dword ptr [esp],ebx  
056C058B 89 54 24 04          mov         dword ptr [esp+4],edx  
056C058F 8B 65 0C             mov         esp,dword ptr [ebp+0Ch]  
056C0592 89 64 24 08          mov         dword ptr [esp+8],esp  <- crash here (esp=[ebp+0Ch]=0x01)
056C0596 8B C8                mov         ecx,eax  
056C0598 89 54 24 10          mov         dword ptr [esp+10h],edx  
056C059C E8 79 03 D5 FA       call        CCheck::performI2 (041091Ah)  


It seems to use esp as general purpose register, but that obviously fails. Is this some bug in AsmJit, or am I doing something wrong?

Palo

Petr Kobalíček

unread,
Dec 18, 2013, 9:32:42 AM12/18/13
to asmjit-dev
Hi Palo,

do you have a small sample that can reproduce the problem or is the code part of something bigger that is not easy to isolate?

In general it shouldn't happen, but if it happened it's definitely bug in asmjit. Which version do you use?

Best regards
Petr Kobalicek


2013/12/18 Palo Marton <palo....@gmail.com>

--
 
---
You received this message because you are subscribed to the Google Groups "asmjit-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to asmjit-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Palo Marton

unread,
Dec 18, 2013, 9:41:04 AM12/18/13
to asmji...@googlegroups.com
Unfotuanelly the code is quite big. But I can give you full assembly produced by AsmJit and few lines of code from my app the probably produced this instruction.



056C0540 55                   push        ebp  
056C0541 8B EC                mov         ebp,esp  
056C0543 53                   push        ebx  
056C0544 56                   push        esi  
056C0545 57                   push        edi  
056C0546 83 EC 2C             sub         esp,2Ch  
056C0549 8B 5D 0C             mov         ebx,dword ptr [ebp+0Ch]  
056C054C 01 1D 88 E8 C1 04    add         dword ptr ds:[4C1E888h],ebx  
056C0552 8B 4D 08             mov         ecx,dword ptr [ebp+8]  
056C0555 8B 34 8D 38 3F C2 04 mov         esi,dword ptr [ecx*4+4C23F38h]  
056C055C 8B 3E                mov         edi,dword ptr [esi]  
056C055E 90                   nop  
056C055F 01 1D 60 F4 C1 04    add         dword ptr ds:[4C1F460h],ebx  
056C0565 F7 DB                neg         ebx  
056C0567 8B 0C BD 38 3F C2 04 mov         ecx,dword ptr [edi*4+4C23F38h]  
056C056E 8B 11                mov         edx,dword ptr [ecx]  
056C0570 90                   nop  
056C0571 01 1D 48 E8 C1 04    add         dword ptr ds:[4C1E848h],ebx  
056C0577 B8 E8 25 0F 07       mov         eax,70F25E8h  
056C057C 89 5D 0C             mov         dword ptr [ebp+0Ch],ebx  
056C057F BB 90 EB C1 04       mov         ebx,4C1EB90h  
056C0584 89 4C 24 14          mov         dword ptr [esp+14h],ecx  
056C0588 89 1C 24             mov         dword ptr [esp],ebx  
056C058B 89 54 24 04          mov         dword ptr [esp+4],edx  
056C058F 8B 65 0C             mov         esp,dword ptr [ebp+0Ch]  
056C0592 89 64 24 08          mov         dword ptr [esp+8],esp  
056C0596 8B C8                mov         ecx,eax  
056C0598 89 54 24 10          mov         dword ptr [esp+10h],edx  
056C059C E8 79 03 D5 FA       call        CCheck::performI2 (041091Ah)  
056C05A1 83 EC 0C             sub         esp,0Ch  
056C05A4 CC                   int         3  
056C05A5 8B 4C 24 14          mov         ecx,dword ptr [esp+14h]  
056C05A9 83 C1 04             add         ecx,4  
056C05AC 8B 11                mov         edx,dword ptr [ecx]  
056C05AE 85 D2                test        edx,edx  
056C05B0 8B 5D 0C             mov         ebx,dword ptr [ebp+0Ch]  
056C05B3 79 BC                jns         056C0571  
056C05B5 F7 DB                neg         ebx  
056C05B7 CC                   int         3  
056C05B8 83 C6 04             add         esi,4  
056C05BB 8B 3E                mov         edi,dword ptr [esi]  
056C05BD 85 FF                test        edi,edi  
056C05BF 79 9E                jns         056C055F  
056C05C1 83 C4 2C             add         esp,2Ch  
056C05C4 5F                   pop         edi  
056C05C5 5E                   pop         esi  
056C05C6 5B                   pop         ebx  
056C05C7 8B E5                mov         esp,ebp  
056C05C9 5D                   pop         ebp  
056C05CA C3                   ret  


nop and int3 instructions in the code were used just as marks to find the place in my source that produced the code. The part of code which causes this bug is produced by this function.


void CScriptObject::Jit_performI(CSInteger *target, AsmJit::Compiler &c, CSInteger *src, AsmJit::GPVar &moznost, AsmJit::GPVar &i) {
void **vfptr=*((void***)this);

int vfptr_index=4;
#ifdef DEBUG
vfptr_index=6;
#endif // DEBUG

void *fn_performI=vfptr[vfptr_index];

// workaround 
AsmJit::GPVar v1(c.newGP(AsmJit::VARIABLE_TYPE_GPD));
AsmJit::GPVar v2(c.newGP(AsmJit::VARIABLE_TYPE_GPD));
c.mov(v1, AsmJit::imm((int)this));
c.mov(v2, AsmJit::imm((int)src));

AsmJit::ECall *ctx=c.call(fn_performI);
ctx->setPrototype(AsmJit::CALL_CONV_MSTHISCALL, AsmJit::FunctionBuilder4<void, CScriptObject*, CSInteger*, int, int>());

//ctx->setArgument(0, AsmJit::imm((int)this));
//ctx->setArgument(1, AsmJit::imm((int)src));
ctx->setArgument(0, v1);
ctx->setArgument(1, v2);

ctx->setArgument(2, moznost);
ctx->setArgument(3, i);

//this->performI2(src, 10,20);
}

Palo Marton

unread,
Dec 18, 2013, 9:51:17 AM12/18/13
to asmjit-dev
It seems that GPVar&i is located on position [ebp+0x0Ch] and function call needs to move it to [esp+8] as a function parameter in MSTHISCALL convention. Because both of these locations are in memory, it needs some temporary register to handle this. There is probably some bug in how this temporary register is allocated.

Can you please point me to a function in AsmJit source that is responsible for this allocation, so I can check it also?

I'm using V1.0-beta4.

p.

Petr Kobalíček

unread,
Dec 18, 2013, 9:53:41 AM12/18/13
to asmjit-dev
I think I know where the problem may be.

The generated code:

056C058F 8B 65 0C             mov         esp,dword ptr [ebp+0Ch]  
056C0592 89 64 24 08          mov         dword ptr [esp+8],esp  

Is generated by Compiler before the function call and it basically prepares one function argument. I think that the bug is function-call, not in the register allocator itself.

How urgent the bug is, I'm not sure I can track it today, but weekend will be definitely fine.

Best regards,
Petr Kobalicek

Palo Marton

unread,
Dec 18, 2013, 9:56:01 AM12/18/13
to asmji...@googlegroups.com
A the momemnt I am stuck on that. Do you have some quick workaround? I think that this situation can be handled e.g. by using sequence of push+pop instructions, so it will not need a new register.

Palo Marton

unread,
Dec 18, 2013, 9:57:24 AM12/18/13
to asmjit-dev
Is the problem here?

  // --------------------------------------------------------------------------
  // STEP 4:
  //
  // Get temporary register that we can use to pass input function arguments.
  // Now it's safe to do, because the non-needed variables should be spilled.
  // --------------------------------------------------------------------------

  temporaryGpReg = _findTemporaryGpRegister(cc);
  temporaryXmmReg = _findTemporaryXmmRegister(cc);

  // If failed to get temporary register then we need just to pick one.
  if (temporaryGpReg == INVALID_VALUE)
  {
    // TODO.
  }

Petr Kobalíček

unread,
Dec 18, 2013, 10:08:51 AM12/18/13
to asmjit-dev
I did a quick check and I think that the problem is in _findTemporaryGpRegister() function.

I can't test it right now, but I think that the function should be updated:

uint32_t ECall::_findTemporaryGpRegister(CompilerContext& cc) ASMJIT_NOTHROW
{
  uint32_t i;
  uint32_t mask;

  uint32_t passedGP = getPrototype().getPassedGP();
  uint32_t candidate = INVALID_VALUE;

  // Find all registers used to pass function arguments. We shouldn't use these
  // if possible.
  for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1)
  {
    // HERE IS THE QUICK FIX:
    if (i == 4)
      continue;

    if (cc._state.gp[i] == NULL)
    {
      // If this register is used to pass arguments to function, we will mark
      // it and use it only if there is no other one.
      if ((passedGP & mask) != 0)
        candidate = i;
      else
        return i;
    }
  }

  return candidate;
}

I think you can safely ignore the "// TODO" comments, because the _findTemporaryGpRegister() is called always right after some registers not used by the call are spilled, however I'm not sure how safe the assumption is.

Hope that this is the right workaround.

Best,
Petr

Palo Marton

unread,
Dec 18, 2013, 10:18:26 AM12/18/13
to asmjit-dev
Thanks!

Your QUICK FIX needed another fix (same problem with EBP), but it seems to work.

 // HERE IS THE QUICK FIX:
 if (i == REG_INDEX_ESP || i==REG_INDEX_EBP)
 continue;

My app is still crashing, but now it seems to crash somewhere else ;-)

p.

Palo Marton

unread,
Dec 18, 2013, 10:30:40 AM12/18/13
to asmjit-dev
Hm, now _findTemporaryGpRegister() returns INVALID_VALUE sometimes :-(

Petr Kobalíček

unread,
Dec 18, 2013, 10:46:04 AM12/18/13
to asmjit-dev
Hi Palo,

try to replace it with the file attached.

Best regards
Petr Kobalicek
CompilerX86X64.cpp

Palo Marton

unread,
Dec 18, 2013, 11:14:55 AM12/18/13
to asmjit-dev
This seems to help for "small" test. The breakpoint I have on:

 if (temporaryGpReg == INVALID_VALUE)
 {
 int i=1/(temporaryGpReg-INVALID_VALUE);
 // Still invalid?
 }

is not hit there.

But for bigger input for my program the app still crashes on assertion in AsmJit:

          ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPB_LO) ||
                        dst.isRegType(REG_TYPE_GPB_HI) ||
                        dst.isRegType(REG_TYPE_GPW   ) ||
                        dst.isRegType(REG_TYPE_GPD   ) ||
                        dst.isRegType(REG_TYPE_GPQ   ) );

I will investigate this futher and let you know.

BTW: Thanks for your great support!

bests,
Palo


Palo Marton

unread,
Dec 18, 2013, 11:23:01 AM12/18/13
to asmjit-dev
dst._reg.code = 0xffffffff

probably some invalid dst value.

call stack:

  roz.exe!AsmJit::assertionFailure(const char * file, int line, const char * exp) Line 26 C++
  roz.exe!AsmJit::AssemblerCore::_emitInstruction(unsigned int code, const AsmJit::Operand * o0, const AsmJit::Operand * o1, const AsmJit::Operand * o2) Line 1560 C++
  roz.exe!AsmJit::AssemblerCore::_emitInstruction(unsigned int code, const AsmJit::Operand * o0, const AsmJit::Operand * o1) Line 915 C++
  roz.exe!AsmJit::EInstruction::emit(AsmJit::Assembler & a) Line 2012 C++
> roz.exe!AsmJit::CompilerCore::serialize(AsmJit::Assembler & a) Line 7810 C++
  roz.exe!AsmJit::CompilerCore::make() Line 7633 C++


Palo Marton

unread,
Dec 18, 2013, 4:13:07 PM12/18/13
to asmji...@googlegroups.com
this last problem was probably my bug - some memory overwrite or something...
at least I can not reproduce it any more after fixing few bugs in my code.

Dňa streda, 18. decembra 2013 17:23:01 UTC+1 Palo Marton napísal(-a):
Reply all
Reply to author
Forward
0 new messages