#8199: Get rid of HEAP_ALLOCED -------------------------------------+------------------------------------- Reporter: ezyang | Owner: ezyang Type: feature | Status: new request | Milestone: 7.10.1 Priority: normal | Version: 7.7 Component: Compiler | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Project (more Unknown/Multiple | than a week) Type of failure: | Blocked By: 5435 None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: D207 | -------------------------------------+------------------------------------- Comment (by ajp): Method 1 from the attached task may actually be made to work (at least on Linux). The key point is that we don't have to use the memory address that we happened to be given at startup. We can shift it to an aligned location using MREMAP, and simply include a mb of padding at the end to avoid trashing anything. Here's a modification of the code in the attached task that demostrates shifting the memory address with zero copies. {{{ ┌─[anders gurney] [~/devel/alignment] └─[139] cat test.S .section foo,"aw" .p2align 20 .global foo_start .global foo_end foo_start: .ascii "A" .fill 1048576 foo_end: .ascii "B" ┌─[anders gurney] [~/devel/alignment] └─[0] cat main.c #define _GNU_SOURCE #include <stdio.h> #include <sys/mman.h> extern char foo_start; extern char foo_end; size_t mb = 1024 * 1024; size_t round_to_mb(size_t x) { return (x + mb - 1) & ~(mb - 1); } size_t main(void) { printf("%c %c\n", foo_start, foo_end); // force libtest.so to be loaded printf("%p foo_start\n", &foo_start); printf("%p foo_end\n", &foo_end); printf("%d delta\n", &foo_end - &foo_start); void *next_mb_aligned_address = (void *) round_to_mb((size_t)&foo_start); printf("%p next mb aligned address\n", next_mb_aligned_address); void* new_address = mremap(&foo_start, 4096, 4096, MREMAP_MAYMOVE | MREMAP_FIXED, next_mb_aligned_address); printf("%p %p // should be the same\n", new_address, next_mb_aligned_address); printf("%c // should be A\n", * (char *) new_address); printf("%c // should be B\n", foo_end); printf("and this should segfault\n"); printf("%c\n", foo_start); } ┌─[anders gurney] [~/devel/alignment] └─[0] gcc test.S -shared -o libtest.so -fPIC ┌─[anders gurney] [~/devel/alignment] └─[0] gcc -Wl,-R`pwd` -L. main.c -ltest -g -O0 -fPIC && ./a.out /nix/store/ycmsiznf2484vbjwmj57jdy2ncyrj7fj-binutils-2.23.1/bin/ld: warning: type and size of dynamic symbol `foo_start' are not defined /nix/store/ycmsiznf2484vbjwmj57jdy2ncyrj7fj-binutils-2.23.1/bin/ld: warning: type and size of dynamic symbol `foo_end' are not defined A B 0x7f8318c95000 foo_start 0x7f8318d95001 foo_end 1048577 delta 0x7f8318d00000 next mb aligned address 0x7f8318d00000 0x7f8318d00000 // should be the same A // should be A B // should be B and this should segfault zsh: segmentation fault ./a.out }}} Is there sonething fundamental that would prohibit this technique from working? It seems neater than the idea in #9706, as it - doesn't rely on overcommit - doesn't screw up accounting of VMA size - doesn't "use up" the trick of putting objects in arbitrary memory locations with MAP_FIXED. This could for example be used by an optimized application at the app level to use 48 bit pointers for a large skiplist. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8199#comment:45> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler