+#ifdef USE_MMAP
+#define ROUND_UP(x,size) ((x + size - 1) & ~(size - 1))
+
+static void *
+mmapForLinker (size_t bytes, nat flags, int fd)
+{
+ void *map_addr = NULL;
+ void *result;
+ int pagesize, size;
+
+ pagesize = getpagesize();
+ size = ROUND_UP(bytes, pagesize);
+
+#if defined(x86_64_HOST_ARCH)
+mmap_again:
+
+ if (mmap_32bit_base != 0) {
+ map_addr = mmap_32bit_base;
+ }
+#endif
+
+ result = mmap(map_addr, size, PROT_EXEC|PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|TRY_MAP_32BIT|flags, fd, 0);
+
+ if (result == MAP_FAILED) {
+ sysErrorBelch("mmap");
+ stg_exit(EXIT_FAILURE);
+ }
+
+#if defined(x86_64_HOST_ARCH)
+ if (mmap_32bit_base != 0) {
+ if (result == map_addr) {
+ mmap_32bit_base = map_addr + size;
+ } else {
+ if ((W_)result > 0x80000000) {
+ // oops, we were given memory over 2Gb
+ // ... try allocating memory somewhere else?;
+ barf("loadObj: failed to mmap() memory below 2Gb; asked for %lu bytes at %p, got %p. Try specifying an address with +RTS -xm<addr> -RTS", size, map_addr, result);
+ } else {
+ // hmm, we were given memory somewhere else, but it's
+ // still under 2Gb so we can use it. Next time, ask
+ // for memory right after the place we just got some
+ mmap_32bit_base = (void*)result + size;
+ }
+ }
+ } else {
+ if ((W_)result > 0x80000000) {
+ // oops, we were given memory over 2Gb
+ // ... try allocating memory somewhere else?;
+ debugTrace(DEBUG_linker,"MAP_32BIT didn't work; gave us %lu bytes at 0x%p", bytes, result);
+ munmap(result, size);
+
+ // Set a base address and try again... (guess: 1Gb)
+ mmap_32bit_base = (void*)0x40000000;
+ goto mmap_again;
+ }
+ }
+#endif
+
+ return result;
+}
+#endif // USE_MMAP
+