Allocate bss section within proper range of other sections
[ghc.git] / rts / linker / MachO.c
1 #include "Rts.h"
2
3 #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
4
5 #if defined(ios_HOST_OS)
6 #if !RTS_LINKER_USE_MMAP
7 #error "ios must use mmap and mprotect!"
8 #endif
9 /* for roundUpToPage */
10 #include "sm/OSMem.h"
11 #endif
12
13 #include "RtsUtils.h"
14 #include "GetEnv.h"
15 #include "LinkerInternals.h"
16 #include "linker/MachO.h"
17 #include "linker/CacheFlush.h"
18 #include "linker/SymbolExtras.h"
19
20 #include <string.h>
21 #include <regex.h>
22 #include <mach/machine.h>
23 #include <mach-o/fat.h>
24 #include <mach-o/loader.h>
25 #include <mach-o/nlist.h>
26 #include <mach-o/reloc.h>
27
28 #if defined(HAVE_SYS_MMAN_H) && RTS_LINKER_USE_MMAP
29 # include <sys/mman.h>
30 #endif
31
32 #if defined(powerpc_HOST_ARCH)
33 # include <mach-o/ppc/reloc.h>
34 #endif
35
36 #if defined(x86_64_HOST_ARCH)
37 # include <mach-o/x86_64/reloc.h>
38 #endif
39
40 #if defined(aarch64_HOST_ARCH)
41 # include <mach-o/arm64/reloc.h>
42 #endif
43
44 /*
45 Support for MachO linking on Darwin/MacOS X
46 by Wolfgang Thaller (wolfgang.thaller@gmx.net)
47
48 I hereby formally apologize for the hackish nature of this code.
49 Things that need to be done:
50 *) implement ocVerifyImage_MachO
51 *) add still more sanity checks.
52 */
53 #if defined(aarch64_HOST_ARCH)
54 /* aarch64 linker by moritz angermann <moritz@lichtzwerge.de> */
55
56 /* often times we need to extend some value of certain number of bits
57 * int an int64_t for e.g. relative offsets.
58 */
59 int64_t signExtend(uint64_t val, uint8_t bits);
60 /* Helper functions to check some instruction properties */
61 bool isVectorPp(uint32_t *p);
62 bool isLoadStore(uint32_t *p);
63
64 /* aarch64 relocations may contain an addend alreay in the position
65 * where we want to write the address offset to. Thus decoding as well
66 * as encoding is needed.
67 */
68 bool fitsBits(size_t bits, int64_t value);
69 int64_t decodeAddend(ObjectCode * oc, Section * section,
70 MachORelocationInfo * ri);
71 void encodeAddend(ObjectCode * oc, Section * section,
72 MachORelocationInfo * ri, int64_t addend);
73
74 /* finding and making stubs. We don't need to care about the symbol they
75 * represent. As long as two stubs point to the same address, they are identical
76 */
77 bool findStub(Section * section, void ** addr);
78 bool makeStub(Section * section, void ** addr);
79 void freeStubs(Section * section);
80
81 /* Global Offset Table logic */
82 bool isGotLoad(MachORelocationInfo * ri);
83 bool needGotSlot(MachONList * symbol);
84 bool makeGot(ObjectCode * oc);
85 void freeGot(ObjectCode * oc);
86 #endif /* aarch64_HOST_ARCH */
87
88 #if defined(ios_HOST_OS)
89 /* on iOS we need to ensure we only have r+w or r+x pages hence we need to mmap
90 * pages r+w and r+x mprotect them later on.
91 */
92 bool ocMprotect_MachO( ObjectCode *oc );
93 #endif /* ios_HOST_OS */
94
95 /*
96 * Initialize some common data in the object code so we don't have to
97 * continuously look up the addresses.
98 */
99 void
100 ocInit_MachO(ObjectCode * oc)
101 {
102 ocDeinit_MachO(oc);
103
104 oc->info = (struct ObjectCodeFormatInfo*)stgCallocBytes(
105 1, sizeof *oc->info,
106 "ocInit_MachO(ObjectCodeFormatInfo)");
107 oc->info->header = (MachOHeader *) oc->image;
108 oc->info->symCmd = NULL;
109 oc->info->segCmd = NULL;
110 oc->info->dsymCmd = NULL;
111
112 MachOLoadCommand *lc = (MachOLoadCommand*)(oc->image + sizeof(MachOHeader));
113 for(size_t i = 0; i < oc->info->header->ncmds; i++) {
114 if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) {
115 oc->info->segCmd = (MachOSegmentCommand*) lc;
116 }
117 else if (lc->cmd == LC_SYMTAB) {
118 oc->info->symCmd = (MachOSymtabCommand*) lc;
119 }
120 else if (lc->cmd == LC_DYSYMTAB) {
121 oc->info->dsymCmd = (MachODsymtabCommand*) lc;
122 }
123 lc = (MachOLoadCommand *) ( ((char*)lc) + lc->cmdsize );
124 }
125 if (NULL == oc->info->segCmd) {
126 barf("ocGetNames_MachO: no segment load command");
127 }
128
129 oc->info->macho_sections = (MachOSection*) (oc->info->segCmd+1);
130 oc->n_sections = oc->info->segCmd->nsects;
131
132 oc->info->nlist = oc->info->symCmd == NULL
133 ? NULL
134 : (MachONList *)(oc->image + oc->info->symCmd->symoff);
135 oc->info->names = oc->info->symCmd == NULL
136 ? NULL
137 : (oc->image + oc->info->symCmd->stroff);
138
139 /* If we have symbols, allocate and fill the macho_symbols
140 * This will make relocation easier.
141 */
142 oc->info->n_macho_symbols = 0;
143 oc->info->macho_symbols = NULL;
144
145 if(NULL != oc->info->nlist) {
146 oc->info->n_macho_symbols = oc->info->symCmd->nsyms;
147 oc->info->macho_symbols = (MachOSymbol*)stgCallocBytes(
148 oc->info->symCmd->nsyms,
149 sizeof(MachOSymbol),
150 "ocInit_MachO(MachOSymbol)");
151 for(uint32_t i = 0; i < oc->info->symCmd->nsyms; i++) {
152 oc->info->macho_symbols[i].name = oc->info->names
153 + oc->info->nlist[i].n_un.n_strx;
154 oc->info->macho_symbols[i].nlist = &oc->info->nlist[i];
155 /* we don't have an address for this symbol yet; this will be
156 * populated during ocGetNames_MachO. hence addr = NULL
157 */
158 oc->info->macho_symbols[i].addr = NULL;
159 }
160 }
161 }
162
163 void
164 ocDeinit_MachO(ObjectCode * oc) {
165 if (oc->info != NULL) {
166 if(oc->info->n_macho_symbols > 0) {
167 stgFree(oc->info->macho_symbols);
168 }
169 #if defined(aarch64_HOST_ARCH)
170 freeGot(oc);
171 for(int i = 0; i < oc->n_sections; i++) {
172 freeStubs(&oc->sections[i]);
173 }
174 #endif
175 stgFree(oc->info);
176 oc->info = NULL;
177 }
178 }
179
180 static int
181 resolveImports(
182 ObjectCode* oc,
183 MachOSection *sect, // ptr to lazy or non-lazy symbol pointer section
184 unsigned long *indirectSyms);
185
186 #if NEED_SYMBOL_EXTRAS
187 #if defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
188
189 int
190 ocAllocateExtras_MachO(ObjectCode* oc)
191 {
192 IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: start\n"));
193
194 if (NULL != oc->info->symCmd) {
195 IF_DEBUG(linker,
196 debugBelch("ocAllocateExtras_MachO: allocate %d symbols\n",
197 oc->info->symCmd->nsyms));
198 IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: done\n"));
199 return ocAllocateExtras(oc, oc->info->symCmd->nsyms, 0, 0);
200 }
201
202 IF_DEBUG(linker,
203 debugBelch("ocAllocateExtras_MachO: allocated no symbols\n"));
204 IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: done\n"));
205 return ocAllocateExtras(oc, 0, 0, 0);
206 }
207
208 #else
209 #error Unknown MachO architecture
210 #endif /* HOST_ARCH */
211 #endif /* NEED_SYMBOL_EXTRAS */
212
213 int
214 ocVerifyImage_MachO(ObjectCode * oc)
215 {
216 char *image = (char*) oc->image;
217 MachOHeader *header = (MachOHeader*) image;
218
219 IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: start\n"));
220
221 #if defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
222 if(header->magic != MH_MAGIC_64) {
223 errorBelch("Could not load image %s: bad magic!\n"
224 " Expected %08x (64bit), got %08x%s\n",
225 oc->fileName, MH_MAGIC_64, header->magic,
226 header->magic == MH_MAGIC ? " (32bit)." : ".");
227 return 0;
228 }
229 #else
230 if(header->magic != MH_MAGIC) {
231 errorBelch("Could not load image %s: bad magic!\n"
232 " Expected %08x (32bit), got %08x%s\n",
233 oc->fileName, MH_MAGIC, header->magic,
234 header->magic == MH_MAGIC_64 ? " (64bit)." : ".");
235 return 0;
236 }
237 #endif
238
239 // FIXME: do some more verifying here
240 IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: done\n"));
241 return 1;
242 }
243
244 static int
245 resolveImports(
246 ObjectCode* oc,
247 MachOSection *sect, // ptr to lazy or non-lazy symbol pointer section
248 unsigned long *indirectSyms)
249 {
250 size_t itemSize = 4;
251
252 IF_DEBUG(linker, debugBelch("resolveImports: start\n"));
253
254 #if defined(i386_HOST_ARCH)
255 int isJumpTable = 0;
256
257 if (strcmp(sect->sectname,"__jump_table") == 0) {
258 isJumpTable = 1;
259 itemSize = 5;
260 ASSERT(sect->reserved2 == itemSize);
261 }
262
263 #endif
264
265 for(unsigned i = 0; i * itemSize < sect->size; i++)
266 {
267 // according to otool, reserved1 contains the first index into the
268 // indirect symbol table
269 unsigned long indirectSymbolIndex = indirectSyms[sect->reserved1+i];
270 MachOSymbol *symbol = &oc->info->macho_symbols[indirectSymbolIndex];
271 SymbolAddr* addr = NULL;
272
273 IF_DEBUG(linker, debugBelch("resolveImports: resolving %s\n", symbol->name));
274
275 if ((symbol->nlist->n_type & N_TYPE) == N_UNDF
276 && (symbol->nlist->n_type & N_EXT) && (symbol->nlist->n_value != 0)) {
277 addr = (SymbolAddr*) (symbol->nlist->n_value);
278 IF_DEBUG(linker, debugBelch("resolveImports: undefined external %s has value %p\n", symbol->name, addr));
279 } else {
280 addr = lookupSymbol_(symbol->name);
281 IF_DEBUG(linker, debugBelch("resolveImports: looking up %s, %p\n", symbol->name, addr));
282 }
283
284 if (addr == NULL)
285 {
286 errorBelch("\nlookupSymbol failed in resolveImports\n"
287 "%s: unknown symbol `%s'", oc->fileName, symbol->name);
288 return 0;
289 }
290 ASSERT(addr);
291
292 #if defined(i386_HOST_ARCH)
293 if (isJumpTable) {
294 checkProddableBlock(oc,oc->image + sect->offset + i*itemSize, 5);
295
296 *(oc->image + sect->offset + i * itemSize) = 0xe9; // jmp opcode
297 *(unsigned*)(oc->image + sect->offset + i*itemSize + 1)
298 = (SymbolAddr*)addr - (oc->image + sect->offset + i*itemSize + 5);
299 }
300 else
301 #endif
302 {
303 checkProddableBlock(oc,
304 ((void**)(oc->image + sect->offset)) + i,
305 sizeof(void *));
306 ((void**)(oc->image + sect->offset))[i] = addr;
307 }
308 }
309
310 IF_DEBUG(linker, debugBelch("resolveImports: done\n"));
311 return 1;
312 }
313
314 #if defined(aarch64_HOST_ARCH)
315 /* aarch64 linker by moritz angermann <moritz@lichtzwerge.de> */
316
317 int64_t
318 signExtend(uint64_t val, uint8_t bits) {
319 return (int64_t)(val << (64-bits)) >> (64-bits);
320 }
321
322 bool
323 isVectorOp(uint32_t *p) {
324 return (*p & 0x04800000) == 0x04800000;
325 }
326
327 bool
328 isLoadStore(uint32_t *p) {
329 return (*p & 0x3B000000) == 0x39000000;
330 }
331
332 int64_t
333 decodeAddend(ObjectCode * oc, Section * section, MachORelocationInfo * ri) {
334
335 /* the instruction. It is 32bit wide */
336 uint32_t * p = (uint32_t*)((uint8_t*)section->start + ri->r_address);
337
338 checkProddableBlock(oc, (void*)p, 1 << ri->r_length);
339
340 switch(ri->r_type) {
341 case ARM64_RELOC_UNSIGNED:
342 case ARM64_RELOC_SUBTRACTOR: {
343 switch (ri->r_length) {
344 case 0: return signExtend(*(uint8_t*)p, 8 * (1 << ri->r_length));
345 case 1: return signExtend(*(uint16_t*)p, 8 * (1 << ri->r_length));
346 case 2: return signExtend(*(uint32_t*)p, 8 * (1 << ri->r_length));
347 case 3: return signExtend(*(uint64_t*)p, 8 * (1 << ri->r_length));
348 default:
349 barf("Unsupported r_length (%d) for SUBTRACTOR relocation",
350 ri->r_length);
351 }
352 }
353 case ARM64_RELOC_BRANCH26:
354 /* take the lower 26 bits and shift them by 2. The last two are
355 * implicilty 0 (as the instructions must be aligned!) and sign
356 * extend to 64 bits.
357 */
358 return signExtend( (*p & 0x03FFFFFF) << 2, 28 );
359 case ARM64_RELOC_PAGE21:
360 case ARM64_RELOC_GOT_LOAD_PAGE21:
361 /* take the instruction bits masked with 0x6 (0110), and push them
362 * down. into the last two bits, and mask in the
363 *
364 * the 21 bits are encoded as follows in the instruction
365 *
366 * -**- ---* **** **** **** **** ***-- ----
367 * ^^
368 * ''-- these are the low two bits.
369 */
370 return signExtend( (*p & 0x60000000) >> 29
371 | ((*p & 0x01FFFFE0) >> 3) << 12, 33);
372 case ARM64_RELOC_PAGEOFF12:
373 case ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
374 /* the 12 bits for the page offset are encoded from bit 11 onwards
375 *
376 * ---- ---- --** **** **** **-- ---- ----
377 */
378 int64_t a = (*p & 0x003FFC00) >> 10;
379 int shift = 0;
380 if (isLoadStore(p)) {
381 shift = (*p >> 30) & 0x3;
382 if(0 == shift && isVectorOp(p)) {
383 shift = 4;
384 }
385 }
386 return a << shift;
387 }
388 }
389 barf("unsupported relocation type: %d\n", ri->r_type);
390 }
391
392 inline bool
393 fitsBits(size_t bits, int64_t value) {
394 if(bits == 64) return true;
395 if(bits > 64) barf("fits_bits with %d bits and an 64bit integer!", bits);
396 return 0 == (value >> bits) // All bits off: 0
397 || -1 == (value >> bits); // All bits on: -1
398 }
399
400 void
401 encodeAddend(ObjectCode * oc, Section * section,
402 MachORelocationInfo * ri, int64_t addend) {
403 uint32_t * p = (uint32_t*)((uint8_t*)section->start + ri->r_address);
404
405 checkProddableBlock(oc, (void*)p, 1 << ri->r_length);
406
407 switch (ri->r_type) {
408 case ARM64_RELOC_UNSIGNED:
409 case ARM64_RELOC_SUBTRACTOR: {
410 if(!fitsBits(8 << ri->r_length, addend))
411 barf("Relocation out of range for UNSIGNED/SUBTRACTOR");
412 switch (ri->r_length) {
413 case 0: *(uint8_t*)p = (uint8_t)addend; break;
414 case 1: *(uint16_t*)p = (uint16_t)addend; break;
415 case 2: *(uint32_t*)p = (uint32_t)addend; break;
416 case 3: *(uint64_t*)p = (uint64_t)addend; break;
417 default:
418 barf("Unsupported r_length (%d) for SUBTRACTOR relocation",
419 ri->r_length);
420 }
421 return;
422 }
423 case ARM64_RELOC_BRANCH26: {
424 /* We can only store 26 bits in the instruction, due to alignment we
425 * do not need the last two bits of the value. If the value >> 2
426 * still exceeds 26bits, we won't be able to reach it.
427 */
428 if(!fitsBits(26, addend >> 2))
429 barf("Relocation target for BRACH26 out of range.");
430 *p = (*p & 0xFC000000) | ((uint32_t)(addend >> 2) & 0x03FFFFFF);
431 return;
432 }
433 case ARM64_RELOC_PAGE21:
434 case ARM64_RELOC_GOT_LOAD_PAGE21: {
435 /* We store 21bits, in bits 6 to 24, and bits 30 and 31.
436 * The encoded value describes a multiple of 4k pages, and together
437 * with the PAGEOFF12 relocation allows to address a relative range
438 * of +-4GB.
439 */
440 if(!fitsBits(21, addend >> 12))
441 barf("Relocation target for PAGE21 out of range.");
442 *p = (*p & 0x9F00001F) | (uint32_t)((addend << 17) & 0x60000000)
443 | (uint32_t)((addend >> 9) & 0x00FFFFE0);
444 return;
445 }
446 case ARM64_RELOC_PAGEOFF12:
447 case ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
448 /* Store an offset into a page (4k). Depending on the instruction
449 * the bits are stored at slightly different positions.
450 */
451 if(!fitsBits(12, addend))
452 barf("Relocation target for PAGEOFF12 out or range.");
453
454 int shift = 0;
455 if(isLoadStore(p)) {
456 shift = (*p >> 30) & 0x3;
457 if(0 == shift && isVectorOp(p)) {
458 shift = 4;
459 }
460 }
461 *p = (*p & 0xFFC003FF)
462 | ((uint32_t)(addend >> shift << 10) & 0x003FFC00);
463 return;
464 }
465 }
466 barf("unsupported relocation type: %d\n", ri->r_type);
467 }
468
469 bool
470 isGotLoad(struct relocation_info * ri) {
471 return ri->r_type == ARM64_RELOC_GOT_LOAD_PAGE21
472 || ri->r_type == ARM64_RELOC_GOT_LOAD_PAGEOFF12;
473 }
474
475 /* This is very similar to makeSymbolExtra
476 * However, as we load sections into different
477 * pages, that may be further appart than
478 * branching allows, we'll use some extra
479 * space at the end of each section allocated
480 * for stubs.
481 */
482 bool
483 findStub(Section * section, void ** addr) {
484
485 for(Stub * s = section->info->stubs; s != NULL; s = s->next) {
486 if(s->target == *addr) {
487 *addr = s->addr;
488 return EXIT_SUCCESS;
489 }
490 }
491 return EXIT_FAILURE;
492 }
493
494 bool
495 makeStub(Section * section, void ** addr) {
496
497 Stub * s = stgCallocBytes(1, sizeof(Stub), "makeStub(Stub)");
498 s->target = *addr;
499 s->addr = (uint8_t*)section->info->stub_offset
500 + ((8+8)*section->info->nstubs) + 8;
501 s->next = NULL;
502
503 /* target address */
504 *(uint64_t*)((uint8_t*)s->addr - 8) = (uint64_t)s->target;
505 /* ldr x16, - (8 bytes) */
506 *(uint32_t*)(s->addr) = (uint32_t)0x58ffffd0;
507 /* br x16 */
508 *(uint32_t*)((uint8_t*)s->addr + 4) = (uint32_t)0xd61f0200;
509
510 if(section->info->nstubs == 0) {
511 /* no stubs yet, let's just create this one */
512 section->info->stubs = s;
513 } else {
514 Stub * tail = section->info->stubs;
515 while(tail->next != NULL) tail = tail->next;
516 tail->next = s;
517 }
518 section->info->nstubs += 1;
519 *addr = s->addr;
520 return EXIT_SUCCESS;
521 }
522 void
523 freeStubs(Section * section) {
524 if(section->info->nstubs == 0)
525 return;
526 Stub * last = section->info->stubs;
527 while(last->next != NULL) {
528 Stub * t = last;
529 last = last->next;
530 stgFree(t);
531 }
532 section->info->stubs = NULL;
533 section->info->nstubs = 0;
534 }
535
536 /*
537 * Check if we need a global offset table slot for a
538 * given symbol
539 */
540 bool
541 needGotSlot(MachONList * symbol) {
542 return (symbol->n_type & N_EXT) /* is an external symbol */
543 && (N_UNDF == (symbol->n_type & N_TYPE) /* and is undefined */
544 || NO_SECT != symbol->n_sect); /* or is defined in a
545 * different section */
546 }
547
548 bool
549 makeGot(ObjectCode * oc) {
550 size_t got_slots = 0;
551
552 for(size_t i=0; i < oc->info->n_macho_symbols; i++)
553 if(needGotSlot(oc->info->macho_symbols[i].nlist))
554 got_slots += 1;
555
556 if(got_slots > 0) {
557 oc->info->got_size = got_slots * sizeof(void*);
558 oc->info->got_start = mmap(NULL, oc->info->got_size,
559 PROT_READ | PROT_WRITE,
560 MAP_ANON | MAP_PRIVATE,
561 -1, 0);
562 if( oc->info->got_start == MAP_FAILED ) {
563 barf("MAP_FAILED. errno=%d", errno );
564 return EXIT_FAILURE;
565 }
566 /* update got_addr */
567 size_t slot = 0;
568 for(size_t i=0; i < oc->info->n_macho_symbols; i++)
569 if(needGotSlot(oc->info->macho_symbols[i].nlist))
570 oc->info->macho_symbols[i].got_addr
571 = ((uint8_t*)oc->info->got_start)
572 + (slot++ * sizeof(void *));
573 }
574 return EXIT_SUCCESS;
575 }
576
577 void
578 freeGot(ObjectCode * oc) {
579 munmap(oc->info->got_start, oc->info->got_size);
580 oc->info->got_start = NULL;
581 oc->info->got_size = 0;
582 }
583
584 static int
585 relocateSectionAarch64(ObjectCode * oc, Section * section)
586 {
587 if(section->size == 0)
588 return 1;
589 /* at this point, we have:
590 *
591 * - loaded the sections (potentially into non-contiguous memory),
592 * (in ocGetNames_MachO)
593 * - registered exported sybmols
594 * (in ocGetNames_MachO)
595 * - and fixed the nlist[i].n_value for common storage symbols (N_UNDF,
596 * N_EXT and n_value != 0) so that they point into the common storage.
597 * (in ocGetNames_MachO)
598 * - All oc->symbols however should now point at the right place.
599 */
600
601 /* we need to care about the explicit addend */
602 int64_t explicit_addend = 0;
603 size_t nreloc = section->info->macho_section->nreloc;
604
605 for(size_t i = 0; i < nreloc; i++) {
606 MachORelocationInfo * ri = &section->info->relocation_info[i];
607 switch (ri->r_type) {
608 case ARM64_RELOC_UNSIGNED: {
609 MachOSymbol* symbol = &oc->info->macho_symbols[ri->r_symbolnum];
610 int64_t addend = decodeAddend(oc, section, ri);
611 uint64_t value = 0;
612 if(symbol->nlist->n_type & N_EXT) {
613 /* external symbols should be able to be
614 * looked up via the lookupSymbol_ function.
615 * Either through the global symbol hashmap
616 * or asking the system, if not found
617 * in the symbol hashmap
618 */
619 value = (uint64_t)lookupSymbol_((char*)symbol->name);
620 if(!value)
621 barf("Could not lookup symbol: %s!", symbol->name);
622 } else {
623 value = (uint64_t)symbol->addr; // address of the symbol.
624 }
625 encodeAddend(oc, section, ri, value + addend);
626 break;
627 }
628 case ARM64_RELOC_SUBTRACTOR:
629 {
630 MachOSymbol* symbol = &oc->info->macho_symbols[ri->r_symbolnum];
631 // subtractor and unsigned are called in tandem:
632 // first pc <- pc - symbol address (SUBTRACTOR)
633 // second pc <- pc + symbol address (UNSIGNED)
634 // to achieve pc <- pc + target - base.
635 //
636 // the current implementation uses absolute addresses,
637 // which is simpler than trying to do this section
638 // relative, but could more easily lead to overflow.
639 //
640 if(!(i+1 < nreloc)
641 || !(section->info->relocation_info[i+1].r_type
642 == ARM64_RELOC_UNSIGNED))
643 barf("SUBTRACTOR relocation *must* be followed by UNSIGNED relocation.");
644
645 int64_t addend = decodeAddend(oc, section, ri);
646 int64_t value = (uint64_t)symbol->addr;
647 encodeAddend(oc, section, ri, addend - value);
648 break;
649 }
650 case ARM64_RELOC_BRANCH26: {
651 MachOSymbol* symbol = &oc->info->macho_symbols[ri->r_symbolnum];
652
653 // pre-existing addend
654 int64_t addend = decodeAddend(oc, section, ri);
655 // address of the branch (b/bl) instruction.
656 uint64_t pc = (uint64_t)section->start + ri->r_address;
657 uint64_t value = 0;
658 if(symbol->nlist->n_type & N_EXT) {
659 value = (uint64_t)lookupSymbol_((char*)symbol->name);
660 if(!value)
661 barf("Could not lookup symbol: %s!", symbol->name);
662 } else {
663 value = (uint64_t)symbol->addr; // address of the symbol.
664 }
665 if((value - pc + addend) >> (2 + 26)) {
666 /* we need a stub */
667 /* check if we already have that stub */
668 if(findStub(section, (void**)&value)) {
669 /* did not find it. Crete a new stub. */
670 if(makeStub(section, (void**)&value)) {
671 barf("could not find or make stub");
672 }
673 }
674 }
675 encodeAddend(oc, section, ri, value - pc + addend);
676 break;
677 }
678 case ARM64_RELOC_PAGE21:
679 case ARM64_RELOC_GOT_LOAD_PAGE21: {
680 MachOSymbol* symbol = &oc->info->macho_symbols[ri->r_symbolnum];
681 int64_t addend = decodeAddend(oc, section, ri);
682 if(!(explicit_addend == 0 || addend == 0))
683 barf("explicit_addend and addend can't be set at the same time.");
684 uint64_t pc = (uint64_t)section->start + ri->r_address;
685 uint64_t value = (uint64_t)(isGotLoad(ri) ? symbol->got_addr : symbol->addr);
686 encodeAddend(oc, section, ri, ((value + addend + explicit_addend) & (-4096)) - (pc & (-4096)));
687
688 // reset, just in case.
689 explicit_addend = 0;
690 break;
691 }
692 case ARM64_RELOC_PAGEOFF12:
693 case ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
694 MachOSymbol* symbol = &oc->info->macho_symbols[ri->r_symbolnum];
695 int64_t addend = decodeAddend(oc, section, ri);
696 if(!(explicit_addend == 0 || addend == 0))
697 barf("explicit_addend and addend can't be set at the same time.");
698 uint64_t value = (uint64_t)(isGotLoad(ri) ? symbol->got_addr : symbol->addr);
699 encodeAddend(oc, section, ri, 0xFFF & (value + addend + explicit_addend));
700
701 // reset, just in case.
702 explicit_addend = 0;
703 break;
704 }
705 case ARM64_RELOC_ADDEND: {
706 explicit_addend = signExtend(ri->r_symbolnum, 24);
707 if(!(i+1 < nreloc)
708 || !(section->info->relocation_info[i+1].r_type == ARM64_RELOC_PAGE21
709 || section->info->relocation_info[i+1].r_type == ARM64_RELOC_PAGEOFF12))
710 barf("ADDEND relocation *must* be followed by PAGE or PAGEOFF relocation");
711 break;
712 }
713 default: {
714 barf("Relocation of type: %d not (yet) supported!\n", ri->r_type);
715 }
716 }
717 }
718 return 1;
719 }
720
721 #else /* non aarch64_HOST_ARCH branch -- aarch64 doesn't use relocateAddress */
722
723 /*
724 * Try to find the final loaded address for some addres.
725 * Look through all sections, locating the section that
726 * contains the address and compute the absolue address.
727 */
728 static unsigned long
729 relocateAddress(
730 ObjectCode* oc,
731 int nSections,
732 MachOSection* sections,
733 unsigned long address)
734 {
735 int i;
736 IF_DEBUG(linker, debugBelch("relocateAddress: start\n"));
737 for (i = 0; i < nSections; i++)
738 {
739 IF_DEBUG(linker, debugBelch(" relocating address in section %d\n", i));
740 if (sections[i].addr <= address
741 && address < sections[i].addr + sections[i].size)
742 {
743 return (unsigned long)oc->image
744 + sections[i].offset + address - sections[i].addr;
745 }
746 }
747 barf("Invalid Mach-O file:"
748 "Address out of bounds while relocating object file");
749 return 0;
750 }
751
752 #endif /* aarch64_HOST_ARCH */
753
754 #if !defined(aarch64_HOST_ARCH)
755 static int
756 relocateSection(
757 ObjectCode* oc,
758 char *image,
759 MachOSymtabCommand *symLC, MachONList *nlist,
760 int nSections, MachOSection* sections, MachOSection *sect)
761 {
762 MachORelocationInfo *relocs;
763 int i, n;
764
765 IF_DEBUG(linker, debugBelch("relocateSection: start\n"));
766
767 if(!strcmp(sect->sectname,"__la_symbol_ptr"))
768 return 1;
769 else if(!strcmp(sect->sectname,"__nl_symbol_ptr"))
770 return 1;
771 else if(!strcmp(sect->sectname,"__la_sym_ptr2"))
772 return 1;
773 else if(!strcmp(sect->sectname,"__la_sym_ptr3"))
774 return 1;
775
776 n = sect->nreloc;
777 IF_DEBUG(linker, debugBelch("relocateSection: number of relocations: %d\n", n));
778
779 relocs = (MachORelocationInfo*) (image + sect->reloff);
780
781 for(i = 0; i < n; i++)
782 {
783 #if defined(x86_64_HOST_ARCH)
784 MachORelocationInfo *reloc = &relocs[i];
785
786 char *thingPtr = image + sect->offset + reloc->r_address;
787 uint64_t thing;
788 /* We shouldn't need to initialise this, but gcc on OS X 64 bit
789 complains that it may be used uninitialized if we don't */
790 uint64_t value = 0;
791 uint64_t baseValue;
792 int type = reloc->r_type;
793
794 IF_DEBUG(linker, debugBelch("relocateSection: relocation %d\n", i));
795 IF_DEBUG(linker, debugBelch(" : type = %d\n", reloc->r_type));
796 IF_DEBUG(linker, debugBelch(" : address = %d\n", reloc->r_address));
797 IF_DEBUG(linker, debugBelch(" : symbolnum = %u\n", reloc->r_symbolnum));
798 IF_DEBUG(linker, debugBelch(" : pcrel = %d\n", reloc->r_pcrel));
799 IF_DEBUG(linker, debugBelch(" : length = %d\n", reloc->r_length));
800 IF_DEBUG(linker, debugBelch(" : extern = %d\n", reloc->r_extern));
801 IF_DEBUG(linker, debugBelch(" : type = %d\n", reloc->r_type));
802
803 switch(reloc->r_length)
804 {
805 case 0:
806 checkProddableBlock(oc,thingPtr,1);
807 thing = *(uint8_t*)thingPtr;
808 baseValue = (uint64_t)thingPtr + 1;
809 break;
810 case 1:
811 checkProddableBlock(oc,thingPtr,2);
812 thing = *(uint16_t*)thingPtr;
813 baseValue = (uint64_t)thingPtr + 2;
814 break;
815 case 2:
816 checkProddableBlock(oc,thingPtr,4);
817 thing = *(uint32_t*)thingPtr;
818 baseValue = (uint64_t)thingPtr + 4;
819 break;
820 case 3:
821 checkProddableBlock(oc,thingPtr,8);
822 thing = *(uint64_t*)thingPtr;
823 baseValue = (uint64_t)thingPtr + 8;
824 break;
825 default:
826 barf("Unknown size.");
827 }
828
829 IF_DEBUG(linker,
830 debugBelch("relocateSection: length = %d, thing = %" PRId64 ", baseValue = %p\n",
831 reloc->r_length, thing, (char *)baseValue));
832
833 if (type == X86_64_RELOC_GOT
834 || type == X86_64_RELOC_GOT_LOAD)
835 {
836 MachONList *symbol = &nlist[reloc->r_symbolnum];
837 SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
838 SymbolAddr* addr = NULL;
839
840 IF_DEBUG(linker, debugBelch("relocateSection: making jump island for %s, extern = %d, X86_64_RELOC_GOT\n", nm, reloc->r_extern));
841
842 ASSERT(reloc->r_extern);
843 if (reloc->r_extern == 0) {
844 errorBelch("\nrelocateSection: global offset table relocation for symbol with r_extern == 0\n");
845 }
846
847 if (symbol->n_type & N_EXT) {
848 // The external bit is set, meaning the symbol is exported,
849 // and therefore can be looked up in this object module's
850 // symtab, or it is undefined, meaning dlsym must be used
851 // to resolve it.
852
853 addr = lookupSymbol_(nm);
854 IF_DEBUG(linker, debugBelch("relocateSection: looked up %s, "
855 "external X86_64_RELOC_GOT or X86_64_RELOC_GOT_LOAD\n", nm));
856 IF_DEBUG(linker, debugBelch(" : addr = %p\n", addr));
857
858 if (addr == NULL) {
859 errorBelch("\nlookupSymbol failed in relocateSection (RELOC_GOT)\n"
860 "%s: unknown symbol `%s'", oc->fileName, nm);
861 return 0;
862 }
863 } else {
864 IF_DEBUG(linker, debugBelch("relocateSection: %s is not an exported symbol\n", nm));
865
866 // The symbol is not exported, or defined in another
867 // module, so it must be in the current object module,
868 // at the location given by the section index and
869 // symbol address (symbol->n_value)
870
871 if ((symbol->n_type & N_TYPE) == N_SECT) {
872 addr = (void *)relocateAddress(oc, nSections, sections, symbol->n_value);
873 IF_DEBUG(linker, debugBelch("relocateSection: calculated relocation %p of "
874 "non-external X86_64_RELOC_GOT or X86_64_RELOC_GOT_LOAD\n",
875 (void *)symbol->n_value));
876 IF_DEBUG(linker, debugBelch(" : addr = %p\n", addr));
877 } else {
878 errorBelch("\nrelocateSection: %s is not exported,"
879 " and should be defined in a section, but isn't!\n", nm);
880 }
881 }
882
883 value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, (unsigned long)addr)->addr;
884
885 type = X86_64_RELOC_SIGNED;
886 }
887 else if (reloc->r_extern)
888 {
889 MachONList *symbol = &nlist[reloc->r_symbolnum];
890 SymbolName* nm = image + symLC->stroff + symbol->n_un.n_strx;
891 SymbolAddr* addr = NULL;
892
893 IF_DEBUG(linker, debugBelch("relocateSection: looking up external symbol %s\n", nm));
894 IF_DEBUG(linker, debugBelch(" : type = %d\n", symbol->n_type));
895 IF_DEBUG(linker, debugBelch(" : sect = %d\n", symbol->n_sect));
896 IF_DEBUG(linker, debugBelch(" : desc = %d\n", symbol->n_desc));
897 IF_DEBUG(linker, debugBelch(" : value = %p\n", (void *)symbol->n_value));
898
899 if ((symbol->n_type & N_TYPE) == N_SECT) {
900 value = relocateAddress(oc, nSections, sections,
901 symbol->n_value);
902 IF_DEBUG(linker, debugBelch("relocateSection, defined external symbol %s, relocated address %p\n", nm, (void *)value));
903 }
904 else {
905 addr = lookupSymbol_(nm);
906 if (addr == NULL)
907 {
908 errorBelch("\nlookupSymbol failed in relocateSection (relocate external)\n"
909 "%s: unknown symbol `%s'", oc->fileName, nm);
910 return 0;
911 }
912
913 value = (uint64_t) addr;
914 IF_DEBUG(linker, debugBelch("relocateSection: external symbol %s, address %p\n", nm, (void *)value));
915 }
916 }
917 else
918 {
919 // If the relocation is not through the global offset table
920 // or external, then set the value to the baseValue. This
921 // will leave displacements into the __const section
922 // unchanged (as they ought to be).
923
924 value = baseValue;
925 }
926
927 IF_DEBUG(linker, debugBelch("relocateSection: value = %p\n", (void *)value));
928
929 if (type == X86_64_RELOC_BRANCH)
930 {
931 if((int32_t)(value - baseValue) != (int64_t)(value - baseValue))
932 {
933 ASSERT(reloc->r_extern);
934 value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, value)
935 -> jumpIsland;
936 }
937 ASSERT((int32_t)(value - baseValue) == (int64_t)(value - baseValue));
938 type = X86_64_RELOC_SIGNED;
939 }
940
941 switch(type)
942 {
943 case X86_64_RELOC_UNSIGNED:
944 ASSERT(!reloc->r_pcrel);
945 thing += value;
946 break;
947 case X86_64_RELOC_SIGNED:
948 case X86_64_RELOC_SIGNED_1:
949 case X86_64_RELOC_SIGNED_2:
950 case X86_64_RELOC_SIGNED_4:
951 ASSERT(reloc->r_pcrel);
952 thing += value - baseValue;
953 break;
954 case X86_64_RELOC_SUBTRACTOR:
955 ASSERT(!reloc->r_pcrel);
956 thing -= value;
957 break;
958 default:
959 barf("unknown relocation");
960 }
961
962 switch(reloc->r_length)
963 {
964 case 0:
965 *(uint8_t*)thingPtr = thing;
966 break;
967 case 1:
968 *(uint16_t*)thingPtr = thing;
969 break;
970 case 2:
971 *(uint32_t*)thingPtr = thing;
972 break;
973 case 3:
974 *(uint64_t*)thingPtr = thing;
975 break;
976 }
977 #else /* x86_64_HOST_ARCH */
978 if(relocs[i].r_address & R_SCATTERED)
979 {
980 MachOScatteredRelocationInfo *scat =
981 (MachOScatteredRelocationInfo*) &relocs[i];
982
983 if(!scat->r_pcrel)
984 {
985 if(scat->r_length == 2)
986 {
987 unsigned long word = 0;
988 unsigned long* wordPtr = (unsigned long*) (image + sect->offset + scat->r_address);
989
990 /* In this check we assume that sizeof(unsigned long) = 2 * sizeof(unsigned short)
991 on powerpc_HOST_ARCH */
992 checkProddableBlock(oc,wordPtr,sizeof(unsigned long));
993
994 // Note on relocation types:
995 // i386 uses the GENERIC_RELOC_* types,
996 // while ppc uses special PPC_RELOC_* types.
997 // *_RELOC_VANILLA and *_RELOC_PAIR have the same value
998 // in both cases, all others are different.
999 // Therefore, we use GENERIC_RELOC_VANILLA
1000 // and GENERIC_RELOC_PAIR instead of the PPC variants,
1001 // and use #ifdefs for the other types.
1002
1003 // Step 1: Figure out what the relocated value should be
1004 if (scat->r_type == GENERIC_RELOC_VANILLA) {
1005 word = *wordPtr
1006 + (unsigned long) relocateAddress(oc,
1007 nSections,
1008 sections,
1009 scat->r_value)
1010 - scat->r_value;
1011 }
1012 else if(scat->r_type == GENERIC_RELOC_SECTDIFF
1013 || scat->r_type == GENERIC_RELOC_LOCAL_SECTDIFF)
1014 {
1015 MachOScatteredRelocationInfo *pair =
1016 (MachOScatteredRelocationInfo*) &relocs[i+1];
1017
1018 if (!pair->r_scattered || pair->r_type != GENERIC_RELOC_PAIR) {
1019 barf("Invalid Mach-O file: "
1020 "RELOC_*_SECTDIFF not followed by RELOC_PAIR");
1021 }
1022
1023 word = (unsigned long)
1024 (relocateAddress(oc, nSections, sections, scat->r_value)
1025 - relocateAddress(oc, nSections, sections, pair->r_value));
1026 i++;
1027 }
1028 else {
1029 barf ("Don't know how to handle this Mach-O "
1030 "scattered relocation entry: "
1031 "object file %s; entry type %ld; "
1032 "address %#lx\n",
1033 OC_INFORMATIVE_FILENAME(oc),
1034 scat->r_type,
1035 scat->r_address);
1036 return 0;
1037 }
1038
1039 if(scat->r_type == GENERIC_RELOC_VANILLA
1040 || scat->r_type == GENERIC_RELOC_SECTDIFF
1041 || scat->r_type == GENERIC_RELOC_LOCAL_SECTDIFF)
1042 {
1043 *wordPtr = word;
1044 }
1045 }
1046 else
1047 {
1048 barf("Can't handle Mach-O scattered relocation entry "
1049 "with this r_length tag: "
1050 "object file %s; entry type %ld; "
1051 "r_length tag %ld; address %#lx\n",
1052 OC_INFORMATIVE_FILENAME(oc),
1053 scat->r_type,
1054 scat->r_length,
1055 scat->r_address);
1056 return 0;
1057 }
1058 }
1059 else /* scat->r_pcrel */
1060 {
1061 barf("Don't know how to handle *PC-relative* Mach-O "
1062 "scattered relocation entry: "
1063 "object file %s; entry type %ld; address %#lx\n",
1064 OC_INFORMATIVE_FILENAME(oc),
1065 scat->r_type,
1066 scat->r_address);
1067 return 0;
1068 }
1069
1070 }
1071 else /* !(relocs[i].r_address & R_SCATTERED) */
1072 {
1073 MachORelocationInfo *reloc = &relocs[i];
1074 if (reloc->r_pcrel && !reloc->r_extern) {
1075 IF_DEBUG(linker, debugBelch("relocateSection: pc relative but not external, skipping\n"));
1076 continue;
1077 }
1078
1079 if (reloc->r_length == 2) {
1080 unsigned long word = 0;
1081 unsigned long* wordPtr = (unsigned long*) (image + sect->offset + reloc->r_address);
1082
1083 checkProddableBlock(oc,wordPtr, sizeof(unsigned long));
1084
1085 if (reloc->r_type == GENERIC_RELOC_VANILLA) {
1086 word = *wordPtr;
1087 }
1088 else {
1089 barf("Can't handle this Mach-O relocation entry "
1090 "(not scattered): "
1091 "object file %s; entry type %ld; address %#lx\n",
1092 OC_INFORMATIVE_FILENAME(oc),
1093 reloc->r_type,
1094 reloc->r_address);
1095 return 0;
1096 }
1097
1098 if (!reloc->r_extern) {
1099 long delta = sections[reloc->r_symbolnum-1].offset
1100 - sections[reloc->r_symbolnum-1].addr
1101 + ((long) image);
1102
1103 word += delta;
1104 }
1105 else {
1106 MachONList *symbol = &nlist[reloc->r_symbolnum];
1107 char *nm = image + symLC->stroff + symbol->n_un.n_strx;
1108 void *symbolAddress = lookupSymbol_(nm);
1109
1110 if (!symbolAddress) {
1111 errorBelch("\nunknown symbol `%s'", nm);
1112 return 0;
1113 }
1114
1115 if (reloc->r_pcrel) {
1116 word += (unsigned long) symbolAddress
1117 - (((long)image) + sect->offset - sect->addr);
1118 }
1119 else {
1120 word += (unsigned long) symbolAddress;
1121 }
1122 }
1123
1124 if (reloc->r_type == GENERIC_RELOC_VANILLA) {
1125 *wordPtr = word;
1126 continue;
1127 }
1128 }
1129 else
1130 {
1131 barf("Can't handle Mach-O relocation entry (not scattered) "
1132 "with this r_length tag: "
1133 "object file %s; entry type %ld; "
1134 "r_length tag %ld; address %#lx\n",
1135 OC_INFORMATIVE_FILENAME(oc),
1136 reloc->r_type,
1137 reloc->r_length,
1138 reloc->r_address);
1139 return 0;
1140 }
1141 }
1142 #endif /* x86_64_HOST_ARCH */
1143 }
1144
1145 IF_DEBUG(linker, debugBelch("relocateSection: done\n"));
1146 return 1;
1147 }
1148 #endif /* aarch64_HOST_ARCH */
1149
1150 /* Note [mmap r+w+x]
1151 * ~~~~~~~~~~~~~~~~~
1152 *
1153 * iOS does not permit to mmap r+w+x, hence wo only mmap r+w, and later change
1154 * to r+x via mprotect. While this could would be nice to have for all hosts
1155 * and not just for iOS, it entail that the rest of the linker code supports
1156 * that, this includes:
1157 *
1158 * - mmap and mprotect need to be available.
1159 * - text and data sections need to be mapped into different pages. Ideally
1160 * the text and data sections would be aggregated, to prevent using a single
1161 * page for every section, however tiny.
1162 * - the relocation code for each object file format / architecture, needs to
1163 * respect the (now) non-contiguousness of the sections.
1164 * - with sections being mapped potentially far apart from each other, it must
1165 * be made sure that the pages are reachable within the architectures
1166 * addressability for relative or absolute access.
1167 */
1168
1169 int
1170 ocGetNames_MachO(ObjectCode* oc)
1171 {
1172 unsigned curSymbol = 0;
1173
1174 unsigned long commonSize = 0;
1175 SymbolAddr* commonStorage = NULL;
1176 unsigned long commonCounter;
1177
1178 IF_DEBUG(linker,debugBelch("ocGetNames_MachO: start\n"));
1179
1180 Section *secArray;
1181 secArray = (Section*)stgCallocBytes(
1182 sizeof(Section),
1183 oc->info->segCmd->nsects,
1184 "ocGetNames_MachO(sections)");
1185
1186 oc->sections = secArray;
1187
1188 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: will load %d sections\n",
1189 oc->n_sections));
1190 for(int i=0; i < oc->n_sections; i++)
1191 {
1192 MachOSection * section = &oc->info->macho_sections[i];
1193
1194 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: section %d\n", i));
1195
1196 if (section->size == 0) {
1197 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: found a zero length section, skipping\n"));
1198 continue;
1199 }
1200
1201 // XXX, use SECTION_TYPE attributes, instead of relying on the name?
1202
1203 SectionKind kind = SECTIONKIND_OTHER;
1204
1205 if (0==strcmp(section->sectname,"__text")) {
1206 kind = SECTIONKIND_CODE_OR_RODATA;
1207 }
1208 else if (0==strcmp(section->sectname,"__const") ||
1209 0==strcmp(section->sectname,"__data") ||
1210 0==strcmp(section->sectname,"__bss") ||
1211 0==strcmp(section->sectname,"__common") ||
1212 0==strcmp(section->sectname,"__mod_init_func")) {
1213 kind = SECTIONKIND_RWDATA;
1214 }
1215
1216 switch(section->flags & SECTION_TYPE) {
1217 #if defined(ios_HOST_OS)
1218 case S_ZEROFILL:
1219 case S_GB_ZEROFILL: {
1220 // See Note [mmap r+w+x]
1221 void * mem = mmap(NULL, section->size,
1222 PROT_READ | PROT_WRITE,
1223 MAP_ANON | MAP_PRIVATE,
1224 -1, 0);
1225 if( mem == MAP_FAILED ) {
1226 barf("failed to mmap allocate memory for zerofill section %d of size %d. errno = %d", i, section->size, errno);
1227 }
1228 addSection(&secArray[i], kind, SECTION_MMAP, mem, section->size,
1229 0, mem, roundUpToPage(section->size));
1230 addProddableBlock(oc, mem, (int)section->size);
1231
1232 secArray[i].info->nstubs = 0;
1233 secArray[i].info->stub_offset = NULL;
1234 secArray[i].info->stub_size = 0;
1235 secArray[i].info->stubs = NULL;
1236
1237 secArray[i].info->macho_section = section;
1238 secArray[i].info->relocation_info
1239 = (MachORelocationInfo*)(oc->image + section->reloff);
1240 break;
1241 }
1242 default: {
1243 // The secion should have a non-zero offset. As the offset is
1244 // relativ to the image, and must be somewhere after the header.
1245 if(section->offset == 0) barf("section with zero offset!");
1246 /* on iOS, we must allocate the code in r+x sections and
1247 * the data in r+w sections, as the system does not allow
1248 * for r+w+x, we must allocate each section in a new page
1249 * range.
1250 *
1251 * copy the sections's memory to some page-aligned place via
1252 * mmap and memcpy. This will later allow us to selectively
1253 * use mprotect on pages with data (r+w) and pages text (r+x).
1254 * We initially start with r+w, so that we can modify the
1255 * pages during relocations, prior to setting it r+x.
1256 */
1257
1258 /* We also need space for stubs. As pages can be assigned
1259 * randomly in the addressable space, we need to keep the
1260 * stubs close to the section. The strategy we are going
1261 * to use is to allocate them right after the section. And
1262 * we are going to be generous and allocare a stub slot
1263 * for each relocation to keep it simple.
1264 */
1265 size_t n_ext_sec_sym = section->nreloc; /* number of relocations
1266 * for this section. Should
1267 * be a good upper bound
1268 */
1269 size_t stub_space = /* eight bytes for the 64 bit address,
1270 * and another eight bytes for the two
1271 * instructions (ldr, br) for each relocation.
1272 */ 16 * n_ext_sec_sym;
1273 // See Note [mmap r+w+x]
1274 void * mem = mmap(NULL, section->size+stub_space,
1275 PROT_READ | PROT_WRITE,
1276 MAP_ANON | MAP_PRIVATE,
1277 -1, 0);
1278 if( mem == MAP_FAILED ) {
1279 barf("failed to mmap allocate memory to load section %d. errno = %d", i, errno );
1280 }
1281 memcpy( mem, oc->image + section->offset, section->size);
1282
1283 addSection(&secArray[i], kind, SECTION_MMAP,
1284 mem, section->size,
1285 0, mem, roundUpToPage(section->size+stub_space));
1286 addProddableBlock(oc, mem, (int)section->size);
1287
1288 secArray[i].info->nstubs = 0;
1289 secArray[i].info->stub_offset = ((uint8_t*)mem) + section->size;
1290 secArray[i].info->stub_size = stub_space;
1291 secArray[i].info->stubs = NULL;
1292
1293 secArray[i].info->macho_section = section;
1294 secArray[i].info->relocation_info
1295 = (MachORelocationInfo*)(oc->image + section->reloff);
1296 break;
1297 }
1298
1299 #else /* any other host */
1300 case S_ZEROFILL:
1301 case S_GB_ZEROFILL: {
1302 char * zeroFillArea;
1303 if (RTS_LINKER_USE_MMAP) {
1304 zeroFillArea = mmapForLinker(section->size, MAP_ANONYMOUS,
1305 -1, 0);
1306 if (zeroFillArea == NULL) return 0;
1307 memset(zeroFillArea, 0, section->size);
1308 }
1309 else {
1310 zeroFillArea = stgCallocBytes(1,section->size,
1311 "ocGetNames_MachO(common symbols)");
1312 }
1313 section->offset = zeroFillArea - oc->image;
1314
1315 addSection(&secArray[i], kind, SECTION_NOMEM,
1316 (void *)(oc->image + section->offset),
1317 section->size,
1318 0, 0, 0);
1319
1320 addProddableBlock(oc,
1321 (void *) (oc->image + section->offset),
1322 section->size);
1323
1324 secArray[i].info->nstubs = 0;
1325 secArray[i].info->stub_offset = NULL;
1326 secArray[i].info->stub_size = 0;
1327 secArray[i].info->stubs = NULL;
1328
1329 secArray[i].info->macho_section = section;
1330 secArray[i].info->relocation_info
1331 = (MachORelocationInfo*)(oc->image + section->reloff);
1332 FALLTHROUGH;
1333 }
1334 default: {
1335 // just set the pointer to the loaded image.
1336 addSection(&secArray[i], kind, SECTION_NOMEM,
1337 (void *)(oc->image + section->offset),
1338 section->size,
1339 0, 0, 0);
1340
1341 addProddableBlock(oc,
1342 (void *) (oc->image + section->offset),
1343 section->size);
1344
1345 secArray[i].info->nstubs = 0;
1346 secArray[i].info->stub_offset = NULL;
1347 secArray[i].info->stub_size = 0;
1348 secArray[i].info->stubs = NULL;
1349
1350 secArray[i].info->macho_section = section;
1351 secArray[i].info->relocation_info
1352 = (MachORelocationInfo*)(oc->image + section->reloff);
1353 }
1354 #endif
1355 }
1356
1357 }
1358 /* now, as all sections have been loaded, we can resolve the absolute
1359 * address of symbols defined in those sections.
1360 */
1361 for(size_t i=0; i < oc->info->n_macho_symbols; i++) {
1362 MachOSymbol * s = &oc->info->macho_symbols[i];
1363 if( N_SECT == (s->nlist->n_type & N_TYPE) ) {
1364 /* section is given */
1365 uint8_t n = s->nlist->n_sect - 1;
1366 if(0 == oc->info->macho_sections[n].size) {
1367 continue;
1368 }
1369 if(s->nlist->n_sect == NO_SECT)
1370 barf("Symbol with N_SECT type, but no section.");
1371
1372 /* addr <- offset in memory where this section resides
1373 * - address rel. to the image where this section is stored
1374 * + symbol offset in the image
1375 */
1376 s->addr = (uint8_t*)oc->sections[n].start
1377 - oc->info->macho_sections[n].addr
1378 + s->nlist->n_value;
1379 if(NULL == s->addr)
1380 barf("Failed to compute address for symbol %s", s->name);
1381 }
1382 }
1383
1384 // count external symbols defined here
1385 oc->n_symbols = 0;
1386 if (oc->info->symCmd) {
1387 for (size_t i = 0; i < oc->info->n_macho_symbols; i++) {
1388 if (oc->info->nlist[i].n_type & N_STAB) {
1389 ;
1390 }
1391 else if(oc->info->nlist[i].n_type & N_EXT)
1392 {
1393 if((oc->info->nlist[i].n_type & N_TYPE) == N_UNDF
1394 && (oc->info->nlist[i].n_value != 0))
1395 {
1396 commonSize += oc->info->nlist[i].n_value;
1397 oc->n_symbols++;
1398 }
1399 else if((oc->info->nlist[i].n_type & N_TYPE) == N_SECT)
1400 oc->n_symbols++;
1401 }
1402 }
1403 }
1404 /* allocate space for the exported symbols
1405 * in the object code. This is used to track
1406 * which symbols will have to be removed when
1407 * this object code is unloaded
1408 */
1409 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: %d external symbols\n",
1410 oc->n_symbols));
1411 oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(Symbol_t),
1412 "ocGetNames_MachO(oc->symbols)");
1413
1414 if (oc->info->symCmd) {
1415 for (size_t i = 0; i < oc->info->n_macho_symbols; i++) {
1416 SymbolName* nm = oc->info->macho_symbols[i].name;
1417 if(oc->info->nlist[i].n_type & N_STAB)
1418 {
1419 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: Skip STAB: %s\n", nm));
1420 }
1421 else if((oc->info->nlist[i].n_type & N_TYPE) == N_SECT)
1422 {
1423 if(oc->info->nlist[i].n_type & N_EXT)
1424 {
1425 if ( (oc->info->nlist[i].n_desc & N_WEAK_DEF)
1426 && lookupSymbol_(nm)) {
1427 // weak definition, and we already have a definition
1428 IF_DEBUG(linker, debugBelch(" weak: %s\n", nm));
1429 }
1430 else
1431 {
1432 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting %s\n", nm));
1433 SymbolAddr* addr = oc->info->macho_symbols[i].addr;
1434
1435 ghciInsertSymbolTable( oc->fileName
1436 , symhash
1437 , nm
1438 , addr
1439 , HS_BOOL_FALSE
1440 , oc);
1441
1442 oc->symbols[curSymbol].name = nm;
1443 oc->symbols[curSymbol].addr = addr;
1444 curSymbol++;
1445 }
1446 }
1447 else
1448 {
1449 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: \t...not external, skipping %s\n", nm));
1450 }
1451 }
1452 else
1453 {
1454 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: \t...not defined in this section, skipping %s\n", nm));
1455 }
1456 }
1457 }
1458
1459 /* setup the common storage */
1460 commonStorage = stgCallocBytes(1,commonSize,"ocGetNames_MachO(common symbols)");
1461 commonCounter = (unsigned long)commonStorage;
1462
1463 if (oc->info->symCmd) {
1464 for (size_t i = 0; i < oc->info->n_macho_symbols; i++) {
1465 SymbolName* nm = oc->info->macho_symbols[i].name;
1466 MachONList *nlist = &oc->info->nlist[i];
1467 if((nlist->n_type & N_TYPE) == N_UNDF
1468 && (nlist->n_type & N_EXT)
1469 && (nlist->n_value != 0)) {
1470 unsigned long sz = nlist->n_value;
1471
1472 nlist->n_value = commonCounter;
1473
1474 /* also set the final address to the macho_symbol */
1475 oc->info->macho_symbols[i].addr = (void*)commonCounter;
1476
1477 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: inserting common symbol: %s\n", nm));
1478 ghciInsertSymbolTable(oc->fileName, symhash, nm,
1479 (void*)commonCounter, HS_BOOL_FALSE, oc);
1480 oc->symbols[curSymbol].name = nm;
1481 oc->symbols[curSymbol].addr = oc->info->macho_symbols[i].addr;
1482 curSymbol++;
1483
1484 commonCounter += sz;
1485 }
1486 }
1487 }
1488 #if defined(aarch64_HOST_ARCH)
1489 /* Setup the global offset table
1490 * This is for symbols that are external, and not defined here.
1491 * So that we can load their address indirectly.
1492 *
1493 * We will get GOT request for any symbol that is
1494 * - EXT and UNDF
1495 * - EXT and not in the same section.
1496 *
1497 * As sections are not necessarily contiguous and can live
1498 * anywhere in the addressable space. This obviously makes
1499 * sense. However it took me a while to figure this out.
1500 */
1501 makeGot(oc);
1502
1503 /* at this point, macho_symbols, should know the addresses for
1504 * all symbols defined by this object code.
1505 * - those that are defined in sections.
1506 * - those that are undefined, but have a value (common storage).
1507 */
1508 #endif
1509 IF_DEBUG(linker, debugBelch("ocGetNames_MachO: done\n"));
1510 return 1;
1511 }
1512
1513 #if defined(ios_HOST_OS)
1514 bool
1515 ocMprotect_MachO( ObjectCode *oc ) {
1516 for(int i=0; i < oc->n_sections; i++) {
1517 Section * section = &oc->sections[i];
1518 if(section->size == 0) continue;
1519 if( (section->info->macho_section->flags & SECTION_ATTRIBUTES_USR)
1520 == S_ATTR_PURE_INSTRUCTIONS) {
1521 if( 0 != mprotect(section->start,
1522 section->size + section->info->stub_size,
1523 PROT_READ | PROT_EXEC) ) {
1524 barf("mprotect failed! errno = %d", errno);
1525 return false;
1526 }
1527 }
1528 }
1529 return true;
1530 }
1531 #endif
1532
1533 int
1534 ocResolve_MachO(ObjectCode* oc)
1535 {
1536 IF_DEBUG(linker, debugBelch("ocResolve_MachO: start\n"));
1537
1538 if(NULL != oc->info->dsymCmd)
1539 {
1540 unsigned long *indirectSyms
1541 = (unsigned long*) (oc->image + oc->info->dsymCmd->indirectsymoff);
1542
1543 IF_DEBUG(linker, debugBelch("ocResolve_MachO: resolving dsymLC\n"));
1544 for (int i = 0; i < oc->n_sections; i++)
1545 {
1546 const char * sectionName = oc->info->macho_sections[i].sectname;
1547 if( !strcmp(sectionName,"__la_symbol_ptr")
1548 || !strcmp(sectionName,"__la_sym_ptr2")
1549 || !strcmp(sectionName,"__la_sym_ptr3"))
1550 {
1551 if(!resolveImports(oc,&oc->info->macho_sections[i],
1552 indirectSyms))
1553 return 0;
1554 }
1555 else if(!strcmp(sectionName,"__nl_symbol_ptr")
1556 || !strcmp(sectionName,"__pointers"))
1557 {
1558 if(!resolveImports(oc,&oc->info->macho_sections[i],
1559 indirectSyms))
1560 return 0;
1561 }
1562 else if(!strcmp(sectionName,"__jump_table"))
1563 {
1564 if(!resolveImports(oc,&oc->info->macho_sections[i],
1565 indirectSyms))
1566 return 0;
1567 }
1568 else
1569 {
1570 IF_DEBUG(linker, debugBelch("ocResolve_MachO: unknown section\n"));
1571 }
1572 }
1573 }
1574 #if defined(aarch64_HOST_ARCH)
1575 /* fill the GOT table */
1576 for(size_t i = 0; i < oc->info->n_macho_symbols; i++) {
1577 MachOSymbol * symbol = &oc->info->macho_symbols[i];
1578 if(needGotSlot(symbol->nlist)) {
1579 if(N_UNDF == (symbol->nlist->n_type & N_TYPE)) {
1580 /* an undefined symbol. So we need to ensure we
1581 * have the address.
1582 */
1583 if(NULL == symbol->addr) {
1584 symbol->addr = lookupSymbol_((char*)symbol->name);
1585 if(NULL == symbol->addr)
1586 barf("Failed to lookup symbol: %s", symbol->name);
1587 } else {
1588 // we already have the address.
1589 }
1590 } /* else it was defined in the same object,
1591 * just a different section. We should have
1592 * the address as well already
1593 */
1594 if(NULL == symbol->addr) {
1595 barf("Something went wrong!");
1596 }
1597 if(NULL == symbol->got_addr) {
1598 barf("Not good either!");
1599 }
1600 *(uint64_t*)symbol->got_addr = (uint64_t)symbol->addr;
1601 }
1602 }
1603 #endif
1604
1605 for(int i = 0; i < oc->n_sections; i++)
1606 {
1607 IF_DEBUG(linker, debugBelch("ocResolve_MachO: relocating section %d\n", i));
1608
1609 #if defined aarch64_HOST_ARCH
1610 if (!relocateSectionAarch64(oc, &oc->sections[i]))
1611 return 0;
1612 #else
1613 if (!relocateSection(oc,oc->image,oc->info->symCmd,oc->info->nlist,
1614 oc->info->segCmd->nsects,oc->info->macho_sections,
1615 &oc->info->macho_sections[i]))
1616 return 0;
1617 #endif
1618 }
1619 #if defined(ios_HOST_OS)
1620 if(!ocMprotect_MachO ( oc ))
1621 return 0;
1622 #endif
1623
1624 return 1;
1625 }
1626
1627 int
1628 ocRunInit_MachO ( ObjectCode *oc )
1629 {
1630 if (NULL == oc->info->segCmd) {
1631 barf("ocRunInit_MachO: no segment load command");
1632 }
1633
1634 int argc, envc;
1635 char **argv, **envv;
1636
1637 getProgArgv(&argc, &argv);
1638 getProgEnvv(&envc, &envv);
1639
1640 for (int i = 0; i < oc->n_sections; i++) {
1641 // ToDo: replace this with a proper check for the S_MOD_INIT_FUNC_POINTERS
1642 // flag. We should do this elsewhere in the Mach-O linker code
1643 // too. Note that the system linker will *refuse* to honor
1644 // sections which don't have this flag, so this could cause
1645 // weird behavior divergence (albeit reproducible).
1646 if (0 == strcmp(oc->info->macho_sections[i].sectname,
1647 "__mod_init_func")) {
1648
1649 void *init_startC = oc->sections[i].start;
1650 init_t *init = (init_t*)init_startC;
1651 init_t *init_end = (init_t*)((uint8_t*)init_startC
1652 + oc->sections[i].info->macho_section->size);
1653 for (; init < init_end; init++) {
1654 (*init)(argc, argv, envv);
1655 }
1656 }
1657 }
1658
1659 freeProgEnvv(envc, envv);
1660 return 1;
1661 }
1662
1663 /*
1664 * Figure out by how much to shift the entire Mach-O file in memory
1665 * when loading so that its single segment ends up 16-byte-aligned
1666 */
1667 int
1668 machoGetMisalignment( FILE * f )
1669 {
1670 MachOHeader header;
1671 int misalignment;
1672
1673 {
1674 size_t n = fread(&header, sizeof(header), 1, f);
1675 if (n != 1) {
1676 barf("machoGetMisalignment: can't read the Mach-O header");
1677 }
1678 }
1679 fseek(f, -sizeof(header), SEEK_CUR);
1680
1681 #if defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH)
1682 if(header.magic != MH_MAGIC_64) {
1683 barf("Bad magic. Expected: %08x, got: %08x.",
1684 MH_MAGIC_64, header.magic);
1685 }
1686 #else
1687 if(header.magic != MH_MAGIC) {
1688 barf("Bad magic. Expected: %08x, got: %08x.",
1689 MH_MAGIC, header.magic);
1690 }
1691 #endif
1692
1693 misalignment = (header.sizeofcmds + sizeof(header))
1694 & 0xF;
1695
1696 return misalignment ? (16 - misalignment) : 0;
1697 }
1698
1699 #endif /* darwin_HOST_OS, ios_HOST_OS */