github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/ld/ldmacho.c (about) 1 /* 2 Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c 3 http://code.swtch.com/plan9port/src/tip/src/libmach/ 4 5 Copyright © 2004 Russ Cox. 6 Portions Copyright © 2008-2010 Google Inc. 7 Portions Copyright © 2010 The Go Authors. 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 */ 27 28 #include "l.h" 29 #include "lib.h" 30 31 enum { 32 MACHO_FAKE_GOTPCREL = 100, // from macho.h 33 34 N_EXT = 0x01, 35 N_TYPE = 0x1e, 36 N_STAB = 0xe0, 37 }; 38 39 typedef struct MachoObj MachoObj; 40 typedef struct MachoCmd MachoCmd; 41 typedef struct MachoSeg MachoSeg; 42 typedef struct MachoSect MachoSect; 43 typedef struct MachoRel MachoRel; 44 typedef struct MachoSymtab MachoSymtab; 45 typedef struct MachoSym MachoSym; 46 typedef struct MachoDysymtab MachoDysymtab; 47 48 enum 49 { 50 MachoCpuVax = 1, 51 MachoCpu68000 = 6, 52 MachoCpu386 = 7, 53 MachoCpuAmd64 = 0x1000007, 54 MachoCpuMips = 8, 55 MachoCpu98000 = 10, 56 MachoCpuHppa = 11, 57 MachoCpuArm = 12, 58 MachoCpu88000 = 13, 59 MachoCpuSparc = 14, 60 MachoCpu860 = 15, 61 MachoCpuAlpha = 16, 62 MachoCpuPower = 18, 63 64 MachoCmdSegment = 1, 65 MachoCmdSymtab = 2, 66 MachoCmdSymseg = 3, 67 MachoCmdThread = 4, 68 MachoCmdDysymtab = 11, 69 MachoCmdSegment64 = 25, 70 71 MachoFileObject = 1, 72 MachoFileExecutable = 2, 73 MachoFileFvmlib = 3, 74 MachoFileCore = 4, 75 MachoFilePreload = 5, 76 }; 77 78 struct MachoSeg 79 { 80 char name[16+1]; 81 uint64 vmaddr; 82 uint64 vmsize; 83 uint32 fileoff; 84 uint32 filesz; 85 uint32 maxprot; 86 uint32 initprot; 87 uint32 nsect; 88 uint32 flags; 89 MachoSect *sect; 90 }; 91 92 struct MachoSect 93 { 94 char name[16+1]; 95 char segname[16+1]; 96 uint64 addr; 97 uint64 size; 98 uint32 off; 99 uint32 align; 100 uint32 reloff; 101 uint32 nreloc; 102 uint32 flags; 103 uint32 res1; 104 uint32 res2; 105 Sym *sym; 106 107 MachoRel *rel; 108 }; 109 110 struct MachoRel 111 { 112 uint32 addr; 113 uint32 symnum; 114 uint8 pcrel; 115 uint8 length; 116 uint8 extrn; 117 uint8 type; 118 uint8 scattered; 119 uint32 value; 120 }; 121 122 struct MachoSymtab 123 { 124 uint32 symoff; 125 uint32 nsym; 126 uint32 stroff; 127 uint32 strsize; 128 129 char *str; 130 MachoSym *sym; 131 }; 132 133 struct MachoSym 134 { 135 char *name; 136 uint8 type; 137 uint8 sectnum; 138 uint16 desc; 139 char kind; 140 uint64 value; 141 Sym *sym; 142 }; 143 144 struct MachoDysymtab 145 { 146 uint32 ilocalsym; 147 uint32 nlocalsym; 148 uint32 iextdefsym; 149 uint32 nextdefsym; 150 uint32 iundefsym; 151 uint32 nundefsym; 152 uint32 tocoff; 153 uint32 ntoc; 154 uint32 modtaboff; 155 uint32 nmodtab; 156 uint32 extrefsymoff; 157 uint32 nextrefsyms; 158 uint32 indirectsymoff; 159 uint32 nindirectsyms; 160 uint32 extreloff; 161 uint32 nextrel; 162 uint32 locreloff; 163 uint32 nlocrel; 164 uint32 *indir; 165 }; 166 167 struct MachoCmd 168 { 169 int type; 170 uint32 off; 171 uint32 size; 172 MachoSeg seg; 173 MachoSymtab sym; 174 MachoDysymtab dsym; 175 }; 176 177 struct MachoObj 178 { 179 Biobuf *f; 180 int64 base; // off in f where Mach-O begins 181 int64 len; // length of Mach-O 182 int is64; 183 char *name; 184 185 Endian *e; 186 uint cputype; 187 uint subcputype; 188 uint32 filetype; 189 uint32 flags; 190 MachoCmd *cmd; 191 uint ncmd; 192 }; 193 194 static int 195 unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz) 196 { 197 uint32 (*e4)(uchar*); 198 uint64 (*e8)(uchar*); 199 MachoSect *s; 200 int i; 201 202 e4 = m->e->e32; 203 e8 = m->e->e64; 204 205 c->type = type; 206 c->size = sz; 207 switch(type){ 208 default: 209 return -1; 210 case MachoCmdSegment: 211 if(sz < 56) 212 return -1; 213 strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); 214 c->seg.vmaddr = e4(p+24); 215 c->seg.vmsize = e4(p+28); 216 c->seg.fileoff = e4(p+32); 217 c->seg.filesz = e4(p+36); 218 c->seg.maxprot = e4(p+40); 219 c->seg.initprot = e4(p+44); 220 c->seg.nsect = e4(p+48); 221 c->seg.flags = e4(p+52); 222 c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); 223 if(sz < 56+c->seg.nsect*68) 224 return -1; 225 p += 56; 226 for(i=0; i<c->seg.nsect; i++) { 227 s = &c->seg.sect[i]; 228 strecpy(s->name, s->name+sizeof s->name, (char*)p+0); 229 strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); 230 s->addr = e4(p+32); 231 s->size = e4(p+36); 232 s->off = e4(p+40); 233 s->align = e4(p+44); 234 s->reloff = e4(p+48); 235 s->nreloc = e4(p+52); 236 s->flags = e4(p+56); 237 s->res1 = e4(p+60); 238 s->res2 = e4(p+64); 239 p += 68; 240 } 241 break; 242 case MachoCmdSegment64: 243 if(sz < 72) 244 return -1; 245 strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); 246 c->seg.vmaddr = e8(p+24); 247 c->seg.vmsize = e8(p+32); 248 c->seg.fileoff = e8(p+40); 249 c->seg.filesz = e8(p+48); 250 c->seg.maxprot = e4(p+56); 251 c->seg.initprot = e4(p+60); 252 c->seg.nsect = e4(p+64); 253 c->seg.flags = e4(p+68); 254 c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); 255 if(sz < 72+c->seg.nsect*80) 256 return -1; 257 p += 72; 258 for(i=0; i<c->seg.nsect; i++) { 259 s = &c->seg.sect[i]; 260 strecpy(s->name, s->name+sizeof s->name, (char*)p+0); 261 strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); 262 s->addr = e8(p+32); 263 s->size = e8(p+40); 264 s->off = e4(p+48); 265 s->align = e4(p+52); 266 s->reloff = e4(p+56); 267 s->nreloc = e4(p+60); 268 s->flags = e4(p+64); 269 s->res1 = e4(p+68); 270 s->res2 = e4(p+72); 271 // p+76 is reserved 272 p += 80; 273 } 274 break; 275 case MachoCmdSymtab: 276 if(sz < 24) 277 return -1; 278 c->sym.symoff = e4(p+8); 279 c->sym.nsym = e4(p+12); 280 c->sym.stroff = e4(p+16); 281 c->sym.strsize = e4(p+20); 282 break; 283 case MachoCmdDysymtab: 284 if(sz < 80) 285 return -1; 286 c->dsym.ilocalsym = e4(p+8); 287 c->dsym.nlocalsym = e4(p+12); 288 c->dsym.iextdefsym = e4(p+16); 289 c->dsym.nextdefsym = e4(p+20); 290 c->dsym.iundefsym = e4(p+24); 291 c->dsym.nundefsym = e4(p+28); 292 c->dsym.tocoff = e4(p+32); 293 c->dsym.ntoc = e4(p+36); 294 c->dsym.modtaboff = e4(p+40); 295 c->dsym.nmodtab = e4(p+44); 296 c->dsym.extrefsymoff = e4(p+48); 297 c->dsym.nextrefsyms = e4(p+52); 298 c->dsym.indirectsymoff = e4(p+56); 299 c->dsym.nindirectsyms = e4(p+60); 300 c->dsym.extreloff = e4(p+64); 301 c->dsym.nextrel = e4(p+68); 302 c->dsym.locreloff = e4(p+72); 303 c->dsym.nlocrel = e4(p+76); 304 break; 305 } 306 return 0; 307 } 308 309 static int 310 macholoadrel(MachoObj *m, MachoSect *sect) 311 { 312 MachoRel *rel, *r; 313 uchar *buf, *p; 314 int i, n; 315 uint32 v; 316 317 if(sect->rel != nil || sect->nreloc == 0) 318 return 0; 319 rel = mal(sect->nreloc * sizeof r[0]); 320 n = sect->nreloc * 8; 321 buf = mal(n); 322 if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n) 323 return -1; 324 for(i=0; i<sect->nreloc; i++) { 325 r = &rel[i]; 326 p = buf+i*8; 327 r->addr = m->e->e32(p); 328 329 // TODO(rsc): Wrong interpretation for big-endian bitfields? 330 if(r->addr & 0x80000000) { 331 // scatterbrained relocation 332 r->scattered = 1; 333 v = r->addr >> 24; 334 r->addr &= 0xFFFFFF; 335 r->type = v & 0xF; 336 v >>= 4; 337 r->length = 1<<(v&3); 338 v >>= 2; 339 r->pcrel = v & 1; 340 r->value = m->e->e32(p+4); 341 } else { 342 v = m->e->e32(p+4); 343 r->symnum = v & 0xFFFFFF; 344 v >>= 24; 345 r->pcrel = v&1; 346 v >>= 1; 347 r->length = 1<<(v&3); 348 v >>= 2; 349 r->extrn = v&1; 350 v >>= 1; 351 r->type = v; 352 } 353 } 354 sect->rel = rel; 355 return 0; 356 } 357 358 static int 359 macholoaddsym(MachoObj *m, MachoDysymtab *d) 360 { 361 uchar *p; 362 int i, n; 363 364 n = d->nindirectsyms; 365 366 p = mal(n*4); 367 if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4) 368 return -1; 369 370 d->indir = (uint32*)p; 371 for(i=0; i<n; i++) 372 d->indir[i] = m->e->e32(p+4*i); 373 return 0; 374 } 375 376 static int 377 macholoadsym(MachoObj *m, MachoSymtab *symtab) 378 { 379 char *strbuf; 380 uchar *symbuf, *p; 381 int i, n, symsize; 382 MachoSym *sym, *s; 383 uint32 v; 384 385 if(symtab->sym != nil) 386 return 0; 387 388 strbuf = mal(symtab->strsize); 389 if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize) 390 return -1; 391 392 symsize = 12; 393 if(m->is64) 394 symsize = 16; 395 n = symtab->nsym * symsize; 396 symbuf = mal(n); 397 if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n) 398 return -1; 399 sym = mal(symtab->nsym * sizeof sym[0]); 400 p = symbuf; 401 for(i=0; i<symtab->nsym; i++) { 402 s = &sym[i]; 403 v = m->e->e32(p); 404 if(v >= symtab->strsize) 405 return -1; 406 s->name = strbuf + v; 407 s->type = p[4]; 408 s->sectnum = p[5]; 409 s->desc = m->e->e16(p+6); 410 if(m->is64) 411 s->value = m->e->e64(p+8); 412 else 413 s->value = m->e->e32(p+8); 414 p += symsize; 415 } 416 symtab->str = strbuf; 417 symtab->sym = sym; 418 return 0; 419 } 420 421 void 422 ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) 423 { 424 int i, j, is64; 425 uint64 secaddr; 426 uchar hdr[7*4], *cmdp; 427 uchar tmp[4]; 428 uchar *dat; 429 ulong ncmd, cmdsz, ty, sz, off; 430 MachoObj *m; 431 Endian *e; 432 int64 base; 433 MachoSect *sect; 434 MachoRel *rel; 435 Sym *s, *s1, *outer; 436 MachoCmd *c; 437 MachoSymtab *symtab; 438 MachoDysymtab *dsymtab; 439 MachoSym *sym; 440 Reloc *r, *rp; 441 char *name; 442 443 version++; 444 base = Boffset(f); 445 if(Bread(f, hdr, sizeof hdr) != sizeof hdr) 446 goto bad; 447 448 if((be.e32(hdr)&~1) == 0xFEEDFACE){ 449 e = &be; 450 }else if((le.e32(hdr)&~1) == 0xFEEDFACE){ 451 e = ≤ 452 }else{ 453 werrstr("bad magic - not mach-o file"); 454 goto bad; 455 } 456 457 is64 = e->e32(hdr) == 0xFEEDFACF; 458 ncmd = e->e32(hdr+4*4); 459 cmdsz = e->e32(hdr+5*4); 460 if(ncmd > 0x10000 || cmdsz >= 0x01000000){ 461 werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz); 462 goto bad; 463 } 464 if(is64) 465 Bread(f, tmp, 4); // skip reserved word in header 466 467 m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz); 468 m->f = f; 469 m->e = e; 470 m->cputype = e->e32(hdr+1*4); 471 m->subcputype = e->e32(hdr+2*4); 472 m->filetype = e->e32(hdr+3*4); 473 m->ncmd = ncmd; 474 m->flags = e->e32(hdr+6*4); 475 m->is64 = is64; 476 m->base = base; 477 m->len = len; 478 m->name = pn; 479 480 switch(thechar) { 481 default: 482 diag("%s: mach-o %s unimplemented", pn, thestring); 483 return; 484 case '6': 485 if(e != &le || m->cputype != MachoCpuAmd64) { 486 diag("%s: mach-o object but not amd64", pn); 487 return; 488 } 489 break; 490 case '8': 491 if(e != &le || m->cputype != MachoCpu386) { 492 diag("%s: mach-o object but not 386", pn); 493 return; 494 } 495 break; 496 } 497 498 m->cmd = (MachoCmd*)(m+1); 499 off = sizeof hdr; 500 cmdp = (uchar*)(m->cmd+ncmd); 501 if(Bread(f, cmdp, cmdsz) != cmdsz){ 502 werrstr("reading cmds: %r"); 503 goto bad; 504 } 505 506 // read and parse load commands 507 c = nil; 508 symtab = nil; 509 dsymtab = nil; 510 for(i=0; i<ncmd; i++){ 511 ty = e->e32(cmdp); 512 sz = e->e32(cmdp+4); 513 m->cmd[i].off = off; 514 unpackcmd(cmdp, m, &m->cmd[i], ty, sz); 515 cmdp += sz; 516 off += sz; 517 if(ty == MachoCmdSymtab) { 518 if(symtab != nil) { 519 werrstr("multiple symbol tables"); 520 goto bad; 521 } 522 symtab = &m->cmd[i].sym; 523 macholoadsym(m, symtab); 524 } 525 if(ty == MachoCmdDysymtab) { 526 dsymtab = &m->cmd[i].dsym; 527 macholoaddsym(m, dsymtab); 528 } 529 if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) { 530 if(c != nil) { 531 werrstr("multiple load commands"); 532 goto bad; 533 } 534 c = &m->cmd[i]; 535 } 536 } 537 538 // load text and data segments into memory. 539 // they are not as small as the load commands, but we'll need 540 // the memory anyway for the symbol images, so we might 541 // as well use one large chunk. 542 if(c == nil) { 543 werrstr("no load command"); 544 goto bad; 545 } 546 if(symtab == nil) { 547 // our work is done here - no symbols means nothing can refer to this file 548 return; 549 } 550 551 if(c->seg.fileoff+c->seg.filesz >= len) { 552 werrstr("load segment out of range"); 553 goto bad; 554 } 555 556 dat = mal(c->seg.filesz); 557 if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) { 558 werrstr("cannot load object data: %r"); 559 goto bad; 560 } 561 562 for(i=0; i<c->seg.nsect; i++) { 563 sect = &c->seg.sect[i]; 564 if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0) 565 continue; 566 if(strcmp(sect->name, "__eh_frame") == 0) 567 continue; 568 name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name); 569 s = lookup(name, version); 570 if(s->type != 0) { 571 werrstr("duplicate %s/%s", sect->segname, sect->name); 572 goto bad; 573 } 574 free(name); 575 576 s->np = sect->size; 577 s->size = s->np; 578 if((sect->flags & 0xff) == 1) // S_ZEROFILL 579 s->p = mal(s->size); 580 else { 581 s->p = dat + sect->addr - c->seg.vmaddr; 582 } 583 584 if(strcmp(sect->segname, "__TEXT") == 0) { 585 if(strcmp(sect->name, "__text") == 0) 586 s->type = STEXT; 587 else 588 s->type = SRODATA; 589 } else { 590 if (strcmp(sect->name, "__bss") == 0) { 591 s->type = SBSS; 592 s->np = 0; 593 } else 594 s->type = SDATA; 595 } 596 sect->sym = s; 597 } 598 599 // enter sub-symbols into symbol table. 600 // have to guess sizes from next symbol. 601 for(i=0; i<symtab->nsym; i++) { 602 int v; 603 sym = &symtab->sym[i]; 604 if(sym->type&N_STAB) 605 continue; 606 // TODO: check sym->type against outer->type. 607 name = sym->name; 608 if(name[0] == '_' && name[1] != '\0') 609 name++; 610 v = 0; 611 if(!(sym->type&N_EXT)) 612 v = version; 613 s = lookup(name, v); 614 if(!(sym->type&N_EXT)) 615 s->dupok = 1; 616 sym->sym = s; 617 if(sym->sectnum == 0) // undefined 618 continue; 619 if(sym->sectnum > c->seg.nsect) { 620 werrstr("reference to invalid section %d", sym->sectnum); 621 goto bad; 622 } 623 sect = &c->seg.sect[sym->sectnum-1]; 624 outer = sect->sym; 625 if(outer == nil) { 626 werrstr("reference to invalid section %s/%s", sect->segname, sect->name); 627 continue; 628 } 629 if(s->outer != S) { 630 if(s->dupok) 631 continue; 632 diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); 633 errorexit(); 634 } 635 s->type = outer->type | SSUB; 636 s->sub = outer->sub; 637 outer->sub = s; 638 s->outer = outer; 639 s->value = sym->value - sect->addr; 640 if(!(s->cgoexport & CgoExportDynamic)) 641 s->dynimplib = nil; // satisfy dynimport 642 if(outer->type == STEXT) { 643 Prog *p; 644 645 if(s->text != P) 646 diag("%s sym#%d: duplicate definition of %s", pn, i, s->name); 647 // build a TEXT instruction with a unique pc 648 // just to make the rest of the linker happy. 649 // TODO: this is too 6l-specific ? 650 p = prg(); 651 p->as = ATEXT; 652 p->from.type = D_EXTERN; 653 p->from.sym = s; 654 p->textflag = 7; 655 p->to.type = D_CONST; 656 p->link = nil; 657 p->pc = pc++; 658 s->text = p; 659 } 660 sym->sym = s; 661 } 662 663 // Sort outer lists by address, adding to textp. 664 // This keeps textp in increasing address order. 665 for(i=0; i<c->seg.nsect; i++) { 666 sect = &c->seg.sect[i]; 667 if((s = sect->sym) == S) 668 continue; 669 if(s->sub) { 670 s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); 671 672 // assign sizes, now that we know symbols in sorted order. 673 for(s1 = s->sub; s1 != S; s1 = s1->sub) { 674 if(s1->sub) 675 s1->size = s1->sub->value - s1->value; 676 else 677 s1->size = s->value + s->size - s1->value; 678 } 679 } 680 if(s->type == STEXT) { 681 if(etextp) 682 etextp->next = s; 683 else 684 textp = s; 685 etextp = s; 686 for(s1 = s->sub; s1 != S; s1 = s1->sub) { 687 etextp->next = s1; 688 etextp = s1; 689 } 690 } 691 } 692 693 // load relocations 694 for(i=0; i<c->seg.nsect; i++) { 695 sect = &c->seg.sect[i]; 696 if((s = sect->sym) == S) 697 continue; 698 macholoadrel(m, sect); 699 if(sect->rel == nil) 700 continue; 701 r = mal(sect->nreloc*sizeof r[0]); 702 rp = r; 703 rel = sect->rel; 704 for(j=0; j<sect->nreloc; j++, rel++) { 705 if(rel->scattered) { 706 int k; 707 MachoSect *ks; 708 709 if(thechar != '8') { 710 // mach-o only uses scattered relocation on 32-bit platforms 711 diag("unexpected scattered relocation"); 712 continue; 713 } 714 715 // on 386, rewrite scattered 4/1 relocation and some 716 // scattered 2/1 relocation into the pseudo-pc-relative 717 // reference that it is. 718 // assume that the second in the pair is in this section 719 // and use that as the pc-relative base. 720 if(j+1 >= sect->nreloc) { 721 werrstr("unsupported scattered relocation %d", (int)rel->type); 722 goto bad; 723 } 724 if(!(rel+1)->scattered || (rel+1)->type != 1 || 725 (rel->type != 4 && rel->type != 2) || 726 (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) { 727 werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type); 728 goto bad; 729 } 730 731 rp->siz = rel->length; 732 rp->off = rel->addr; 733 734 // NOTE(rsc): I haven't worked out why (really when) 735 // we should ignore the addend on a 736 // scattered relocation, but it seems that the 737 // common case is we ignore it. 738 // It's likely that this is not strictly correct 739 // and that the math should look something 740 // like the non-scattered case below. 741 rp->add = 0; 742 743 // want to make it pc-relative aka relative to rp->off+4 744 // but the scatter asks for relative to off = (rel+1)->value - sect->addr. 745 // adjust rp->add accordingly. 746 rp->type = D_PCREL; 747 rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); 748 749 // now consider the desired symbol. 750 // find the section where it lives. 751 for(k=0; k<c->seg.nsect; k++) { 752 ks = &c->seg.sect[k]; 753 if(ks->addr <= rel->value && rel->value < ks->addr+ks->size) 754 goto foundk; 755 } 756 werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr); 757 goto bad; 758 foundk: 759 if(ks->sym != S) { 760 rp->sym = ks->sym; 761 rp->add += rel->value - ks->addr; 762 } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) { 763 // handle reference to __IMPORT/__pointers. 764 // how much worse can this get? 765 // why are we supporting 386 on the mac anyway? 766 rp->type = 512 + MACHO_FAKE_GOTPCREL; 767 // figure out which pointer this is a reference to. 768 k = ks->res1 + (rel->value - ks->addr) / 4; 769 // load indirect table for __pointers 770 // fetch symbol number 771 if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) { 772 werrstr("invalid scattered relocation: indirect symbol reference out of range"); 773 goto bad; 774 } 775 k = dsymtab->indir[k]; 776 if(k < 0 || k >= symtab->nsym) { 777 werrstr("invalid scattered relocation: symbol reference out of range"); 778 goto bad; 779 } 780 rp->sym = symtab->sym[k].sym; 781 } else { 782 werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name); 783 goto bad; 784 } 785 rp++; 786 // skip #1 of 2 rel; continue skips #2 of 2. 787 rel++; 788 j++; 789 continue; 790 } 791 792 rp->siz = rel->length; 793 rp->type = 512 + (rel->type<<1) + rel->pcrel; 794 rp->off = rel->addr; 795 796 // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). 797 if (thechar == '6' && rel->extrn == 0 && rel->type == 1) { 798 // Calculate the addend as the offset into the section. 799 // 800 // The rip-relative offset stored in the object file is encoded 801 // as follows: 802 // 803 // movsd 0x00000360(%rip),%xmm0 804 // 805 // To get the absolute address of the value this rip-relative address is pointing 806 // to, we must add the address of the next instruction to it. This is done by 807 // taking the address of the relocation and adding 4 to it (since the rip-relative 808 // offset can at most be 32 bits long). To calculate the offset into the section the 809 // relocation is referencing, we subtract the vaddr of the start of the referenced 810 // section found in the original object file. 811 // 812 // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] 813 secaddr = c->seg.sect[rel->symnum-1].addr; 814 rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr; 815 } else 816 rp->add = (int32)e->e32(s->p+rp->off); 817 818 // For i386 Mach-O PC-relative, the addend is written such that 819 // it *is* the PC being subtracted. Use that to make 820 // it match our version of PC-relative. 821 if(rel->pcrel && thechar == '8') 822 rp->add += rp->off+rp->siz; 823 if(!rel->extrn) { 824 if(rel->symnum < 1 || rel->symnum > c->seg.nsect) { 825 werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect); 826 goto bad; 827 } 828 rp->sym = c->seg.sect[rel->symnum-1].sym; 829 if(rp->sym == nil) { 830 werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name); 831 goto bad; 832 } 833 // References to symbols in other sections 834 // include that information in the addend. 835 // We only care about the delta from the 836 // section base. 837 if(thechar == '8') 838 rp->add -= c->seg.sect[rel->symnum-1].addr; 839 } else { 840 if(rel->symnum >= symtab->nsym) { 841 werrstr("invalid relocation: symbol reference out of range"); 842 goto bad; 843 } 844 rp->sym = symtab->sym[rel->symnum].sym; 845 } 846 rp++; 847 } 848 qsort(r, rp - r, sizeof r[0], rbyoff); 849 s->r = r; 850 s->nr = rp - r; 851 } 852 return; 853 854 bad: 855 diag("%s: malformed mach-o file: %r", pn); 856 }