Print this page
3337 x64 link-editor is painfully literal-minded about TLS

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/sgs/libld/common/machrel.amd.c
          +++ new/usr/src/cmd/sgs/libld/common/machrel.amd.c
↓ open down ↓ 506 lines elided ↑ open up ↑
 507  507           * .byte 0x66
 508  508           */
 509  509          0x66,
 510  510          /*
 511  511           * movq %fs:0, %rax
 512  512           */
 513  513          0x64, 0x48, 0x8b, 0x04, 0x25,
 514  514          0x00, 0x00, 0x00, 0x00
 515  515  };
 516  516  
      517 +#define REX_B           0x1
      518 +#define REX_X           0x2
      519 +#define REX_R           0x4
      520 +#define REX_W           0x8
      521 +#define REX_PREFIX      0x40
      522 +
      523 +#define REX_RW          (REX_PREFIX | REX_R | REX_W)
      524 +#define REX_BW          (REX_PREFIX | REX_B | REX_W)
      525 +#define REX_BRW         (REX_PREFIX | REX_B | REX_R | REX_W)
      526 +
      527 +#define REG_ESP         0x4
      528 +
      529 +#define INSN_ADDMR      0x03    /* addq mem,reg */
      530 +#define INSN_ADDIR      0x81    /* addq imm,reg */
      531 +#define INSN_MOVMR      0x8b    /* movq mem,reg */
      532 +#define INSN_MOVIR      0xc7    /* movq imm,reg */
      533 +#define INSN_LEA        0x8d    /* leaq mem,reg */
 517  534  
 518  535  static Fixupret
 519  536  tls_fixups(Ofl_desc *ofl, Rel_desc *arsp)
 520  537  {
 521  538          Sym_desc        *sdp = arsp->rel_sym;
 522  539          Word            rtype = arsp->rel_rtype;
 523  540          uchar_t         *offset;
 524  541  
 525  542          offset = (uchar_t *)((uintptr_t)arsp->rel_roffset +
 526  543              (uintptr_t)_elf_getxoff(arsp->rel_isdesc->is_indata) +
 527  544              (uintptr_t)RELAUX_GET_OSDESC(arsp)->os_outdata->d_buf);
 528  545  
      546 +        /*
      547 +         * Note that in certain of the original insn sequences below, the
      548 +         * instructions are not necessarily adjacent
      549 +         */
 529  550          if (sdp->sd_ref == REF_DYN_NEED) {
 530  551                  /*
 531  552                   * IE reference model
 532  553                   */
 533  554                  switch (rtype) {
 534  555                  case R_AMD64_TLSGD:
 535  556                          /*
 536  557                           *  GD -> IE
 537  558                           *
 538  559                           * Transition:
↓ open down ↓ 59 lines elided ↑ open up ↑
 598  619                  arsp->rel_roffset += 8;
 599  620                  arsp->rel_raddend = 0;
 600  621  
 601  622                  /*
 602  623                   * Adjust 'offset' to beginning of instruction sequence.
 603  624                   */
 604  625                  offset -= 4;
 605  626                  (void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le));
 606  627                  return (FIX_RELOC);
 607  628  
 608      -        case R_AMD64_GOTTPOFF:
      629 +        case R_AMD64_GOTTPOFF: {
 609  630                  /*
 610  631                   * IE -> LE
 611  632                   *
 612      -                 * Transition:
 613      -                 *      0x00 movq %fs:0, %rax
 614      -                 *      0x09 addq x@gottopoff(%rip), %rax
 615      -                 *      0x10
      633 +                 * Transition 1:
      634 +                 *      movq %fs:0, %reg
      635 +                 *      addq x@gottpoff(%rip), %reg
 616  636                   * To:
 617      -                 *      0x00 movq %fs:0, %rax
 618      -                 *      0x09 leaq x@tpoff(%rax), %rax
 619      -                 *      0x10
      637 +                 *      movq %fs:0, %reg
      638 +                 *      leaq x@tpoff(%reg), %reg
      639 +                 *
      640 +                 * Transition (as a special case):
      641 +                 *      movq %fs:0, %r12/%rsp
      642 +                 *      addq x@gottpoff(%rip), %r12/%rsp
      643 +                 * To:
      644 +                 *      movq %fs:0, %r12/%rsp
      645 +                 *      addq x@tpoff(%rax), %r12/%rsp
      646 +                 *
      647 +                 * Transition 2:
      648 +                 *      movq x@gottpoff(%rip), %reg
      649 +                 *      movq %fs:(%reg), %reg
      650 +                 * To:
      651 +                 *      movq x@tpoff(%reg), %reg
      652 +                 *      movq %fs:(%reg), %reg
 620  653                   */
      654 +                Conv_inv_buf_t  inv_buf;
      655 +                uint8_t reg;            /* Register */
      656 +
      657 +                offset -= 3;
      658 +
      659 +                reg = offset[2] >> 3; /* Encoded dest. reg. operand */
      660 +
 621  661                  DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH,
 622  662                      R_AMD64_TPOFF32, arsp, ld_reloc_sym_name));
 623  663                  arsp->rel_rtype = R_AMD64_TPOFF32;
 624  664                  arsp->rel_raddend = 0;
 625  665  
 626  666                  /*
 627      -                 * Adjust 'offset' to beginning of instruction sequence.
      667 +                 * This is transition 2, and the special case of form 1 where
      668 +                 * a normal transition would index %rsp or %r12 and need a SIB
      669 +                 * byte in the leaq for which we lack space
 628  670                   */
 629      -                offset -= 12;
      671 +                if ((offset[1] == INSN_MOVMR) ||
      672 +                    ((offset[1] == INSN_ADDMR) && (reg == REG_ESP))) {
      673 +                        /*
      674 +                         * If we needed an extra bit of MOD.reg to refer to
      675 +                         * this register as the dest of the original movq we
      676 +                         * need an extra bit of MOD.rm to refer to it in the
      677 +                         * dest of the replacement movq or addq.
      678 +                         */
      679 +                        if (offset[0] == REX_RW)
      680 +                                offset[0] = REX_BW;
 630  681  
 631      -                /*
 632      -                 * Same code sequence used in the GD -> LE transition.
 633      -                 */
 634      -                (void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le));
 635      -                return (FIX_RELOC);
      682 +                        offset[1] = (offset[1] == INSN_MOVMR) ?
      683 +                            INSN_MOVIR : INSN_ADDIR;
      684 +                        offset[2] = 0xc0 | reg;
      685 +
      686 +                        return (FIX_RELOC);
      687 +                } else if (offset[1] == INSN_ADDMR) {
      688 +                        /*
      689 +                         * If we needed an extra bit of MOD.reg to refer to
      690 +                         * this register in the dest of the addq we need an
      691 +                         * extra bit of both MOD.reg and MOD.rm to refer to it
      692 +                         * in the source and dest of the leaq
      693 +                         */
      694 +                        if (offset[0] == REX_RW)
      695 +                                offset[0] = REX_BRW;
      696 +
      697 +                        offset[1] = INSN_LEA;
      698 +                        offset[2] = 0x80 | (reg << 3) | reg;
 636  699  
      700 +                        return (FIX_RELOC);
      701 +                }
      702 +
      703 +                ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_BADTLSINS),
      704 +                    conv_reloc_amd64_type(arsp->rel_rtype, 0, &inv_buf),
      705 +                    arsp->rel_isdesc->is_file->ifl_name,
      706 +                    ld_reloc_sym_name(arsp),
      707 +                    arsp->rel_isdesc->is_name,
      708 +                    EC_OFF(arsp->rel_roffset));
      709 +                return (FIX_ERROR);
      710 +        }
 637  711          case R_AMD64_TLSLD:
 638  712                  /*
 639  713                   * LD -> LE
 640  714                   *
 641  715                   * Transition
 642  716                   *      0x00 leaq x1@tlsgd(%rip), %rdi
 643  717                   *      0x07 call __tls_get_addr@plt
 644  718                   *      0x0c
 645  719                   * To:
 646  720                   *      0x00 .byte 0x66
↓ open down ↓ 991 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX