Allocate bss section within proper range of other sections
[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 #if defined(OBJFORMAT_ELF)
23 # include "linker/Elf.h"
24 #elif defined(OBJFORMAT_MACHO)
25 # include "linker/MachO.h"
26 #endif
27
28 #include <string.h>
29 #if RTS_LINKER_USE_MMAP
30 #include <sys/mman.h>
31 #endif /* RTS_LINKER_USE_MMAP */
32
33 /*
34 ocAllocateExtras
35
36 Allocate additional space at the end of the object file image to make room
37 for jump islands (powerpc, x86_64, arm), GOT entries (x86_64) and
38 bss sections.
39
40 PowerPC relative branch instructions have a 24 bit displacement field.
41 As PPC code is always 4-byte-aligned, this yields a +-32MB range.
42 If a particular imported symbol is outside this range, we have to redirect
43 the jump to a short piece of new code that just loads the 32bit absolute
44 address and jumps there.
45 On x86_64, PC-relative jumps and PC-relative accesses to the GOT are limited
46 to 32 bits (+-2GB).
47
48 This function just allocates space for one SymbolExtra for every
49 undefined symbol in the object file. The code for the jump islands is
50 filled in by makeSymbolExtra below.
51 */
52
53 int ocAllocateExtras(ObjectCode* oc, int count, int first, int bssSize)
54 {
55 void* oldImage = oc->image;
56
57 if (count > 0 || bssSize > 0) {
58 if (!RTS_LINKER_USE_MMAP) {
59
60 // round up to the nearest 4
61 int aligned = (oc->fileSize + 3) & ~3;
62 int misalignment = oc->misalignment;
63
64 oc->image -= misalignment;
65 oc->image = stgReallocBytes( oc->image,
66 misalignment +
67 aligned + sizeof (SymbolExtra) * count,
68 "ocAllocateExtras" );
69 oc->image += misalignment;
70
71 oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
72 } else if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
73 /* Keep image, bssExtras and symbol_extras contiguous */
74 size_t n = roundUpToPage(oc->fileSize);
75 bssSize = roundUpToAlign(bssSize, 8);
76 size_t allocated_size = n + bssSize + (sizeof(SymbolExtra) * count);
77 void *new = mmapForLinker(allocated_size, MAP_ANONYMOUS, -1, 0);
78 if (new) {
79 memcpy(new, oc->image, oc->fileSize);
80 if (oc->imageMapped) {
81 munmap(oc->image, n);
82 }
83 oc->image = new;
84 oc->imageMapped = true;
85 oc->fileSize = allocated_size;
86 oc->symbol_extras = (SymbolExtra *) (oc->image + n + bssSize);
87 oc->bssBegin = oc->image + n;
88 oc->bssEnd = oc->image + n + bssSize;
89 }
90 else {
91 oc->symbol_extras = NULL;
92 return 0;
93 }
94 } else {
95 oc->symbol_extras = m32_alloc(sizeof(SymbolExtra) * count, 8);
96 if (oc->symbol_extras == NULL) return 0;
97 }
98 }
99
100 if (oc->symbol_extras != NULL) {
101 memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
102 }
103
104 // ObjectCodeFormatInfo contains computed addresses based on offset to
105 // image, if the address of image changes, we need to invalidate
106 // the ObjectCodeFormatInfo and recompute it.
107 if (oc->image != oldImage) {
108 #if defined(OBJFORMAT_MACHO)
109 ocInit_MachO( oc );
110 #endif
111 #if defined(OBJFORMAT_ELF)
112 ocInit_ELF( oc );
113 #endif
114 }
115
116 oc->first_symbol_extra = first;
117 oc->n_symbol_extras = count;
118
119 return 1;
120 }
121
122
123 #if !defined(arm_HOST_ARCH)
124 SymbolExtra* makeSymbolExtra( ObjectCode const* oc,
125 unsigned long symbolNumber,
126 unsigned long target )
127 {
128 SymbolExtra *extra;
129
130 ASSERT( symbolNumber >= oc->first_symbol_extra
131 && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras);
132
133 extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra];
134
135 #if defined(powerpc_HOST_ARCH)
136 // lis r12, hi16(target)
137 extra->jumpIsland.lis_r12 = 0x3d80;
138 extra->jumpIsland.hi_addr = target >> 16;
139
140 // ori r12, r12, lo16(target)
141 extra->jumpIsland.ori_r12_r12 = 0x618c;
142 extra->jumpIsland.lo_addr = target & 0xffff;
143
144 // mtctr r12
145 extra->jumpIsland.mtctr_r12 = 0x7d8903a6;
146
147 // bctr
148 extra->jumpIsland.bctr = 0x4e800420;
149 #endif /* powerpc_HOST_ARCH */
150 #if defined(x86_64_HOST_ARCH)
151 // jmp *-14(%rip)
152 static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
153 extra->addr = target;
154 memcpy(extra->jumpIsland, jmp, 6);
155 #endif /* x86_64_HOST_ARCH */
156
157 return extra;
158 }
159 #endif /* !arm_HOST_ARCH */
160 #endif /* !x86_64_HOST_ARCH) || !mingw32_HOST_OS */
161 #endif // NEED_SYMBOL_EXTRAS