17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21141040e8Srie 227c478bd9Sstevel@tonic-gate /* 23*ba2be530Sab * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24b3fbe5e6Sseizo * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 28*ba2be530Sab /* Get the x86 version of the relocation engine */ 29*ba2be530Sab #define DO_RELOC_LIBLD_X86 30*ba2be530Sab 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 337c478bd9Sstevel@tonic-gate #include <strings.h> 347c478bd9Sstevel@tonic-gate #include <sys/elf_amd64.h> 357c478bd9Sstevel@tonic-gate #include <debug.h> 367c478bd9Sstevel@tonic-gate #include <reloc.h> 37*ba2be530Sab #include <i386/machdep_x86.h> 385aefb655Srie #include "msg.h" 395aefb655Srie #include "_libld.h" 40*ba2be530Sab #include "unwind.amd.h" 41*ba2be530Sab 42*ba2be530Sab 43*ba2be530Sab /* Forward declarations */ 44*ba2be530Sab static Gotndx *ld_find_gotndx(List *, Gotref, Ofl_desc *, Rel_desc *); 45*ba2be530Sab static Xword ld_calc_got_offset(Rel_desc *, Ofl_desc *); 467c478bd9Sstevel@tonic-gate 47*ba2be530Sab 48*ba2be530Sab static Word 495aefb655Srie ld_init_rel(Rel_desc *reld, void *reloc) 507c478bd9Sstevel@tonic-gate { 517c478bd9Sstevel@tonic-gate Rela * rel = (Rela *)reloc; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* LINTED */ 54*ba2be530Sab reld->rel_rtype = (Word)ELF_R_TYPE(rel->r_info, M_MACH); 557c478bd9Sstevel@tonic-gate reld->rel_roffset = rel->r_offset; 567c478bd9Sstevel@tonic-gate reld->rel_raddend = rel->r_addend; 577c478bd9Sstevel@tonic-gate reld->rel_typedata = 0; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate reld->rel_flags |= FLG_REL_RELA; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate return ((Word)ELF_R_SYM(rel->r_info)); 627c478bd9Sstevel@tonic-gate } 637c478bd9Sstevel@tonic-gate 64*ba2be530Sab static void 655aefb655Srie ld_mach_eflags(Ehdr *ehdr, Ofl_desc *ofl) 667c478bd9Sstevel@tonic-gate { 675aefb655Srie ofl->ofl_dehdr->e_flags |= ehdr->e_flags; 687c478bd9Sstevel@tonic-gate } 697c478bd9Sstevel@tonic-gate 70*ba2be530Sab static void 715aefb655Srie ld_mach_make_dynamic(Ofl_desc *ofl, size_t *cnt) 727c478bd9Sstevel@tonic-gate { 737c478bd9Sstevel@tonic-gate if (!(ofl->ofl_flags & FLG_OF_RELOBJ)) { 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * Create this entry if we are going to create a PLT table. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate if (ofl->ofl_pltcnt) 787c478bd9Sstevel@tonic-gate (*cnt)++; /* DT_PLTGOT */ 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 82*ba2be530Sab static void 835aefb655Srie ld_mach_update_odynamic(Ofl_desc *ofl, Dyn **dyn) 847c478bd9Sstevel@tonic-gate { 855aefb655Srie if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) && ofl->ofl_pltcnt) { 865aefb655Srie (*dyn)->d_tag = DT_PLTGOT; 875aefb655Srie if (ofl->ofl_osgot) 885aefb655Srie (*dyn)->d_un.d_ptr = ofl->ofl_osgot->os_shdr->sh_addr; 895aefb655Srie else 905aefb655Srie (*dyn)->d_un.d_ptr = 0; 915aefb655Srie (*dyn)++; 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 95*ba2be530Sab static Xword 965aefb655Srie ld_calc_plt_addr(Sym_desc *sdp, Ofl_desc *ofl) 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate Xword value; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate value = (Xword)(ofl->ofl_osplt->os_shdr->sh_addr) + 1017c478bd9Sstevel@tonic-gate M_PLT_RESERVSZ + ((sdp->sd_aux->sa_PLTndx - 1) * M_PLT_ENTSIZE); 1027c478bd9Sstevel@tonic-gate return (value); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * Build a single plt entry - code is: 1077c478bd9Sstevel@tonic-gate * JMP *name1@GOTPCREL(%rip) 1087c478bd9Sstevel@tonic-gate * PUSHL $index 1097c478bd9Sstevel@tonic-gate * JMP .PLT0 1107c478bd9Sstevel@tonic-gate */ 111b3fbe5e6Sseizo static uchar_t pltn_entry[M_PLT_ENTSIZE] = { 1127c478bd9Sstevel@tonic-gate /* 0x00 jmpq *name1@GOTPCREL(%rip) */ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 1137c478bd9Sstevel@tonic-gate /* 0x06 pushq $index */ 0x68, 0x00, 0x00, 0x00, 0x00, 1147c478bd9Sstevel@tonic-gate /* 0x0b jmpq .plt0(%rip) */ 0xe9, 0x00, 0x00, 0x00, 0x00 1157c478bd9Sstevel@tonic-gate /* 0x10 */ 1167c478bd9Sstevel@tonic-gate }; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static uintptr_t 1197c478bd9Sstevel@tonic-gate plt_entry(Ofl_desc * ofl, Sym_desc * sdp) 1207c478bd9Sstevel@tonic-gate { 121b3fbe5e6Sseizo uchar_t *plt0, *pltent, *gotent; 1227c478bd9Sstevel@tonic-gate Sword plt_off; 1237c478bd9Sstevel@tonic-gate Word got_off; 1247c478bd9Sstevel@tonic-gate Xword val1; 125*ba2be530Sab int bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate got_off = sdp->sd_aux->sa_PLTGOTndx * M_GOT_ENTSIZE; 1287c478bd9Sstevel@tonic-gate plt_off = M_PLT_RESERVSZ + ((sdp->sd_aux->sa_PLTndx - 1) * 1297c478bd9Sstevel@tonic-gate M_PLT_ENTSIZE); 130b3fbe5e6Sseizo plt0 = (uchar_t *)(ofl->ofl_osplt->os_outdata->d_buf); 1317c478bd9Sstevel@tonic-gate pltent = plt0 + plt_off; 132b3fbe5e6Sseizo gotent = (uchar_t *)(ofl->ofl_osgot->os_outdata->d_buf) + got_off; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate bcopy(pltn_entry, pltent, sizeof (pltn_entry)); 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * Fill in the got entry with the address of the next instruction. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate /* LINTED */ 139b3fbe5e6Sseizo *(Word *)gotent = ofl->ofl_osplt->os_shdr->sh_addr + plt_off + 140b3fbe5e6Sseizo M_PLT_INSSIZE; 141*ba2be530Sab if (bswap) 142*ba2be530Sab /* LINTED */ 143*ba2be530Sab *(Word *)gotent = ld_bswap_Word(*(Word *)gotent); 1447c478bd9Sstevel@tonic-gate 145f3324781Sab /* 146f3324781Sab * If '-z noreloc' is specified - skip the do_reloc_ld 147f3324781Sab * stage. 148f3324781Sab */ 149f3324781Sab if (!OFL_DO_RELOC(ofl)) 150f3324781Sab return (1); 151f3324781Sab 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * patchup: 1547c478bd9Sstevel@tonic-gate * jmpq *name1@gotpcrel(%rip) 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * NOTE: 0x06 represents next instruction. 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate val1 = (ofl->ofl_osgot->os_shdr->sh_addr + got_off) - 159de777a60Sab (ofl->ofl_osplt->os_shdr->sh_addr + plt_off) - 0x06; 1607c478bd9Sstevel@tonic-gate 161f3324781Sab if (do_reloc_ld(R_AMD64_GOTPCREL, &pltent[0x02], 162f3324781Sab &val1, MSG_ORIG(MSG_SYM_PLTENT), 163f3324781Sab MSG_ORIG(MSG_SPECFIL_PLTENT), bswap, ofl->ofl_lml) == 0) { 164f3324781Sab eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_PLT_PLTNFAIL), 165f3324781Sab sdp->sd_aux->sa_PLTndx, demangle(sdp->sd_name)); 166f3324781Sab return (S_ERROR); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * patchup: 1717c478bd9Sstevel@tonic-gate * pushq $pltndx 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate val1 = (Xword)(sdp->sd_aux->sa_PLTndx - 1); 174f3324781Sab 175f3324781Sab if (do_reloc_ld(R_AMD64_32, &pltent[0x07], 176f3324781Sab &val1, MSG_ORIG(MSG_SYM_PLTENT), 177f3324781Sab MSG_ORIG(MSG_SPECFIL_PLTENT), bswap, ofl->ofl_lml) == 0) { 178f3324781Sab eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_PLT_PLTNFAIL), 179f3324781Sab sdp->sd_aux->sa_PLTndx, demangle(sdp->sd_name)); 180f3324781Sab return (S_ERROR); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * patchup: 1857c478bd9Sstevel@tonic-gate * jmpq .plt0(%rip) 186f3324781Sab * NOTE: 0x10 represents next instruction. The rather complex 187f3324781Sab * series of casts is necessary to sign extend an offset into 188f3324781Sab * a 64-bit value while satisfying various compiler error 189f3324781Sab * checks. Handle with care. 1907c478bd9Sstevel@tonic-gate */ 191b3fbe5e6Sseizo val1 = (Xword)((intptr_t)((uintptr_t)plt0 - 192b3fbe5e6Sseizo (uintptr_t)(&pltent[0x10]))); 193b3fbe5e6Sseizo 194f3324781Sab if (do_reloc_ld(R_AMD64_PC32, &pltent[0x0c], 195f3324781Sab &val1, MSG_ORIG(MSG_SYM_PLTENT), 196f3324781Sab MSG_ORIG(MSG_SPECFIL_PLTENT), bswap, ofl->ofl_lml) == 0) { 197f3324781Sab eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_PLT_PLTNFAIL), 198f3324781Sab sdp->sd_aux->sa_PLTndx, demangle(sdp->sd_name)); 199f3324781Sab return (S_ERROR); 2007c478bd9Sstevel@tonic-gate } 201f3324781Sab 2027c478bd9Sstevel@tonic-gate return (1); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 205*ba2be530Sab static uintptr_t 2065aefb655Srie ld_perform_outreloc(Rel_desc * orsp, Ofl_desc * ofl) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate Os_desc * relosp, * osp = 0; 2097c478bd9Sstevel@tonic-gate Word ndx; 2107c478bd9Sstevel@tonic-gate Xword roffset, value; 2117c478bd9Sstevel@tonic-gate Sxword raddend; 2127c478bd9Sstevel@tonic-gate Rela rea; 2137c478bd9Sstevel@tonic-gate char *relbits; 2147c478bd9Sstevel@tonic-gate Sym_desc * sdp, * psym = (Sym_desc *)0; 2157c478bd9Sstevel@tonic-gate int sectmoved = 0; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate raddend = orsp->rel_raddend; 2187c478bd9Sstevel@tonic-gate sdp = orsp->rel_sym; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* 2217c478bd9Sstevel@tonic-gate * If the section this relocation is against has been discarded 2227c478bd9Sstevel@tonic-gate * (-zignore), then also discard (skip) the relocation itself. 2237c478bd9Sstevel@tonic-gate */ 2247c478bd9Sstevel@tonic-gate if (orsp->rel_isdesc && ((orsp->rel_flags & 2257c478bd9Sstevel@tonic-gate (FLG_REL_GOT | FLG_REL_BSS | FLG_REL_PLT | FLG_REL_NOINFO)) == 0) && 2267c478bd9Sstevel@tonic-gate (orsp->rel_isdesc->is_flags & FLG_IS_DISCARD)) { 2275aefb655Srie DBG_CALL(Dbg_reloc_discard(ofl->ofl_lml, M_MACH, orsp)); 2287c478bd9Sstevel@tonic-gate return (1); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * If this is a relocation against a move table, or expanded move 2337c478bd9Sstevel@tonic-gate * table, adjust the relocation entries. 2347c478bd9Sstevel@tonic-gate */ 2357c478bd9Sstevel@tonic-gate if (orsp->rel_move) 2365aefb655Srie ld_adj_movereloc(ofl, orsp); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * If this is a relocation against a section then we need to adjust the 2407c478bd9Sstevel@tonic-gate * raddend field to compensate for the new position of the input section 2417c478bd9Sstevel@tonic-gate * within the new output section. 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate if (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) { 2447c478bd9Sstevel@tonic-gate if (ofl->ofl_parsym.head && 2457c478bd9Sstevel@tonic-gate (sdp->sd_isc->is_flags & FLG_IS_RELUPD) && 2467c478bd9Sstevel@tonic-gate /* LINTED */ 2475aefb655Srie (psym = ld_am_I_partial(orsp, orsp->rel_raddend))) { 2485aefb655Srie DBG_CALL(Dbg_move_outsctadj(ofl->ofl_lml, psym)); 2497c478bd9Sstevel@tonic-gate sectmoved = 1; 2507c478bd9Sstevel@tonic-gate if (ofl->ofl_flags & FLG_OF_RELOBJ) 2517c478bd9Sstevel@tonic-gate raddend = psym->sd_sym->st_value; 2527c478bd9Sstevel@tonic-gate else 2537c478bd9Sstevel@tonic-gate raddend = psym->sd_sym->st_value - 2547c478bd9Sstevel@tonic-gate psym->sd_isc->is_osdesc->os_shdr->sh_addr; 2557c478bd9Sstevel@tonic-gate /* LINTED */ 2567c478bd9Sstevel@tonic-gate raddend += (Off)_elf_getxoff(psym->sd_isc->is_indata); 2577c478bd9Sstevel@tonic-gate if (psym->sd_isc->is_shdr->sh_flags & SHF_ALLOC) 2587c478bd9Sstevel@tonic-gate raddend += 259de777a60Sab psym->sd_isc->is_osdesc->os_shdr->sh_addr; 2607c478bd9Sstevel@tonic-gate } else { 2617c478bd9Sstevel@tonic-gate /* LINTED */ 2627c478bd9Sstevel@tonic-gate raddend += (Off)_elf_getxoff(sdp->sd_isc->is_indata); 2637c478bd9Sstevel@tonic-gate if (sdp->sd_isc->is_shdr->sh_flags & SHF_ALLOC) 2647c478bd9Sstevel@tonic-gate raddend += 265de777a60Sab sdp->sd_isc->is_osdesc->os_shdr->sh_addr; 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate value = sdp->sd_sym->st_value; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (orsp->rel_flags & FLG_REL_GOT) { 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * Note: for GOT relative relocations on amd64 2747c478bd9Sstevel@tonic-gate * we discard the addend. It was relevant 2757c478bd9Sstevel@tonic-gate * to the reference - not to the data item 2767c478bd9Sstevel@tonic-gate * being referenced (ie: that -4 thing). 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate raddend = 0; 2797c478bd9Sstevel@tonic-gate osp = ofl->ofl_osgot; 2805aefb655Srie roffset = ld_calc_got_offset(orsp, ofl); 2815aefb655Srie 2827c478bd9Sstevel@tonic-gate } else if (orsp->rel_flags & FLG_REL_PLT) { 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * Note that relocations for PLT's actually 2857c478bd9Sstevel@tonic-gate * cause a relocation againt the GOT. 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate osp = ofl->ofl_osplt; 2887c478bd9Sstevel@tonic-gate roffset = (ofl->ofl_osgot->os_shdr->sh_addr) + 2897c478bd9Sstevel@tonic-gate sdp->sd_aux->sa_PLTGOTndx * M_GOT_ENTSIZE; 2907c478bd9Sstevel@tonic-gate raddend = 0; 2917c478bd9Sstevel@tonic-gate if (plt_entry(ofl, sdp) == S_ERROR) 2927c478bd9Sstevel@tonic-gate return (S_ERROR); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate } else if (orsp->rel_flags & FLG_REL_BSS) { 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * This must be a R_AMD64_COPY. For these set the roffset to 2977c478bd9Sstevel@tonic-gate * point to the new symbols location. 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate osp = ofl->ofl_isbss->is_osdesc; 3007c478bd9Sstevel@tonic-gate roffset = value; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * The raddend doesn't mean anything in a R_SPARC_COPY 3047c478bd9Sstevel@tonic-gate * relocation. Null it out because it can confuse people. 3057c478bd9Sstevel@tonic-gate */ 3067c478bd9Sstevel@tonic-gate raddend = 0; 3077c478bd9Sstevel@tonic-gate } else { 3087c478bd9Sstevel@tonic-gate osp = orsp->rel_osdesc; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Calculate virtual offset of reference point; equals offset 3127c478bd9Sstevel@tonic-gate * into section + vaddr of section for loadable sections, or 3137c478bd9Sstevel@tonic-gate * offset plus section displacement for nonloadable sections. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate roffset = orsp->rel_roffset + 3167c478bd9Sstevel@tonic-gate (Off)_elf_getxoff(orsp->rel_isdesc->is_indata); 3177c478bd9Sstevel@tonic-gate if (!(ofl->ofl_flags & FLG_OF_RELOBJ)) 3187c478bd9Sstevel@tonic-gate roffset += orsp->rel_isdesc->is_osdesc-> 3197c478bd9Sstevel@tonic-gate os_shdr->sh_addr; 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate if ((osp == 0) || ((relosp = osp->os_relosdesc) == 0)) 3237c478bd9Sstevel@tonic-gate relosp = ofl->ofl_osrel; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Assign the symbols index for the output relocation. If the 3277c478bd9Sstevel@tonic-gate * relocation refers to a SECTION symbol then it's index is based upon 3287c478bd9Sstevel@tonic-gate * the output sections symbols index. Otherwise the index can be 3297c478bd9Sstevel@tonic-gate * derived from the symbols index itself. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate if (orsp->rel_rtype == R_AMD64_RELATIVE) 3327c478bd9Sstevel@tonic-gate ndx = STN_UNDEF; 3337c478bd9Sstevel@tonic-gate else if ((orsp->rel_flags & FLG_REL_SCNNDX) || 3347c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION)) { 3357c478bd9Sstevel@tonic-gate if (sectmoved == 0) { 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * Check for a null input section. This can 3387c478bd9Sstevel@tonic-gate * occur if this relocation references a symbol 3397c478bd9Sstevel@tonic-gate * generated by sym_add_sym(). 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate if ((sdp->sd_isc != 0) && 3427c478bd9Sstevel@tonic-gate (sdp->sd_isc->is_osdesc != 0)) 3437c478bd9Sstevel@tonic-gate ndx = sdp->sd_isc->is_osdesc->os_scnsymndx; 3447c478bd9Sstevel@tonic-gate else 3457c478bd9Sstevel@tonic-gate ndx = sdp->sd_shndx; 3467c478bd9Sstevel@tonic-gate } else 3477c478bd9Sstevel@tonic-gate ndx = ofl->ofl_sunwdata1ndx; 3487c478bd9Sstevel@tonic-gate } else 3497c478bd9Sstevel@tonic-gate ndx = sdp->sd_symndx; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Add the symbols 'value' to the addend field. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if (orsp->rel_flags & FLG_REL_ADVAL) 3557c478bd9Sstevel@tonic-gate raddend += value; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* 3587010c12aSrie * The addend field for R_AMD64_DTPMOD64 means nothing. The addend 3597010c12aSrie * is propagated in the corresponding R_AMD64_DTPOFF64 relocation. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate if (orsp->rel_rtype == R_AMD64_DTPMOD64) 3627c478bd9Sstevel@tonic-gate raddend = 0; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate relbits = (char *)relosp->os_outdata->d_buf; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate rea.r_info = ELF_R_INFO(ndx, orsp->rel_rtype); 3677c478bd9Sstevel@tonic-gate rea.r_offset = roffset; 3687c478bd9Sstevel@tonic-gate rea.r_addend = raddend; 3695aefb655Srie DBG_CALL(Dbg_reloc_out(ofl, ELF_DBG_LD, SHT_RELA, &rea, relosp->os_name, 3705aefb655Srie orsp->rel_sname)); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Assert we haven't walked off the end of our relocation table. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate assert(relosp->os_szoutrels <= relosp->os_shdr->sh_size); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate (void) memcpy((relbits + relosp->os_szoutrels), 3787c478bd9Sstevel@tonic-gate (char *)&rea, sizeof (Rela)); 3797c478bd9Sstevel@tonic-gate relosp->os_szoutrels += (Xword)sizeof (Rela); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Determine if this relocation is against a non-writable, allocatable 3837c478bd9Sstevel@tonic-gate * section. If so we may need to provide a text relocation diagnostic. 3847c478bd9Sstevel@tonic-gate * Note that relocations against the .plt (R_AMD64_JUMP_SLOT) actually 3857c478bd9Sstevel@tonic-gate * result in modifications to the .got. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate if (orsp->rel_rtype == R_AMD64_JUMP_SLOT) 3887c478bd9Sstevel@tonic-gate osp = ofl->ofl_osgot; 3897c478bd9Sstevel@tonic-gate 3905aefb655Srie ld_reloc_remain_entry(orsp, osp, ofl); 3917c478bd9Sstevel@tonic-gate return (1); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * amd64 Instructions for TLS processing 3967c478bd9Sstevel@tonic-gate */ 397b3fbe5e6Sseizo static uchar_t tlsinstr_gd_ie[] = { 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * 0x00 movq %fs:0, %rax 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate 0x64, 0x48, 0x8b, 0x04, 0x25, 4027c478bd9Sstevel@tonic-gate 0x00, 0x00, 0x00, 0x00, 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * 0x09 addq x@gottpoff(%rip), %rax 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate 0x48, 0x03, 0x05, 0x00, 0x00, 4077c478bd9Sstevel@tonic-gate 0x00, 0x00 4087c478bd9Sstevel@tonic-gate }; 4097c478bd9Sstevel@tonic-gate 410b3fbe5e6Sseizo static uchar_t tlsinstr_gd_le[] = { 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * 0x00 movq %fs:0, %rax 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate 0x64, 0x48, 0x8b, 0x04, 0x25, 4157c478bd9Sstevel@tonic-gate 0x00, 0x00, 0x00, 0x00, 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * 0x09 leaq x@gottpoff(%rip), %rax 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate 0x48, 0x8d, 0x80, 0x00, 0x00, 4207c478bd9Sstevel@tonic-gate 0x00, 0x00 4217c478bd9Sstevel@tonic-gate }; 4227c478bd9Sstevel@tonic-gate 423b3fbe5e6Sseizo static uchar_t tlsinstr_ld_le[] = { 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * .byte 0x66 4267c478bd9Sstevel@tonic-gate */ 4277c478bd9Sstevel@tonic-gate 0x66, 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * .byte 0x66 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate 0x66, 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * .byte 0x66 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate 0x66, 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * movq %fs:0, %rax 4387c478bd9Sstevel@tonic-gate */ 4397c478bd9Sstevel@tonic-gate 0x64, 0x48, 0x8b, 0x04, 0x25, 4407c478bd9Sstevel@tonic-gate 0x00, 0x00, 0x00, 0x00 4417c478bd9Sstevel@tonic-gate }; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate 4445aefb655Srie static Fixupret 4455aefb655Srie tls_fixups(Ofl_desc *ofl, Rel_desc *arsp) 4467c478bd9Sstevel@tonic-gate { 4477c478bd9Sstevel@tonic-gate Sym_desc *sdp = arsp->rel_sym; 4487c478bd9Sstevel@tonic-gate Word rtype = arsp->rel_rtype; 449b3fbe5e6Sseizo uchar_t *offset; 4507c478bd9Sstevel@tonic-gate 451b3fbe5e6Sseizo offset = (uchar_t *)((uintptr_t)arsp->rel_roffset + 452b3fbe5e6Sseizo (uintptr_t)_elf_getxoff(arsp->rel_isdesc->is_indata) + 453b3fbe5e6Sseizo (uintptr_t)arsp->rel_osdesc->os_outdata->d_buf); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (sdp->sd_ref == REF_DYN_NEED) { 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * IE reference model 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate switch (rtype) { 4607c478bd9Sstevel@tonic-gate case R_AMD64_TLSGD: 4617c478bd9Sstevel@tonic-gate /* 4627c478bd9Sstevel@tonic-gate * GD -> IE 4637c478bd9Sstevel@tonic-gate * 4647c478bd9Sstevel@tonic-gate * Transition: 4657c478bd9Sstevel@tonic-gate * 0x00 .byte 0x66 4667c478bd9Sstevel@tonic-gate * 0x01 leaq x@tlsgd(%rip), %rdi 4677c478bd9Sstevel@tonic-gate * 0x08 .word 0x6666 4687c478bd9Sstevel@tonic-gate * 0x0a rex64 4697c478bd9Sstevel@tonic-gate * 0x0b call __tls_get_addr@plt 4707c478bd9Sstevel@tonic-gate * 0x10 4717c478bd9Sstevel@tonic-gate * To: 4727c478bd9Sstevel@tonic-gate * 0x00 movq %fs:0, %rax 4737c478bd9Sstevel@tonic-gate * 0x09 addq x@gottpoff(%rip), %rax 4747c478bd9Sstevel@tonic-gate * 0x10 4757c478bd9Sstevel@tonic-gate */ 4765aefb655Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 477051d39bbSrie R_AMD64_GOTTPOFF, arsp)); 4787c478bd9Sstevel@tonic-gate arsp->rel_rtype = R_AMD64_GOTTPOFF; 4797c478bd9Sstevel@tonic-gate arsp->rel_roffset += 8; 4807c478bd9Sstevel@tonic-gate arsp->rel_raddend = (Sxword)-4; 4815aefb655Srie 4827c478bd9Sstevel@tonic-gate /* 483051d39bbSrie * Adjust 'offset' to beginning of instruction 4847c478bd9Sstevel@tonic-gate * sequence. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate offset -= 4; 4877c478bd9Sstevel@tonic-gate (void) memcpy(offset, tlsinstr_gd_ie, 4885aefb655Srie sizeof (tlsinstr_gd_ie)); 4897c478bd9Sstevel@tonic-gate return (FIX_RELOC); 4905aefb655Srie 4917c478bd9Sstevel@tonic-gate case R_AMD64_PLT32: 4927c478bd9Sstevel@tonic-gate /* 493051d39bbSrie * Fixup done via the TLS_GD relocation. 4947c478bd9Sstevel@tonic-gate */ 4955aefb655Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 496051d39bbSrie R_AMD64_NONE, arsp)); 4977c478bd9Sstevel@tonic-gate return (FIX_DONE); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * LE reference model 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate switch (rtype) { 5057c478bd9Sstevel@tonic-gate case R_AMD64_TLSGD: 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * GD -> LE 5087c478bd9Sstevel@tonic-gate * 5097c478bd9Sstevel@tonic-gate * Transition: 5107c478bd9Sstevel@tonic-gate * 0x00 .byte 0x66 5117c478bd9Sstevel@tonic-gate * 0x01 leaq x@tlsgd(%rip), %rdi 5127c478bd9Sstevel@tonic-gate * 0x08 .word 0x6666 5137c478bd9Sstevel@tonic-gate * 0x0a rex64 5147c478bd9Sstevel@tonic-gate * 0x0b call __tls_get_addr@plt 5157c478bd9Sstevel@tonic-gate * 0x10 5167c478bd9Sstevel@tonic-gate * To: 5177c478bd9Sstevel@tonic-gate * 0x00 movq %fs:0, %rax 5187c478bd9Sstevel@tonic-gate * 0x09 leaq x@tpoff(%rax), %rax 5197c478bd9Sstevel@tonic-gate * 0x10 5207c478bd9Sstevel@tonic-gate */ 5215aefb655Srie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 522051d39bbSrie R_AMD64_TPOFF32, arsp)); 5237c478bd9Sstevel@tonic-gate arsp->rel_rtype = R_AMD64_TPOFF32; 5247c478bd9Sstevel@tonic-gate arsp->rel_roffset += 8; 5257c478bd9Sstevel@tonic-gate arsp->rel_raddend = 0; 5265aefb655Srie 5277c478bd9Sstevel@tonic-gate /* 528051d39bbSrie * Adjust 'offset' to beginning of instruction sequence. 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate offset -= 4; 5315aefb655Srie (void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le)); 5327c478bd9Sstevel@tonic-gate return (FIX_RELOC); 5335aefb655Srie 5347c478bd9Sstevel@tonic-gate case R_AMD64_GOTTPOFF: 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * IE -> LE 5377c478bd9Sstevel@tonic-gate * 5387c478bd9Sstevel@tonic-gate * Transition: 5397c478bd9Sstevel@tonic-gate * 0x00 movq %fs:0, %rax 5407c478bd9Sstevel@tonic-gate * 0x09 addq x@gottopoff(%rip), %rax 5417c478bd9Sstevel@tonic-gate * 0x10 5427c478bd9Sstevel@tonic-gate * To: 5437c478bd9Sstevel@tonic-gate * 0x00 movq %fs:0, %rax 5447c478bd9Sstevel@tonic-gate * 0x09 leaq x@tpoff(%rax), %rax 5457c478bd9Sstevel@tonic-gate * 0x10 5467c478bd9Sstevel@tonic-gate */ 547051d39bbSrie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 548051d39bbSrie R_AMD64_TPOFF32, arsp)); 5497c478bd9Sstevel@tonic-gate arsp->rel_rtype = R_AMD64_TPOFF32; 5507c478bd9Sstevel@tonic-gate arsp->rel_raddend = 0; 5515aefb655Srie 5527c478bd9Sstevel@tonic-gate /* 553051d39bbSrie * Adjust 'offset' to beginning of instruction sequence. 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate offset -= 12; 5565aefb655Srie 5577c478bd9Sstevel@tonic-gate /* 558051d39bbSrie * Same code sequence used in the GD -> LE transition. 5597c478bd9Sstevel@tonic-gate */ 5605aefb655Srie (void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le)); 5617c478bd9Sstevel@tonic-gate return (FIX_RELOC); 5625aefb655Srie 5637c478bd9Sstevel@tonic-gate case R_AMD64_TLSLD: 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * LD -> LE 5667c478bd9Sstevel@tonic-gate * 5677c478bd9Sstevel@tonic-gate * Transition 5687c478bd9Sstevel@tonic-gate * 0x00 leaq x1@tlsgd(%rip), %rdi 5697c478bd9Sstevel@tonic-gate * 0x07 call __tls_get_addr@plt 5707c478bd9Sstevel@tonic-gate * 0x0c 5717c478bd9Sstevel@tonic-gate * To: 5727c478bd9Sstevel@tonic-gate * 0x00 .byte 0x66 5737c478bd9Sstevel@tonic-gate * 0x01 .byte 0x66 5747c478bd9Sstevel@tonic-gate * 0x02 .byte 0x66 5757c478bd9Sstevel@tonic-gate * 0x03 movq %fs:0, %rax 5767c478bd9Sstevel@tonic-gate */ 577051d39bbSrie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 578051d39bbSrie R_AMD64_NONE, arsp)); 5797c478bd9Sstevel@tonic-gate offset -= 3; 5805aefb655Srie (void) memcpy(offset, tlsinstr_ld_le, sizeof (tlsinstr_ld_le)); 5817c478bd9Sstevel@tonic-gate return (FIX_DONE); 5825aefb655Srie 5837c478bd9Sstevel@tonic-gate case R_AMD64_DTPOFF32: 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * LD->LE 5867c478bd9Sstevel@tonic-gate * 5877c478bd9Sstevel@tonic-gate * Transition: 5887c478bd9Sstevel@tonic-gate * 0x00 leaq x1@dtpoff(%rax), %rcx 5897c478bd9Sstevel@tonic-gate * To: 5907c478bd9Sstevel@tonic-gate * 0x00 leaq x1@tpoff(%rax), %rcx 5917c478bd9Sstevel@tonic-gate */ 592051d39bbSrie DBG_CALL(Dbg_reloc_transition(ofl->ofl_lml, M_MACH, 593051d39bbSrie R_AMD64_TPOFF32, arsp)); 5947c478bd9Sstevel@tonic-gate arsp->rel_rtype = R_AMD64_TPOFF32; 5957c478bd9Sstevel@tonic-gate arsp->rel_raddend = 0; 5967c478bd9Sstevel@tonic-gate return (FIX_RELOC); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate return (FIX_RELOC); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 602*ba2be530Sab static uintptr_t 6035aefb655Srie ld_do_activerelocs(Ofl_desc *ofl) 6047c478bd9Sstevel@tonic-gate { 605141040e8Srie Rel_desc *arsp; 606141040e8Srie Rel_cache *rcp; 607141040e8Srie Listnode *lnp; 6087c478bd9Sstevel@tonic-gate uintptr_t return_code = 1; 6097c478bd9Sstevel@tonic-gate Word flags = ofl->ofl_flags; 6107c478bd9Sstevel@tonic-gate 6117010c12aSrie if (ofl->ofl_actrels.head) 6127010c12aSrie DBG_CALL(Dbg_reloc_doact_title(ofl->ofl_lml)); 6137010c12aSrie 6147c478bd9Sstevel@tonic-gate /* 615141040e8Srie * Process active relocations. 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate for (LIST_TRAVERSE(&ofl->ofl_actrels, lnp, rcp)) { 6187c478bd9Sstevel@tonic-gate /* LINTED */ 6197c478bd9Sstevel@tonic-gate for (arsp = (Rel_desc *)(rcp + 1); 6207c478bd9Sstevel@tonic-gate arsp < rcp->rc_free; arsp++) { 621b3fbe5e6Sseizo uchar_t *addr; 6227c478bd9Sstevel@tonic-gate Xword value; 6237c478bd9Sstevel@tonic-gate Sym_desc *sdp; 6247c478bd9Sstevel@tonic-gate const char *ifl_name; 6257c478bd9Sstevel@tonic-gate Xword refaddr; 6267c478bd9Sstevel@tonic-gate int moved = 0; 6277c478bd9Sstevel@tonic-gate Gotref gref; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * If the section this relocation is against has been 6317c478bd9Sstevel@tonic-gate * discarded (-zignore), then discard (skip) the 6327c478bd9Sstevel@tonic-gate * relocation itself. 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate if ((arsp->rel_isdesc->is_flags & FLG_IS_DISCARD) && 6357c478bd9Sstevel@tonic-gate ((arsp->rel_flags & 6367c478bd9Sstevel@tonic-gate (FLG_REL_GOT | FLG_REL_BSS | 6377c478bd9Sstevel@tonic-gate FLG_REL_PLT | FLG_REL_NOINFO)) == 0)) { 6385aefb655Srie DBG_CALL(Dbg_reloc_discard(ofl->ofl_lml, 6395aefb655Srie M_MACH, arsp)); 6407c478bd9Sstevel@tonic-gate continue; 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate * We deteremine what the 'got reference' 6457c478bd9Sstevel@tonic-gate * model (if required) is at this point. This 6467c478bd9Sstevel@tonic-gate * needs to be done before tls_fixup() since 6477c478bd9Sstevel@tonic-gate * it may 'transition' our instructions. 6487c478bd9Sstevel@tonic-gate * 6497c478bd9Sstevel@tonic-gate * The got table entries have already been assigned, 6507c478bd9Sstevel@tonic-gate * and we bind to those initial entries. 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate if (arsp->rel_flags & FLG_REL_DTLS) 6537c478bd9Sstevel@tonic-gate gref = GOT_REF_TLSGD; 6547c478bd9Sstevel@tonic-gate else if (arsp->rel_flags & FLG_REL_MTLS) 6557c478bd9Sstevel@tonic-gate gref = GOT_REF_TLSLD; 6567c478bd9Sstevel@tonic-gate else if (arsp->rel_flags & FLG_REL_STLS) 6577c478bd9Sstevel@tonic-gate gref = GOT_REF_TLSIE; 6587c478bd9Sstevel@tonic-gate else 6597c478bd9Sstevel@tonic-gate gref = GOT_REF_GENERIC; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate /* 6627c478bd9Sstevel@tonic-gate * Perform any required TLS fixups. 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate if (arsp->rel_flags & FLG_REL_TLSFIX) { 6657c478bd9Sstevel@tonic-gate Fixupret ret; 666141040e8Srie 6675aefb655Srie if ((ret = tls_fixups(ofl, arsp)) == FIX_ERROR) 6687c478bd9Sstevel@tonic-gate return (S_ERROR); 6697c478bd9Sstevel@tonic-gate if (ret == FIX_DONE) 6707c478bd9Sstevel@tonic-gate continue; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * If this is a relocation against a move table, or 6757c478bd9Sstevel@tonic-gate * expanded move table, adjust the relocation entries. 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate if (arsp->rel_move) 6785aefb655Srie ld_adj_movereloc(ofl, arsp); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate sdp = arsp->rel_sym; 6817c478bd9Sstevel@tonic-gate refaddr = arsp->rel_roffset + 6827c478bd9Sstevel@tonic-gate (Off)_elf_getxoff(arsp->rel_isdesc->is_indata); 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if ((arsp->rel_flags & FLG_REL_CLVAL) || 6857c478bd9Sstevel@tonic-gate (arsp->rel_flags & FLG_REL_GOTCL)) 6867c478bd9Sstevel@tonic-gate value = 0; 6877c478bd9Sstevel@tonic-gate else if (ELF_ST_TYPE(sdp->sd_sym->st_info) == 6887c478bd9Sstevel@tonic-gate STT_SECTION) { 689141040e8Srie Sym_desc *sym; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * The value for a symbol pointing to a SECTION 6937c478bd9Sstevel@tonic-gate * is based off of that sections position. 6947c478bd9Sstevel@tonic-gate * 6955aefb655Srie * The second argument of the ld_am_I_partial() 6965aefb655Srie * is the value stored at the target address 6977c478bd9Sstevel@tonic-gate * relocation is going to be applied. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate if ((sdp->sd_isc->is_flags & FLG_IS_RELUPD) && 7007c478bd9Sstevel@tonic-gate /* LINTED */ 7015aefb655Srie (sym = ld_am_I_partial(arsp, *(Xword *) 702b3fbe5e6Sseizo ((uchar_t *) 703b3fbe5e6Sseizo arsp->rel_isdesc->is_indata->d_buf + 7047c478bd9Sstevel@tonic-gate arsp->rel_roffset)))) { 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * If the symbol is moved, 7077c478bd9Sstevel@tonic-gate * adjust the value 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate value = sym->sd_sym->st_value; 7107c478bd9Sstevel@tonic-gate moved = 1; 7117c478bd9Sstevel@tonic-gate } else { 712141040e8Srie value = _elf_getxoff( 713141040e8Srie sdp->sd_isc->is_indata); 7147c478bd9Sstevel@tonic-gate if (sdp->sd_isc->is_shdr->sh_flags & 7157c478bd9Sstevel@tonic-gate SHF_ALLOC) 716de777a60Sab value += 717de777a60Sab sdp->sd_isc->is_osdesc-> 718de777a60Sab os_shdr->sh_addr; 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate if (sdp->sd_isc->is_shdr->sh_flags & SHF_TLS) 7217c478bd9Sstevel@tonic-gate value -= ofl->ofl_tlsphdr->p_vaddr; 7222926dd2eSrie 7232926dd2eSrie } else if (IS_SIZE(arsp->rel_rtype)) { 7242926dd2eSrie /* 7252926dd2eSrie * Size relocations require the symbols size. 7262926dd2eSrie */ 7272926dd2eSrie value = sdp->sd_sym->st_size; 728141040e8Srie } else { 7297c478bd9Sstevel@tonic-gate /* 7307010c12aSrie * Else the value is the symbols value. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate value = sdp->sd_sym->st_value; 733141040e8Srie } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * Relocation against the GLOBAL_OFFSET_TABLE. 7377c478bd9Sstevel@tonic-gate */ 7387c478bd9Sstevel@tonic-gate if (arsp->rel_flags & FLG_REL_GOT) 7397c478bd9Sstevel@tonic-gate arsp->rel_osdesc = ofl->ofl_osgot; 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * If loadable and not producing a relocatable object 7437c478bd9Sstevel@tonic-gate * add the sections virtual address to the reference 7447c478bd9Sstevel@tonic-gate * address. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate if ((arsp->rel_flags & FLG_REL_LOAD) && 747141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) 7487c478bd9Sstevel@tonic-gate refaddr += arsp->rel_isdesc->is_osdesc-> 7497c478bd9Sstevel@tonic-gate os_shdr->sh_addr; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * If this entry has a PLT assigned to it, it's 7537c478bd9Sstevel@tonic-gate * value is actually the address of the PLT (and 7547c478bd9Sstevel@tonic-gate * not the address of the function). 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate if (IS_PLT(arsp->rel_rtype)) { 7577c478bd9Sstevel@tonic-gate if (sdp->sd_aux && sdp->sd_aux->sa_PLTndx) 7585aefb655Srie value = ld_calc_plt_addr(sdp, ofl); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * Add relocations addend to value. Add extra 7637c478bd9Sstevel@tonic-gate * relocation addend if needed. 7647c478bd9Sstevel@tonic-gate * 7657c478bd9Sstevel@tonic-gate * Note: for GOT relative relocations on amd64 7667c478bd9Sstevel@tonic-gate * we discard the addend. It was relevant 7677c478bd9Sstevel@tonic-gate * to the reference - not to the data item 7687c478bd9Sstevel@tonic-gate * being referenced (ie: that -4 thing). 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate if ((arsp->rel_flags & FLG_REL_GOT) == 0) 7717c478bd9Sstevel@tonic-gate value += arsp->rel_raddend; 7727c478bd9Sstevel@tonic-gate 773141040e8Srie /* 774141040e8Srie * Determine whether the value needs further adjustment. 775141040e8Srie * Filter through the attributes of the relocation to 776141040e8Srie * determine what adjustment is required. Note, many 777141040e8Srie * of the following cases are only applicable when a 778141040e8Srie * .got is present. As a .got is not generated when a 779141040e8Srie * relocatable object is being built, any adjustments 780141040e8Srie * that require a .got need to be skipped. 781141040e8Srie */ 782141040e8Srie if ((arsp->rel_flags & FLG_REL_GOT) && 783141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 7847c478bd9Sstevel@tonic-gate Xword R1addr; 7857c478bd9Sstevel@tonic-gate uintptr_t R2addr; 7867c478bd9Sstevel@tonic-gate Word gotndx; 7877c478bd9Sstevel@tonic-gate Gotndx *gnp; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* 7907c478bd9Sstevel@tonic-gate * Perform relocation against GOT table. Since 7917c478bd9Sstevel@tonic-gate * this doesn't fit exactly into a relocation 7927c478bd9Sstevel@tonic-gate * we place the appropriate byte in the GOT 7937c478bd9Sstevel@tonic-gate * directly 7947c478bd9Sstevel@tonic-gate * 7957c478bd9Sstevel@tonic-gate * Calculate offset into GOT at which to apply 7967c478bd9Sstevel@tonic-gate * the relocation. 7977c478bd9Sstevel@tonic-gate */ 7985aefb655Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), gref, 7997c478bd9Sstevel@tonic-gate ofl, arsp); 8007c478bd9Sstevel@tonic-gate assert(gnp); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if (arsp->rel_rtype == R_AMD64_DTPOFF64) 8037c478bd9Sstevel@tonic-gate gotndx = gnp->gn_gotndx + 1; 8047c478bd9Sstevel@tonic-gate else 8057c478bd9Sstevel@tonic-gate gotndx = gnp->gn_gotndx; 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate R1addr = (Xword)(gotndx * M_GOT_ENTSIZE); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * Add the GOTs data's offset. 8117c478bd9Sstevel@tonic-gate */ 8127c478bd9Sstevel@tonic-gate R2addr = R1addr + (uintptr_t) 8137c478bd9Sstevel@tonic-gate arsp->rel_osdesc->os_outdata->d_buf; 8147c478bd9Sstevel@tonic-gate 8155aefb655Srie DBG_CALL(Dbg_reloc_doact(ofl->ofl_lml, 8165aefb655Srie ELF_DBG_LD, M_MACH, SHT_RELA, 8177c478bd9Sstevel@tonic-gate arsp->rel_rtype, R1addr, value, 8187c478bd9Sstevel@tonic-gate arsp->rel_sname, arsp->rel_osdesc)); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * And do it. 8227c478bd9Sstevel@tonic-gate */ 823f3324781Sab if (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) 824f3324781Sab *(Xword *)R2addr = 825*ba2be530Sab ld_bswap_Xword(value); 826f3324781Sab else 827f3324781Sab *(Xword *)R2addr = value; 8287c478bd9Sstevel@tonic-gate continue; 8297c478bd9Sstevel@tonic-gate 830141040e8Srie } else if (IS_GOT_BASED(arsp->rel_rtype) && 831141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 8327c478bd9Sstevel@tonic-gate value -= ofl->ofl_osgot->os_shdr->sh_addr; 833141040e8Srie 834141040e8Srie } else if (IS_GOTPCREL(arsp->rel_rtype) && 835141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 836141040e8Srie Gotndx *gnp; 837141040e8Srie 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * Calculation: 8407c478bd9Sstevel@tonic-gate * G + GOT + A - P 8417c478bd9Sstevel@tonic-gate */ 8425aefb655Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 8437c478bd9Sstevel@tonic-gate gref, ofl, arsp); 844141040e8Srie assert(gnp); 8457c478bd9Sstevel@tonic-gate value = (Xword)(ofl->ofl_osgot->os_shdr-> 8467c478bd9Sstevel@tonic-gate sh_addr) + ((Xword)gnp->gn_gotndx * 8477c478bd9Sstevel@tonic-gate M_GOT_ENTSIZE) + arsp->rel_raddend - 8487c478bd9Sstevel@tonic-gate refaddr; 849141040e8Srie 850141040e8Srie } else if (IS_GOT_PC(arsp->rel_rtype) && 851141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 852141040e8Srie value = (Xword)(ofl->ofl_osgot->os_shdr-> 85354d82594Sseizo sh_addr) - refaddr + arsp->rel_raddend; 854141040e8Srie 8557c478bd9Sstevel@tonic-gate } else if ((IS_PC_RELATIVE(arsp->rel_rtype)) && 856141040e8Srie (((flags & FLG_OF_RELOBJ) == 0) || 8577c478bd9Sstevel@tonic-gate (arsp->rel_osdesc == sdp->sd_isc->is_osdesc))) { 8587c478bd9Sstevel@tonic-gate value -= refaddr; 859141040e8Srie 8607c478bd9Sstevel@tonic-gate } else if (IS_TLS_INS(arsp->rel_rtype) && 861141040e8Srie IS_GOT_RELATIVE(arsp->rel_rtype) && 862141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 8637c478bd9Sstevel@tonic-gate Gotndx *gnp; 8647c478bd9Sstevel@tonic-gate 8655aefb655Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), gref, 8667c478bd9Sstevel@tonic-gate ofl, arsp); 867141040e8Srie assert(gnp); 8687c478bd9Sstevel@tonic-gate value = (Xword)gnp->gn_gotndx * M_GOT_ENTSIZE; 869141040e8Srie 870141040e8Srie } else if (IS_GOT_RELATIVE(arsp->rel_rtype) && 871141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 872141040e8Srie Gotndx *gnp; 8737c478bd9Sstevel@tonic-gate 8745aefb655Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 8757c478bd9Sstevel@tonic-gate gref, ofl, arsp); 8767c478bd9Sstevel@tonic-gate assert(gnp); 8777c478bd9Sstevel@tonic-gate value = (Xword)gnp->gn_gotndx * M_GOT_ENTSIZE; 878141040e8Srie 879141040e8Srie } else if ((arsp->rel_flags & FLG_REL_STLS) && 880141040e8Srie ((flags & FLG_OF_RELOBJ) == 0)) { 8817c478bd9Sstevel@tonic-gate Xword tlsstatsize; 882141040e8Srie 8837c478bd9Sstevel@tonic-gate /* 8847c478bd9Sstevel@tonic-gate * This is the LE TLS reference model. Static 8857c478bd9Sstevel@tonic-gate * offset is hard-coded. 8867c478bd9Sstevel@tonic-gate */ 887141040e8Srie tlsstatsize = 888141040e8Srie S_ROUND(ofl->ofl_tlsphdr->p_memsz, 8897c478bd9Sstevel@tonic-gate M_TLSSTATALIGN); 8907c478bd9Sstevel@tonic-gate value = tlsstatsize - value; 891141040e8Srie 8927c478bd9Sstevel@tonic-gate /* 893141040e8Srie * Since this code is fixed up, it assumes a 894141040e8Srie * negative offset that can be added to the 895141040e8Srie * thread pointer. 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate if (arsp->rel_rtype == R_AMD64_TPOFF32) 8987c478bd9Sstevel@tonic-gate value = -value; 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate if (arsp->rel_isdesc->is_file) 9027c478bd9Sstevel@tonic-gate ifl_name = arsp->rel_isdesc->is_file->ifl_name; 9037c478bd9Sstevel@tonic-gate else 9047c478bd9Sstevel@tonic-gate ifl_name = MSG_INTL(MSG_STR_NULL); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * Make sure we have data to relocate. Compiler and 9087c478bd9Sstevel@tonic-gate * assembler developers have been known to generate 9097c478bd9Sstevel@tonic-gate * relocations against invalid sections (normally .bss), 9107c478bd9Sstevel@tonic-gate * so for their benefit give them sufficient information 9117c478bd9Sstevel@tonic-gate * to help analyze the problem. End users should never 9127c478bd9Sstevel@tonic-gate * see this. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate if (arsp->rel_isdesc->is_indata->d_buf == 0) { 915de777a60Sab Conv_inv_buf_t inv_buf; 916de777a60Sab 9175aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, 9185aefb655Srie MSG_INTL(MSG_REL_EMPTYSEC), 919de777a60Sab conv_reloc_amd64_type(arsp->rel_rtype, 920de777a60Sab 0, &inv_buf), ifl_name, 921de777a60Sab demangle(arsp->rel_sname), 9227c478bd9Sstevel@tonic-gate arsp->rel_isdesc->is_name); 9237c478bd9Sstevel@tonic-gate return (S_ERROR); 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * Get the address of the data item we need to modify. 9287c478bd9Sstevel@tonic-gate */ 929b3fbe5e6Sseizo addr = (uchar_t *)((uintptr_t)arsp->rel_roffset + 930b3fbe5e6Sseizo (uintptr_t)_elf_getxoff(arsp->rel_isdesc-> 931b3fbe5e6Sseizo is_indata)); 9327c478bd9Sstevel@tonic-gate 9335aefb655Srie DBG_CALL(Dbg_reloc_doact(ofl->ofl_lml, ELF_DBG_LD, 9345aefb655Srie M_MACH, SHT_RELA, arsp->rel_rtype, EC_NATPTR(addr), 9355aefb655Srie value, arsp->rel_sname, arsp->rel_osdesc)); 9367c478bd9Sstevel@tonic-gate addr += (uintptr_t)arsp->rel_osdesc->os_outdata->d_buf; 9377c478bd9Sstevel@tonic-gate 9385aefb655Srie if ((((uintptr_t)addr - (uintptr_t)ofl->ofl_nehdr) > 9397c478bd9Sstevel@tonic-gate ofl->ofl_size) || (arsp->rel_roffset > 9407c478bd9Sstevel@tonic-gate arsp->rel_osdesc->os_shdr->sh_size)) { 941de777a60Sab int class; 942de777a60Sab Conv_inv_buf_t inv_buf; 9437c478bd9Sstevel@tonic-gate 944b3fbe5e6Sseizo if (((uintptr_t)addr - 9455aefb655Srie (uintptr_t)ofl->ofl_nehdr) > ofl->ofl_size) 9467c478bd9Sstevel@tonic-gate class = ERR_FATAL; 9477c478bd9Sstevel@tonic-gate else 9487c478bd9Sstevel@tonic-gate class = ERR_WARNING; 9497c478bd9Sstevel@tonic-gate 9505aefb655Srie eprintf(ofl->ofl_lml, class, 9515aefb655Srie MSG_INTL(MSG_REL_INVALOFFSET), 952de777a60Sab conv_reloc_amd64_type(arsp->rel_rtype, 953de777a60Sab 0, &inv_buf), ifl_name, 954de777a60Sab arsp->rel_isdesc->is_name, 9557c478bd9Sstevel@tonic-gate demangle(arsp->rel_sname), 9567c478bd9Sstevel@tonic-gate EC_ADDR((uintptr_t)addr - 9575aefb655Srie (uintptr_t)ofl->ofl_nehdr)); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (class == ERR_FATAL) { 9607c478bd9Sstevel@tonic-gate return_code = S_ERROR; 9617c478bd9Sstevel@tonic-gate continue; 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * The relocation is additive. Ignore the previous 9677c478bd9Sstevel@tonic-gate * symbol value if this local partial symbol is 9687c478bd9Sstevel@tonic-gate * expanded. 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate if (moved) 9717c478bd9Sstevel@tonic-gate value -= *addr; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate /* 974f3324781Sab * If '-z noreloc' is specified - skip the do_reloc_ld 9757c478bd9Sstevel@tonic-gate * stage. 9767c478bd9Sstevel@tonic-gate */ 977f3324781Sab if (OFL_DO_RELOC(ofl)) { 978f3324781Sab /* 979f3324781Sab * If this is a PROGBITS section and the 980f3324781Sab * running linker has a different byte order 981f3324781Sab * than the target host, tell do_reloc_ld() 982f3324781Sab * to swap bytes. 983f3324781Sab */ 984f3324781Sab if (do_reloc_ld((uchar_t)arsp->rel_rtype, 9855aefb655Srie addr, &value, arsp->rel_sname, ifl_name, 986f3324781Sab OFL_SWAP_RELOC_DATA(ofl, arsp), 9875aefb655Srie ofl->ofl_lml) == 0) 9887c478bd9Sstevel@tonic-gate return_code = S_ERROR; 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate return (return_code); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 995*ba2be530Sab static uintptr_t 9965aefb655Srie ld_add_outrel(Word flags, Rel_desc *rsp, Ofl_desc *ofl) 9977c478bd9Sstevel@tonic-gate { 998141040e8Srie Rel_desc *orsp; 999141040e8Srie Rel_cache *rcp; 1000141040e8Srie Sym_desc *sdp = rsp->rel_sym; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* 10037c478bd9Sstevel@tonic-gate * Static executables *do not* want any relocations against them. 10047c478bd9Sstevel@tonic-gate * Since our engine still creates relocations against a WEAK UNDEFINED 10057c478bd9Sstevel@tonic-gate * symbol in a static executable, it's best to disable them here 10067c478bd9Sstevel@tonic-gate * instead of through out the relocation code. 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate if ((ofl->ofl_flags & (FLG_OF_STATIC | FLG_OF_EXEC)) == 10097c478bd9Sstevel@tonic-gate (FLG_OF_STATIC | FLG_OF_EXEC)) 10107c478bd9Sstevel@tonic-gate return (1); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * If no relocation cache structures are available allocate 10147c478bd9Sstevel@tonic-gate * a new one and link it into the cache list. 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate if ((ofl->ofl_outrels.tail == 0) || 10177c478bd9Sstevel@tonic-gate ((rcp = (Rel_cache *)ofl->ofl_outrels.tail->data) == 0) || 10187c478bd9Sstevel@tonic-gate ((orsp = rcp->rc_free) == rcp->rc_end)) { 10197c478bd9Sstevel@tonic-gate static size_t nextsize = 0; 10207c478bd9Sstevel@tonic-gate size_t size; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Output relocation numbers can vary considerably between 10247c478bd9Sstevel@tonic-gate * building executables or shared objects (pic vs. non-pic), 10257c478bd9Sstevel@tonic-gate * etc. But, they typically aren't very large, so for these 10267c478bd9Sstevel@tonic-gate * objects use a standard bucket size. For building relocatable 10277c478bd9Sstevel@tonic-gate * objects, typically there will be an output relocation for 10287c478bd9Sstevel@tonic-gate * every input relocation. 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate if (nextsize == 0) { 10317c478bd9Sstevel@tonic-gate if (ofl->ofl_flags & FLG_OF_RELOBJ) { 10327c478bd9Sstevel@tonic-gate if ((size = ofl->ofl_relocincnt) == 0) 10337c478bd9Sstevel@tonic-gate size = REL_LOIDESCNO; 10347c478bd9Sstevel@tonic-gate if (size > REL_HOIDESCNO) 10357c478bd9Sstevel@tonic-gate nextsize = REL_HOIDESCNO; 10367c478bd9Sstevel@tonic-gate else 10377c478bd9Sstevel@tonic-gate nextsize = REL_LOIDESCNO; 10387c478bd9Sstevel@tonic-gate } else 10397c478bd9Sstevel@tonic-gate nextsize = size = REL_HOIDESCNO; 10407c478bd9Sstevel@tonic-gate } else 10417c478bd9Sstevel@tonic-gate size = nextsize; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate size = size * sizeof (Rel_desc); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate if (((rcp = libld_malloc(sizeof (Rel_cache) + size)) == 0) || 10467c478bd9Sstevel@tonic-gate (list_appendc(&ofl->ofl_outrels, rcp) == 0)) 10477c478bd9Sstevel@tonic-gate return (S_ERROR); 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate /* LINTED */ 10507c478bd9Sstevel@tonic-gate rcp->rc_free = orsp = (Rel_desc *)(rcp + 1); 10517c478bd9Sstevel@tonic-gate /* LINTED */ 10527c478bd9Sstevel@tonic-gate rcp->rc_end = (Rel_desc *)((char *)rcp->rc_free + size); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * If we are adding a output relocation against a section 10577c478bd9Sstevel@tonic-gate * symbol (non-RELATIVE) then mark that section. These sections 10587c478bd9Sstevel@tonic-gate * will be added to the .dynsym symbol table. 10597c478bd9Sstevel@tonic-gate */ 10607c478bd9Sstevel@tonic-gate if (sdp && (rsp->rel_rtype != M_R_RELATIVE) && 10617c478bd9Sstevel@tonic-gate ((flags & FLG_REL_SCNNDX) || 10627c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION))) { 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate /* 10657c478bd9Sstevel@tonic-gate * If this is a COMMON symbol - no output section 10667c478bd9Sstevel@tonic-gate * exists yet - (it's created as part of sym_validate()). 10677c478bd9Sstevel@tonic-gate * So - we mark here that when it's created it should 10687c478bd9Sstevel@tonic-gate * be tagged with the FLG_OS_OUTREL flag. 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate if ((sdp->sd_flags & FLG_SY_SPECSEC) && 10710bc07c75Srie (sdp->sd_sym->st_shndx == SHN_COMMON)) { 10727c478bd9Sstevel@tonic-gate if (ELF_ST_TYPE(sdp->sd_sym->st_info) != STT_TLS) 10737c478bd9Sstevel@tonic-gate ofl->ofl_flags1 |= FLG_OF1_BSSOREL; 10747c478bd9Sstevel@tonic-gate else 10757c478bd9Sstevel@tonic-gate ofl->ofl_flags1 |= FLG_OF1_TLSOREL; 1076141040e8Srie } else { 1077141040e8Srie Os_desc *osp = sdp->sd_isc->is_osdesc; 10787c478bd9Sstevel@tonic-gate 1079c1c6f601Srie if (osp && ((osp->os_flags & FLG_OS_OUTREL) == 0)) { 10807c478bd9Sstevel@tonic-gate ofl->ofl_dynshdrcnt++; 10817c478bd9Sstevel@tonic-gate osp->os_flags |= FLG_OS_OUTREL; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate *orsp = *rsp; 10877c478bd9Sstevel@tonic-gate orsp->rel_flags |= flags; 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate rcp->rc_free++; 10907c478bd9Sstevel@tonic-gate ofl->ofl_outrelscnt++; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if (flags & FLG_REL_GOT) 10937c478bd9Sstevel@tonic-gate ofl->ofl_relocgotsz += (Xword)sizeof (Rela); 10947c478bd9Sstevel@tonic-gate else if (flags & FLG_REL_PLT) 10957c478bd9Sstevel@tonic-gate ofl->ofl_relocpltsz += (Xword)sizeof (Rela); 10967c478bd9Sstevel@tonic-gate else if (flags & FLG_REL_BSS) 10977c478bd9Sstevel@tonic-gate ofl->ofl_relocbsssz += (Xword)sizeof (Rela); 10987c478bd9Sstevel@tonic-gate else if (flags & FLG_REL_NOINFO) 10997c478bd9Sstevel@tonic-gate ofl->ofl_relocrelsz += (Xword)sizeof (Rela); 11007c478bd9Sstevel@tonic-gate else 11017c478bd9Sstevel@tonic-gate orsp->rel_osdesc->os_szoutrels += (Xword)sizeof (Rela); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate if (orsp->rel_rtype == M_R_RELATIVE) 11047c478bd9Sstevel@tonic-gate ofl->ofl_relocrelcnt++; 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate /* 11077c478bd9Sstevel@tonic-gate * We don't perform sorting on PLT relocations because 11087c478bd9Sstevel@tonic-gate * they have already been assigned a PLT index and if we 11097c478bd9Sstevel@tonic-gate * were to sort them we would have to re-assign the plt indexes. 11107c478bd9Sstevel@tonic-gate */ 11117c478bd9Sstevel@tonic-gate if (!(flags & FLG_REL_PLT)) 11127c478bd9Sstevel@tonic-gate ofl->ofl_reloccnt++; 11137c478bd9Sstevel@tonic-gate 1114141040e8Srie /* 1115141040e8Srie * Insure a GLOBAL_OFFSET_TABLE is generated if required. 1116141040e8Srie */ 1117141040e8Srie if (IS_GOT_REQUIRED(orsp->rel_rtype)) 1118141040e8Srie ofl->ofl_flags |= FLG_OF_BLDGOT; 1119141040e8Srie 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * Identify and possibly warn of a displacement relocation. 11227c478bd9Sstevel@tonic-gate */ 11237c478bd9Sstevel@tonic-gate if (orsp->rel_flags & FLG_REL_DISP) { 11247c478bd9Sstevel@tonic-gate ofl->ofl_dtflags_1 |= DF_1_DISPRELPND; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate if (ofl->ofl_flags & FLG_OF_VERBOSE) 11275aefb655Srie ld_disp_errmsg(MSG_INTL(MSG_REL_DISPREL4), orsp, ofl); 11287c478bd9Sstevel@tonic-gate } 11295aefb655Srie DBG_CALL(Dbg_reloc_ors_entry(ofl->ofl_lml, ELF_DBG_LD, SHT_RELA, 11305aefb655Srie M_MACH, orsp)); 11317c478bd9Sstevel@tonic-gate return (1); 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate /* 11357c478bd9Sstevel@tonic-gate * process relocation for a LOCAL symbol 11367c478bd9Sstevel@tonic-gate */ 1137*ba2be530Sab static uintptr_t 11385aefb655Srie ld_reloc_local(Rel_desc * rsp, Ofl_desc * ofl) 11397c478bd9Sstevel@tonic-gate { 11407c478bd9Sstevel@tonic-gate Word flags = ofl->ofl_flags; 11417c478bd9Sstevel@tonic-gate Sym_desc *sdp = rsp->rel_sym; 11420bc07c75Srie Word shndx = sdp->sd_sym->st_shndx; 11437c478bd9Sstevel@tonic-gate Word ortype = rsp->rel_rtype; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * if ((shared object) and (not pc relative relocation) and 11477c478bd9Sstevel@tonic-gate * (not against ABS symbol)) 11487c478bd9Sstevel@tonic-gate * then 11497c478bd9Sstevel@tonic-gate * build R_AMD64_RELATIVE 11507c478bd9Sstevel@tonic-gate * fi 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate if ((flags & FLG_OF_SHAROBJ) && (rsp->rel_flags & FLG_REL_LOAD) && 11532926dd2eSrie !(IS_PC_RELATIVE(rsp->rel_rtype)) && !(IS_SIZE(rsp->rel_rtype)) && 11547c478bd9Sstevel@tonic-gate !(IS_GOT_BASED(rsp->rel_rtype)) && 11557c478bd9Sstevel@tonic-gate !(rsp->rel_isdesc != NULL && 11567c478bd9Sstevel@tonic-gate (rsp->rel_isdesc->is_shdr->sh_type == SHT_SUNW_dof)) && 11577c478bd9Sstevel@tonic-gate (((sdp->sd_flags & FLG_SY_SPECSEC) == 0) || 11587c478bd9Sstevel@tonic-gate (shndx != SHN_ABS) || (sdp->sd_aux && sdp->sd_aux->sa_symspec))) { 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * R_AMD64_RELATIVE updates a 64bit address, if this 11627c478bd9Sstevel@tonic-gate * relocation isn't a 64bit binding then we can not 11637c478bd9Sstevel@tonic-gate * simplify it to a RELATIVE relocation. 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate if (reloc_table[ortype].re_fsize != sizeof (Addr)) { 11665aefb655Srie return (ld_add_outrel(NULL, rsp, ofl)); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate rsp->rel_rtype = R_AMD64_RELATIVE; 11705aefb655Srie if (ld_add_outrel(FLG_REL_ADVAL, rsp, ofl) == S_ERROR) 11717c478bd9Sstevel@tonic-gate return (S_ERROR); 11727c478bd9Sstevel@tonic-gate rsp->rel_rtype = ortype; 11737c478bd9Sstevel@tonic-gate return (1); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate 1176b3fbe5e6Sseizo /* 1177b3fbe5e6Sseizo * If the relocation is against a 'non-allocatable' section 1178b3fbe5e6Sseizo * and we can not resolve it now - then give a warning 1179b3fbe5e6Sseizo * message. 1180b3fbe5e6Sseizo * 1181b3fbe5e6Sseizo * We can not resolve the symbol if either: 1182b3fbe5e6Sseizo * a) it's undefined 1183b3fbe5e6Sseizo * b) it's defined in a shared library and a 1184b3fbe5e6Sseizo * COPY relocation hasn't moved it to the executable 1185b3fbe5e6Sseizo * 1186b3fbe5e6Sseizo * Note: because we process all of the relocations against the 1187b3fbe5e6Sseizo * text segment before any others - we know whether 1188b3fbe5e6Sseizo * or not a copy relocation will be generated before 1189b3fbe5e6Sseizo * we get here (see reloc_init()->reloc_segments()). 1190b3fbe5e6Sseizo */ 11917c478bd9Sstevel@tonic-gate if (!(rsp->rel_flags & FLG_REL_LOAD) && 1192b3fbe5e6Sseizo ((shndx == SHN_UNDEF) || 1193b3fbe5e6Sseizo ((sdp->sd_ref == REF_DYN_NEED) && 1194b3fbe5e6Sseizo ((sdp->sd_flags & FLG_SY_MVTOCOMM) == 0)))) { 1195de777a60Sab Conv_inv_buf_t inv_buf; 1196de777a60Sab 1197b3fbe5e6Sseizo /* 1198b3fbe5e6Sseizo * If the relocation is against a SHT_SUNW_ANNOTATE 1199b3fbe5e6Sseizo * section - then silently ignore that the relocation 1200b3fbe5e6Sseizo * can not be resolved. 1201b3fbe5e6Sseizo */ 1202b3fbe5e6Sseizo if (rsp->rel_osdesc && 1203b3fbe5e6Sseizo (rsp->rel_osdesc->os_shdr->sh_type == SHT_SUNW_ANNOTATE)) 1204b3fbe5e6Sseizo return (0); 12055aefb655Srie (void) eprintf(ofl->ofl_lml, ERR_WARNING, 12065aefb655Srie MSG_INTL(MSG_REL_EXTERNSYM), 1207de777a60Sab conv_reloc_amd64_type(rsp->rel_rtype, 0, &inv_buf), 12087c478bd9Sstevel@tonic-gate rsp->rel_isdesc->is_file->ifl_name, 12097c478bd9Sstevel@tonic-gate demangle(rsp->rel_sname), rsp->rel_osdesc->os_name); 12107c478bd9Sstevel@tonic-gate return (1); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /* 12147c478bd9Sstevel@tonic-gate * Perform relocation. 12157c478bd9Sstevel@tonic-gate */ 12165aefb655Srie return (ld_add_actrel(NULL, rsp, ofl)); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate 1220*ba2be530Sab static uintptr_t 12215aefb655Srie ld_reloc_TLS(Boolean local, Rel_desc * rsp, Ofl_desc * ofl) 12227c478bd9Sstevel@tonic-gate { 12237c478bd9Sstevel@tonic-gate Word rtype = rsp->rel_rtype; 12247c478bd9Sstevel@tonic-gate Sym_desc *sdp = rsp->rel_sym; 12257c478bd9Sstevel@tonic-gate Word flags = ofl->ofl_flags; 12267c478bd9Sstevel@tonic-gate Gotndx *gnp; 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate /* 1229d326b23bSrie * If we're building an executable - use either the IE or LE access 1230d326b23bSrie * model. If we're building a shared object process any IE model. 12317c478bd9Sstevel@tonic-gate */ 1232d326b23bSrie if ((flags & FLG_OF_EXEC) || (IS_TLS_IE(rtype))) { 12337c478bd9Sstevel@tonic-gate /* 1234d326b23bSrie * Set the DF_STATIC_TLS flag. 12357c478bd9Sstevel@tonic-gate */ 12367c478bd9Sstevel@tonic-gate ofl->ofl_dtflags |= DF_STATIC_TLS; 12377c478bd9Sstevel@tonic-gate 1238d326b23bSrie if (!local || ((flags & FLG_OF_EXEC) == 0)) { 12397c478bd9Sstevel@tonic-gate /* 1240d326b23bSrie * Assign a GOT entry for static TLS references. 12417c478bd9Sstevel@tonic-gate */ 1242d326b23bSrie if ((gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 1243d326b23bSrie GOT_REF_TLSIE, ofl, rsp)) == 0) { 12447c478bd9Sstevel@tonic-gate 1245d326b23bSrie if (ld_assign_got_TLS(local, rsp, ofl, sdp, 1246d326b23bSrie gnp, GOT_REF_TLSIE, FLG_REL_STLS, 1247d326b23bSrie rtype, R_AMD64_TPOFF64, 0) == S_ERROR) 1248d326b23bSrie return (S_ERROR); 1249d326b23bSrie } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate /* 1252d326b23bSrie * IE access model. 12537c478bd9Sstevel@tonic-gate */ 12547c478bd9Sstevel@tonic-gate if (IS_TLS_IE(rtype)) 12555aefb655Srie return (ld_add_actrel(FLG_REL_STLS, rsp, ofl)); 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 1258d326b23bSrie * Fixups are required for other executable models. 12597c478bd9Sstevel@tonic-gate */ 12605aefb655Srie return (ld_add_actrel((FLG_REL_TLSFIX | FLG_REL_STLS), 12617c478bd9Sstevel@tonic-gate rsp, ofl)); 12627c478bd9Sstevel@tonic-gate } 1263d326b23bSrie 12647c478bd9Sstevel@tonic-gate /* 1265d326b23bSrie * LE access model. 12667c478bd9Sstevel@tonic-gate */ 12677c478bd9Sstevel@tonic-gate if (IS_TLS_LE(rtype)) 12685aefb655Srie return (ld_add_actrel(FLG_REL_STLS, rsp, ofl)); 1269d326b23bSrie 12705aefb655Srie return (ld_add_actrel((FLG_REL_TLSFIX | FLG_REL_STLS), 12715aefb655Srie rsp, ofl)); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 1275d326b23bSrie * Building a shared object. 1276d326b23bSrie * 1277d326b23bSrie * Assign a GOT entry for a dynamic TLS reference. 12787c478bd9Sstevel@tonic-gate */ 12795aefb655Srie if (IS_TLS_LD(rtype) && ((gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), 12807c478bd9Sstevel@tonic-gate GOT_REF_TLSLD, ofl, rsp)) == 0)) { 1281d326b23bSrie 1282d326b23bSrie if (ld_assign_got_TLS(local, rsp, ofl, sdp, gnp, GOT_REF_TLSLD, 1283d326b23bSrie FLG_REL_MTLS, rtype, R_AMD64_DTPMOD64, 0) == S_ERROR) 12847c478bd9Sstevel@tonic-gate return (S_ERROR); 1285d326b23bSrie 12865aefb655Srie } else if (IS_TLS_GD(rtype) && 1287d326b23bSrie ((gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), GOT_REF_TLSGD, 1288d326b23bSrie ofl, rsp)) == 0)) { 1289d326b23bSrie 1290d326b23bSrie if (ld_assign_got_TLS(local, rsp, ofl, sdp, gnp, GOT_REF_TLSGD, 1291d326b23bSrie FLG_REL_DTLS, rtype, R_AMD64_DTPMOD64, 1292d326b23bSrie R_AMD64_DTPOFF64) == S_ERROR) 12937c478bd9Sstevel@tonic-gate return (S_ERROR); 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate if (IS_TLS_LD(rtype)) 12975aefb655Srie return (ld_add_actrel(FLG_REL_MTLS, rsp, ofl)); 12987c478bd9Sstevel@tonic-gate 12995aefb655Srie return (ld_add_actrel(FLG_REL_DTLS, rsp, ofl)); 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 1303*ba2be530Sab static Gotndx * 13045aefb655Srie ld_find_gotndx(List * lst, Gotref gref, Ofl_desc * ofl, Rel_desc * rdesc) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate Listnode * lnp; 13077c478bd9Sstevel@tonic-gate Gotndx * gnp; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate assert(rdesc != 0); 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate if ((gref == GOT_REF_TLSLD) && ofl->ofl_tlsldgotndx) 13127c478bd9Sstevel@tonic-gate return (ofl->ofl_tlsldgotndx); 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate for (LIST_TRAVERSE(lst, lnp, gnp)) { 13157c478bd9Sstevel@tonic-gate if ((rdesc->rel_raddend == gnp->gn_addend) && 13167c478bd9Sstevel@tonic-gate (gnp->gn_gotref == gref)) { 13177c478bd9Sstevel@tonic-gate return (gnp); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate return ((Gotndx *)0); 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 1323*ba2be530Sab static Xword 13245aefb655Srie ld_calc_got_offset(Rel_desc * rdesc, Ofl_desc * ofl) 13257c478bd9Sstevel@tonic-gate { 13267c478bd9Sstevel@tonic-gate Os_desc *osp = ofl->ofl_osgot; 13277c478bd9Sstevel@tonic-gate Sym_desc *sdp = rdesc->rel_sym; 13287c478bd9Sstevel@tonic-gate Xword gotndx; 13297c478bd9Sstevel@tonic-gate Gotref gref; 13307c478bd9Sstevel@tonic-gate Gotndx *gnp; 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate if (rdesc->rel_flags & FLG_REL_DTLS) 13337c478bd9Sstevel@tonic-gate gref = GOT_REF_TLSGD; 13347c478bd9Sstevel@tonic-gate else if (rdesc->rel_flags & FLG_REL_MTLS) 13357c478bd9Sstevel@tonic-gate gref = GOT_REF_TLSLD; 13367c478bd9Sstevel@tonic-gate else if (rdesc->rel_flags & FLG_REL_STLS) 13377c478bd9Sstevel@tonic-gate gref = GOT_REF_TLSIE; 13387c478bd9Sstevel@tonic-gate else 13397c478bd9Sstevel@tonic-gate gref = GOT_REF_GENERIC; 13407c478bd9Sstevel@tonic-gate 13415aefb655Srie gnp = ld_find_gotndx(&(sdp->sd_GOTndxs), gref, ofl, rdesc); 13427c478bd9Sstevel@tonic-gate assert(gnp); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate gotndx = (Xword)gnp->gn_gotndx; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if ((rdesc->rel_flags & FLG_REL_DTLS) && 13477c478bd9Sstevel@tonic-gate (rdesc->rel_rtype == R_AMD64_DTPOFF64)) 13487c478bd9Sstevel@tonic-gate gotndx++; 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate return ((Xword)(osp->os_shdr->sh_addr + (gotndx * M_GOT_ENTSIZE))); 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate /* ARGSUSED5 */ 1355*ba2be530Sab static uintptr_t 1356d326b23bSrie ld_assign_got_ndx(List * lst, Gotndx * pgnp, Gotref gref, Ofl_desc * ofl, 13577c478bd9Sstevel@tonic-gate Rel_desc * rsp, Sym_desc * sdp) 13587c478bd9Sstevel@tonic-gate { 13597c478bd9Sstevel@tonic-gate Xword raddend; 13607c478bd9Sstevel@tonic-gate Gotndx *gnp, *_gnp; 13617c478bd9Sstevel@tonic-gate Listnode *lnp, *plnp; 13627c478bd9Sstevel@tonic-gate uint_t gotents; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate raddend = rsp->rel_raddend; 13657c478bd9Sstevel@tonic-gate if (pgnp && (pgnp->gn_addend == raddend) && 13667c478bd9Sstevel@tonic-gate (pgnp->gn_gotref == gref)) 13677c478bd9Sstevel@tonic-gate return (1); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if ((gref == GOT_REF_TLSGD) || (gref == GOT_REF_TLSLD)) 13707c478bd9Sstevel@tonic-gate gotents = 2; 13717c478bd9Sstevel@tonic-gate else 13727c478bd9Sstevel@tonic-gate gotents = 1; 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate plnp = 0; 13757c478bd9Sstevel@tonic-gate for (LIST_TRAVERSE(lst, lnp, _gnp)) { 13767c478bd9Sstevel@tonic-gate if (_gnp->gn_addend > raddend) 13777c478bd9Sstevel@tonic-gate break; 13787c478bd9Sstevel@tonic-gate plnp = lnp; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Allocate a new entry. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate if ((gnp = libld_calloc(sizeof (Gotndx), 1)) == 0) 13857c478bd9Sstevel@tonic-gate return (S_ERROR); 13867c478bd9Sstevel@tonic-gate gnp->gn_addend = raddend; 13877c478bd9Sstevel@tonic-gate gnp->gn_gotndx = ofl->ofl_gotcnt; 13887c478bd9Sstevel@tonic-gate gnp->gn_gotref = gref; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate ofl->ofl_gotcnt += gotents; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate if (gref == GOT_REF_TLSLD) { 13937c478bd9Sstevel@tonic-gate ofl->ofl_tlsldgotndx = gnp; 13947c478bd9Sstevel@tonic-gate return (1); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate if (plnp == 0) { 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * Insert at head of list 14007c478bd9Sstevel@tonic-gate */ 14017c478bd9Sstevel@tonic-gate if (list_prependc(lst, (void *)gnp) == 0) 14027c478bd9Sstevel@tonic-gate return (S_ERROR); 14037c478bd9Sstevel@tonic-gate } else if (_gnp->gn_addend > raddend) { 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Insert in middle of lest 14067c478bd9Sstevel@tonic-gate */ 14077c478bd9Sstevel@tonic-gate if (list_insertc(lst, (void *)gnp, plnp) == 0) 14087c478bd9Sstevel@tonic-gate return (S_ERROR); 14097c478bd9Sstevel@tonic-gate } else { 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Append to tail of list 14127c478bd9Sstevel@tonic-gate */ 14137c478bd9Sstevel@tonic-gate if (list_appendc(lst, (void *)gnp) == 0) 14147c478bd9Sstevel@tonic-gate return (S_ERROR); 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate return (1); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate 1419*ba2be530Sab static void 14205aefb655Srie ld_assign_plt_ndx(Sym_desc * sdp, Ofl_desc *ofl) 14217c478bd9Sstevel@tonic-gate { 14227c478bd9Sstevel@tonic-gate sdp->sd_aux->sa_PLTndx = 1 + ofl->ofl_pltcnt++; 14237c478bd9Sstevel@tonic-gate sdp->sd_aux->sa_PLTGOTndx = ofl->ofl_gotcnt++; 1424141040e8Srie ofl->ofl_flags |= FLG_OF_BLDGOT; 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 1427b3fbe5e6Sseizo static uchar_t plt0_template[M_PLT_ENTSIZE] = { 14287c478bd9Sstevel@tonic-gate /* 0x00 PUSHQ GOT+8(%rip) */ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, 14297c478bd9Sstevel@tonic-gate /* 0x06 JMP *GOT+16(%rip) */ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 14307c478bd9Sstevel@tonic-gate /* 0x0c NOP */ 0x90, 14317c478bd9Sstevel@tonic-gate /* 0x0d NOP */ 0x90, 14327c478bd9Sstevel@tonic-gate /* 0x0e NOP */ 0x90, 14337c478bd9Sstevel@tonic-gate /* 0x0f NOP */ 0x90 14347c478bd9Sstevel@tonic-gate }; 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /* 14377c478bd9Sstevel@tonic-gate * Initializes .got[0] with the _DYNAMIC symbol value. 14387c478bd9Sstevel@tonic-gate */ 1439*ba2be530Sab static uintptr_t 1440d326b23bSrie ld_fillin_gotplt(Ofl_desc *ofl) 14417c478bd9Sstevel@tonic-gate { 1442*ba2be530Sab int bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0; 1443*ba2be530Sab 14447c478bd9Sstevel@tonic-gate if (ofl->ofl_osgot) { 1445d326b23bSrie Sym_desc *sdp; 14467c478bd9Sstevel@tonic-gate 14475aefb655Srie if ((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_DYNAMIC_U), 14487c478bd9Sstevel@tonic-gate SYM_NOHASH, 0, ofl)) != NULL) { 1449d326b23bSrie uchar_t *genptr; 1450d326b23bSrie 1451d326b23bSrie genptr = ((uchar_t *)ofl->ofl_osgot->os_outdata->d_buf + 14527c478bd9Sstevel@tonic-gate (M_GOT_XDYNAMIC * M_GOT_ENTSIZE)); 14537c478bd9Sstevel@tonic-gate /* LINTED */ 14547c478bd9Sstevel@tonic-gate *(Xword *)genptr = sdp->sd_sym->st_value; 1455*ba2be530Sab if (bswap) 1456*ba2be530Sab /* LINTED */ 1457*ba2be530Sab *(Xword *)genptr = 1458*ba2be530Sab /* LINTED */ 1459*ba2be530Sab ld_bswap_Xword(*(Xword *)genptr); 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate } 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate /* 14647c478bd9Sstevel@tonic-gate * Fill in the reserved slot in the procedure linkage table the first 14657c478bd9Sstevel@tonic-gate * entry is: 14667c478bd9Sstevel@tonic-gate * 0x00 PUSHQ GOT+8(%rip) # GOT[1] 14677c478bd9Sstevel@tonic-gate * 0x06 JMP *GOT+16(%rip) # GOT[2] 14687c478bd9Sstevel@tonic-gate * 0x0c NOP 14697c478bd9Sstevel@tonic-gate * 0x0d NOP 14707c478bd9Sstevel@tonic-gate * 0x0e NOP 14717c478bd9Sstevel@tonic-gate * 0x0f NOP 14727c478bd9Sstevel@tonic-gate */ 1473f3324781Sab if ((ofl->ofl_flags & FLG_OF_DYNAMIC) && ofl->ofl_osplt) { 1474d326b23bSrie uchar_t *pltent; 1475d326b23bSrie Xword val1; 14767c478bd9Sstevel@tonic-gate 1477b3fbe5e6Sseizo pltent = (uchar_t *)ofl->ofl_osplt->os_outdata->d_buf; 14787c478bd9Sstevel@tonic-gate bcopy(plt0_template, pltent, sizeof (plt0_template)); 14797c478bd9Sstevel@tonic-gate 1480f3324781Sab /* 1481f3324781Sab * If '-z noreloc' is specified - skip the do_reloc_ld 1482f3324781Sab * stage. 1483f3324781Sab */ 1484f3324781Sab if (!OFL_DO_RELOC(ofl)) 1485f3324781Sab return (1); 1486f3324781Sab 14877c478bd9Sstevel@tonic-gate /* 14887c478bd9Sstevel@tonic-gate * filin: 14897c478bd9Sstevel@tonic-gate * PUSHQ GOT + 8(%rip) 14907c478bd9Sstevel@tonic-gate * 14917c478bd9Sstevel@tonic-gate * Note: 0x06 below represents the offset to the 14927c478bd9Sstevel@tonic-gate * next instruction - which is what %rip will 14937c478bd9Sstevel@tonic-gate * be pointing at. 14947c478bd9Sstevel@tonic-gate */ 14957c478bd9Sstevel@tonic-gate val1 = (ofl->ofl_osgot->os_shdr->sh_addr) + 1496de777a60Sab (M_GOT_XLINKMAP * M_GOT_ENTSIZE) - 1497de777a60Sab ofl->ofl_osplt->os_shdr->sh_addr - 0x06; 14987c478bd9Sstevel@tonic-gate 1499f3324781Sab if (do_reloc_ld(R_AMD64_GOTPCREL, &pltent[0x02], 1500f3324781Sab &val1, MSG_ORIG(MSG_SYM_PLTENT), 1501f3324781Sab MSG_ORIG(MSG_SPECFIL_PLTENT), bswap, ofl->ofl_lml) == 0) { 1502f3324781Sab eprintf(ofl->ofl_lml, ERR_FATAL, 1503f3324781Sab MSG_INTL(MSG_PLT_PLT0FAIL)); 1504f3324781Sab return (S_ERROR); 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate 15077c478bd9Sstevel@tonic-gate /* 15087c478bd9Sstevel@tonic-gate * filin: 15097c478bd9Sstevel@tonic-gate * JMP *GOT+16(%rip) 15107c478bd9Sstevel@tonic-gate */ 15117c478bd9Sstevel@tonic-gate val1 = (ofl->ofl_osgot->os_shdr->sh_addr) + 1512de777a60Sab (M_GOT_XRTLD * M_GOT_ENTSIZE) - 1513de777a60Sab ofl->ofl_osplt->os_shdr->sh_addr - 0x0c; 1514f3324781Sab 1515f3324781Sab if (do_reloc_ld(R_AMD64_GOTPCREL, &pltent[0x08], 1516f3324781Sab &val1, MSG_ORIG(MSG_SYM_PLTENT), 1517f3324781Sab MSG_ORIG(MSG_SPECFIL_PLTENT), bswap, ofl->ofl_lml) == 0) { 1518f3324781Sab eprintf(ofl->ofl_lml, ERR_FATAL, 1519f3324781Sab MSG_INTL(MSG_PLT_PLT0FAIL)); 1520f3324781Sab return (S_ERROR); 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate } 1523f3324781Sab 15247c478bd9Sstevel@tonic-gate return (1); 15257c478bd9Sstevel@tonic-gate } 1526*ba2be530Sab 1527*ba2be530Sab 1528*ba2be530Sab 1529*ba2be530Sab /* 1530*ba2be530Sab * Template for generating "void (*)(void)" function 1531*ba2be530Sab */ 1532*ba2be530Sab static const uchar_t nullfunc_tmpl[] = { /* amd64 */ 1533*ba2be530Sab /* 0x00 */ 0x55, /* pushq %rbp */ 1534*ba2be530Sab /* 0x01 */ 0x48, 0x8b, 0xec, /* movq %rsp,%rbp */ 1535*ba2be530Sab /* 0x04 */ 0x48, 0x8b, 0xe5, /* movq %rbp,%rsp */ 1536*ba2be530Sab /* 0x07 */ 0x5d, /* popq %rbp */ 1537*ba2be530Sab /* 0x08 */ 0xc3 /* ret */ 1538*ba2be530Sab }; 1539*ba2be530Sab 1540*ba2be530Sab 1541*ba2be530Sab /* 1542*ba2be530Sab * Return the ld_targ definition for this target. 1543*ba2be530Sab */ 1544*ba2be530Sab const Target * 1545*ba2be530Sab ld_targ_init_x86(void) 1546*ba2be530Sab { 1547*ba2be530Sab static const Target _ld_targ = { 1548*ba2be530Sab { /* Target_mach */ 1549*ba2be530Sab M_MACH, /* m_mach */ 1550*ba2be530Sab M_MACHPLUS, /* m_machplus */ 1551*ba2be530Sab M_FLAGSPLUS, /* m_flagsplus */ 1552*ba2be530Sab M_CLASS, /* m_class */ 1553*ba2be530Sab M_DATA, /* m_data */ 1554*ba2be530Sab 1555*ba2be530Sab M_SEGM_ALIGN, /* m_segm_align */ 1556*ba2be530Sab M_SEGM_ORIGIN, /* m_segm_origin */ 1557*ba2be530Sab M_DATASEG_PERM, /* m_dataseg_perm */ 1558*ba2be530Sab M_WORD_ALIGN, /* m_word_align */ 1559*ba2be530Sab MSG_ORIG(MSG_PTH_RTLD_AMD64), /* m_def_interp */ 1560*ba2be530Sab 1561*ba2be530Sab /* Relocation type codes */ 1562*ba2be530Sab M_R_ARRAYADDR, /* m_r_arrayaddr */ 1563*ba2be530Sab M_R_COPY, /* m_r_copy */ 1564*ba2be530Sab M_R_GLOB_DAT, /* m_r_glob_dat */ 1565*ba2be530Sab M_R_JMP_SLOT, /* m_r_jmp_slot */ 1566*ba2be530Sab M_R_NUM, /* m_r_num */ 1567*ba2be530Sab M_R_NONE, /* m_r_none */ 1568*ba2be530Sab M_R_RELATIVE, /* m_r_relative */ 1569*ba2be530Sab M_R_REGISTER, /* m_r_register */ 1570*ba2be530Sab 1571*ba2be530Sab /* Relocation related constants */ 1572*ba2be530Sab M_REL_DT_COUNT, /* m_rel_dt_count */ 1573*ba2be530Sab M_REL_DT_ENT, /* m_rel_dt_ent */ 1574*ba2be530Sab M_REL_DT_SIZE, /* m_rel_dt_size */ 1575*ba2be530Sab M_REL_DT_TYPE, /* m_rel_dt_type */ 1576*ba2be530Sab M_REL_SHT_TYPE, /* m_rel_sht_type */ 1577*ba2be530Sab 1578*ba2be530Sab /* GOT related constants */ 1579*ba2be530Sab M_GOT_ENTSIZE, /* m_got_entsize */ 1580*ba2be530Sab M_GOT_XNumber, /* m_got_xnumber */ 1581*ba2be530Sab 1582*ba2be530Sab /* PLT related constants */ 1583*ba2be530Sab M_PLT_ALIGN, /* m_plt_align */ 1584*ba2be530Sab M_PLT_ENTSIZE, /* m_plt_entsize */ 1585*ba2be530Sab M_PLT_RESERVSZ, /* m_plt_reservsz */ 1586*ba2be530Sab M_PLT_SHF_FLAGS, /* m_plt_shf_flags */ 1587*ba2be530Sab 1588*ba2be530Sab M_DT_REGISTER, /* m_dt_register */ 1589*ba2be530Sab }, 1590*ba2be530Sab { /* Target_machid */ 1591*ba2be530Sab M_ID_ARRAY, /* id_array */ 1592*ba2be530Sab M_ID_BSS, /* id_bss */ 1593*ba2be530Sab M_ID_CAP, /* id_cap */ 1594*ba2be530Sab M_ID_DATA, /* id_data */ 1595*ba2be530Sab M_ID_DYNAMIC, /* id_dynamic */ 1596*ba2be530Sab M_ID_DYNSORT, /* id_dynsort */ 1597*ba2be530Sab M_ID_DYNSTR, /* id_dynstr */ 1598*ba2be530Sab M_ID_DYNSYM, /* id_dynsym */ 1599*ba2be530Sab M_ID_DYNSYM_NDX, /* id_dynsym_ndx */ 1600*ba2be530Sab M_ID_GOT, /* id_got */ 1601*ba2be530Sab M_ID_UNKNOWN, /* id_gotdata (unused) */ 1602*ba2be530Sab M_ID_HASH, /* id_hash */ 1603*ba2be530Sab M_ID_INTERP, /* id_interp */ 1604*ba2be530Sab M_ID_LBSS, /* id_lbss */ 1605*ba2be530Sab M_ID_LDYNSYM, /* id_ldynsym */ 1606*ba2be530Sab M_ID_NOTE, /* id_note */ 1607*ba2be530Sab M_ID_NULL, /* id_null */ 1608*ba2be530Sab M_ID_PLT, /* id_plt */ 1609*ba2be530Sab M_ID_REL, /* id_rel */ 1610*ba2be530Sab M_ID_STRTAB, /* id_strtab */ 1611*ba2be530Sab M_ID_SYMINFO, /* id_syminfo */ 1612*ba2be530Sab M_ID_SYMTAB, /* id_symtab */ 1613*ba2be530Sab M_ID_SYMTAB_NDX, /* id_symtab_ndx */ 1614*ba2be530Sab M_ID_TEXT, /* id_text */ 1615*ba2be530Sab M_ID_TLS, /* id_tls */ 1616*ba2be530Sab M_ID_TLSBSS, /* id_tlsbss */ 1617*ba2be530Sab M_ID_UNKNOWN, /* id_unknown */ 1618*ba2be530Sab M_ID_UNWIND, /* id_unwind */ 1619*ba2be530Sab M_ID_USER, /* id_user */ 1620*ba2be530Sab M_ID_VERSION, /* id_version */ 1621*ba2be530Sab }, 1622*ba2be530Sab { /* Target_nullfunc */ 1623*ba2be530Sab nullfunc_tmpl, /* nf_template */ 1624*ba2be530Sab sizeof (nullfunc_tmpl), /* nf_size */ 1625*ba2be530Sab }, 1626*ba2be530Sab { /* Target_machrel */ 1627*ba2be530Sab reloc_table, 1628*ba2be530Sab 1629*ba2be530Sab ld_init_rel, /* mr_init_rel */ 1630*ba2be530Sab ld_mach_eflags, /* mr_mach_eflags */ 1631*ba2be530Sab ld_mach_make_dynamic, /* mr_mach_make_dynamic */ 1632*ba2be530Sab ld_mach_update_odynamic, /* mr_mach_update_odynamic */ 1633*ba2be530Sab ld_calc_plt_addr, /* mr_calc_plt_addr */ 1634*ba2be530Sab ld_perform_outreloc, /* mr_perform_outreloc */ 1635*ba2be530Sab ld_do_activerelocs, /* mr_do_activerelocs */ 1636*ba2be530Sab ld_add_outrel, /* mr_add_outrel */ 1637*ba2be530Sab NULL, /* mr_reloc_register */ 1638*ba2be530Sab ld_reloc_local, /* mr_reloc_local */ 1639*ba2be530Sab NULL, /* mr_reloc_GOTOP */ 1640*ba2be530Sab ld_reloc_TLS, /* mr_reloc_TLS */ 1641*ba2be530Sab NULL, /* mr_assign_got */ 1642*ba2be530Sab ld_find_gotndx, /* mr_find_gotndx */ 1643*ba2be530Sab ld_calc_got_offset, /* mr_calc_got_offset */ 1644*ba2be530Sab ld_assign_got_ndx, /* mr_assign_got_ndx */ 1645*ba2be530Sab ld_assign_plt_ndx, /* mr_assign_plt_ndx */ 1646*ba2be530Sab NULL, /* mr_allocate_got */ 1647*ba2be530Sab ld_fillin_gotplt, /* mr_fillin_gotplt */ 1648*ba2be530Sab }, 1649*ba2be530Sab { /* Target_machsym */ 1650*ba2be530Sab NULL, /* ms_reg_check */ 1651*ba2be530Sab NULL, /* ms_mach_sym_typecheck */ 1652*ba2be530Sab NULL, /* ms_is_regsym */ 1653*ba2be530Sab NULL, /* ms_reg_find */ 1654*ba2be530Sab NULL /* ms_reg_enter */ 1655*ba2be530Sab }, 1656*ba2be530Sab { /* Target_unwind */ 1657*ba2be530Sab make_amd64_unwindhdr, /* uw_make_unwindhdr */ 1658*ba2be530Sab populate_amd64_unwindhdr, /* uw_populate_unwindhdr */ 1659*ba2be530Sab append_amd64_unwind, /* uw_append_unwind */ 1660*ba2be530Sab } 1661*ba2be530Sab }; 1662*ba2be530Sab 1663*ba2be530Sab return (&_ld_targ); 1664*ba2be530Sab } 1665