Programs and patches

Conditional move experiments

Supporting code and results related to conditional-move performance.

Last updated · 12 May 2010

/*
 * example3.c
 * - Example program for the "Emulating the CMOV instruction" article.
 * - In this example the parent clears SIGTERM generated by the child.
 * 
 * Michal Ludvig <michal@logix.cz> (c) 2003
 * Homepage: /devel/cmov-article
 *
 * This code is public domain. Use it as you want to, 
 * but don't blame me if something doesn't work as you 
 * expect.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ptrace.h>

void child ()
{
    ptrace (PTRACE_TRACEME, 0, NULL, NULL);
    kill (getpid (), SIGTERM);
    exit (5);
}

void parent ()
{
  int status;
  pid_t pid;

  while ((pid = wait4 (-1, &status, WUNTRACED, NULL)) >= 0)
    {
      printf ("PID[%lu]: ", pid);
      if (WIFEXITED (status))
        printf ("WEXITSTATUS: %d\n", WEXITSTATUS (status));
      else if (WIFSIGNALED (status))
        printf ("WTERMSIG: %d (%s)\n", WTERMSIG (status),
                strsignal (WTERMSIG (status)));
      else if (WIFSTOPPED (status))
        {
          int signal = WSTOPSIG (status);
          printf ("WSTOPSIG: %d (%s)\n", signal, strsignal (signal));
          if (signal == SIGTERM)
            signal = 0;
          ptrace (PTRACE_CONT, pid, NULL, signal);
        }
    }
}

int
main ()
{
  if (fork ())
    parent ();
  else
    child ();

  exit (0);
}
/*
 * example3.c
 * - Example program for the "Emulating the CMOV instruction" article.
 * - This example skips over the "UD2" instructions in the slave process.
 * 
 * Michal Ludvig <michal@logix.cz> (c) 2003
 * Homepage: /devel/cmov-article
 *
 * This code is public domain. Use it as you want to, 
 * but don't blame me if something doesn't work as you 
 * expect.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ptrace.h>

#ifndef offsetof
#define offsetof(STRUCT,MEMBER) ((long)&((STRUCT *)0)->MEMBER)
#endif

void child ()
{
    ptrace (PTRACE_TRACEME, 0, NULL, NULL);
    /* ud2 is an official "Undefined instruction", opcode 0x0f 0x0b */
    asm ("ud2");
    exit (5);
}

/* Skip over "ud2" instructions.  */
int handle_SIGILL (pid_t pid)
{
  long eip_offset = offsetof (struct user, regs.eip);
  long eip, opcode;

  /* Read EIP, i.e. the address where the exception occured.  */
  eip = ptrace (PTRACE_PEEKUSER, pid, eip_offset, NULL);
  if (eip == -1 && errno)
    return -1;

  /* Read instruction opcode from that address.  */
  opcode = ptrace (PTRACE_PEEKTEXT, pid, eip, NULL);
  if (opcode == -1 && errno)
    return -1;

  /* Test if it is a "known" instruction, i.e. "ud2".  */
  if ((opcode & 0x00FF) != 0x0f &&
      (opcode & 0xFF00) >> 8 != 0x0b)
    return -1;

  /* Increment the instruction pointer by 2, i.e. skip over "ud2"  */
  if (ptrace (PTRACE_POKEUSER, pid, eip_offset, eip + 2))
    return -1;

  return 0;
}

void parent ()
{
  int status;
  pid_t pid;

  while ((pid = wait4 (-1, &status, WUNTRACED, NULL)) >= 0)
    {
      printf ("PID[%lu]: ", pid);
      if (WIFEXITED (status))
        printf ("WEXITSTATUS: %d\n", WEXITSTATUS (status));
      else if (WIFSIGNALED (status))
        printf ("WTERMSIG: %d (%s)\n", WTERMSIG (status),
                strsignal (WTERMSIG (status)));
      else if (WIFSTOPPED (status))
        {
          int signal = WSTOPSIG (status);
          printf ("WSTOPSIG: %d (%s)\n", signal, strsignal (signal));
          if (signal == SIGILL && handle_SIGILL (pid) == 0)
              signal = 0;
          ptrace (PTRACE_CONT, pid, NULL, signal);
        }
    }
}

int
main ()
{
  if (fork ())
    parent ();
  else
    child ();

  exit (0);
}