#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
static int
return_1(void)
{
	return 1;
}
static void
return_1_end(void)
{
}
static int
return_2(void)
{
	return 2;
}
static void
return_2_end(void)
{
}
int
main(int argc, char *argv[])
{
        void *maprw, *maprx;
	int rv;
	size_t page = (size_t)sysconf(_SC_PAGESIZE);
	// Create the first mapping that has no protections, but intended
	// protections only
	maprw = mmap(NULL, page,
	    PROT_MPROTECT(PROT_EXEC|PROT_WRITE|PROT_READ),
            MAP_ANON|MAP_PRIVATE, -1, 0);
	if (maprw == MAP_FAILED)
		err(EXIT_FAILURE, "mmap failed");
        // Create the second mapping for the same physical space, which
	// again has no protections.
	maprx = mremap(maprw, page, NULL, page, MAP_REMAPDUP);
	if (maprx == MAP_FAILED)
		err(EXIT_FAILURE, "mremap failed");
	// Set the first mapping read/write
        if (mprotect(maprw, page, PROT_READ|PROT_WRITE) == -1)
		err(EXIT_FAILURE, "mprotect(rw) failed");
	// Set the second mapping read/execute
        if (mprotect(maprx, page, PROT_READ|PROT_EXEC) == -1)
		err(EXIT_FAILURE, "mprotect(rx) failed");
#define XS(a) (size_t)((uintptr_t)(a ## _end) - (uintptr_t)(a))
	// Copy and run the first function
	memcpy(maprw, return_1, XS(return_1));
	__builtin___clear_cache(maprw, (void *)((uintptr_t)maprw + page));
	rv = ((int (*)(void))maprx)();
	printf("%d\n", rv);
	// Copy and run the second function
	memcpy(maprw, return_2, XS(return_2));
	__builtin___clear_cache(maprw, (void *)((uintptr_t)maprw + page));
	rv = ((int (*)(void))maprx)();
	printf("%d\n", rv);
	return EXIT_SUCCESS;
}