Trap and Emulate in x86-64

CS 301: Assembly Language Programming Lecture, Dr. Lawlor

Not every sequence of bytes makes a valid x86-64 instruction.  This is a good thing, because it allows hardware designers to add new features to new chips.

For example, an opcode map shows 0x06, 0x07, 0x0E, 0x16, 0x17, and many other bytes are invalid, and will result in an illegal instruction exception (SIGILL) at runtime.

If instruction 0x0E is later used to send email, for example, you can port that functionality to older machines by registering a signal handler for SIGILL, and manually faking the functionality of the command:
#include <signal.h>

void bad_instruction(int sig, siginfo_t *HowCome, void *ucontextv) {
	struct ucontext *uc=(struct ucontext *)ucontextv;
	struct sigcontext *r=(struct sigcontext *)(&uc->uc_mcontext);

	unsigned char c=*(unsigned char *)(r->rip); // read bad instruction
	std::cout<<"Fixing bad instruction byte "<<(int)c<<std::endl;
	r->rip++; // skip over bad instruction byte
	r->rax=1234; // change machine state
}

class static_init {
public:
	static_init() {
        	struct sigaction sa;
        	sa.sa_sigaction = bad_instruction;
        	sigemptyset( &sa.sa_mask );
        	sa.sa_flags = 0;
		sa.sa_flags |= SA_SIGINFO; /* we want a siginfo_t */
		sa.sa_flags |= SA_RESTART; /* restart interrupted syscalls 
(no EINTR errors) */
        	if (sigaction (SIGILL, &sa, 0)) {
			perror("sigaction");
			exit(1);
        	}
	}
};

extern "C" long run_code(void);

__asm__ (
".intel_syntax noprefix /* use good syntax */ \n\
.text /* make executable */  \n\
run_code:\n\
  .byte 0x06, 0x07, 0x0E  /* examples of bad code bytes */ \n\
  ret\n\
\n\
.att_syntax prefix\n"
);

long foo(void) {
	static static_init init;
	
	return run_code();
}

(Try this in NetRun now!)

The 64-bit disassembly of the "run_code" function is:

0000000000000000 <run_code>:
   0:	06                   	(bad)  
   1:	07                   	(bad)  
   2:	0e                   	(bad)  
   3:	c3                   	ret    

At runtime this prints:

Fixing bad instruction byte 6
Fixing bad instruction byte 7
Fixing bad instruction byte 14
Program complete.  Return 1234 (0x4D2)
So it works!