void
gum_spinlock_init (GumSpinlock * spinlock)
{
  GumSpinlockImpl * self = (GumSpinlockImpl *) spinlock;
  GumX86Writer cw;
  gpointer try_again_label = "gum_spinlock_try_again";
  gpointer beach_label = "gum_spinlock_beach";

  self->is_held = FALSE;

  self->code = gum_alloc_n_pages (1, GUM_PAGE_RWX);

  gum_x86_writer_init (&cw, self->code);

  self->acquire_impl = GUM_POINTER_TO_FUNCPTR (GumSpinlockAcquireFunc,
      gum_x86_writer_cur (&cw));
  gum_x86_writer_put_mov_reg_u32 (&cw, GUM_REG_EDX, 1);

  gum_x86_writer_put_label (&cw, try_again_label);
  gum_x86_writer_put_mov_reg_u32 (&cw, GUM_REG_EAX, 0);
  gum_x86_writer_put_lock_cmpxchg_reg_ptr_reg (&cw, GUM_REG_RCX, GUM_REG_EDX);
  gum_x86_writer_put_jcc_short_label (&cw, GUM_X86_JZ, beach_label,
      GUM_NO_HINT);

  gum_x86_writer_put_pause (&cw);
  gum_x86_writer_put_jmp_short_label (&cw, try_again_label);

  gum_x86_writer_put_label (&cw, beach_label);
  gum_x86_writer_put_ret (&cw);

  gum_x86_writer_free (&cw);
}
static void
test_relocator_fixture_teardown (TestRelocatorFixture * fixture,
                                 gconstpointer data)
{
  gum_x86_relocator_free (&fixture->rl);
  gum_x86_writer_free (&fixture->cw);
  gum_free_pages (fixture->output);
}
void
lowlevel_helpers_init (void)
{
  GumX86Writer cw;

  g_assert (clobber_test_function == NULL);

  clobber_test_function = GUM_POINTER_TO_FUNCPTR (ClobberTestFunc,
      gum_alloc_n_pages (1, GUM_PAGE_RWX));
  gum_x86_writer_init (&cw, (gpointer) (gsize) clobber_test_function);
  gum_x86_writer_put_nop (&cw);
  gum_x86_writer_put_nop (&cw);
  gum_x86_writer_put_nop (&cw);
  gum_x86_writer_put_nop (&cw);
  gum_x86_writer_put_nop (&cw);
  gum_x86_writer_put_ret (&cw);
  gum_x86_writer_free (&cw);
}
static void
test_code_writer_fixture_teardown (TestCodeWriterFixture * fixture,
                                   gconstpointer data)
{
  gum_x86_writer_free (&fixture->cw);
}