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