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