diff options
author | Ben Gamari <bgamari.foss@gmail.com> | 2016-11-02 15:01:15 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2016-11-02 15:42:00 -0400 |
commit | 3f05126253a7d68b37a388c26b586d94e871614e (patch) | |
tree | 16ac13364193992be02b12ddf0068d2343ad91b6 | |
parent | 43c8c1c4a21c3b0a281433394163ba46a124a925 (diff) | |
download | haskell-3f05126253a7d68b37a388c26b586d94e871614e.tar.gz |
linker: Split symbol extras logic into new source file
Test Plan: Validate
Reviewers: erikd, austin, simonmar
Reviewed By: simonmar
Subscribers: thomie
Differential Revision: https://phabricator.haskell.org/D2646
-rw-r--r-- | rts/Linker.c | 201 | ||||
-rw-r--r-- | rts/linker/SymbolExtras.c | 209 | ||||
-rw-r--r-- | rts/linker/SymbolExtras.h | 30 |
3 files changed, 240 insertions, 200 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index 74b48225eb..8147ed8552 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -29,6 +29,7 @@ #include "sm/OSMem.h" #include "linker/M32Alloc.h" #include "linker/CacheFlush.h" +#include "linker/SymbolExtras.h" #include "PathUtils.h" #if !defined(mingw32_HOST_OS) @@ -2667,206 +2668,6 @@ addSection (Section *s, SectionKind kind, SectionAlloc alloc, size, kind )); } - -/* -------------------------------------------------------------------------- - * Symbol Extras. - * This is about allocating a small chunk of memory for every symbol in the - * object file. We make sure that the SymboLExtras are always "in range" of - * limited-range PC-relative instructions on various platforms by allocating - * them right next to the object code itself. - */ - -#if NEED_SYMBOL_EXTRAS -#if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS) - -/* - ocAllocateSymbolExtras - - Allocate additional space at the end of the object file image to make room - for jump islands (powerpc, x86_64, arm) and GOT entries (x86_64). - - PowerPC relative branch instructions have a 24 bit displacement field. - As PPC code is always 4-byte-aligned, this yields a +-32MB range. - If a particular imported symbol is outside this range, we have to redirect - the jump to a short piece of new code that just loads the 32bit absolute - address and jumps there. - On x86_64, PC-relative jumps and PC-relative accesses to the GOT are limited - to 32 bits (+-2GB). - - This function just allocates space for one SymbolExtra for every - undefined symbol in the object file. The code for the jump islands is - filled in by makeSymbolExtra below. -*/ - -static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ) -{ - size_t n; - - if (RTS_LINKER_USE_MMAP && USE_CONTIGUOUS_MMAP) { - n = roundUpToPage(oc->fileSize); - - /* Keep image and symbol_extras contiguous */ - void *new = mmapForLinker(n + (sizeof(SymbolExtra) * count), - MAP_ANONYMOUS, -1, 0); - if (new) { - memcpy(new, oc->image, oc->fileSize); - if (oc->imageMapped) { - munmap(oc->image, n); - } - oc->image = new; - oc->imageMapped = rtsTrue; - oc->fileSize = n + (sizeof(SymbolExtra) * count); - oc->symbol_extras = (SymbolExtra *) (oc->image + n); - } - else { - oc->symbol_extras = NULL; - return 0; - } - } - else if( count > 0 ) { - if (RTS_LINKER_USE_MMAP) { - n = roundUpToPage(oc->fileSize); - - oc->symbol_extras = m32_alloc(sizeof(SymbolExtra) * count, 8); - if (oc->symbol_extras == NULL) return 0; - } - else { - // round up to the nearest 4 - int aligned = (oc->fileSize + 3) & ~3; - int misalignment = oc->misalignment; - - oc->image -= misalignment; - oc->image = stgReallocBytes( oc->image, - misalignment + - aligned + sizeof (SymbolExtra) * count, - "ocAllocateSymbolExtras" ); - oc->image += misalignment; - - oc->symbol_extras = (SymbolExtra *) (oc->image + aligned); - } - } - - if (oc->symbol_extras != NULL) { - memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count ); - } - - oc->first_symbol_extra = first; - oc->n_symbol_extras = count; - - return 1; -} - -#endif -#endif // NEED_SYMBOL_EXTRAS - -#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) -#if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS) - -static SymbolExtra* makeSymbolExtra( ObjectCode* oc, - unsigned long symbolNumber, - unsigned long target ) -{ - SymbolExtra *extra; - - ASSERT( symbolNumber >= oc->first_symbol_extra - && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras); - - extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra]; - -#ifdef powerpc_HOST_ARCH - // lis r12, hi16(target) - extra->jumpIsland.lis_r12 = 0x3d80; - extra->jumpIsland.hi_addr = target >> 16; - - // ori r12, r12, lo16(target) - extra->jumpIsland.ori_r12_r12 = 0x618c; - extra->jumpIsland.lo_addr = target & 0xffff; - - // mtctr r12 - extra->jumpIsland.mtctr_r12 = 0x7d8903a6; - - // bctr - extra->jumpIsland.bctr = 0x4e800420; -#endif -#ifdef x86_64_HOST_ARCH - // jmp *-14(%rip) - static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF }; - extra->addr = target; - memcpy(extra->jumpIsland, jmp, 6); -#endif - - return extra; -} - -#endif -#endif // defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) - -#ifdef arm_HOST_ARCH -static SymbolExtra* makeArmSymbolExtra( ObjectCode* oc, - unsigned long symbolNumber, - unsigned long target, - int fromThumb, - int toThumb ) -{ - SymbolExtra *extra; - - ASSERT( symbolNumber >= oc->first_symbol_extra - && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras); - - extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra]; - - // Make sure instruction mode bit is set properly - if (toThumb) - target |= 1; - else - target &= ~1; - - if (!fromThumb) { - // In ARM encoding: - // movw r12, #0 - // movt r12, #0 - // bx r12 - uint32_t code[] = { 0xe300c000, 0xe340c000, 0xe12fff1c }; - - // Patch lower half-word into movw - code[0] |= ((target>>12) & 0xf) << 16; - code[0] |= target & 0xfff; - // Patch upper half-word into movt - target >>= 16; - code[1] |= ((target>>12) & 0xf) << 16; - code[1] |= target & 0xfff; - - memcpy(extra->jumpIsland, code, 12); - - } else { - // In Thumb encoding: - // movw r12, #0 - // movt r12, #0 - // bx r12 - uint16_t code[] = { 0xf240, 0x0c00, - 0xf2c0, 0x0c00, - 0x4760 }; - - // Patch lower half-word into movw - code[0] |= (target>>12) & 0xf; - code[0] |= ((target>>11) & 0x1) << 10; - code[1] |= ((target>>8) & 0x7) << 12; - code[1] |= target & 0xff; - // Patch upper half-word into movt - target >>= 16; - code[2] |= (target>>12) & 0xf; - code[2] |= ((target>>11) & 0x1) << 10; - code[3] |= ((target>>8) & 0x7) << 12; - code[3] |= target & 0xff; - - memcpy(extra->jumpIsland, code, 10); - } - - return extra; -} -#endif // arm_HOST_ARCH - - /* -------------------------------------------------------------------------- * PEi386(+) specifics (Win32 targets) * ------------------------------------------------------------------------*/ diff --git a/rts/linker/SymbolExtras.c b/rts/linker/SymbolExtras.c new file mode 100644 index 0000000000..c98510488d --- /dev/null +++ b/rts/linker/SymbolExtras.c @@ -0,0 +1,209 @@ +/* -------------------------------------------------------------------------- + * Symbol Extras. + * This is about allocating a small chunk of memory for every symbol in the + * object file. We make sure that the SymboLExtras are always "in range" of + * limited-range PC-relative instructions on various platforms by allocating + * them right next to the object code itself. + * + * This implementation is shared by the MachO and ELF implementations. Windows' + * PEi386 has its own implementation of symbol extras. + */ + +#include "LinkerInternals.h" + +#if NEED_SYMBOL_EXTRAS +#if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS) + +#include "RtsUtils.h" +#include "sm/OSMem.h" +#include "linker/SymbolExtras.h" +#include "linker/M32Alloc.h" + +#include <string.h> +#if RTS_LINKER_USE_MMAP +#include <sys/mman.h> +#endif /* RTS_LINKER_USE_MMAP */ + +/* + ocAllocateSymbolExtras + + Allocate additional space at the end of the object file image to make room + for jump islands (powerpc, x86_64, arm) and GOT entries (x86_64). + + PowerPC relative branch instructions have a 24 bit displacement field. + As PPC code is always 4-byte-aligned, this yields a +-32MB range. + If a particular imported symbol is outside this range, we have to redirect + the jump to a short piece of new code that just loads the 32bit absolute + address and jumps there. + On x86_64, PC-relative jumps and PC-relative accesses to the GOT are limited + to 32 bits (+-2GB). + + This function just allocates space for one SymbolExtra for every + undefined symbol in the object file. The code for the jump islands is + filled in by makeSymbolExtra below. +*/ + +int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ) +{ + size_t n; + + if (RTS_LINKER_USE_MMAP && USE_CONTIGUOUS_MMAP) { + n = roundUpToPage(oc->fileSize); + + /* Keep image and symbol_extras contiguous */ + void *new = mmapForLinker(n + (sizeof(SymbolExtra) * count), + MAP_ANONYMOUS, -1, 0); + if (new) { + memcpy(new, oc->image, oc->fileSize); + if (oc->imageMapped) { + munmap(oc->image, n); + } + oc->image = new; + oc->imageMapped = rtsTrue; + oc->fileSize = n + (sizeof(SymbolExtra) * count); + oc->symbol_extras = (SymbolExtra *) (oc->image + n); + } + else { + oc->symbol_extras = NULL; + return 0; + } + } + else if( count > 0 ) { + if (RTS_LINKER_USE_MMAP) { + n = roundUpToPage(oc->fileSize); + + oc->symbol_extras = m32_alloc(sizeof(SymbolExtra) * count, 8); + if (oc->symbol_extras == NULL) return 0; + } + else { + // round up to the nearest 4 + int aligned = (oc->fileSize + 3) & ~3; + int misalignment = oc->misalignment; + + oc->image -= misalignment; + oc->image = stgReallocBytes( oc->image, + misalignment + + aligned + sizeof (SymbolExtra) * count, + "ocAllocateSymbolExtras" ); + oc->image += misalignment; + + oc->symbol_extras = (SymbolExtra *) (oc->image + aligned); + } + } + + if (oc->symbol_extras != NULL) { + memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count ); + } + + oc->first_symbol_extra = first; + oc->n_symbol_extras = count; + + return 1; +} + + +#ifndef arm_HOST_ARCH +SymbolExtra* makeSymbolExtra( ObjectCode* oc, + unsigned long symbolNumber, + unsigned long target ) +{ + SymbolExtra *extra; + + ASSERT( symbolNumber >= oc->first_symbol_extra + && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras); + + extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra]; + +#ifdef powerpc_HOST_ARCH + // lis r12, hi16(target) + extra->jumpIsland.lis_r12 = 0x3d80; + extra->jumpIsland.hi_addr = target >> 16; + + // ori r12, r12, lo16(target) + extra->jumpIsland.ori_r12_r12 = 0x618c; + extra->jumpIsland.lo_addr = target & 0xffff; + + // mtctr r12 + extra->jumpIsland.mtctr_r12 = 0x7d8903a6; + + // bctr + extra->jumpIsland.bctr = 0x4e800420; +#endif /* powerpc_HOST_ARCH */ +#ifdef x86_64_HOST_ARCH + // jmp *-14(%rip) + static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF }; + extra->addr = target; + memcpy(extra->jumpIsland, jmp, 6); +#endif /* x86_64_HOST_ARCH */ + + return extra; +} +#endif + +#ifdef arm_HOST_ARCH +SymbolExtra* makeArmSymbolExtra( ObjectCode* oc, + unsigned long symbolNumber, + unsigned long target, + int fromThumb, + int toThumb ) +{ + SymbolExtra *extra; + + ASSERT( symbolNumber >= oc->first_symbol_extra + && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras); + + extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra]; + + // Make sure instruction mode bit is set properly + if (toThumb) + target |= 1; + else + target &= ~1; + + if (!fromThumb) { + // In ARM encoding: + // movw r12, #0 + // movt r12, #0 + // bx r12 + uint32_t code[] = { 0xe300c000, 0xe340c000, 0xe12fff1c }; + + // Patch lower half-word into movw + code[0] |= ((target>>12) & 0xf) << 16; + code[0] |= target & 0xfff; + // Patch upper half-word into movt + target >>= 16; + code[1] |= ((target>>12) & 0xf) << 16; + code[1] |= target & 0xfff; + + memcpy(extra->jumpIsland, code, 12); + + } else { + // In Thumb encoding: + // movw r12, #0 + // movt r12, #0 + // bx r12 + uint16_t code[] = { 0xf240, 0x0c00, + 0xf2c0, 0x0c00, + 0x4760 }; + + // Patch lower half-word into movw + code[0] |= (target>>12) & 0xf; + code[0] |= ((target>>11) & 0x1) << 10; + code[1] |= ((target>>8) & 0x7) << 12; + code[1] |= target & 0xff; + // Patch upper half-word into movt + target >>= 16; + code[2] |= (target>>12) & 0xf; + code[2] |= ((target>>11) & 0x1) << 10; + code[3] |= ((target>>8) & 0x7) << 12; + code[3] |= target & 0xff; + + memcpy(extra->jumpIsland, code, 10); + } + + return extra; +} +#endif // arm_HOST_ARCH + +#endif +#endif // NEED_SYMBOL_EXTRAS diff --git a/rts/linker/SymbolExtras.h b/rts/linker/SymbolExtras.h new file mode 100644 index 0000000000..c89777536f --- /dev/null +++ b/rts/linker/SymbolExtras.h @@ -0,0 +1,30 @@ +#ifndef LINKER_SYMBOL_EXTRAS_H +#define LINKER_SYMBOL_EXTRAS_H + +#include "Rts.h" +#include "LinkerInternals.h" + +#include "BeginPrivate.h" + +#if NEED_SYMBOL_EXTRAS + +int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ); + +#ifdef arm_HOST_ARCH +SymbolExtra* makeArmSymbolExtra( ObjectCode* oc, + unsigned long symbolNumber, + unsigned long target, + int fromThumb, + int toThumb ); +#else +SymbolExtra* makeSymbolExtra( ObjectCode* oc, + unsigned long symbolNumber, + unsigned long target ); + +#endif /* arm_HOST_ARCH */ + +#endif /* NEED_SYMBOL_EXTRAS */ + +#include "EndPrivate.h" + +#endif /* LINKER_SYMBOL_EXTRAS_H */ |