1*1618Srie /* 2*1618Srie * CDDL HEADER START 3*1618Srie * 4*1618Srie * The contents of this file are subject to the terms of the 5*1618Srie * Common Development and Distribution License (the "License"). 6*1618Srie * You may not use this file except in compliance with the License. 7*1618Srie * 8*1618Srie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1618Srie * or http://www.opensolaris.org/os/licensing. 10*1618Srie * See the License for the specific language governing permissions 11*1618Srie * and limitations under the License. 12*1618Srie * 13*1618Srie * When distributing Covered Code, include this CDDL HEADER in each 14*1618Srie * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1618Srie * If applicable, add the following below this CDDL HEADER, with the 16*1618Srie * fields enclosed by brackets "[]" replaced with your own identifying 17*1618Srie * information: Portions Copyright [yyyy] [name of copyright owner] 18*1618Srie * 19*1618Srie * CDDL HEADER END 20*1618Srie */ 21*1618Srie 22*1618Srie /* 23*1618Srie * Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. 24*1618Srie * Copyright (c) 1988 AT&T 25*1618Srie * All Rights Reserved 26*1618Srie * 27*1618Srie * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 28*1618Srie * Use is subject to license terms. 29*1618Srie */ 30*1618Srie #pragma ident "%Z%%M% %I% %E% SMI" 31*1618Srie 32*1618Srie #include <string.h> 33*1618Srie #include <stdio.h> 34*1618Srie #include <sys/elf_386.h> 35*1618Srie #include <debug.h> 36*1618Srie #include <reloc.h> 37*1618Srie #include "msg.h" 38*1618Srie #include "_libld.h" 39*1618Srie 40*1618Srie Word 41*1618Srie ld_init_rel(Rel_desc *reld, void *reloc) 42*1618Srie { 43*1618Srie Rel * rel = (Rel *)reloc; 44*1618Srie 45*1618Srie /* LINTED */ 46*1618Srie reld->rel_rtype = (Word)ELF_R_TYPE(rel->r_info); 47*1618Srie reld->rel_roffset = rel->r_offset; 48*1618Srie reld->rel_raddend = 0; 49*1618Srie reld->rel_typedata = 0; 50*1618Srie 51*1618Srie return ((Word)ELF_R_SYM(rel->r_info)); 52*1618Srie } 53*1618Srie 54*1618Srie void 55*1618Srie ld_mach_eflags(Ehdr *ehdr, Ofl_desc *ofl) 56*1618Srie { 57*1618Srie ofl->ofl_dehdr->e_flags |= ehdr->e_flags; 58*1618Srie } 59*1618Srie 60*1618Srie void 61*1618Srie ld_mach_make_dynamic(Ofl_desc *ofl, size_t *cnt) 62*1618Srie { 63*1618Srie if (!(ofl->ofl_flags & FLG_OF_RELOBJ)) { 64*1618Srie /* 65*1618Srie * Create this entry if we are going to create a PLT table. 66*1618Srie */ 67*1618Srie if (ofl->ofl_pltcnt) 68*1618Srie (*cnt)++; /* DT_PLTGOT */ 69*1618Srie } 70*1618Srie } 71*1618Srie 72*1618Srie void 73*1618Srie ld_mach_update_odynamic(Ofl_desc * ofl, Dyn ** dyn) 74*1618Srie { 75*1618Srie if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) && ofl->ofl_pltcnt) { 76*1618Srie (*dyn)->d_tag = DT_PLTGOT; 77*1618Srie if (ofl->ofl_osgot) 78*1618Srie (*dyn)->d_un.d_ptr = ofl->ofl_osgot->os_shdr->sh_addr; 79*1618Srie else 80*1618Srie (*dyn)->d_un.d_ptr = 0; 81*1618Srie (*dyn)++; 82*1618Srie } 83*1618Srie } 84*1618Srie 85*1618Srie Xword 86*1618Srie ld_calc_plt_addr(Sym_desc *sdp, Ofl_desc *ofl) 87*1618Srie { 88*1618Srie Xword value; 89*1618Srie 90*1618Srie value = (Xword)(ofl->ofl_osplt->os_shdr->sh_addr) + 91*1618Srie M_PLT_RESERVSZ + ((sdp->sd_aux->sa_PLTndx - 1) * M_PLT_ENTSIZE); 92*1618Srie return (value); 93*1618Srie } 94*1618Srie 95*1618Srie /* 96*1618Srie * Build a single plt entry - code is: 97*1618Srie * if (building a.out) 98*1618Srie * JMP *got_off 99*1618Srie * else 100*1618Srie * JMP *got_off@GOT(%ebx) 101*1618Srie * PUSHL &rel_off 102*1618Srie * JMP -n(%pc) # -n is pcrel offset to first plt entry 103*1618Srie * 104*1618Srie * The got_off@GOT entry gets filled with the address of the PUSHL, 105*1618Srie * so the first pass through the plt jumps back here, jumping 106*1618Srie * in turn to the first plt entry, which jumps to the dynamic 107*1618Srie * linker. The dynamic linker then patches the GOT, rerouting 108*1618Srie * future plt calls to the proper destination. 109*1618Srie */ 110*1618Srie static void 111*1618Srie plt_entry(Ofl_desc * ofl, Word rel_off, Sym_desc * sdp) 112*1618Srie { 113*1618Srie uchar_t *pltent, *gotent; 114*1618Srie Sword plt_off; 115*1618Srie Word got_off; 116*1618Srie 117*1618Srie got_off = sdp->sd_aux->sa_PLTGOTndx * M_GOT_ENTSIZE; 118*1618Srie plt_off = M_PLT_RESERVSZ + ((sdp->sd_aux->sa_PLTndx - 1) * 119*1618Srie M_PLT_ENTSIZE); 120*1618Srie pltent = (uchar_t *)(ofl->ofl_osplt->os_outdata->d_buf) + plt_off; 121*1618Srie gotent = (uchar_t *)(ofl->ofl_osgot->os_outdata->d_buf) + got_off; 122*1618Srie 123*1618Srie /* 124*1618Srie * Fill in the got entry with the address of the next instruction. 125*1618Srie */ 126*1618Srie /* LINTED */ 127*1618Srie *(Word *)gotent = ofl->ofl_osplt->os_shdr->sh_addr + plt_off + 128*1618Srie M_PLT_INSSIZE; 129*1618Srie 130*1618Srie if (!(ofl->ofl_flags & FLG_OF_SHAROBJ)) { 131*1618Srie pltent[0] = M_SPECIAL_INST; 132*1618Srie pltent[1] = M_JMP_DISP_IND; 133*1618Srie pltent += 2; 134*1618Srie /* LINTED */ 135*1618Srie *(Word *)pltent = (Word)(ofl->ofl_osgot->os_shdr->sh_addr + 136*1618Srie got_off); 137*1618Srie } else { 138*1618Srie pltent[0] = M_SPECIAL_INST; 139*1618Srie pltent[1] = M_JMP_REG_DISP_IND; 140*1618Srie pltent += 2; 141*1618Srie /* LINTED */ 142*1618Srie *(Word *)pltent = (Word)got_off; 143*1618Srie } 144*1618Srie pltent += 4; 145*1618Srie 146*1618Srie pltent[0] = M_INST_PUSHL; 147*1618Srie pltent++; 148*1618Srie /* LINTED */ 149*1618Srie *(Word *)pltent = (Word)rel_off; 150*1618Srie pltent += 4; 151*1618Srie 152*1618Srie plt_off = -(plt_off + 16); /* JMP, PUSHL, JMP take 16 bytes */ 153*1618Srie pltent[0] = M_INST_JMP; 154*1618Srie pltent++; 155*1618Srie /* LINTED */ 156*1618Srie *(Word *)pltent = (Word)plt_off; 157*1618Srie } 158*1618Srie 159*1618Srie uintptr_t 160*1618Srie ld_perform_outreloc(Rel_desc * orsp, Ofl_desc * ofl) 161*1618Srie { 162*1618Srie Os_desc * relosp, * osp = 0; 163*1618Srie Word ndx, roffset, value; 164*1618Srie Rel rea; 165*1618Srie char *relbits; 166*1618Srie Sym_desc * sdp, * psym = (Sym_desc *)0; 167*1618Srie int sectmoved = 0; 168*1618Srie 169*1618Srie sdp = orsp->rel_sym; 170*1618Srie 171*1618Srie /* 172*1618Srie * If the section this relocation is against has been discarded 173*1618Srie * (-zignore), then also discard (skip) the relocation itself. 174*1618Srie */ 175*1618Srie if (orsp->rel_isdesc && ((orsp->rel_flags & 176*1618Srie (FLG_REL_GOT | FLG_REL_BSS | FLG_REL_PLT | FLG_REL_NOINFO)) == 0) && 177*1618Srie (orsp->rel_isdesc->is_flags & FLG_IS_DISCARD)) { 178*1618Srie DBG_CALL(Dbg_reloc_discard(ofl->ofl_lml, M_MACH, orsp)); 179*1618Srie return (1); 180*1618Srie } 181*1618Srie 182*1618Srie /* 183*1618Srie * If this is a relocation against a move table, or expanded move 184*1618Srie * table, adjust the relocation entries. 185*1618Srie */ 186*1618Srie if (orsp->rel_move) 187*1618Srie ld_adj_movereloc(ofl, orsp); 188*1618Srie 189*1618Srie /* 190*1618Srie * If this is a relocation against a section using a partial initialized 191*1618Srie * symbol, adjust the embedded symbol info. 192*1618Srie * 193*1618Srie * The second argument of the am_I_partial() is the value stored at the 194*1618Srie * target address relocation is going to be applied. 195*1618Srie */ 196*1618Srie if (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) { 197*1618Srie if (ofl->ofl_parsym.head && 198*1618Srie (sdp->sd_isc->is_flags & FLG_IS_RELUPD) && 199*1618Srie /* LINTED */ 200*1618Srie (psym = ld_am_I_partial(orsp, *(Xword *) 201*1618Srie ((uchar_t *)(orsp->rel_isdesc->is_indata->d_buf) + 202*1618Srie orsp->rel_roffset)))) { 203*1618Srie DBG_CALL(Dbg_move_outsctadj(ofl->ofl_lml, psym)); 204*1618Srie sectmoved = 1; 205*1618Srie } 206*1618Srie } 207*1618Srie 208*1618Srie value = sdp->sd_sym->st_value; 209*1618Srie 210*1618Srie if (orsp->rel_flags & FLG_REL_GOT) { 211*1618Srie osp = ofl->ofl_osgot; 212*1618Srie roffset = (Word)ld_calc_got_offset(orsp, ofl); 213*1618Srie 214*1618Srie } else if (orsp->rel_flags & FLG_REL_PLT) { 215*1618Srie /* 216*1618Srie * Note that relocations for PLT's actually 217*1618Srie * cause a relocation againt the GOT. 218*1618Srie */ 219*1618Srie osp = ofl->ofl_osplt; 220*1618Srie roffset = (Word) (ofl->ofl_osgot->os_shdr->sh_addr) + 221*1618Srie sdp->sd_aux->sa_PLTGOTndx * M_GOT_ENTSIZE; 222*1618Srie 223*1618Srie plt_entry(ofl, osp->os_relosdesc->os_szoutrels, sdp); 224*1618Srie 225*1618Srie } else if (orsp->rel_flags & FLG_REL_BSS) { 226*1618Srie /* 227*1618Srie * This must be a R_386_COPY. For these set the roffset to 228*1618Srie * point to the new symbols location. 229*1618Srie */ 230*1618Srie osp = ofl->ofl_isbss->is_osdesc; 231*1618Srie roffset = (Word)value; 232*1618Srie } else { 233*1618Srie osp = orsp->rel_osdesc; 234*1618Srie 235*1618Srie /* 236*1618Srie * Calculate virtual offset of reference point; equals offset 237*1618Srie * into section + vaddr of section for loadable sections, or 238*1618Srie * offset plus section displacement for nonloadable sections. 239*1618Srie */ 240*1618Srie roffset = orsp->rel_roffset + 241*1618Srie (Off)_elf_getxoff(orsp->rel_isdesc->is_indata); 242*1618Srie if (!(ofl->ofl_flags & FLG_OF_RELOBJ)) 243*1618Srie roffset += orsp->rel_isdesc->is_osdesc-> 244*1618Srie os_shdr->sh_addr; 245*1618Srie } 246*1618Srie 247*1618Srie if ((osp == 0) || ((relosp = osp->os_relosdesc) == 0)) 248*1618Srie relosp = ofl->ofl_osrel; 249*1618Srie 250*1618Srie /* 251*1618Srie * Assign the symbols index for the output relocation. If the 252*1618Srie * relocation refers to a SECTION symbol then it's index is based upon 253*1618Srie * the output sections symbols index. Otherwise the index can be 254*1618Srie * derived from the symbols index itself. 255*1618Srie */ 256*1618Srie if (orsp->rel_rtype == R_386_RELATIVE) 257*1618Srie ndx = STN_UNDEF; 258*1618Srie else if ((orsp->rel_flags & FLG_REL_SCNNDX) || 259*1618Srie (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION)) { 260*1618Srie if (sectmoved == 0) { 261*1618Srie /* 262*1618Srie * Check for a null input section. This can 263*1618Srie * occur if this relocation references a symbol 264*1618Srie * generated by sym_add_sym(). 265*1618Srie */ 266*1618Srie if ((sdp->sd_isc != 0) && 267*1618Srie (sdp->sd_isc->is_osdesc != 0)) 268*1618Srie ndx = sdp->sd_isc->is_osdesc->os_scnsymndx; 269*1618Srie else 270*1618Srie ndx = sdp->sd_shndx; 271*1618Srie } else 272*1618Srie ndx = ofl->ofl_sunwdata1ndx; 273*1618Srie } else 274*1618Srie ndx = sdp->sd_symndx; 275*1618Srie 276*1618Srie relbits = (char *)relosp->os_outdata->d_buf; 277*1618Srie 278*1618Srie rea.r_info = ELF_R_INFO(ndx, orsp->rel_rtype); 279*1618Srie rea.r_offset = roffset; 280*1618Srie DBG_CALL(Dbg_reloc_out(ofl, ELF_DBG_LD, SHT_REL, &rea, relosp->os_name, 281*1618Srie orsp->rel_sname)); 282*1618Srie 283*1618Srie /* 284*1618Srie * Assert we haven't walked off the end of our relocation table. 285*1618Srie */ 286*1618Srie assert(relosp->os_szoutrels <= relosp->os_shdr->sh_size); 287*1618Srie 288*1618Srie (void) memcpy((relbits + relosp->os_szoutrels), 289*1618Srie (char *)&rea, sizeof (Rel)); 290*1618Srie relosp->os_szoutrels += sizeof (Rel); 291*1618Srie 292*1618Srie /* 293*1618Srie * Determine if this relocation is against a non-writable, allocatable 294*1618Srie * section. If so we may need to provide a text relocation diagnostic. 295*1618Srie * Note that relocations against the .plt (R_386_JMP_SLOT) actually 296*1618Srie * result in modifications to the .got. 297*1618Srie */ 298*1618Srie if (orsp->rel_rtype == R_386_JMP_SLOT) 299*1618Srie osp = ofl->ofl_osgot; 300*1618Srie 301*1618Srie ld_reloc_remain_entry(orsp, osp, ofl); 302*1618Srie return (1); 303*1618Srie } 304*1618Srie 305*1618Srie /* 306*1618Srie * i386 Instructions for TLS processing 307*1618Srie */ 308*1618Srie static uchar_t tlsinstr_gd_ie[] = { 309*1618Srie /* 310*1618Srie * 0x00 movl %gs:0x0, %eax 311*1618Srie */ 312*1618Srie 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, 313*1618Srie /* 314*1618Srie * 0x06 addl x(%eax), %eax 315*1618Srie * 0x0c ... 316*1618Srie */ 317*1618Srie 0x03, 0x80, 0x00, 0x00, 0x00, 0x00 318*1618Srie }; 319*1618Srie 320*1618Srie static uchar_t tlsinstr_gd_le[] = { 321*1618Srie /* 322*1618Srie * 0x00 movl %gs:0x0, %eax 323*1618Srie */ 324*1618Srie 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, 325*1618Srie /* 326*1618Srie * 0x06 addl $0x0, %eax 327*1618Srie */ 328*1618Srie 0x05, 0x00, 0x00, 0x00, 0x00, 329*1618Srie /* 330*1618Srie * 0x0b nop 331*1618Srie * 0x0c 332*1618Srie */ 333*1618Srie 0x90 334*1618Srie }; 335*1618Srie 336*1618Srie static uchar_t tlsinstr_gd_ie_movgs[] = { 337*1618Srie /* 338*1618Srie * movl %gs:0x0,%eax 339*1618Srie */ 340*1618Srie 0x65, 0xa1, 0x00, 0x00, 0x00, 00 341*1618Srie }; 342*1618Srie 343*1618Srie #define TLS_GD_IE_MOV 0x8b /* movl opcode */ 344*1618Srie #define TLS_GD_IE_POP 0x58 /* popl + reg */ 345*1618Srie 346*1618Srie #define TLS_GD_LE_MOVL 0xb8 /* movl + reg */ 347*1618Srie 348*1618Srie #define TLS_NOP 0x90 /* NOP instruction */ 349*1618Srie 350*1618Srie #define MODRM_MSK_MOD 0xc0 351*1618Srie #define MODRM_MSK_RO 0x38 352*1618Srie #define MODRM_MSK_RM 0x07 353*1618Srie 354*1618Srie #define SIB_MSK_SS 0xc0 355*1618Srie #define SIB_MSK_IND 0x38 356*1618Srie #define SIB_MSK_BS 0x07 357*1618Srie 358*1618Srie static Fixupret 359*1618Srie tls_fixups(Ofl_desc *ofl, Rel_desc *arsp) 360*1618Srie { 361*1618Srie Sym_desc *sdp = arsp->rel_sym; 362*1618Srie Word rtype = arsp->rel_rtype; 363*1618Srie uchar_t *offset, r1, r2; 364*1618Srie 365*1618Srie offset = (uchar_t *)((uintptr_t)arsp->rel_roffset + 366*1618Srie (uintptr_t)_elf_getxoff(arsp->rel_isdesc->is_indata) + 367*1618Srie (uintptr_t)arsp->rel_osdesc->os_outdata->d_buf); 368*1618Srie 369*1618Srie if (sdp->sd_ref == REF_DYN_NEED) { 370*1618Srie /* 371*1618Srie * IE reference model 372*1618Srie */ 373*1618Srie switch (rtype) { 374*1618Srie case R_386_TLS_GD: 375*1618Srie /* 376*1618Srie * Transition: 377*1618Srie * 0x0 leal x@tlsgd(,r1,1), %eax 378*1618Srie * 0x7 call ___tls_get_addr 379*1618Srie * 0xc 380*1618Srie * To: 381*1618Srie * 0x0 movl %gs:0, %eax 382*1618Srie * 0x6 addl x@gotntpoff(r1), %eax 383*1618Srie */ 384*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 385*1618Srie rtype, R_386_TLS_GOTIE, arsp->rel_roffset, 386*1618Srie sdp->sd_name)); 387*1618Srie arsp->rel_rtype = R_386_TLS_GOTIE; 388*1618Srie arsp->rel_roffset += 5; 389*1618Srie 390*1618Srie /* 391*1618Srie * Addjust 'offset' to beginning of instruction 392*1618Srie * sequence. 393*1618Srie */ 394*1618Srie offset -= 3; 395*1618Srie r1 = (offset[2] & SIB_MSK_IND) >> 3; 396*1618Srie (void) memcpy(offset, tlsinstr_gd_ie, 397*1618Srie sizeof (tlsinstr_gd_ie)); 398*1618Srie 399*1618Srie /* 400*1618Srie * set register %r1 into the addl 401*1618Srie * instruction. 402*1618Srie */ 403*1618Srie offset[0x7] |= r1; 404*1618Srie return (FIX_RELOC); 405*1618Srie 406*1618Srie case R_386_TLS_GD_PLT: 407*1618Srie /* 408*1618Srie * Fixup done via the TLS_GD relocation 409*1618Srie */ 410*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 411*1618Srie rtype, R_386_NONE, arsp->rel_roffset, 412*1618Srie sdp->sd_name)); 413*1618Srie return (FIX_DONE); 414*1618Srie } 415*1618Srie } 416*1618Srie 417*1618Srie /* 418*1618Srie * LE reference model 419*1618Srie */ 420*1618Srie switch (rtype) { 421*1618Srie case R_386_TLS_GD: 422*1618Srie /* 423*1618Srie * Transition: 424*1618Srie * 0x0 leal x@tlsgd(,r1,1), %eax 425*1618Srie * 0x7 call ___tls_get_addr 426*1618Srie * 0xc 427*1618Srie * To: 428*1618Srie * 0x0 movl %gs:0, %eax 429*1618Srie * 0x6 addl $x@ntpoff, %eax 430*1618Srie * 0xb nop 431*1618Srie * 0xc 432*1618Srie */ 433*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 434*1618Srie rtype, R_386_TLS_LE, arsp->rel_roffset, sdp->sd_name)); 435*1618Srie 436*1618Srie arsp->rel_rtype = R_386_TLS_LE; 437*1618Srie arsp->rel_roffset += 4; 438*1618Srie 439*1618Srie /* 440*1618Srie * Addjust 'offset' to beginning of instruction 441*1618Srie * sequence. 442*1618Srie */ 443*1618Srie offset -= 3; 444*1618Srie (void) memcpy(offset, tlsinstr_gd_le, 445*1618Srie sizeof (tlsinstr_gd_le)); 446*1618Srie return (FIX_RELOC); 447*1618Srie 448*1618Srie case R_386_TLS_GD_PLT: 449*1618Srie case R_386_PLT32: 450*1618Srie /* 451*1618Srie * Fixup done via the TLS_GD relocation 452*1618Srie */ 453*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 454*1618Srie rtype, R_386_NONE, arsp->rel_roffset, sdp->sd_name)); 455*1618Srie return (FIX_DONE); 456*1618Srie 457*1618Srie case R_386_TLS_LDM_PLT: 458*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 459*1618Srie rtype, R_386_NONE, arsp->rel_roffset, sdp->sd_name)); 460*1618Srie 461*1618Srie /* 462*1618Srie * Transition: 463*1618Srie * call __tls_get_addr() 464*1618Srie * to: 465*1618Srie * nop 466*1618Srie * nop 467*1618Srie * nop 468*1618Srie * nop 469*1618Srie * nop 470*1618Srie */ 471*1618Srie *(offset - 1) = TLS_NOP; 472*1618Srie *(offset) = TLS_NOP; 473*1618Srie *(offset + 1) = TLS_NOP; 474*1618Srie *(offset + 2) = TLS_NOP; 475*1618Srie *(offset + 3) = TLS_NOP; 476*1618Srie return (FIX_DONE); 477*1618Srie 478*1618Srie case R_386_TLS_LDM: 479*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 480*1618Srie rtype, R_386_NONE, arsp->rel_roffset, sdp->sd_name)); 481*1618Srie 482*1618Srie /* 483*1618Srie * Transition: 484*1618Srie * 485*1618Srie * 0x00 leal x1@tlsldm(%ebx), %eax 486*1618Srie * 0x06 call ___tls_get_addr 487*1618Srie * 488*1618Srie * to: 489*1618Srie * 490*1618Srie * 0x00 movl %gs:0, %eax 491*1618Srie */ 492*1618Srie (void) memcpy(offset - 2, tlsinstr_gd_ie_movgs, 493*1618Srie sizeof (tlsinstr_gd_ie_movgs)); 494*1618Srie return (FIX_DONE); 495*1618Srie 496*1618Srie case R_386_TLS_LDO_32: 497*1618Srie /* 498*1618Srie * Instructions: 499*1618Srie * 500*1618Srie * 0x10 leal x1@dtpoff(%eax), %edx R_386_TLS_LDO_32 501*1618Srie * to 502*1618Srie * 0x10 leal x1@ntpoff(%eax), %edx R_386_TLS_LE 503*1618Srie * 504*1618Srie */ 505*1618Srie offset -= 2; 506*1618Srie 507*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 508*1618Srie rtype, R_386_TLS_LE, arsp->rel_roffset, sdp->sd_name)); 509*1618Srie arsp->rel_rtype = R_386_TLS_LE; 510*1618Srie return (FIX_RELOC); 511*1618Srie 512*1618Srie case R_386_TLS_GOTIE: 513*1618Srie /* 514*1618Srie * These transitions are a little different than the 515*1618Srie * others, in that we could have multiple instructions 516*1618Srie * pointed to by a single relocation. Depending upon the 517*1618Srie * instruction, we perform a different code transition. 518*1618Srie * 519*1618Srie * Here's the known transitions: 520*1618Srie * 521*1618Srie * 1) movl foo@gotntpoff(%reg1), %reg2 522*1618Srie * 0x8b, 0x80 | (reg2 << 3) | reg1, foo@gotntpoff 523*1618Srie * 524*1618Srie * 2) addl foo@gotntpoff(%reg1), %reg2 525*1618Srie * 0x03, 0x80 | (reg2 << 3) | reg1, foo@gotntpoff 526*1618Srie * 527*1618Srie * Transitions IE -> LE 528*1618Srie * 529*1618Srie * 1) movl $foo@ntpoff, %reg2 530*1618Srie * 0xc7, 0xc0 | reg2, foo@ntpoff 531*1618Srie * 532*1618Srie * 2) addl $foo@ntpoff, %reg2 533*1618Srie * 0x81, 0xc0 | reg2, foo@ntpoff 534*1618Srie * 535*1618Srie * Note: reg1 != 4 (%esp) 536*1618Srie */ 537*1618Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 538*1618Srie rtype, R_386_TLS_LE, arsp->rel_roffset, sdp->sd_name)); 539*1618Srie arsp->rel_rtype = R_386_TLS_LE; 540*1618Srie 541*1618Srie offset -= 2; 542*1618Srie r2 = (offset[1] & MODRM_MSK_RO) >> 3; 543*1618Srie if (offset[0] == 0x8b) { 544*1618Srie /* case 1 above */ 545*1618Srie offset[0] = 0xc7; /* movl */ 546*1618Srie offset[1] = 0xc0 | r2; 547*1618Srie return (FIX_RELOC); 548*1618Srie } 549*1618Srie 550*1618Srie if (offset[0] == 0x03) { 551*1618Srie /* case 2 above */ 552*1618Srie assert(offset[0] == 0x03); 553*1618Srie offset[0] = 0x81; /* addl */ 554*1618Srie offset[1] = 0xc0 | r2; 555*1618Srie return (FIX_RELOC); 556*1618Srie } 557*1618Srie 558*1618Srie /* 559*1618Srie * Unexpected instruction sequence - fatal error. 560*1618Srie */ 561*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLSINS), 562*1618Srie conv_reloc_386_type(arsp->rel_rtype), 563*1618Srie arsp->rel_isdesc->is_file->ifl_name, 564*1618Srie demangle(arsp->rel_sname), arsp->rel_isdesc->is_name, 565*1618Srie EC_OFF(arsp->rel_roffset)); 566*1618Srie return (FIX_ERROR); 567*1618Srie 568*1618Srie case R_386_TLS_IE: 569*1618Srie /* 570*1618Srie * These transitions are a little different than the 571*1618Srie * others, in that we could have multiple instructions 572*1618Srie * pointed to by a single relocation. Depending upon the 573*1618Srie * instruction, we perform a different code transition. 574*1618Srie * 575*1618Srie * Here's the known transitions: 576*1618Srie * 1) movl foo@indntpoff, %eax 577*1618Srie * 0xa1, foo@indntpoff 578*1618Srie * 579*1618Srie * 2) movl foo@indntpoff, %eax 580*1618Srie * 0x8b, 0x05 | (reg << 3), foo@gotntpoff 581*1618Srie * 582*1618Srie * 3) addl foo@indntpoff, %eax 583*1618Srie * 0x03, 0x05 | (reg << 3), foo@gotntpoff 584*1618Srie * 585*1618Srie * Transitions IE -> LE 586*1618Srie * 587*1618Srie * 1) movl $foo@ntpoff, %eax 588*1618Srie * 0xb8, foo@ntpoff 589*1618Srie * 590*1618Srie * 2) movl $foo@ntpoff, %reg 591*1618Srie * 0xc7, 0xc0 | reg, foo@ntpoff 592*1618Srie * 593*1618Srie * 3) addl $foo@ntpoff, %reg 594*1618Srie * 0x81, 0xc0 | reg, foo@ntpoff 595*1618Srie */ 596*1618Srie arsp->rel_rtype = R_386_TLS_LE; 597*1618Srie offset--; 598*1618Srie if (offset[0] == 0xa1) { 599*1618Srie /* case 1 above */ 600*1618Srie offset[0] = 0xb8; /* movl */ 601*1618Srie return (FIX_RELOC); 602*1618Srie } 603*1618Srie 604*1618Srie offset--; 605*1618Srie if (offset[0] == 0x8b) { 606*1618Srie /* case 2 above */ 607*1618Srie r2 = (offset[1] & MODRM_MSK_RO) >> 3; 608*1618Srie offset[0] = 0xc7; /* movl */ 609*1618Srie offset[1] = 0xc0 | r2; 610*1618Srie return (FIX_RELOC); 611*1618Srie } 612*1618Srie if (offset[0] == 0x03) { 613*1618Srie /* case 3 above */ 614*1618Srie r2 = (offset[1] & MODRM_MSK_RO) >> 3; 615*1618Srie offset[0] = 0x81; /* addl */ 616*1618Srie offset[1] = 0xc0 | r2; 617*1618Srie return (FIX_RELOC); 618*1618Srie } 619*1618Srie /* 620*1618Srie * Unexpected instruction sequence - fatal error. 621*1618Srie */ 622*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLSINS), 623*1618Srie conv_reloc_386_type(arsp->rel_rtype), 624*1618Srie arsp->rel_isdesc->is_file->ifl_name, 625*1618Srie demangle(arsp->rel_sname), arsp->rel_isdesc->is_name, 626*1618Srie EC_OFF(arsp->rel_roffset)); 627*1618Srie return (FIX_ERROR); 628*1618Srie } 629*1618Srie return (FIX_RELOC); 630*1618Srie } 631*1618Srie 632*1618Srie uintptr_t 633*1618Srie ld_do_activerelocs(Ofl_desc *ofl) 634*1618Srie { 635*1618Srie Rel_desc *arsp; 636*1618Srie Rel_cache *rcp; 637*1618Srie Listnode *lnp; 638*1618Srie uintptr_t return_code = 1; 639*1618Srie Word flags = ofl->ofl_flags; 640*1618Srie Word dtflags1 = ofl->ofl_dtflags_1; 641*1618Srie 642*1618Srie DBG_CALL(Dbg_reloc_doact_title(ofl->ofl_lml)); 643*1618Srie /* 644*1618Srie * Process active relocations. 645*1618Srie */ 646*1618Srie for (LIST_TRAVERSE(&ofl->ofl_actrels, lnp, rcp)) { 647*1618Srie /* LINTED */ 648*1618Srie for (arsp = (Rel_desc *)(rcp + 1); 649*1618Srie arsp < rcp->rc_free; arsp++) { 650*1618Srie uchar_t *addr; 651*1618Srie Xword value; 652*1618Srie Sym_desc *sdp; 653*1618Srie const char *ifl_name; 654*1618Srie Xword refaddr; 655*1618Srie int moved = 0; 656*1618Srie Gotref gref; 657*1618Srie 658*1618Srie /* 659*1618Srie * If the section this relocation is against has been 660*1618Srie * discarded (-zignore), then discard (skip) the 661*1618Srie * relocation itself. 662*1618Srie */ 663*1618Srie if ((arsp->rel_isdesc->is_flags & FLG_IS_DISCARD) && 664*1618Srie ((arsp->rel_flags & 665*1618Srie (FLG_REL_GOT | FLG_REL_BSS | 666*1618Srie FLG_REL_PLT | FLG_REL_NOINFO)) == 0)) { 667*1618Srie DBG_CALL(Dbg_reloc_discard(ofl->ofl_lml, 668*1618Srie M_MACH, arsp)); 669*1618Srie continue; 670*1618Srie } 671*1618Srie 672*1618Srie /* 673*1618Srie * We deteremine what the 'got reference' 674*1618Srie * model (if required) is at this point. This 675*1618Srie * needs to be done before tls_fixup() since 676*1618Srie * it may 'transition' our instructions. 677*1618Srie * 678*1618Srie * The got table entries have already been assigned, 679*1618Srie * and we bind to those initial entries. 680*1618Srie */ 681*1618Srie if (arsp->rel_flags & FLG_REL_DTLS) 682*1618Srie gref = GOT_REF_TLSGD; 683*1618Srie else if (arsp->rel_flags & FLG_REL_MTLS) 684*1618Srie gref = GOT_REF_TLSLD; 685*1618Srie else if (arsp->rel_flags & FLG_REL_STLS) 686*1618Srie gref = GOT_REF_TLSIE; 687*1618Srie else 688*1618Srie gref = GOT_REF_GENERIC; 689*1618Srie 690*1618Srie /* 691*1618Srie * Perform any required TLS fixups. 692*1618Srie */ 693*1618Srie if (arsp->rel_flags & FLG_REL_TLSFIX) { 694*1618Srie Fixupret ret; 695*1618Srie 696*1618Srie if ((ret = tls_fixups(ofl, arsp)) == FIX_ERROR) 697*1618Srie return (S_ERROR); 698*1618Srie if (ret == FIX_DONE) 699*1618Srie continue; 700*1618Srie } 701*1618Srie 702*1618Srie /* 703*1618Srie * If this is a relocation against a move table, or 704*1618Srie * expanded move table, adjust the relocation entries. 705*1618Srie */ 706*1618Srie if (arsp->rel_move) 707*1618Srie ld_adj_movereloc(ofl, arsp); 708*1618Srie 709*1618Srie sdp = arsp->rel_sym; 710*1618Srie refaddr = arsp->rel_roffset + 711*1618Srie (Off)_elf_getxoff(arsp->rel_isdesc->is_indata); 712*1618Srie 713*1618Srie if (arsp->rel_flags & FLG_REL_CLVAL) 714*1618Srie value = 0; 715*1618Srie else if (ELF_ST_TYPE(sdp->sd_sym->st_info) == 716*1618Srie STT_SECTION) { 717*1618Srie Sym_desc *sym; 718*1618Srie 719*1618Srie /* 720*1618Srie * The value for a symbol pointing to a SECTION 721*1618Srie * is based off of that sections position. 722*1618Srie * 723*1618Srie * The second argument of the ld_am_I_partial() 724*1618Srie * is the value stored at the target address 725*1618Srie * relocation is going to be applied. 726*1618Srie */ 727*1618Srie if ((sdp->sd_isc->is_flags & FLG_IS_RELUPD) && 728*1618Srie /* LINTED */ 729*1618Srie (sym = ld_am_I_partial(arsp, *(Xword *) 730*1618Srie ((uchar_t *) 731*1618Srie arsp->rel_isdesc->is_indata->d_buf + 732*1618Srie arsp->rel_roffset)))) { 733*1618Srie /* 734*1618Srie * If the symbol is moved, 735*1618Srie * adjust the value 736*1618Srie */ 737*1618Srie value = sym->sd_sym->st_value; 738*1618Srie moved = 1; 739*1618Srie } else { 740*1618Srie value = _elf_getxoff( 741*1618Srie sdp->sd_isc->is_indata); 742*1618Srie if (sdp->sd_isc->is_shdr->sh_flags & 743*1618Srie SHF_ALLOC) 744*1618Srie value += sdp->sd_isc-> 745*1618Srie is_osdesc->os_shdr->sh_addr; 746*1618Srie } 747*1618Srie if (sdp->sd_isc->is_shdr->sh_flags & SHF_TLS) 748*1618Srie value -= ofl->ofl_tlsphdr->p_vaddr; 749*1618Srie } else { 750*1618Srie /* 751*1618Srie * else the value is the symbols value 752*1618Srie */ 753*1618Srie value = sdp->sd_sym->st_value; 754*1618Srie } 755*1618Srie 756*1618Srie /* 757*1618Srie * Relocation against the GLOBAL_OFFSET_TABLE. 758*1618Srie */ 759*1618Srie if (arsp->rel_flags & FLG_REL_GOT) 760*1618Srie arsp->rel_osdesc = ofl->ofl_osgot; 761*1618Srie 762*1618Srie /* 763*1618Srie * If loadable and not producing a relocatable object 764*1618Srie * add the sections virtual address to the reference 765*1618Srie * address. 766*1618Srie */ 767*1618Srie if ((arsp->rel_flags & FLG_REL_LOAD) && 768*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) 769*1618Srie refaddr += arsp->rel_isdesc->is_osdesc-> 770*1618Srie os_shdr->sh_addr; 771*1618Srie 772*1618Srie /* 773*1618Srie * If this entry has a PLT assigned to it, it's 774*1618Srie * value is actually the address of the PLT (and 775*1618Srie * not the address of the function). 776*1618Srie */ 777*1618Srie if (IS_PLT(arsp->rel_rtype)) { 778*1618Srie if (sdp->sd_aux && sdp->sd_aux->sa_PLTndx) 779*1618Srie value = ld_calc_plt_addr(sdp, ofl); 780*1618Srie } 781*1618Srie 782*1618Srie /* 783*1618Srie * Determine whether the value needs further adjustment. 784*1618Srie * Filter through the attributes of the relocation to 785*1618Srie * determine what adjustment is required. Note, many 786*1618Srie * of the following cases are only applicable when a 787*1618Srie * .got is present. As a .got is not generated when a 788*1618Srie * relocatable object is being built, any adjustments 789*1618Srie * that require a .got need to be skipped. 790*1618Srie */ 791*1618Srie if ((arsp->rel_flags & FLG_REL_GOT) && 792*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) { 793*1618Srie Xword R1addr; 794*1618Srie uintptr_t R2addr; 795*1618Srie Word gotndx; 796*1618Srie Gotndx *gnp; 797*1618Srie 798*1618Srie /* 799*1618Srie * Perform relocation against GOT table. Since 800*1618Srie * this doesn't fit exactly into a relocation 801*1618Srie * we place the appropriate byte in the GOT 802*1618Srie * directly 803*1618Srie * 804*1618Srie * Calculate offset into GOT at which to apply 805*1618Srie * the relocation. 806*1618Srie */ 807*1618Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), gref, 808*1618Srie ofl, 0); 809*1618Srie assert(gnp); 810*1618Srie 811*1618Srie if (arsp->rel_rtype == R_386_TLS_DTPOFF32) 812*1618Srie gotndx = gnp->gn_gotndx + 1; 813*1618Srie else 814*1618Srie gotndx = gnp->gn_gotndx; 815*1618Srie 816*1618Srie R1addr = (Xword)(gotndx * M_GOT_ENTSIZE); 817*1618Srie 818*1618Srie /* 819*1618Srie * Add the GOTs data's offset. 820*1618Srie */ 821*1618Srie R2addr = R1addr + (uintptr_t) 822*1618Srie arsp->rel_osdesc->os_outdata->d_buf; 823*1618Srie 824*1618Srie DBG_CALL(Dbg_reloc_doact(ofl->ofl_lml, 825*1618Srie ELF_DBG_LD, M_MACH, SHT_REL, 826*1618Srie arsp->rel_rtype, R1addr, value, 827*1618Srie arsp->rel_sname, arsp->rel_osdesc)); 828*1618Srie 829*1618Srie /* 830*1618Srie * And do it. 831*1618Srie */ 832*1618Srie *(Xword *)R2addr = value; 833*1618Srie continue; 834*1618Srie 835*1618Srie } else if (IS_GOT_BASED(arsp->rel_rtype) && 836*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) { 837*1618Srie value -= ofl->ofl_osgot->os_shdr->sh_addr; 838*1618Srie 839*1618Srie } else if (IS_GOT_PC(arsp->rel_rtype) && 840*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) { 841*1618Srie value = 842*1618Srie (Xword)(ofl->ofl_osgot->os_shdr->sh_addr) - 843*1618Srie refaddr; 844*1618Srie 845*1618Srie } else if ((IS_PC_RELATIVE(arsp->rel_rtype)) && 846*1618Srie (((flags & FLG_OF_RELOBJ) == 0) || 847*1618Srie (arsp->rel_osdesc == sdp->sd_isc->is_osdesc))) { 848*1618Srie value -= refaddr; 849*1618Srie 850*1618Srie } else if (IS_TLS_INS(arsp->rel_rtype) && 851*1618Srie IS_GOT_RELATIVE(arsp->rel_rtype) && 852*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) { 853*1618Srie Gotndx *gnp; 854*1618Srie 855*1618Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), gref, 856*1618Srie ofl, 0); 857*1618Srie assert(gnp); 858*1618Srie value = (Xword)gnp->gn_gotndx * M_GOT_ENTSIZE; 859*1618Srie if (arsp->rel_rtype == R_386_TLS_IE) { 860*1618Srie value += 861*1618Srie ofl->ofl_osgot->os_shdr->sh_addr; 862*1618Srie } 863*1618Srie 864*1618Srie } else if (IS_GOT_RELATIVE(arsp->rel_rtype) && 865*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) { 866*1618Srie Gotndx *gnp; 867*1618Srie 868*1618Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 869*1618Srie GOT_REF_GENERIC, ofl, 0); 870*1618Srie assert(gnp); 871*1618Srie value = (Xword)gnp->gn_gotndx * M_GOT_ENTSIZE; 872*1618Srie 873*1618Srie } else if ((arsp->rel_flags & FLG_REL_STLS) && 874*1618Srie ((flags & FLG_OF_RELOBJ) == 0)) { 875*1618Srie Xword tlsstatsize; 876*1618Srie 877*1618Srie /* 878*1618Srie * This is the LE TLS reference model. Static 879*1618Srie * offset is hard-coded. 880*1618Srie */ 881*1618Srie tlsstatsize = 882*1618Srie S_ROUND(ofl->ofl_tlsphdr->p_memsz, 883*1618Srie M_TLSSTATALIGN); 884*1618Srie value = tlsstatsize - value; 885*1618Srie 886*1618Srie /* 887*1618Srie * Since this code is fixed up, it assumes a 888*1618Srie * negative offset that can be added to the 889*1618Srie * thread pointer. 890*1618Srie */ 891*1618Srie if ((arsp->rel_rtype == R_386_TLS_LDO_32) || 892*1618Srie (arsp->rel_rtype == R_386_TLS_LE)) 893*1618Srie value = -value; 894*1618Srie } 895*1618Srie 896*1618Srie if (arsp->rel_isdesc->is_file) 897*1618Srie ifl_name = arsp->rel_isdesc->is_file->ifl_name; 898*1618Srie else 899*1618Srie ifl_name = MSG_INTL(MSG_STR_NULL); 900*1618Srie 901*1618Srie /* 902*1618Srie * Make sure we have data to relocate. Compiler and 903*1618Srie * assembler developers have been known to generate 904*1618Srie * relocations against invalid sections (normally .bss), 905*1618Srie * so for their benefit give them sufficient information 906*1618Srie * to help analyze the problem. End users should never 907*1618Srie * see this. 908*1618Srie */ 909*1618Srie if (arsp->rel_isdesc->is_indata->d_buf == 0) { 910*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, 911*1618Srie MSG_INTL(MSG_REL_EMPTYSEC), 912*1618Srie conv_reloc_386_type(arsp->rel_rtype), 913*1618Srie ifl_name, demangle(arsp->rel_sname), 914*1618Srie arsp->rel_isdesc->is_name); 915*1618Srie return (S_ERROR); 916*1618Srie } 917*1618Srie 918*1618Srie /* 919*1618Srie * Get the address of the data item we need to modify. 920*1618Srie */ 921*1618Srie addr = (uchar_t *)((uintptr_t)arsp->rel_roffset + 922*1618Srie (uintptr_t)_elf_getxoff(arsp->rel_isdesc-> 923*1618Srie is_indata)); 924*1618Srie 925*1618Srie DBG_CALL(Dbg_reloc_doact(ofl->ofl_lml, ELF_DBG_LD, 926*1618Srie M_MACH, SHT_REL, arsp->rel_rtype, EC_NATPTR(addr), 927*1618Srie value, arsp->rel_sname, arsp->rel_osdesc)); 928*1618Srie addr += (uintptr_t)arsp->rel_osdesc->os_outdata->d_buf; 929*1618Srie 930*1618Srie if ((((uintptr_t)addr - (uintptr_t)ofl->ofl_nehdr) > 931*1618Srie ofl->ofl_size) || (arsp->rel_roffset > 932*1618Srie arsp->rel_osdesc->os_shdr->sh_size)) { 933*1618Srie int class; 934*1618Srie 935*1618Srie if (((uintptr_t)addr - 936*1618Srie (uintptr_t)ofl->ofl_nehdr) > ofl->ofl_size) 937*1618Srie class = ERR_FATAL; 938*1618Srie else 939*1618Srie class = ERR_WARNING; 940*1618Srie 941*1618Srie eprintf(ofl->ofl_lml, class, 942*1618Srie MSG_INTL(MSG_REL_INVALOFFSET), 943*1618Srie conv_reloc_386_type(arsp->rel_rtype), 944*1618Srie ifl_name, arsp->rel_isdesc->is_name, 945*1618Srie demangle(arsp->rel_sname), 946*1618Srie EC_ADDR((uintptr_t)addr - 947*1618Srie (uintptr_t)ofl->ofl_nehdr)); 948*1618Srie 949*1618Srie if (class == ERR_FATAL) { 950*1618Srie return_code = S_ERROR; 951*1618Srie continue; 952*1618Srie } 953*1618Srie } 954*1618Srie 955*1618Srie /* 956*1618Srie * The relocation is additive. Ignore the previous 957*1618Srie * symbol value if this local partial symbol is 958*1618Srie * expanded. 959*1618Srie */ 960*1618Srie if (moved) 961*1618Srie value -= *addr; 962*1618Srie 963*1618Srie /* 964*1618Srie * If '-z noreloc' is specified - skip the do_reloc 965*1618Srie * stage. 966*1618Srie */ 967*1618Srie if ((flags & FLG_OF_RELOBJ) || 968*1618Srie !(dtflags1 & DF_1_NORELOC)) { 969*1618Srie if (do_reloc((uchar_t)arsp->rel_rtype, addr, 970*1618Srie &value, arsp->rel_sname, ifl_name, 971*1618Srie ofl->ofl_lml) == 0) 972*1618Srie return_code = S_ERROR; 973*1618Srie } 974*1618Srie } 975*1618Srie } 976*1618Srie return (return_code); 977*1618Srie } 978*1618Srie 979*1618Srie /* 980*1618Srie * Add an output relocation record. 981*1618Srie */ 982*1618Srie uintptr_t 983*1618Srie ld_add_outrel(Word flags, Rel_desc *rsp, Ofl_desc *ofl) 984*1618Srie { 985*1618Srie Rel_desc *orsp; 986*1618Srie Rel_cache *rcp; 987*1618Srie Sym_desc *sdp = rsp->rel_sym; 988*1618Srie 989*1618Srie /* 990*1618Srie * Static executables *do not* want any relocations against them. 991*1618Srie * Since our engine still creates relocations against a WEAK UNDEFINED 992*1618Srie * symbol in a static executable, it's best to disable them here 993*1618Srie * instead of through out the relocation code. 994*1618Srie */ 995*1618Srie if ((ofl->ofl_flags & (FLG_OF_STATIC | FLG_OF_EXEC)) == 996*1618Srie (FLG_OF_STATIC | FLG_OF_EXEC)) 997*1618Srie return (1); 998*1618Srie 999*1618Srie /* 1000*1618Srie * If no relocation cache structures are available allocate 1001*1618Srie * a new one and link it into the cache list. 1002*1618Srie */ 1003*1618Srie if ((ofl->ofl_outrels.tail == 0) || 1004*1618Srie ((rcp = (Rel_cache *)ofl->ofl_outrels.tail->data) == 0) || 1005*1618Srie ((orsp = rcp->rc_free) == rcp->rc_end)) { 1006*1618Srie static size_t nextsize = 0; 1007*1618Srie size_t size; 1008*1618Srie 1009*1618Srie /* 1010*1618Srie * Output relocation numbers can vary considerably between 1011*1618Srie * building executables or shared objects (pic vs. non-pic), 1012*1618Srie * etc. But, they typically aren't very large, so for these 1013*1618Srie * objects use a standard bucket size. For building relocatable 1014*1618Srie * objects, typically there will be an output relocation for 1015*1618Srie * every input relocation. 1016*1618Srie */ 1017*1618Srie if (nextsize == 0) { 1018*1618Srie if (ofl->ofl_flags & FLG_OF_RELOBJ) { 1019*1618Srie if ((size = ofl->ofl_relocincnt) == 0) 1020*1618Srie size = REL_LOIDESCNO; 1021*1618Srie if (size > REL_HOIDESCNO) 1022*1618Srie nextsize = REL_HOIDESCNO; 1023*1618Srie else 1024*1618Srie nextsize = REL_LOIDESCNO; 1025*1618Srie } else 1026*1618Srie nextsize = size = REL_HOIDESCNO; 1027*1618Srie } else 1028*1618Srie size = nextsize; 1029*1618Srie 1030*1618Srie size = size * sizeof (Rel_desc); 1031*1618Srie 1032*1618Srie if (((rcp = libld_malloc(sizeof (Rel_cache) + size)) == 0) || 1033*1618Srie (list_appendc(&ofl->ofl_outrels, rcp) == 0)) 1034*1618Srie return (S_ERROR); 1035*1618Srie 1036*1618Srie /* LINTED */ 1037*1618Srie rcp->rc_free = orsp = (Rel_desc *)(rcp + 1); 1038*1618Srie /* LINTED */ 1039*1618Srie rcp->rc_end = (Rel_desc *)((char *)rcp->rc_free + size); 1040*1618Srie } 1041*1618Srie 1042*1618Srie /* 1043*1618Srie * If we are adding a output relocation against a section 1044*1618Srie * symbol (non-RELATIVE) then mark that section. These sections 1045*1618Srie * will be added to the .dynsym symbol table. 1046*1618Srie */ 1047*1618Srie if (sdp && (rsp->rel_rtype != M_R_RELATIVE) && 1048*1618Srie ((flags & FLG_REL_SCNNDX) || 1049*1618Srie (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION))) { 1050*1618Srie 1051*1618Srie /* 1052*1618Srie * If this is a COMMON symbol - no output section 1053*1618Srie * exists yet - (it's created as part of sym_validate()). 1054*1618Srie * So - we mark here that when it's created it should 1055*1618Srie * be tagged with the FLG_OS_OUTREL flag. 1056*1618Srie */ 1057*1618Srie if ((sdp->sd_flags & FLG_SY_SPECSEC) && 1058*1618Srie (sdp->sd_shndx == SHN_COMMON)) { 1059*1618Srie if (ELF_ST_TYPE(sdp->sd_sym->st_info) != STT_TLS) 1060*1618Srie ofl->ofl_flags1 |= FLG_OF1_BSSOREL; 1061*1618Srie else 1062*1618Srie ofl->ofl_flags1 |= FLG_OF1_TLSOREL; 1063*1618Srie } else { 1064*1618Srie Os_desc *osp = sdp->sd_isc->is_osdesc; 1065*1618Srie 1066*1618Srie if ((osp->os_flags & FLG_OS_OUTREL) == 0) { 1067*1618Srie ofl->ofl_dynshdrcnt++; 1068*1618Srie osp->os_flags |= FLG_OS_OUTREL; 1069*1618Srie } 1070*1618Srie } 1071*1618Srie } 1072*1618Srie 1073*1618Srie *orsp = *rsp; 1074*1618Srie orsp->rel_flags |= flags; 1075*1618Srie 1076*1618Srie rcp->rc_free++; 1077*1618Srie ofl->ofl_outrelscnt++; 1078*1618Srie 1079*1618Srie if (flags & FLG_REL_GOT) 1080*1618Srie ofl->ofl_relocgotsz += (Xword)sizeof (Rel); 1081*1618Srie else if (flags & FLG_REL_PLT) 1082*1618Srie ofl->ofl_relocpltsz += (Xword)sizeof (Rel); 1083*1618Srie else if (flags & FLG_REL_BSS) 1084*1618Srie ofl->ofl_relocbsssz += (Xword)sizeof (Rel); 1085*1618Srie else if (flags & FLG_REL_NOINFO) 1086*1618Srie ofl->ofl_relocrelsz += (Xword)sizeof (Rel); 1087*1618Srie else 1088*1618Srie orsp->rel_osdesc->os_szoutrels += (Xword)sizeof (Rel); 1089*1618Srie 1090*1618Srie if (orsp->rel_rtype == M_R_RELATIVE) 1091*1618Srie ofl->ofl_relocrelcnt++; 1092*1618Srie 1093*1618Srie /* 1094*1618Srie * We don't perform sorting on PLT relocations because 1095*1618Srie * they have already been assigned a PLT index and if we 1096*1618Srie * were to sort them we would have to re-assign the plt indexes. 1097*1618Srie */ 1098*1618Srie if (!(flags & FLG_REL_PLT)) 1099*1618Srie ofl->ofl_reloccnt++; 1100*1618Srie 1101*1618Srie /* 1102*1618Srie * Insure a GLOBAL_OFFSET_TABLE is generated if required. 1103*1618Srie */ 1104*1618Srie if (IS_GOT_REQUIRED(orsp->rel_rtype)) 1105*1618Srie ofl->ofl_flags |= FLG_OF_BLDGOT; 1106*1618Srie 1107*1618Srie /* 1108*1618Srie * Identify and possibly warn of a displacement relocation. 1109*1618Srie */ 1110*1618Srie if (orsp->rel_flags & FLG_REL_DISP) { 1111*1618Srie ofl->ofl_dtflags_1 |= DF_1_DISPRELPND; 1112*1618Srie 1113*1618Srie if (ofl->ofl_flags & FLG_OF_VERBOSE) 1114*1618Srie ld_disp_errmsg(MSG_INTL(MSG_REL_DISPREL4), orsp, ofl); 1115*1618Srie } 1116*1618Srie DBG_CALL(Dbg_reloc_ors_entry(ofl->ofl_lml, ELF_DBG_LD, SHT_REL, 1117*1618Srie M_MACH, orsp)); 1118*1618Srie return (1); 1119*1618Srie } 1120*1618Srie 1121*1618Srie /* 1122*1618Srie * Stub routine since register symbols are not supported on i386. 1123*1618Srie */ 1124*1618Srie /* ARGSUSED */ 1125*1618Srie uintptr_t 1126*1618Srie ld_reloc_register(Rel_desc * rsp, Is_desc * isp, Ofl_desc * ofl) 1127*1618Srie { 1128*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_NOREG)); 1129*1618Srie return (S_ERROR); 1130*1618Srie } 1131*1618Srie 1132*1618Srie /* 1133*1618Srie * process relocation for a LOCAL symbol 1134*1618Srie */ 1135*1618Srie uintptr_t 1136*1618Srie ld_reloc_local(Rel_desc * rsp, Ofl_desc * ofl) 1137*1618Srie { 1138*1618Srie Word flags = ofl->ofl_flags; 1139*1618Srie Sym_desc *sdp = rsp->rel_sym; 1140*1618Srie Word shndx = rsp->rel_sym->sd_shndx; 1141*1618Srie 1142*1618Srie /* 1143*1618Srie * if ((shared object) and (not pc relative relocation) and 1144*1618Srie * (not against ABS symbol)) 1145*1618Srie * then 1146*1618Srie * build R_386_RELATIVE 1147*1618Srie * fi 1148*1618Srie */ 1149*1618Srie if ((flags & FLG_OF_SHAROBJ) && (rsp->rel_flags & FLG_REL_LOAD) && 1150*1618Srie !(IS_PC_RELATIVE(rsp->rel_rtype)) && 1151*1618Srie !(IS_GOT_BASED(rsp->rel_rtype)) && 1152*1618Srie !(rsp->rel_isdesc != NULL && 1153*1618Srie (rsp->rel_isdesc->is_shdr->sh_type == SHT_SUNW_dof)) && 1154*1618Srie (((sdp->sd_flags & FLG_SY_SPECSEC) == 0) || 1155*1618Srie (shndx != SHN_ABS) || (sdp->sd_aux && sdp->sd_aux->sa_symspec))) { 1156*1618Srie Word ortype = rsp->rel_rtype; 1157*1618Srie 1158*1618Srie rsp->rel_rtype = R_386_RELATIVE; 1159*1618Srie if (ld_add_outrel(NULL, rsp, ofl) == S_ERROR) 1160*1618Srie return (S_ERROR); 1161*1618Srie rsp->rel_rtype = ortype; 1162*1618Srie } 1163*1618Srie 1164*1618Srie /* 1165*1618Srie * If the relocation is against a 'non-allocatable' section 1166*1618Srie * and we can not resolve it now - then give a warning 1167*1618Srie * message. 1168*1618Srie * 1169*1618Srie * We can not resolve the symbol if either: 1170*1618Srie * a) it's undefined 1171*1618Srie * b) it's defined in a shared library and a 1172*1618Srie * COPY relocation hasn't moved it to the executable 1173*1618Srie * 1174*1618Srie * Note: because we process all of the relocations against the 1175*1618Srie * text segment before any others - we know whether 1176*1618Srie * or not a copy relocation will be generated before 1177*1618Srie * we get here (see reloc_init()->reloc_segments()). 1178*1618Srie */ 1179*1618Srie if (!(rsp->rel_flags & FLG_REL_LOAD) && 1180*1618Srie ((shndx == SHN_UNDEF) || 1181*1618Srie ((sdp->sd_ref == REF_DYN_NEED) && 1182*1618Srie ((sdp->sd_flags & FLG_SY_MVTOCOMM) == 0)))) { 1183*1618Srie /* 1184*1618Srie * If the relocation is against a SHT_SUNW_ANNOTATE 1185*1618Srie * section - then silently ignore that the relocation 1186*1618Srie * can not be resolved. 1187*1618Srie */ 1188*1618Srie if (rsp->rel_osdesc && 1189*1618Srie (rsp->rel_osdesc->os_shdr->sh_type == SHT_SUNW_ANNOTATE)) 1190*1618Srie return (0); 1191*1618Srie eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_REL_EXTERNSYM), 1192*1618Srie conv_reloc_386_type(rsp->rel_rtype), 1193*1618Srie rsp->rel_isdesc->is_file->ifl_name, 1194*1618Srie demangle(rsp->rel_sname), rsp->rel_osdesc->os_name); 1195*1618Srie return (1); 1196*1618Srie } 1197*1618Srie 1198*1618Srie /* 1199*1618Srie * Perform relocation. 1200*1618Srie */ 1201*1618Srie return (ld_add_actrel(NULL, rsp, ofl)); 1202*1618Srie } 1203*1618Srie 1204*1618Srie uintptr_t 1205*1618Srie /* ARGSUSED */ 1206*1618Srie ld_reloc_GOTOP(Boolean local, Rel_desc * rsp, Ofl_desc * ofl) 1207*1618Srie { 1208*1618Srie /* 1209*1618Srie * Stub routine for common code compatibility, we shouldn't 1210*1618Srie * actually get here on x86. 1211*1618Srie */ 1212*1618Srie assert(0); 1213*1618Srie return (S_ERROR); 1214*1618Srie } 1215*1618Srie 1216*1618Srie uintptr_t 1217*1618Srie ld_reloc_TLS(Boolean local, Rel_desc * rsp, Ofl_desc * ofl) 1218*1618Srie { 1219*1618Srie Word rtype = rsp->rel_rtype; 1220*1618Srie Sym_desc *sdp = rsp->rel_sym; 1221*1618Srie Word flags = ofl->ofl_flags; 1222*1618Srie Word rflags; 1223*1618Srie Gotndx *gnp; 1224*1618Srie 1225*1618Srie /* 1226*1618Srie * all TLS relocations are illegal in a static executable. 1227*1618Srie */ 1228*1618Srie if ((ofl->ofl_flags & (FLG_OF_STATIC | FLG_OF_EXEC)) == 1229*1618Srie (FLG_OF_STATIC | FLG_OF_EXEC)) { 1230*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_TLSSTAT), 1231*1618Srie conv_reloc_386_type(rsp->rel_rtype), 1232*1618Srie rsp->rel_isdesc->is_file->ifl_name, 1233*1618Srie demangle(rsp->rel_sname)); 1234*1618Srie return (S_ERROR); 1235*1618Srie } 1236*1618Srie 1237*1618Srie /* 1238*1618Srie * Any TLS relocation must be against a STT_TLS symbol, all others 1239*1618Srie * are illegal. 1240*1618Srie */ 1241*1618Srie if (ELF_ST_TYPE(sdp->sd_sym->st_info) != STT_TLS) { 1242*1618Srie Ifl_desc *ifl = rsp->rel_isdesc->is_file; 1243*1618Srie 1244*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_TLSBADSYM), 1245*1618Srie conv_reloc_386_type(rsp->rel_rtype), 1246*1618Srie ifl->ifl_name, demangle(rsp->rel_sname), 1247*1618Srie conv_sym_info_type(ifl->ifl_ehdr->e_machine, 1248*1618Srie ELF_ST_TYPE(sdp->sd_sym->st_info))); 1249*1618Srie return (S_ERROR); 1250*1618Srie } 1251*1618Srie 1252*1618Srie /* 1253*1618Srie * We're a executable - use either the IE or LE 1254*1618Srie * access model. 1255*1618Srie */ 1256*1618Srie if (flags & FLG_OF_EXEC) { 1257*1618Srie /* 1258*1618Srie * If we are using either IE or LE reference 1259*1618Srie * model set the DF_STATIC_TLS flag. 1260*1618Srie */ 1261*1618Srie ofl->ofl_dtflags |= DF_STATIC_TLS; 1262*1618Srie 1263*1618Srie if (!local) { 1264*1618Srie Gotref gref; 1265*1618Srie /* 1266*1618Srie * IE access model 1267*1618Srie */ 1268*1618Srie /* 1269*1618Srie * It's not possible for LD or LE reference 1270*1618Srie * models to reference a symbol external to 1271*1618Srie * the current object. 1272*1618Srie */ 1273*1618Srie if (IS_TLS_LD(rtype) || IS_TLS_LE(rtype)) { 1274*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, 1275*1618Srie MSG_INTL(MSG_REL_TLSBND), 1276*1618Srie conv_reloc_386_type(rsp->rel_rtype), 1277*1618Srie rsp->rel_isdesc->is_file->ifl_name, 1278*1618Srie demangle(rsp->rel_sname), 1279*1618Srie sdp->sd_file->ifl_name); 1280*1618Srie return (S_ERROR); 1281*1618Srie } 1282*1618Srie 1283*1618Srie gref = GOT_REF_TLSIE; 1284*1618Srie 1285*1618Srie /* 1286*1618Srie * Assign a GOT entry for static TLS references 1287*1618Srie */ 1288*1618Srie if ((gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 1289*1618Srie gref, ofl, 0)) == 0) { 1290*1618Srie if (ld_assign_gotndx(&(sdp->sd_GOTndxs), 1291*1618Srie gnp, gref, ofl, rsp, sdp) == S_ERROR) 1292*1618Srie return (S_ERROR); 1293*1618Srie rsp->rel_rtype = R_386_TLS_TPOFF; 1294*1618Srie if (ld_add_outrel((FLG_REL_GOT | FLG_REL_STLS), 1295*1618Srie rsp, ofl) == S_ERROR) 1296*1618Srie return (S_ERROR); 1297*1618Srie rsp->rel_rtype = rtype; 1298*1618Srie } 1299*1618Srie if (IS_TLS_IE(rtype)) 1300*1618Srie return (ld_add_actrel(FLG_REL_STLS, rsp, ofl)); 1301*1618Srie 1302*1618Srie /* 1303*1618Srie * If (GD or LD) reference models - fixups 1304*1618Srie * are required. 1305*1618Srie */ 1306*1618Srie return (ld_add_actrel((FLG_REL_TLSFIX | FLG_REL_STLS), 1307*1618Srie rsp, ofl)); 1308*1618Srie } 1309*1618Srie /* 1310*1618Srie * LE access model 1311*1618Srie */ 1312*1618Srie if (IS_TLS_LE(rtype) || (rtype == R_386_TLS_LDO_32)) 1313*1618Srie return (ld_add_actrel(FLG_REL_STLS, rsp, ofl)); 1314*1618Srie 1315*1618Srie return (ld_add_actrel((FLG_REL_TLSFIX | FLG_REL_STLS), 1316*1618Srie rsp, ofl)); 1317*1618Srie } 1318*1618Srie 1319*1618Srie /* 1320*1618Srie * Building a shared object 1321*1618Srie */ 1322*1618Srie 1323*1618Srie /* 1324*1618Srie * Building a shared object - only GD & LD access models 1325*1618Srie * will work here. 1326*1618Srie */ 1327*1618Srie if (IS_TLS_IE(rtype) || IS_TLS_LE(rtype)) { 1328*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_TLSIE), 1329*1618Srie conv_reloc_386_type(rsp->rel_rtype), 1330*1618Srie rsp->rel_isdesc->is_file->ifl_name, 1331*1618Srie demangle(rsp->rel_sname)); 1332*1618Srie return (S_ERROR); 1333*1618Srie } 1334*1618Srie 1335*1618Srie /* 1336*1618Srie * LD access mode can only bind to local symbols. 1337*1618Srie */ 1338*1618Srie if (!local && IS_TLS_LD(rtype)) { 1339*1618Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_TLSBND), 1340*1618Srie conv_reloc_386_type(rsp->rel_rtype), 1341*1618Srie rsp->rel_isdesc->is_file->ifl_name, 1342*1618Srie demangle(rsp->rel_sname), 1343*1618Srie sdp->sd_file->ifl_name); 1344*1618Srie return (S_ERROR); 1345*1618Srie } 1346*1618Srie 1347*1618Srie 1348*1618Srie if (IS_TLS_LD(rtype) && ((gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 1349*1618Srie GOT_REF_TLSLD, ofl, 0)) == 0)) { 1350*1618Srie if (ld_assign_gotndx(&(sdp->sd_GOTndxs), gnp, GOT_REF_TLSLD, 1351*1618Srie ofl, rsp, sdp) == S_ERROR) 1352*1618Srie return (S_ERROR); 1353*1618Srie rflags = FLG_REL_GOT | FLG_REL_MTLS; 1354*1618Srie if (local) 1355*1618Srie rflags |= FLG_REL_SCNNDX; 1356*1618Srie rsp->rel_rtype = R_386_TLS_DTPMOD32; 1357*1618Srie if (ld_add_outrel(rflags, rsp, ofl) == S_ERROR) 1358*1618Srie return (S_ERROR); 1359*1618Srie rsp->rel_rtype = rtype; 1360*1618Srie } else if (IS_TLS_GD(rtype) && 1361*1618Srie ((gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), GOT_REF_TLSGD, 1362*1618Srie ofl, 0)) == 0)) { 1363*1618Srie if (ld_assign_gotndx(&(sdp->sd_GOTndxs), gnp, GOT_REF_TLSGD, 1364*1618Srie ofl, rsp, sdp) == S_ERROR) 1365*1618Srie return (S_ERROR); 1366*1618Srie rflags = FLG_REL_GOT | FLG_REL_DTLS; 1367*1618Srie if (local) 1368*1618Srie rflags |= FLG_REL_SCNNDX; 1369*1618Srie rsp->rel_rtype = R_386_TLS_DTPMOD32; 1370*1618Srie if (ld_add_outrel(rflags, rsp, ofl) == S_ERROR) 1371*1618Srie return (S_ERROR); 1372*1618Srie if (local == TRUE) { 1373*1618Srie rsp->rel_rtype = R_386_TLS_DTPOFF32; 1374*1618Srie if (ld_add_actrel((FLG_REL_GOT | FLG_REL_DTLS), rsp, 1375*1618Srie ofl) == S_ERROR) 1376*1618Srie return (S_ERROR); 1377*1618Srie } else { 1378*1618Srie rsp->rel_rtype = R_386_TLS_DTPOFF32; 1379*1618Srie if (ld_add_outrel((FLG_REL_GOT | FLG_REL_DTLS), rsp, 1380*1618Srie ofl) == S_ERROR) 1381*1618Srie return (S_ERROR); 1382*1618Srie } 1383*1618Srie rsp->rel_rtype = rtype; 1384*1618Srie } 1385*1618Srie /* 1386*1618Srie * For GD/LD TLS reference - TLS_{GD,LD}_CALL, this will eventually 1387*1618Srie * cause a call to __tls_get_addr(). Let's convert this 1388*1618Srie * relocation to that symbol now, and prepare for the PLT magic. 1389*1618Srie */ 1390*1618Srie if ((rtype == R_386_TLS_GD_PLT) || (rtype == R_386_TLS_LDM_PLT)) { 1391*1618Srie Sym_desc * tlsgetsym; 1392*1618Srie 1393*1618Srie if ((tlsgetsym = ld_sym_add_u(MSG_ORIG(MSG_SYM_TLSGETADDR_UU), 1394*1618Srie ofl)) == (Sym_desc *)S_ERROR) 1395*1618Srie return (S_ERROR); 1396*1618Srie rsp->rel_sym = tlsgetsym; 1397*1618Srie rsp->rel_sname = tlsgetsym->sd_name; 1398*1618Srie rsp->rel_rtype = R_386_PLT32; 1399*1618Srie if (ld_reloc_plt(rsp, ofl) == S_ERROR) 1400*1618Srie return (S_ERROR); 1401*1618Srie rsp->rel_sym = sdp; 1402*1618Srie rsp->rel_sname = sdp->sd_name; 1403*1618Srie rsp->rel_rtype = rtype; 1404*1618Srie return (1); 1405*1618Srie } 1406*1618Srie 1407*1618Srie if (IS_TLS_LD(rtype)) 1408*1618Srie return (ld_add_actrel(FLG_REL_MTLS, rsp, ofl)); 1409*1618Srie 1410*1618Srie return (ld_add_actrel(FLG_REL_DTLS, rsp, ofl)); 1411*1618Srie } 1412*1618Srie 1413*1618Srie /* ARGSUSED3 */ 1414*1618Srie Gotndx * 1415*1618Srie ld_find_gotndx(List * lst, Gotref gref, Ofl_desc * ofl, Rel_desc * rdesc) 1416*1618Srie { 1417*1618Srie Listnode * lnp; 1418*1618Srie Gotndx * gnp; 1419*1618Srie 1420*1618Srie if ((gref == GOT_REF_TLSLD) && ofl->ofl_tlsldgotndx) 1421*1618Srie return (ofl->ofl_tlsldgotndx); 1422*1618Srie 1423*1618Srie for (LIST_TRAVERSE(lst, lnp, gnp)) { 1424*1618Srie if (gnp->gn_gotref == gref) 1425*1618Srie return (gnp); 1426*1618Srie } 1427*1618Srie return ((Gotndx *)0); 1428*1618Srie } 1429*1618Srie 1430*1618Srie Xword 1431*1618Srie ld_calc_got_offset(Rel_desc * rdesc, Ofl_desc * ofl) 1432*1618Srie { 1433*1618Srie Os_desc *osp = ofl->ofl_osgot; 1434*1618Srie Sym_desc *sdp = rdesc->rel_sym; 1435*1618Srie Xword gotndx; 1436*1618Srie Gotref gref; 1437*1618Srie Gotndx *gnp; 1438*1618Srie 1439*1618Srie if (rdesc->rel_flags & FLG_REL_DTLS) 1440*1618Srie gref = GOT_REF_TLSGD; 1441*1618Srie else if (rdesc->rel_flags & FLG_REL_MTLS) 1442*1618Srie gref = GOT_REF_TLSLD; 1443*1618Srie else if (rdesc->rel_flags & FLG_REL_STLS) 1444*1618Srie gref = GOT_REF_TLSIE; 1445*1618Srie else 1446*1618Srie gref = GOT_REF_GENERIC; 1447*1618Srie 1448*1618Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), gref, ofl, 0); 1449*1618Srie assert(gnp); 1450*1618Srie 1451*1618Srie gotndx = (Xword)gnp->gn_gotndx; 1452*1618Srie 1453*1618Srie if ((rdesc->rel_flags & FLG_REL_DTLS) && 1454*1618Srie (rdesc->rel_rtype == R_386_TLS_DTPOFF32)) 1455*1618Srie gotndx++; 1456*1618Srie 1457*1618Srie return ((Xword)(osp->os_shdr->sh_addr + (gotndx * M_GOT_ENTSIZE))); 1458*1618Srie } 1459*1618Srie 1460*1618Srie 1461*1618Srie /* ARGSUSED4 */ 1462*1618Srie uintptr_t 1463*1618Srie ld_assign_gotndx(List * lst, Gotndx * pgnp, Gotref gref, Ofl_desc * ofl, 1464*1618Srie Rel_desc * rsp, Sym_desc * sdp) 1465*1618Srie { 1466*1618Srie Gotndx *gnp; 1467*1618Srie uint_t gotents; 1468*1618Srie 1469*1618Srie if (pgnp) 1470*1618Srie return (1); 1471*1618Srie 1472*1618Srie if ((gref == GOT_REF_TLSGD) || (gref == GOT_REF_TLSLD)) 1473*1618Srie gotents = 2; 1474*1618Srie else 1475*1618Srie gotents = 1; 1476*1618Srie 1477*1618Srie if ((gnp = libld_calloc(sizeof (Gotndx), 1)) == 0) 1478*1618Srie return (S_ERROR); 1479*1618Srie gnp->gn_gotndx = ofl->ofl_gotcnt; 1480*1618Srie gnp->gn_gotref = gref; 1481*1618Srie 1482*1618Srie ofl->ofl_gotcnt += gotents; 1483*1618Srie 1484*1618Srie if (gref == GOT_REF_TLSLD) { 1485*1618Srie ofl->ofl_tlsldgotndx = gnp; 1486*1618Srie return (1); 1487*1618Srie } 1488*1618Srie 1489*1618Srie if (list_appendc(lst, (void *)gnp) == 0) 1490*1618Srie return (S_ERROR); 1491*1618Srie 1492*1618Srie return (1); 1493*1618Srie } 1494*1618Srie 1495*1618Srie void 1496*1618Srie ld_assign_plt_ndx(Sym_desc * sdp, Ofl_desc *ofl) 1497*1618Srie { 1498*1618Srie sdp->sd_aux->sa_PLTndx = 1 + ofl->ofl_pltcnt++; 1499*1618Srie sdp->sd_aux->sa_PLTGOTndx = ofl->ofl_gotcnt++; 1500*1618Srie ofl->ofl_flags |= FLG_OF_BLDGOT; 1501*1618Srie } 1502*1618Srie 1503*1618Srie /* 1504*1618Srie * Initializes .got[0] with the _DYNAMIC symbol value. 1505*1618Srie */ 1506*1618Srie uintptr_t 1507*1618Srie ld_fillin_gotplt(Ofl_desc * ofl) 1508*1618Srie { 1509*1618Srie if (ofl->ofl_osgot) { 1510*1618Srie Sym_desc * sdp; 1511*1618Srie 1512*1618Srie if ((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_DYNAMIC_U), 1513*1618Srie SYM_NOHASH, 0, ofl)) != NULL) { 1514*1618Srie uchar_t *genptr = ((uchar_t *) 1515*1618Srie ofl->ofl_osgot->os_outdata->d_buf + 1516*1618Srie (M_GOT_XDYNAMIC * M_GOT_ENTSIZE)); 1517*1618Srie /* LINTED */ 1518*1618Srie *(Word *)genptr = (Word)sdp->sd_sym->st_value; 1519*1618Srie } 1520*1618Srie } 1521*1618Srie 1522*1618Srie /* 1523*1618Srie * Fill in the reserved slot in the procedure linkage table the first 1524*1618Srie * entry is: 1525*1618Srie * if (building a.out) { 1526*1618Srie * PUSHL got[1] # the address of the link map entry 1527*1618Srie * JMP * got[2] # the address of rtbinder 1528*1618Srie * } else { 1529*1618Srie * PUSHL got[1]@GOT(%ebx) # the address of the link map entry 1530*1618Srie * JMP * got[2]@GOT(%ebx) # the address of rtbinder 1531*1618Srie * } 1532*1618Srie */ 1533*1618Srie if ((ofl->ofl_flags & FLG_OF_DYNAMIC) && ofl->ofl_osplt) { 1534*1618Srie uchar_t *pltent; 1535*1618Srie 1536*1618Srie pltent = (uchar_t *)ofl->ofl_osplt->os_outdata->d_buf; 1537*1618Srie if (!(ofl->ofl_flags & FLG_OF_SHAROBJ)) { 1538*1618Srie pltent[0] = M_SPECIAL_INST; 1539*1618Srie pltent[1] = M_PUSHL_DISP; 1540*1618Srie pltent += 2; 1541*1618Srie /* LINTED */ 1542*1618Srie *(Word *)pltent = (Word)(ofl->ofl_osgot->os_shdr-> 1543*1618Srie sh_addr + M_GOT_XLINKMAP * M_GOT_ENTSIZE); 1544*1618Srie pltent += 4; 1545*1618Srie pltent[0] = M_SPECIAL_INST; 1546*1618Srie pltent[1] = M_JMP_DISP_IND; 1547*1618Srie pltent += 2; 1548*1618Srie /* LINTED */ 1549*1618Srie *(Word *)pltent = (Word)(ofl->ofl_osgot->os_shdr-> 1550*1618Srie sh_addr + M_GOT_XRTLD * M_GOT_ENTSIZE); 1551*1618Srie } else { 1552*1618Srie pltent[0] = M_SPECIAL_INST; 1553*1618Srie pltent[1] = M_PUSHL_REG_DISP; 1554*1618Srie pltent += 2; 1555*1618Srie /* LINTED */ 1556*1618Srie *(Word *)pltent = (Word)(M_GOT_XLINKMAP * 1557*1618Srie M_GOT_ENTSIZE); 1558*1618Srie pltent += 4; 1559*1618Srie pltent[0] = M_SPECIAL_INST; 1560*1618Srie pltent[1] = M_JMP_REG_DISP_IND; 1561*1618Srie pltent += 2; 1562*1618Srie /* LINTED */ 1563*1618Srie *(Word *)pltent = (Word)(M_GOT_XRTLD * 1564*1618Srie M_GOT_ENTSIZE); 1565*1618Srie } 1566*1618Srie } 1567*1618Srie return (1); 1568*1618Srie } 1569