github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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 LSym *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 LSym *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 LSym *s, *s1, *outer; 436 MachoCmd *c; 437 MachoSymtab *symtab; 438 MachoDysymtab *dsymtab; 439 MachoSym *sym; 440 Reloc *r, *rp; 441 char *name; 442 443 ctxt->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 USED(dsymtab); 511 for(i=0; i<ncmd; i++){ 512 ty = e->e32(cmdp); 513 sz = e->e32(cmdp+4); 514 m->cmd[i].off = off; 515 unpackcmd(cmdp, m, &m->cmd[i], ty, sz); 516 cmdp += sz; 517 off += sz; 518 if(ty == MachoCmdSymtab) { 519 if(symtab != nil) { 520 werrstr("multiple symbol tables"); 521 goto bad; 522 } 523 symtab = &m->cmd[i].sym; 524 macholoadsym(m, symtab); 525 } 526 if(ty == MachoCmdDysymtab) { 527 dsymtab = &m->cmd[i].dsym; 528 macholoaddsym(m, dsymtab); 529 } 530 if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) { 531 if(c != nil) { 532 werrstr("multiple load commands"); 533 goto bad; 534 } 535 c = &m->cmd[i]; 536 } 537 } 538 539 // load text and data segments into memory. 540 // they are not as small as the load commands, but we'll need 541 // the memory anyway for the symbol images, so we might 542 // as well use one large chunk. 543 if(c == nil) { 544 werrstr("no load command"); 545 goto bad; 546 } 547 if(symtab == nil) { 548 // our work is done here - no symbols means nothing can refer to this file 549 return; 550 } 551 552 if(c->seg.fileoff+c->seg.filesz >= len) { 553 werrstr("load segment out of range"); 554 goto bad; 555 } 556 557 dat = mal(c->seg.filesz); 558 if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) { 559 werrstr("cannot load object data: %r"); 560 goto bad; 561 } 562 563 for(i=0; i<c->seg.nsect; i++) { 564 sect = &c->seg.sect[i]; 565 if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0) 566 continue; 567 if(strcmp(sect->name, "__eh_frame") == 0) 568 continue; 569 name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name); 570 s = linklookup(ctxt, name, ctxt->version); 571 if(s->type != 0) { 572 werrstr("duplicate %s/%s", sect->segname, sect->name); 573 goto bad; 574 } 575 free(name); 576 577 s->np = sect->size; 578 s->size = s->np; 579 if((sect->flags & 0xff) == 1) // S_ZEROFILL 580 s->p = mal(s->size); 581 else { 582 s->p = dat + sect->addr - c->seg.vmaddr; 583 } 584 585 if(strcmp(sect->segname, "__TEXT") == 0) { 586 if(strcmp(sect->name, "__text") == 0) 587 s->type = STEXT; 588 else 589 s->type = SRODATA; 590 } else { 591 if (strcmp(sect->name, "__bss") == 0) { 592 s->type = SNOPTRBSS; 593 s->np = 0; 594 } else 595 s->type = SNOPTRDATA; 596 } 597 sect->sym = s; 598 } 599 600 // enter sub-symbols into symbol table. 601 // have to guess sizes from next symbol. 602 for(i=0; i<symtab->nsym; i++) { 603 int v; 604 sym = &symtab->sym[i]; 605 if(sym->type&N_STAB) 606 continue; 607 // TODO: check sym->type against outer->type. 608 name = sym->name; 609 if(name[0] == '_' && name[1] != '\0') 610 name++; 611 v = 0; 612 if(!(sym->type&N_EXT)) 613 v = ctxt->version; 614 s = linklookup(ctxt, name, v); 615 if(!(sym->type&N_EXT)) 616 s->dupok = 1; 617 sym->sym = s; 618 if(sym->sectnum == 0) // undefined 619 continue; 620 if(sym->sectnum > c->seg.nsect) { 621 werrstr("reference to invalid section %d", sym->sectnum); 622 goto bad; 623 } 624 sect = &c->seg.sect[sym->sectnum-1]; 625 outer = sect->sym; 626 if(outer == nil) { 627 werrstr("reference to invalid section %s/%s", sect->segname, sect->name); 628 continue; 629 } 630 if(s->outer != S) { 631 if(s->dupok) 632 continue; 633 diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); 634 errorexit(); 635 } 636 s->type = outer->type | SSUB; 637 s->sub = outer->sub; 638 outer->sub = s; 639 s->outer = outer; 640 s->value = sym->value - sect->addr; 641 if(!(s->cgoexport & CgoExportDynamic)) 642 s->dynimplib = nil; // satisfy dynimport 643 if(outer->type == STEXT) { 644 if(s->external && !s->dupok) 645 diag("%s: duplicate definition of %s", pn, s->name); 646 s->external = 1; 647 } 648 sym->sym = s; 649 } 650 651 // Sort outer lists by address, adding to textp. 652 // This keeps textp in increasing address order. 653 for(i=0; i<c->seg.nsect; i++) { 654 sect = &c->seg.sect[i]; 655 if((s = sect->sym) == S) 656 continue; 657 if(s->sub) { 658 s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); 659 660 // assign sizes, now that we know symbols in sorted order. 661 for(s1 = s->sub; s1 != S; s1 = s1->sub) { 662 if(s1->sub) 663 s1->size = s1->sub->value - s1->value; 664 else 665 s1->size = s->value + s->size - s1->value; 666 } 667 } 668 if(s->type == STEXT) { 669 if(s->onlist) 670 sysfatal("symbol %s listed multiple times", s->name); 671 s->onlist = 1; 672 if(ctxt->etextp) 673 ctxt->etextp->next = s; 674 else 675 ctxt->textp = s; 676 ctxt->etextp = s; 677 for(s1 = s->sub; s1 != S; s1 = s1->sub) { 678 if(s1->onlist) 679 sysfatal("symbol %s listed multiple times", s1->name); 680 s1->onlist = 1; 681 ctxt->etextp->next = s1; 682 ctxt->etextp = s1; 683 } 684 } 685 } 686 687 // load relocations 688 for(i=0; i<c->seg.nsect; i++) { 689 sect = &c->seg.sect[i]; 690 if((s = sect->sym) == S) 691 continue; 692 macholoadrel(m, sect); 693 if(sect->rel == nil) 694 continue; 695 r = mal(sect->nreloc*sizeof r[0]); 696 rp = r; 697 rel = sect->rel; 698 for(j=0; j<sect->nreloc; j++, rel++) { 699 if(rel->scattered) { 700 int k; 701 MachoSect *ks; 702 703 if(thechar != '8') { 704 // mach-o only uses scattered relocation on 32-bit platforms 705 diag("unexpected scattered relocation"); 706 continue; 707 } 708 709 // on 386, rewrite scattered 4/1 relocation and some 710 // scattered 2/1 relocation into the pseudo-pc-relative 711 // reference that it is. 712 // assume that the second in the pair is in this section 713 // and use that as the pc-relative base. 714 if(j+1 >= sect->nreloc) { 715 werrstr("unsupported scattered relocation %d", (int)rel->type); 716 goto bad; 717 } 718 if(!(rel+1)->scattered || (rel+1)->type != 1 || 719 (rel->type != 4 && rel->type != 2) || 720 (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) { 721 werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type); 722 goto bad; 723 } 724 725 rp->siz = rel->length; 726 rp->off = rel->addr; 727 728 // NOTE(rsc): I haven't worked out why (really when) 729 // we should ignore the addend on a 730 // scattered relocation, but it seems that the 731 // common case is we ignore it. 732 // It's likely that this is not strictly correct 733 // and that the math should look something 734 // like the non-scattered case below. 735 rp->add = 0; 736 737 // want to make it pc-relative aka relative to rp->off+4 738 // but the scatter asks for relative to off = (rel+1)->value - sect->addr. 739 // adjust rp->add accordingly. 740 rp->type = R_PCREL; 741 rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); 742 743 // now consider the desired symbol. 744 // find the section where it lives. 745 for(k=0; k<c->seg.nsect; k++) { 746 ks = &c->seg.sect[k]; 747 if(ks->addr <= rel->value && rel->value < ks->addr+ks->size) 748 goto foundk; 749 } 750 werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr); 751 goto bad; 752 foundk: 753 if(ks->sym != S) { 754 rp->sym = ks->sym; 755 rp->add += rel->value - ks->addr; 756 } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) { 757 // handle reference to __IMPORT/__pointers. 758 // how much worse can this get? 759 // why are we supporting 386 on the mac anyway? 760 rp->type = 512 + MACHO_FAKE_GOTPCREL; 761 // figure out which pointer this is a reference to. 762 k = ks->res1 + (rel->value - ks->addr) / 4; 763 // load indirect table for __pointers 764 // fetch symbol number 765 if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) { 766 werrstr("invalid scattered relocation: indirect symbol reference out of range"); 767 goto bad; 768 } 769 k = dsymtab->indir[k]; 770 if(k < 0 || k >= symtab->nsym) { 771 werrstr("invalid scattered relocation: symbol reference out of range"); 772 goto bad; 773 } 774 rp->sym = symtab->sym[k].sym; 775 } else { 776 werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name); 777 goto bad; 778 } 779 rp++; 780 // skip #1 of 2 rel; continue skips #2 of 2. 781 rel++; 782 j++; 783 continue; 784 } 785 786 rp->siz = rel->length; 787 rp->type = 512 + (rel->type<<1) + rel->pcrel; 788 rp->off = rel->addr; 789 790 // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). 791 if (thechar == '6' && rel->extrn == 0 && rel->type == 1) { 792 // Calculate the addend as the offset into the section. 793 // 794 // The rip-relative offset stored in the object file is encoded 795 // as follows: 796 // 797 // movsd 0x00000360(%rip),%xmm0 798 // 799 // To get the absolute address of the value this rip-relative address is pointing 800 // to, we must add the address of the next instruction to it. This is done by 801 // taking the address of the relocation and adding 4 to it (since the rip-relative 802 // offset can at most be 32 bits long). To calculate the offset into the section the 803 // relocation is referencing, we subtract the vaddr of the start of the referenced 804 // section found in the original object file. 805 // 806 // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] 807 secaddr = c->seg.sect[rel->symnum-1].addr; 808 rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr; 809 } else 810 rp->add = (int32)e->e32(s->p+rp->off); 811 812 // For i386 Mach-O PC-relative, the addend is written such that 813 // it *is* the PC being subtracted. Use that to make 814 // it match our version of PC-relative. 815 if(rel->pcrel && thechar == '8') 816 rp->add += rp->off+rp->siz; 817 if(!rel->extrn) { 818 if(rel->symnum < 1 || rel->symnum > c->seg.nsect) { 819 werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect); 820 goto bad; 821 } 822 rp->sym = c->seg.sect[rel->symnum-1].sym; 823 if(rp->sym == nil) { 824 werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name); 825 goto bad; 826 } 827 // References to symbols in other sections 828 // include that information in the addend. 829 // We only care about the delta from the 830 // section base. 831 if(thechar == '8') 832 rp->add -= c->seg.sect[rel->symnum-1].addr; 833 } else { 834 if(rel->symnum >= symtab->nsym) { 835 werrstr("invalid relocation: symbol reference out of range"); 836 goto bad; 837 } 838 rp->sym = symtab->sym[rel->symnum].sym; 839 } 840 rp++; 841 } 842 qsort(r, rp - r, sizeof r[0], rbyoff); 843 s->r = r; 844 s->nr = rp - r; 845 } 846 return; 847 848 bad: 849 diag("%s: malformed mach-o file: %r", pn); 850 }