Skip to content

Instantly share code, notes, and snippets.

@ericoporto
Last active July 15, 2023 11:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericoporto/cf1c419aaa81e97e598b4739c674498a to your computer and use it in GitHub Desktop.
Save ericoporto/cf1c419aaa81e97e598b4739c674498a to your computer and use it in GitHub Desktop.

The following part of jjsat commit here https://github.com/jjsat/ags/commit/22221b6d3ebffdd7c7e32e5ccb95a590e5a8307a#diff-4db3d150dec6fcd9180c42130e5d06d6f11649403d1a1d46700564785284e0dbR1456-R1481

We see that load.sp.offs was used to load the value of the stack pointer (SP) with an offset, moving the stack pointer up or down.

But then, after the commit, it changed from

case SCMD_LOADSPOFFS:
  inst->registers[SREG_MAR] = inst->registers[SREG_SP] - arg1;

to

case SCMD_LOADSPOFFS:

  // 64 bit: Rewrite offset so that it doesn't point inside a variable
  original_sp_diff = arg1;
  new_sp_diff = 0;
  sp_index = inst->stackSizeIndex - 1;

  while (original_sp_diff > 0)
  {
    if (inst->stackSizes[sp_index] == -1)
    {
      original_sp_diff -= 4;
      new_sp_diff += sizeof(long);//inst->stackSizes[sp_index];
      sp_index--;
    }
    else
    {
      original_sp_diff -= inst->stackSizes[sp_index];
      new_sp_diff += inst->stackSizes[sp_index];
      sp_index--;
    }
  }

  if (sp_index < -1)
    cc_error("Stack offset cannot be rewritten. Stack corrupted?");

  inst->registers[SREG_MAR] = inst->registers[SREG_SP] - new_sp_diff;

So this 64-bit compatibility commit eventually made into the current ccInstance::GetStackPtrOffsetRw we are familiar nowadays.

RuntimeScriptValue ccInstance::GetStackPtrOffsetRw(int32_t rw_offset)
{
    int32_t total_off = 0;
    RuntimeScriptValue *stack_entry = registers[SREG_SP].RValue;
    while (total_off < rw_offset && stack_entry >= &stack[0])
    {
        stack_entry--;
        total_off += stack_entry->Size;
    }
    CC_ERROR_IF_RETVAL(total_off < rw_offset, RuntimeScriptValue, "accessing address before stack's head");
    RuntimeScriptValue stack_ptr;
    stack_ptr.SetStackPtr(stack_entry);
    stack_ptr.IValue += total_off - rw_offset; // possibly offset to the mid-array
    // Could be accessing array element, so state error only if stack entry does not refer to data array
    CC_ERROR_IF_RETVAL((total_off > rw_offset) && (stack_entry->Type != kScValData), RuntimeScriptValue,
        "stack offset backward: trying to access stack data inside stack entry, stack corrupted?")
    return stack_ptr;
}

I wonder if there is some way to rewrite this so no loop is needed.

  • SCMD_LOADSPOFFS
  • Get memory address of stack variable at arg1 offset and save it in reg[MAR]
  • m[MAR] = m[SP] - arg1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment