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