Revert "Batch merge"
[ghc.git] / rts / linker / SymbolExtras.c
1 /* --------------------------------------------------------------------------
2 * Symbol Extras.
3 * This is about allocating a small chunk of memory for every symbol in the
4 * object file. We make sure that the SymboLExtras are always "in range" of
5 * limited-range PC-relative instructions on various platforms by allocating
6 * them right next to the object code itself.
7 *
8 * This implementation is shared by the MachO and ELF implementations. Windows'
9 * PEi386 has its own implementation of symbol extras.
10 */
11
12 #include "LinkerInternals.h"
13
14 #if defined(NEED_SYMBOL_EXTRAS)
15 #if !defined(x86_64_HOST_ARCH) || !defined(mingw32_HOST_OS)
16
17 #include "RtsUtils.h"
18 #include "sm/OSMem.h"
19 #include "linker/SymbolExtras.h"
20 #include "linker/M32Alloc.h"
21
22 #include <string.h>
23 #if RTS_LINKER_USE_MMAP
24 #include <sys/mman.h>
25 #endif /* RTS_LINKER_USE_MMAP */
26
27 /*
28 ocAllocateSymbolExtras
29
30 Allocate additional space at the end of the object file image to make room
31 for jump islands (powerpc, x86_64, arm) and GOT entries (x86_64).
32
33 PowerPC relative branch instructions have a 24 bit displacement field.
34 As PPC code is always 4-byte-aligned, this yields a +-32MB range.
35 If a particular imported symbol is outside this range, we have to redirect
36 the jump to a short piece of new code that just loads the 32bit absolute
37 address and jumps there.
38 On x86_64, PC-relative jumps and PC-relative accesses to the GOT are limited
39 to 32 bits (+-2GB).
40
41 This function just allocates space for one SymbolExtra for every
42 undefined symbol in the object file. The code for the jump islands is
43 filled in by makeSymbolExtra below.
44 */
45
46 int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
47 {
48 size_t n;
49
50 if (RTS_LINKER_USE_MMAP && USE_CONTIGUOUS_MMAP) {
51 n = roundUpToPage(oc->fileSize);
52
53 /* Keep image and symbol_extras contiguous */
54
55 size_t allocated_size = n + (sizeof(SymbolExtra) * count);
56 void *new = mmapForLinker(allocated_size, MAP_ANONYMOUS, -1, 0);
57 if (new) {
58 memcpy(new, oc->image, oc->fileSize);
59 if (oc->imageMapped) {
60 munmap(oc->image, n);
61 }
62 oc->image = new;
63 oc->imageMapped = true;
64 oc->fileSize = n + (sizeof(SymbolExtra) * count);
65 oc->symbol_extras = (SymbolExtra *) (oc->image + n);
66 if(mprotect(new, allocated_size, PROT_READ | PROT_EXEC) != 0) {
67 sysErrorBelch("unable to protect memory");
68 }
69 }
70 else {
71 oc->symbol_extras = NULL;
72 return 0;
73 }
74 }
75 else if( count > 0 ) {
76 if (RTS_LINKER_USE_MMAP) {
77 n = roundUpToPage(oc->fileSize);
78
79 oc->symbol_extras = m32_alloc(sizeof(SymbolExtra) * count, 8);
80 if (oc->symbol_extras == NULL) return 0;
81 }
82 else {
83 // round up to the nearest 4
84 int aligned = (oc->fileSize + 3) & ~3;
85 int misalignment = oc->misalignment;
86
87 oc->image -= misalignment;
88 oc->image = stgReallocBytes( oc->image,
89 misalignment +
90 aligned + sizeof (SymbolExtra) * count,
91 "ocAllocateSymbolExtras" );
92 oc->image += misalignment;
93
94 oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
95 }
96 }
97
98 if (oc->symbol_extras != NULL) {
99 memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
100 }
101
102 oc->first_symbol_extra = first;
103 oc->n_symbol_extras = count;
104
105 return 1;
106 }
107
108
109 #if !defined(arm_HOST_ARCH)
110 SymbolExtra* makeSymbolExtra( ObjectCode const* oc,
111 unsigned long symbolNumber,
112 unsigned long target )
113 {
114 SymbolExtra *extra;
115
116 ASSERT( symbolNumber >= oc->first_symbol_extra
117 && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras);
118
119 extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra];
120
121 #if defined(powerpc_HOST_ARCH)
122 // lis r12, hi16(target)
123 extra->jumpIsland.lis_r12 = 0x3d80;
124 extra->jumpIsland.hi_addr = target >> 16;
125
126 // ori r12, r12, lo16(target)
127 extra->jumpIsland.ori_r12_r12 = 0x618c;
128 extra->jumpIsland.lo_addr = target & 0xffff;
129
130 // mtctr r12
131 extra->jumpIsland.mtctr_r12 = 0x7d8903a6;
132
133 // bctr
134 extra->jumpIsland.bctr = 0x4e800420;
135 #endif /* powerpc_HOST_ARCH */
136 #if defined(x86_64_HOST_ARCH)
137 // jmp *-14(%rip)
138 static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
139 extra->addr = target;
140 memcpy(extra->jumpIsland, jmp, 6);
141 #endif /* x86_64_HOST_ARCH */
142
143 return extra;
144 }
145 #endif /* !arm_HOST_ARCH */
146 #endif /* !x86_64_HOST_ARCH) || !mingw32_HOST_OS */
147 #endif // NEED_SYMBOL_EXTRAS