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