github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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, *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 sym->sym = s; 615 if(sym->sectnum == 0) // undefined 616 continue; 617 if(sym->sectnum > c->seg.nsect) { 618 werrstr("reference to invalid section %d", sym->sectnum); 619 goto bad; 620 } 621 sect = &c->seg.sect[sym->sectnum-1]; 622 outer = sect->sym; 623 if(outer == nil) { 624 werrstr("reference to invalid section %s/%s", sect->segname, sect->name); 625 continue; 626 } 627 if(s->outer != S) { 628 if(s->dupok) 629 continue; 630 diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); 631 errorexit(); 632 } 633 s->type = outer->type | SSUB; 634 s->sub = outer->sub; 635 outer->sub = s; 636 s->outer = outer; 637 s->value = sym->value - sect->addr; 638 if(i+1 < symtab->nsym) 639 s->size = (sym+1)->value - sym->value; 640 else 641 s->size = sect->addr + sect->size - sym->value; 642 if(!(s->cgoexport & CgoExportDynamic)) 643 s->dynimplib = nil; // satisfy dynimport 644 if(outer->type == STEXT) { 645 Prog *p; 646 647 if(s->text != P) 648 diag("%s sym#%d: duplicate definition of %s", pn, i, s->name); 649 // build a TEXT instruction with a unique pc 650 // just to make the rest of the linker happy. 651 // TODO: this is too 6l-specific ? 652 p = prg(); 653 p->as = ATEXT; 654 p->from.type = D_EXTERN; 655 p->from.sym = s; 656 p->textflag = 7; 657 p->to.type = D_CONST; 658 p->link = nil; 659 p->pc = pc++; 660 s->text = p; 661 } 662 sym->sym = s; 663 } 664 665 // Sort outer lists by address, adding to textp. 666 // This keeps textp in increasing address order. 667 for(i=0; i<c->seg.nsect; i++) { 668 sect = &c->seg.sect[i]; 669 if((s = sect->sym) == S) 670 continue; 671 if(s->sub) 672 s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); 673 if(s->type == STEXT) { 674 if(etextp) 675 etextp->next = s; 676 else 677 textp = s; 678 etextp = s; 679 for(s = s->sub; s != S; s = s->sub) { 680 etextp->next = s; 681 etextp = s; 682 } 683 } 684 } 685 686 // load relocations 687 for(i=0; i<c->seg.nsect; i++) { 688 sect = &c->seg.sect[i]; 689 if((s = sect->sym) == S) 690 continue; 691 macholoadrel(m, sect); 692 if(sect->rel == nil) 693 continue; 694 r = mal(sect->nreloc*sizeof r[0]); 695 rp = r; 696 rel = sect->rel; 697 for(j=0; j<sect->nreloc; j++, rel++) { 698 if(rel->scattered) { 699 int k; 700 MachoSect *ks; 701 702 if(thechar != '8') { 703 // mach-o only uses scattered relocation on 32-bit platforms 704 diag("unexpected scattered relocation"); 705 continue; 706 } 707 708 // on 386, rewrite scattered 4/1 relocation and some 709 // scattered 2/1 relocation into the pseudo-pc-relative 710 // reference that it is. 711 // assume that the second in the pair is in this section 712 // and use that as the pc-relative base. 713 if(j+1 >= sect->nreloc) { 714 werrstr("unsupported scattered relocation %d", (int)rel->type); 715 goto bad; 716 } 717 if(!(rel+1)->scattered || (rel+1)->type != 1 || 718 (rel->type != 4 && rel->type != 2) || 719 (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) { 720 werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type); 721 goto bad; 722 } 723 724 rp->siz = rel->length; 725 rp->off = rel->addr; 726 727 // NOTE(rsc): I haven't worked out why (really when) 728 // we should ignore the addend on a 729 // scattered relocation, but it seems that the 730 // common case is we ignore it. 731 // It's likely that this is not strictly correct 732 // and that the math should look something 733 // like the non-scattered case below. 734 rp->add = 0; 735 736 // want to make it pc-relative aka relative to rp->off+4 737 // but the scatter asks for relative to off = (rel+1)->value - sect->addr. 738 // adjust rp->add accordingly. 739 rp->type = D_PCREL; 740 rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); 741 742 // now consider the desired symbol. 743 // find the section where it lives. 744 for(k=0; k<c->seg.nsect; k++) { 745 ks = &c->seg.sect[k]; 746 if(ks->addr <= rel->value && rel->value < ks->addr+ks->size) 747 goto foundk; 748 } 749 werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr); 750 goto bad; 751 foundk: 752 if(ks->sym != S) { 753 rp->sym = ks->sym; 754 rp->add += rel->value - ks->addr; 755 } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) { 756 // handle reference to __IMPORT/__pointers. 757 // how much worse can this get? 758 // why are we supporting 386 on the mac anyway? 759 rp->type = 512 + MACHO_FAKE_GOTPCREL; 760 // figure out which pointer this is a reference to. 761 k = ks->res1 + (rel->value - ks->addr) / 4; 762 // load indirect table for __pointers 763 // fetch symbol number 764 if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) { 765 werrstr("invalid scattered relocation: indirect symbol reference out of range"); 766 goto bad; 767 } 768 k = dsymtab->indir[k]; 769 if(k < 0 || k >= symtab->nsym) { 770 werrstr("invalid scattered relocation: symbol reference out of range"); 771 goto bad; 772 } 773 rp->sym = symtab->sym[k].sym; 774 } else { 775 werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name); 776 goto bad; 777 } 778 rp++; 779 // skip #1 of 2 rel; continue skips #2 of 2. 780 rel++; 781 j++; 782 continue; 783 } 784 785 rp->siz = rel->length; 786 rp->type = 512 + (rel->type<<1) + rel->pcrel; 787 rp->off = rel->addr; 788 789 // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). 790 if (thechar == '6' && rel->extrn == 0 && rel->type == 1) { 791 // Calculate the addend as the offset into the section. 792 // 793 // The rip-relative offset stored in the object file is encoded 794 // as follows: 795 // 796 // movsd 0x00000360(%rip),%xmm0 797 // 798 // To get the absolute address of the value this rip-relative address is pointing 799 // to, we must add the address of the next instruction to it. This is done by 800 // taking the address of the relocation and adding 4 to it (since the rip-relative 801 // offset can at most be 32 bits long). To calculate the offset into the section the 802 // relocation is referencing, we subtract the vaddr of the start of the referenced 803 // section found in the original object file. 804 // 805 // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] 806 secaddr = c->seg.sect[rel->symnum-1].addr; 807 rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr; 808 } else 809 rp->add = (int32)e->e32(s->p+rp->off); 810 811 // For i386 Mach-O PC-relative, the addend is written such that 812 // it *is* the PC being subtracted. Use that to make 813 // it match our version of PC-relative. 814 if(rel->pcrel && thechar == '8') 815 rp->add += rp->off+rp->siz; 816 if(!rel->extrn) { 817 if(rel->symnum < 1 || rel->symnum > c->seg.nsect) { 818 werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect); 819 goto bad; 820 } 821 rp->sym = c->seg.sect[rel->symnum-1].sym; 822 if(rp->sym == nil) { 823 werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name); 824 goto bad; 825 } 826 // References to symbols in other sections 827 // include that information in the addend. 828 // We only care about the delta from the 829 // section base. 830 if(thechar == '8') 831 rp->add -= c->seg.sect[rel->symnum-1].addr; 832 } else { 833 if(rel->symnum >= symtab->nsym) { 834 werrstr("invalid relocation: symbol reference out of range"); 835 goto bad; 836 } 837 rp->sym = symtab->sym[rel->symnum].sym; 838 } 839 rp++; 840 } 841 qsort(r, rp - r, sizeof r[0], rbyoff); 842 s->r = r; 843 s->nr = rp - r; 844 } 845 return; 846 847 bad: 848 diag("%s: malformed mach-o file: %r", pn); 849 }