#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <elf.h>

unsigned char *save;
void *restart;

void *segv(unsigned int a, struct sigcontext c)
{
	unsigned int x = *(&a + 6);
	if (save != 0) {
		*(&a + 6) = (unsigned int)(save + 16*1024);
		save = 0;
	} else
		*(&a + 6) += 16*1024;
	if (*(&a + 6) < x)
		_exit(0);
//	*(&a + 15) = (unsigned int)restart;
	c.eip = (unsigned int)restart;
}

char *get_name(uint8_t *ptr)
{
	int i;
	Elf32_Ehdr *ehdr = (Elf32_Ehdr*)ptr;
	Elf32_Phdr *phdr = (Elf32_Phdr*)(ptr + ehdr->e_phoff);
	Elf32_Dyn *dyn = NULL;
	uint32_t name = 0;
	char *strtab = NULL;
	for (i = 0; i < ehdr->e_phnum; i++)
		if (phdr[i].p_type == PT_DYNAMIC) {
			dyn = (Elf32_Dyn*)phdr[i].p_vaddr;
			break;
		}
	if (dyn) {
		while (dyn->d_tag != DT_NULL) {
			if (dyn->d_tag == DT_SONAME)
				name = dyn->d_un.d_val;
			if (dyn->d_tag == DT_STRTAB)
				strtab = (char*)dyn->d_un.d_ptr;
			dyn++;
		}
		if (name && strtab)
			return strtab + name;
	}
	return NULL;
}

int main(int argc, char **argv, char **envp)
{
	struct sigaction sa;

	bzero(&sa, sizeof(sa));
	sa.sa_handler = (void(*)(int))segv;
	sigaction(11, &sa, 0);
	
	for(restart = &&__restart;;) {
		register char *ptr asm("esi") = NULL;
		volatile register char foo;
		save = 0;
__restart:	foo = *ptr;
		for (save = ptr ;; ptr -= 4096)
			if (*(uint32_t*)ptr == 0x464c457f)
				break;
		printf("ELF found @ %08x, name %s\n", ptr, get_name(ptr));

		for (save = 0 ;; ptr += 4096)
			foo = *ptr;
	}
}
