head	1.19;
access;
symbols
	netbsd-11-0-RC5:1.19
	netbsd-11-0-RC4:1.19
	netbsd-11-0-RC3:1.19
	netbsd-11-0-RC2:1.19
	netbsd-11-0-RC1:1.19
	perseant-exfatfs-base-20250801:1.19
	netbsd-11:1.19.0.2
	netbsd-11-base:1.19
	netbsd-10-1-RELEASE:1.17.2.1
	perseant-exfatfs-base-20240630:1.18
	perseant-exfatfs:1.18.0.2
	perseant-exfatfs-base:1.18
	netbsd-8-3-RELEASE:1.2.8.1
	netbsd-9-4-RELEASE:1.13.2.1
	netbsd-10-0-RELEASE:1.17.2.1
	netbsd-10-0-RC6:1.17.2.1
	netbsd-10-0-RC5:1.17.2.1
	netbsd-10-0-RC4:1.17.2.1
	netbsd-10-0-RC3:1.17.2.1
	netbsd-10-0-RC2:1.17.2.1
	netbsd-10-0-RC1:1.17.2.1
	netbsd-10:1.17.0.2
	netbsd-10-base:1.17
	netbsd-9-3-RELEASE:1.13
	cjep_sun2x-base1:1.14
	cjep_sun2x:1.14.0.4
	cjep_sun2x-base:1.14
	cjep_staticlib_x-base1:1.14
	netbsd-9-2-RELEASE:1.13
	cjep_staticlib_x:1.14.0.2
	cjep_staticlib_x-base:1.14
	netbsd-9-1-RELEASE:1.13
	phil-wifi-20200421:1.13
	phil-wifi-20200411:1.13
	is-mlppp:1.13.0.4
	is-mlppp-base:1.13
	phil-wifi-20200406:1.13
	netbsd-8-2-RELEASE:1.2.8.1
	netbsd-9-0-RELEASE:1.13
	netbsd-9-0-RC2:1.13
	netbsd-9-0-RC1:1.13
	phil-wifi-20191119:1.13
	netbsd-9:1.13.0.2
	netbsd-9-base:1.13
	phil-wifi-20190609:1.13
	netbsd-8-1-RELEASE:1.2.8.1
	netbsd-8-1-RC1:1.2.8.1
	pgoyette-compat-merge-20190127:1.7.2.4
	pgoyette-compat-20190127:1.13
	pgoyette-compat-20190118:1.12
	pgoyette-compat-1226:1.12
	pgoyette-compat-1126:1.12
	pgoyette-compat-1020:1.10
	pgoyette-compat-0930:1.10
	pgoyette-compat-0906:1.8
	netbsd-7-2-RELEASE:1.1.2.1
	pgoyette-compat-0728:1.8
	netbsd-8-0-RELEASE:1.2.8.1
	phil-wifi:1.7.0.4
	phil-wifi-base:1.7
	pgoyette-compat-0625:1.7
	netbsd-8-0-RC2:1.2.8.1
	pgoyette-compat-0521:1.7
	pgoyette-compat-0502:1.7
	pgoyette-compat-0422:1.7
	netbsd-8-0-RC1:1.2.8.1
	pgoyette-compat-0415:1.7
	pgoyette-compat-0407:1.7
	pgoyette-compat-0330:1.7
	pgoyette-compat-0322:1.7
	pgoyette-compat-0315:1.7
	netbsd-7-1-2-RELEASE:1.1.2.1
	pgoyette-compat:1.7.0.2
	pgoyette-compat-base:1.7
	netbsd-7-1-1-RELEASE:1.1.2.1
	matt-nb8-mediatek:1.2.8.1.0.2
	matt-nb8-mediatek-base:1.2.8.1
	perseant-stdc-iso10646:1.3.0.2
	perseant-stdc-iso10646-base:1.3
	netbsd-8:1.2.0.8
	netbsd-8-base:1.2
	prg-localcount2-base3:1.2
	prg-localcount2-base2:1.2
	prg-localcount2-base1:1.2
	prg-localcount2:1.2.0.6
	prg-localcount2-base:1.2
	pgoyette-localcount-20170426:1.2
	bouyer-socketcan-base1:1.2
	pgoyette-localcount-20170320:1.2
	netbsd-7-1:1.1.2.1.0.4
	netbsd-7-1-RELEASE:1.1.2.1
	netbsd-7-1-RC2:1.1.2.1
	netbsd-7-nhusb-base-20170116:1.1.2.1
	bouyer-socketcan:1.2.0.4
	bouyer-socketcan-base:1.2
	pgoyette-localcount-20170107:1.2
	netbsd-7-1-RC1:1.1.2.1
	pgoyette-localcount-20161104:1.2
	netbsd-7-0-2-RELEASE:1.1
	localcount-20160914:1.2
	netbsd-7-nhusb:1.1.2.1.0.2
	netbsd-7-nhusb-base:1.1.2.1
	pgoyette-localcount-20160806:1.2
	pgoyette-localcount-20160726:1.2
	pgoyette-localcount:1.2.0.2
	pgoyette-localcount-base:1.2
	netbsd-7-0-1-RELEASE:1.1
	netbsd-7-0:1.1.0.6
	netbsd-7-0-RELEASE:1.1
	netbsd-7-0-RC3:1.1
	netbsd-7-0-RC2:1.1
	netbsd-7-0-RC1:1.1
	tls-maxphys-base:1.1
	tls-maxphys:1.1.0.4
	netbsd-7:1.1.0.2
	netbsd-7-base:1.1;
locks; strict;
comment	@ * @;


1.19
date	2024.07.22.23.10.35;	author riastradh;	state Exp;
branches;
next	1.18;
commitid	p1FHYC54EYCwcTiF;

1.18
date	2023.06.04.01.24.56;	author joerg;	state Exp;
branches
	1.18.2.1;
next	1.17;
commitid	jBAtDE6SYslzbzrE;

1.17
date	2022.12.03.09.10.40;	author skrll;	state Exp;
branches
	1.17.2.1;
next	1.16;
commitid	DxcJcDUCQ4B7K54E;

1.16
date	2022.06.21.06.52.17;	author skrll;	state Exp;
branches;
next	1.15;
commitid	4HTax0jdtswlhSID;

1.15
date	2022.05.31.08.43.14;	author andvar;	state Exp;
branches;
next	1.14;
commitid	yPbXHl19O9q2zbGD;

1.14
date	2020.06.16.21.01.30;	author joerg;	state Exp;
branches;
next	1.13;
commitid	UKSaednCRCEtBucC;

1.13
date	2019.01.18.11.59.03;	author skrll;	state Exp;
branches
	1.13.2.1;
next	1.12;
commitid	gN3qAkY8cHxt8g8B;

1.12
date	2018.11.23.11.26.05;	author skrll;	state Exp;
branches;
next	1.11;
commitid	MlsJanylb9d8M31B;

1.11
date	2018.11.23.10.59.20;	author skrll;	state Exp;
branches;
next	1.10;
commitid	di9Ztjrc5i7XC31B;

1.10
date	2018.09.20.19.02.22;	author jakllsch;	state Exp;
branches;
next	1.9;
commitid	wxqJ4BZPZlE6mSSA;

1.9
date	2018.09.20.18.41.05;	author jakllsch;	state Exp;
branches;
next	1.8;
commitid	hX7B1wUA5FureSSA;

1.8
date	2018.07.16.00.29.37;	author christos;	state Exp;
branches;
next	1.7;
commitid	0CENHtW7DWtWjiKA;

1.7
date	2018.02.04.21.49.51;	author skrll;	state Exp;
branches
	1.7.2.1
	1.7.4.1;
next	1.6;
commitid	qFAQlRPYfvSjBApA;

1.6
date	2017.08.28.06.59.25;	author nisimura;	state Exp;
branches;
next	1.5;
commitid	9ZdjAoKHUkvtPW4A;

1.5
date	2017.08.23.09.17.48;	author nisimura;	state Exp;
branches;
next	1.4;
commitid	bn8Ak9vx4ysCKj4A;

1.4
date	2017.08.10.19.03.25;	author joerg;	state Exp;
branches;
next	1.3;
commitid	UgH5577k4GrjpH2A;

1.3
date	2017.06.19.11.57.01;	author joerg;	state Exp;
branches;
next	1.2;
commitid	pYVYx1tH1kZmHYVz;

1.2
date	2014.08.25.20.40.52;	author joerg;	state Exp;
branches
	1.2.8.1;
next	1.1;
commitid	hm6gwLhn9YorHMNx;

1.1
date	2014.08.10.05.47.37;	author matt;	state Exp;
branches
	1.1.2.1
	1.1.4.1;
next	;
commitid	RVnl0fvYYjtzeMLx;

1.18.2.1
date	2025.08.02.05.55.01;	author perseant;	state Exp;
branches;
next	;
commitid	23j6GFaDws3O875G;

1.17.2.1
date	2023.08.01.16.34.58;	author martin;	state Exp;
branches;
next	;
commitid	ygiHGMga8HEgs6zE;

1.13.2.1
date	2023.08.04.12.55.46;	author martin;	state Exp;
branches;
next	1.13.2.2;
commitid	WQUk0iGBkKS39tzE;

1.13.2.2
date	2024.08.07.10.45.41;	author martin;	state Exp;
branches;
next	;
commitid	oeC8MTiJlGv6zSkF;

1.7.2.1
date	2018.07.28.04.37.23;	author pgoyette;	state Exp;
branches;
next	1.7.2.2;
commitid	1UP1xAIUxv1ZgRLA;

1.7.2.2
date	2018.09.30.01.45.34;	author pgoyette;	state Exp;
branches;
next	1.7.2.3;
commitid	SQ44grEPCeKPh4UA;

1.7.2.3
date	2018.11.26.01.52.13;	author pgoyette;	state Exp;
branches;
next	1.7.2.4;
commitid	Zj4q5SspGdKXto1B;

1.7.2.4
date	2019.01.26.21.59.58;	author pgoyette;	state Exp;
branches;
next	;
commitid	JKpcmvSjdT25dl9B;

1.7.4.1
date	2019.06.10.22.05.30;	author christos;	state Exp;
branches;
next	;
commitid	jtc8rnCzWiEEHGqB;

1.2.8.1
date	2017.07.04.12.47.58;	author martin;	state Exp;
branches;
next	;
commitid	WH1NGk1BGSqEwUXz;

1.1.2.1
date	2016.03.06.18.17.55;	author martin;	state Exp;
branches;
next	;
commitid	Ns3WeAQc8ORoVBXy;

1.1.4.1
date	2014.08.10.05.47.37;	author tls;	state dead;
branches;
next	1.1.4.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.4.2
date	2014.08.20.00.02.22;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;


desc
@@


1.19
log
@ld.elf_so: Cite reference for Arm ELF relocations.

PR lib/58455: Missing references for processor-specific ELF
relocation semantics
@
text
@/* $NetBSD: mdreloc.c,v 1.18 2023/06/04 01:24:56 joerg Exp $ */

/*-
 * Copyright (c) 2014 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Matt Thomas of 3am Software Foundry.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*-
 * Copyright (c) 2014-2015 The FreeBSD Foundation
 * All rights reserved.
 *
 * Portions of this software were developed by Andrew Turner
 * under sponsorship from the FreeBSD Foundation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.18 2023/06/04 01:24:56 joerg Exp $");
#endif /* not lint */

/*
 * AArch64 ELF relocations.
 *
 * References:
 *
 *	[AAELF64] ELF for the Arm 64-bit Architecture (AArch64),
 *	2022Q3.  Arm Ltd.
 *	https://github.com/ARM-software/abi-aa/blob/2982a9f3b512a5bfdc9e3fea5d3b298f9165c36b/aaelf64/aaelf64.rst
 *
 *	[TLSDESC] Glauber de Oliveira Costa and Alexandre Oliva,
 *	`Thread-Local Storage Access in Dynamic Libraries in the ARM
 *	Platform', 2006.
 *	https://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf
 */

#include <sys/types.h>
#include <string.h>

#include "debug.h"
#include "rtld.h"

struct tls_data {
	size_t		td_tlsindex;
	Elf_Addr	td_tlsoffs;
};

void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
Elf_Addr _rtld_bind(const Obj_Entry *, Elf_Word);
void *_rtld_tlsdesc_static(void *);
void *_rtld_tlsdesc_undef(void *);
void *_rtld_tlsdesc_dynamic(void *);

/*
 * AARCH64 PLT looks like this;
 *
 *	PLT HEADER <8 instructions>
 *	PLT ENTRY #0 <4 instructions>
 *	PLT ENTRY #1 <4 instructions>
 *	.
 *	.
 *	PLT ENTRY #n <4 instructions>
 *
 * PLT HEADER
 *	stp  x16, x30, [sp, #-16]!
 *	adrp x16, (GOT+16)
 *	ldr  x17, [x16, #PLT_GOT+0x10]
 *	add  x16, x16, #PLT_GOT+0x10
 *	br   x17
 *	nop
 *	nop
 *	nop
 *
 * PLT ENTRY #n
 *	adrp x16, PLTGOT + n * 8
 *	ldr  x17, [x16, PLTGOT + n * 8]
 *	add  x16, x16, :lo12:PLTGOT + n * 8
 *	br   x17
 */
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{

	obj->pltgot[1] = (Elf_Addr) obj;
	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}

static struct tls_data *
_rtld_tlsdesc_alloc(size_t tlsindex, Elf_Addr offs)
{
	struct tls_data *tlsdesc;

	tlsdesc = xmalloc(sizeof(*tlsdesc));
	tlsdesc->td_tlsindex = tlsindex;
	tlsdesc->td_tlsoffs = offs;

	return tlsdesc;
}

static void
_rtld_tlsdesc_fill(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where, u_int flags)
{
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Elf_Addr offs = 0;
	unsigned long symnum = ELF_R_SYM(rela->r_info);

	if (symnum != 0) {
		def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags);
		if (def == NULL)
			_rtld_die();
		if (def == &_rtld_sym_zero) {
			/* Weak undefined thread variable */
			where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
			where[1] = rela->r_addend;

			rdbg(("TLSDESC %s (weak) in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)where[1]));

			return;
		}
		offs = def->st_value;
	} else {
		defobj = obj;
	}
	offs += rela->r_addend;

	if (defobj->tls_static) {
		/* Variable is in initially allocated TLS segment */
		where[0] = (Elf_Addr)_rtld_tlsdesc_static;
		where[1] = defobj->tlsoffset + offs +
		    sizeof(struct tls_tcb);

		rdbg(("TLSDESC %s --> %p static",
		    obj->path, (void *)where[1]));
	} else {
		/* TLS offset is unknown at load time, use dynamic resolving */
		where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
		where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(defobj->tlsindex, offs);

		rdbg(("TLSDESC %s in %s --> %p dynamic (%zu, %p)",
		    obj->strtab + obj->symtab[symnum].st_name,
		    obj->path, (void *)where[1], defobj->tlsindex, (void *)offs));
	}
}

void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
	const Elf_Rela *rela = 0, *relalim;
	Elf_Addr relasz = 0;
	Elf_Addr *where;

	for (; dynp->d_tag != DT_NULL; dynp++) {
		switch (dynp->d_tag) {
		case DT_RELA:
			rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_RELASZ:
			relasz = dynp->d_un.d_val;
			break;
		}
	}
	relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
	for (; rela < relalim; rela++) {
		where = (Elf_Addr *)(relocbase + rela->r_offset);
		*where += (Elf_Addr)relocbase;
	}
}

int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
	const Elf_Sym *def = NULL;
	const Obj_Entry *defobj = NULL;
	unsigned long last_symnum = ULONG_MAX;

	for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) {
		Elf_Addr        *where;
		Elf_Addr	tmp;
		unsigned long	symnum = ULONG_MAX;

		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);

		switch (ELF_R_TYPE(rela->r_info)) {
		case R_TYPE(ABS64):	/* word S + A */
		case R_TYPE(GLOB_DAT):	/* word S + A */
		case R_TLS_TYPE(TLS_DTPREL):
		case R_TLS_TYPE(TLS_DTPMOD):
		case R_TLS_TYPE(TLS_TPREL):
			symnum = ELF_R_SYM(rela->r_info);
			if (last_symnum != symnum) {
				last_symnum = symnum;
				def = _rtld_find_symdef(symnum, obj, &defobj,
				    false);
				if (def == NULL)
					return -1;
			}

		default:
			break;
		}

		switch (ELF_R_TYPE(rela->r_info)) {
		case R_TYPE(NONE):
			break;

		case R_TYPE(ABS64):	/* word S + A */
		case R_TYPE(GLOB_DAT):	/* word S + A */
			tmp = (Elf_Addr)defobj->relocbase + def->st_value +
			    rela->r_addend;
			if (*where != tmp)
				*where = tmp;
			rdbg(("ABS64/GLOB_DAT %s in %s --> %p @@ %p in %s",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp, where, defobj->path));
			break;

		case R_TYPE(IRELATIVE):
			/* IFUNC relocations are handled in _rtld_call_ifunc */
			if (obj->ifunc_remaining_nonplt == 0)
				obj->ifunc_remaining_nonplt = obj->relalim - rela;
			rdbg(("IRELATIVE in %s, %zx", obj->path,
			    obj->ifunc_remaining_nonplt));
			/* FALLTHROUGH */

		case R_TYPE(RELATIVE):	/* word B + A */
			*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
			rdbg(("RELATIVE in %s --> %p", obj->path,
			    (void *)*where));
			break;

		case R_TYPE(COPY):
			/*
			 * These are deferred until all other relocations have
			 * been done.  All we do here is make sure that the
			 * COPY relocation is not in a shared library.  They
			 * are allowed only in executable files.
			 */
			if (obj->isdynamic) {
				_rtld_error(
			"%s: Unexpected R_COPY relocation in shared library",
				    obj->path);
				return -1;
			}
			rdbg(("COPY (avoid in main)"));
			break;

		case R_TYPE(TLSDESC):
			_rtld_tlsdesc_fill(obj, rela, where, 0);
			break;

		case R_TLS_TYPE(TLS_DTPREL):
			*where = (Elf_Addr)(def->st_value + rela->r_addend);

			rdbg(("TLS_DTPREL %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)*where));
			break;

		case R_TLS_TYPE(TLS_DTPMOD):
			*where = (Elf_Addr)(defobj->tlsindex);

			rdbg(("TLS_DTPMOD %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)*where));
			break;

		case R_TLS_TYPE(TLS_TPREL):
			if (!defobj->tls_static &&
			    _rtld_tls_offset_allocate(__UNCONST(defobj)))
				return -1;

			*where = (Elf_Addr)(def->st_value + defobj->tlsoffset +
			    rela->r_addend + sizeof(struct tls_tcb));

			rdbg(("TLS_TPREL %s in %s --> %p in %s",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)*where, defobj->path));
			break;

		default:
			rdbg(("sym = %lu, type = %lu, offset = %p, "
			    "addend = %p, contents = %p",
			    (u_long)ELF_R_SYM(rela->r_info),
			    (u_long)ELF_R_TYPE(rela->r_info),
			    (void *)rela->r_offset, (void *)rela->r_addend,
			    (void *)*where));
			_rtld_error("%s: Unsupported relocation type %ld "
			    "in non-PLT relocations",
			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
			return -1;
		}
	}
	return 0;
}

int
_rtld_relocate_plt_lazy(Obj_Entry *obj)
{

	if (!obj->relocbase)
		return 0;

	for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);

		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT) ||
		       ELF_R_TYPE(rela->r_info) == R_TYPE(TLSDESC) ||
		       ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE));

		switch (ELF_R_TYPE(rela->r_info)) {
		case R_TYPE(JUMP_SLOT):
			/* Just relocate the GOT slots pointing into the PLT */
			*where += (Elf_Addr)obj->relocbase;
			rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
			break;
		case R_TYPE(TLSDESC):
			_rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT);
			break;
		case R_TYPE(IRELATIVE):
			obj->ifunc_remaining = obj->pltrelalim - rela;
			break;
		}
	}

	return 0;
}

void
_rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
{
	const Elf_Rela *rela;
	Elf_Addr *where, target;

	while (obj->ifunc_remaining > 0 && _rtld_objgen == cur_objgen) {
		rela = obj->pltrelalim - obj->ifunc_remaining;
		--obj->ifunc_remaining;
		if (ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)) {
			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
			target = (Elf_Addr)(obj->relocbase + rela->r_addend);
			_rtld_exclusive_exit(mask);
			target = _rtld_resolve_ifunc2(obj, target);
			_rtld_exclusive_enter(mask);
			if (*where != target)
				*where = target;
		}
	}
}

static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
	Elf_Addr *tp)
{
	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
	Elf_Addr new_value;
	const Elf_Sym  *def;
	const Obj_Entry *defobj;

	switch (ELF_R_TYPE(rela->r_info)) {
	case R_TYPE(JUMP_SLOT):
		def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj,
		    &defobj, tp != NULL);
		if (__predict_false(def == NULL))
			return -1;
		if (__predict_false(def == &_rtld_sym_zero))
			return 0;

		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
			if (tp == NULL)
				return 0;
			new_value = _rtld_resolve_ifunc(defobj, def);
		} else {
			new_value = (Elf_Addr)(defobj->relocbase +
			     def->st_value);
		}
		rdbg(("bind now/fixup in %s --> old=%p new=%p",
		    defobj->strtab + def->st_name, (void *)*where,
		    (void *)new_value));
		if (*where != new_value)
			*where = new_value;
		if (tp)
			*tp = new_value;
		break;
	case R_TYPE(TLSDESC):
		_rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT);
		break;
	}

	return 0;
}

Elf_Addr
_rtld_bind(const Obj_Entry *obj, Elf_Word relaidx)
{
	const Elf_Rela *rela = obj->pltrela + relaidx;
	Elf_Addr new_value = 0;

	_rtld_shared_enter();
	int err = _rtld_relocate_plt_object(obj, rela, &new_value);
	if (err)
		_rtld_die();
	_rtld_shared_exit();

	return new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
	const Elf_Rela *rela;
	int err = 0;

	for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
		err = _rtld_relocate_plt_object(obj, rela, NULL);
		if (err)
			break;
	}

	return err;
}
@


1.18
log
@Fix interactions of initial-exec TLS model and dlopen

(1) If an initial-exec relocation was used for a non-local symbol
(i.e. the definition of the symbol is in a different DSO), the
computation of the static TLS offset used the wrong DSO.
This would effectively mean the wrong address was computed
(PR toolchain/50277, PR pkg/57445).

Fix this by forcing the computation of the correct DSO (the one defining
the symbol).

This code uses __UNCONST to avoid the vast interface changes for this
special case.

(2) If symbols from a DSO loaded via dlopen are used with both
global-dynamic/local-dynamic and initial-exec relocations AND
a initial-exec relocation was resolved first in a thread, a split brain
situation could exist where the dynamic relocations would use one memory
block (separate allocation) and the initial-exec relocations the static
per-thread TLS space.

(3) If the initial-exec relocation in (2) is seen after any thread has
already used a GD/LD allocation, bail out. Since IE relocations are used
only in the GOT, this will prevent the dlopen. This is a bit more
aggressive than necessary, but a full blown reference counting doesn't
seem to be justified.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.17 2022/12/03 09:10:40 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.17 2022/12/03 09:10:40 skrll Exp $");
d66 15
@


1.18.2.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.19 2024/07/22 23:10:35 riastradh Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.19 2024/07/22 23:10:35 riastradh Exp $");
a65 15
/*
 * AArch64 ELF relocations.
 *
 * References:
 *
 *	[AAELF64] ELF for the Arm 64-bit Architecture (AArch64),
 *	2022Q3.  Arm Ltd.
 *	https://github.com/ARM-software/abi-aa/blob/2982a9f3b512a5bfdc9e3fea5d3b298f9165c36b/aaelf64/aaelf64.rst
 *
 *	[TLSDESC] Glauber de Oliveira Costa and Alexandre Oliva,
 *	`Thread-Local Storage Access in Dynamic Libraries in the ARM
 *	Platform', 2006.
 *	https://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf
 */

@


1.17
log
@Whitespace. NFC.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.16 2022/06/21 06:52:17 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.16 2022/06/21 06:52:17 skrll Exp $");
d160 1
a160 1
	if (defobj->tls_done) {
d302 2
a303 2
			if (!defobj->tls_done &&
			    _rtld_tls_offset_allocate(obj))
@


1.17.2.1
log
@Pull up following revision(s) (requested by riastradh in ticket #297):

	distrib/sets/lists/tests/shl.mi: revision 1.14
	distrib/sets/lists/tests/shl.mi: revision 1.15
	distrib/sets/lists/tests/shl.mi: revision 1.16
	tests/libexec/ld.elf_so/helper_def_static/h_def_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_def_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_def_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_onlyuse_static/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_static/Makefile: revision 1.2
	libexec/ld.elf_so/arch/mips/mips_reloc.c: revision 1.75
	distrib/sets/lists/tests/mi: revision 1.1265
	libexec/ld.elf_so/arch/sh3/mdreloc.c: revision 1.36
	libexec/ld.elf_so/rtld.c: revision 1.214
	tests/libexec/ld.elf_so/helper_onlydef_static/Makefile: revision 1.1
	distrib/sets/lists/debug/mi: revision 1.400
	tests/libexec/ld.elf_so/helper_onlydef_static/Makefile: revision 1.2
	distrib/sets/lists/debug/mi: revision 1.401
	distrib/sets/lists/debug/mi: revision 1.402
	tests/libexec/ld.elf_so/helper_dso2/Makefile: revision 1.2
	distrib/sets/lists/debug/mi: revision 1.403
	tests/libexec/ld.elf_so/helper_symver_dso0/Makefile: revision 1.2
	libexec/ld.elf_so/arch/x86_64/mdreloc.c: revision 1.48
	distrib/sets/lists/debug/mi: revision 1.406
	tests/libexec/ld.elf_so/helper_use_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_use_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_ifunc_dso/Makefile: revision 1.2
	libexec/ld.elf_so/arch/sparc64/mdreloc.c: revision 1.70
	libexec/ld.elf_so/arch/aarch64/mdreloc.c: revision 1.18
	tests/libexec/ld.elf_so/helper_abuse_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_abuse_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/Makefile: revision 1.13
	libexec/ld.elf_so/arch/arm/mdreloc.c: revision 1.46
	libexec/ld.elf_so/rtld.h: revision 1.146
	tests/libexec/ld.elf_so/Makefile: revision 1.14
	distrib/sets/lists/debug/shl.mi: revision 1.306
	tests/libexec/ld.elf_so/Makefile: revision 1.15
	tests/libexec/ld.elf_so/helper_abuse_static/Makefile: revision 1.1
	distrib/sets/lists/debug/shl.mi: revision 1.307
	tests/libexec/ld.elf_so/Makefile: revision 1.16
	tests/libexec/ld.elf_so/helper_abuse_static/Makefile: revision 1.2
	distrib/sets/lists/debug/shl.mi: revision 1.308
	tests/libexec/ld.elf_so/Makefile: revision 1.17
	distrib/sets/lists/debug/shl.mi: revision 1.309
	tests/libexec/ld.elf_so/Makefile: revision 1.18
	tests/libexec/ld.elf_so/Makefile: revision 1.19
	libexec/ld.elf_so/tls.c: revision 1.16
	libexec/ld.elf_so/tls.c: revision 1.17
	libexec/ld.elf_so/tls.c: revision 1.18
	libexec/ld.elf_so/tls.c: revision 1.19
	tests/libexec/ld.elf_so/helper_onlydef_static/h_onlydef_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_use_static/h_use_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_use_static/h_use_static.c: revision 1.2
	tests/libexec/ld.elf_so/helper_def_static/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_def_static/Makefile: revision 1.2
	libexec/ld.elf_so/arch/hppa/hppa_reloc.c: revision 1.50
	distrib/sets/lists/debug/shl.mi: revision 1.310
	libexec/ld.elf_so/README.TLS: revision 1.6
	distrib/sets/lists/debug/shl.mi: revision 1.311
	distrib/sets/lists/debug/shl.mi: revision 1.314
	tests/libexec/ld.elf_so/helper_dso3/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_symver_dso1/Makefile: revision 1.4
	libexec/ld.elf_so/arch/powerpc/ppc_reloc.c: revision 1.63
	tests/libexec/ld.elf_so/helper_def_dynamic/h_def_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlydef/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_onlydef/Makefile: revision 1.2
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.10
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.11
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.12
	libexec/ld.elf_so/map_object.c: revision 1.66
	tests/libexec/ld.elf_so/helper.mk: revision 1.1
	libexec/ld.elf_so/arch/sparc/mdreloc.c: revision 1.57
	libexec/ld.elf_so/map_object.c: revision 1.67
	tests/libexec/ld.elf_so/helper_onlydef/h_onlydef.c: revision 1.1
	tests/libexec/ld.elf_so/helper_symver_dso2/Makefile: revision 1.4
	tests/libexec/ld.elf_so/helper_use_static/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_use_static/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_use_static/Makefile: revision 1.3
	tests/libexec/ld.elf_so/helper_use_dynamic/h_use_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_abuse_static/h_abuse_static.c: revision 1.1
	libexec/ld.elf_so/arch/riscv/mdreloc.c: revision 1.9
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.1
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.2
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.3
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.4
	tests/libexec/ld.elf_so/helper_onlyctor_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.5
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.6
	libexec/ld.elf_so/arch/m68k/mdreloc.c: revision 1.34
	tests/libexec/ld.elf_so/helper_onlyctor_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.7
	libexec/ld.elf_so/arch/i386/mdreloc.c: revision 1.42
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.8
	libexec/ld.elf_so/arch/i386/mdreloc.c: revision 1.43
	libexec/ld.elf_so/arch/or1k/mdreloc.c: revision 1.4
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.9
	tests/libexec/ld.elf_so/helper_onlyuse_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_abuse_dynamic/h_abuse_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyctor_dynamic/h_onlyctor_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_static/h_onlyuse_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_dynamic/h_onlyuse_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_dso1/Makefile: revision 1.2
	distrib/sets/lists/tests/shl.mi: revision 1.12
	distrib/sets/lists/tests/shl.mi: revision 1.13
	libexec/ld.elf_so/arch/alpha/alpha_reloc.c: revision 1.44
	(all via patch)

ld.elf_so: New test for extern initial-exec TLS, PR toolchain/50277.

ld.elf_so: Fix extern TLS test to match PR toolchain/50277.
Now it's actually testing the problem.
ld.elf_so: Nix inadvertently committed private test program.
ld.elf_so: Fix set lists for MKDEBUG=yes builds with t_tls_extern.

ld.elf_so: Sprinkle tls debug messages.

ld.elf_so: Make tls alloc debug messages more detailed and greppable.

ld.elf_so: Test variations on PR toolchain/50277.

ld.elf_so: Test extern dynamic TLS too.

ld.elf_so: Factor out logic in TLS tests to make writing more easier.
No functional change intended.

ld.elf_so: Test TLS abuse of static def, dynamic use and vice versa.

ld.elf_so: Shorter test names.
No functional non-cosmetic change intended.

ld.elf_so: Separately test eager and lazy resolution of def tls ptr.
eager: before loading use library
lazy: after loading use library

Add recent ld.elf_so test helpers debug info
ld.elf_so: Add new files to debug/shl.mi.

ld.elf_so: tls_extern dynamic_defabuse_eager must xfail differently.
If a symbol has already been resolved as dynamic TLS, any library
that tries to use it as static TLS cannot be dlopened.

ld.elf_so: Test another edge case of mismatched TLS models.
One library defines a symbol and _doesn't_ use it, so it has no
indication of whether the symbol is for static TLS or dynamic TLS,
and then two other libraries use it in different ways.

ld.elf_so: Test dynamic-then-static abuse via ctor.

ld.elf_so: Fix missing tab in debug/shl.mi in last change.

Fix interactions of initial-exec TLS model and dlopen
(1) If an initial-exec relocation was used for a non-local symbol
(i.e. the definition of the symbol is in a different DSO), the
computation of the static TLS offset used the wrong DSO.
This would effectively mean the wrong address was computed
(PR toolchain/50277, PR pkg/57445).
Fix this by forcing the computation of the correct DSO (the one defining
the symbol).
This code uses __UNCONST to avoid the vast interface changes for this
special case.
(2) If symbols from a DSO loaded via dlopen are used with both
global-dynamic/local-dynamic and initial-exec relocations AND
a initial-exec relocation was resolved first in a thread, a split brain
situation could exist where the dynamic relocations would use one memory
block (separate allocation) and the initial-exec relocations the static
per-thread TLS space.
(3) If the initial-exec relocation in (2) is seen after any thread has
already used a GD/LD allocation, bail out. Since IE relocations are used
only in the GOT, this will prevent the dlopen. This is a bit more
aggressive than necessary, but a full blown reference counting doesn't
seem to be justified.
Avoid using uninitialized variable "symnum" when building with DEBUG
enabled by borrowing the rdbg_symname() macro from arch/x86_64.
ld.elf_so: Sprinkle more debug messages on dlopen and error.
PR pkg/57445
Fix MKDEBUGLIB build by adding these installed files to the debug
set list.
XXX
One could argue that these files are not of any use, so why install
them?  I don't have a good argument either way, and this is (for
now) a simple work-around for PR bin/57455   Please feel free to
commit a different fix to avoid installing these files at all.
Fix markup of libh_ MKDEBUGLIB=yes only files
TLS variant I archs need to fudge the offset by the size of the TCB.
tests/libexec/ld.elf_so: Fix helper library makefiles.
1. Consolidate logic into a single helper.mk to reduce duplication.
2. Set NO* variables, not MK* variables which are reserved for user.
3. Avoid eager X!= in favour of lazy ${X:sh}.
4. Mark _g.a set list entries obsolete.  Never should've been built!
PR misc/57462
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.18 2023/06/04 01:24:56 joerg Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.18 2023/06/04 01:24:56 joerg Exp $");
d160 1
a160 1
	if (defobj->tls_static) {
d302 2
a303 2
			if (!defobj->tls_static &&
			    _rtld_tls_offset_allocate(__UNCONST(defobj)))
@


1.16
log
@Support ifunc on aarch64. The tests pass at least.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.15 2022/05/31 08:43:14 andvar Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.15 2022/05/31 08:43:14 andvar Exp $");
d291 1
a292 1
			break;
a298 1

@


1.15
log
@fix various typos in comments, documentation and messages.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg Exp $");
d251 8
d341 3
a343 2
		assert((ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT)) ||
		    (ELF_R_TYPE(rela->r_info) == R_TYPE(TLSDESC)));
d354 3
@


1.14
log
@Honor addend for R_AARCH64_TLS_TPREL relocation.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $");
d161 1
a161 1
		/* Variable is in initialy allocated TLS segment */
@


1.13
log
@Adapt https://svnweb.freebsd.org/base?view=revision&revision=342113 to
NetBSD.

This brings us resolving for dynamically loaded libraries and makes
tests/libexec/ld.elf_so/t_thread_local_dtor pass.

With suggestions from joerg@@
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.12 2018/11/23 11:26:05 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.12 2018/11/23 11:26:05 skrll Exp $");
d299 3
a301 2
			*where = (Elf_Addr)def->st_value + defobj->tlsoffset +
			    sizeof(struct tls_tcb);
@


1.13.2.1
log
@Pull up following revision(s), all via patch,
(requested by riastradh in ticket #1699):

	distrib/sets/lists/tests/shl.mi: revision 1.14
	distrib/sets/lists/tests/shl.mi: revision 1.15
	distrib/sets/lists/tests/shl.mi: revision 1.16
	tests/libexec/ld.elf_so/helper_def_static/h_def_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_def_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_def_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_onlyuse_static/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_static/Makefile: revision 1.2
	libexec/ld.elf_so/arch/mips/mips_reloc.c: revision 1.75
	distrib/sets/lists/tests/mi: revision 1.1265
	libexec/ld.elf_so/arch/sh3/mdreloc.c: revision 1.36
	libexec/ld.elf_so/rtld.c: revision 1.214
	tests/libexec/ld.elf_so/helper_onlydef_static/Makefile: revision 1.1
	distrib/sets/lists/debug/mi: revision 1.400
	tests/libexec/ld.elf_so/helper_onlydef_static/Makefile: revision 1.2
	distrib/sets/lists/debug/mi: revision 1.401
	distrib/sets/lists/debug/mi: revision 1.402
	tests/libexec/ld.elf_so/helper_dso2/Makefile: revision 1.2
	distrib/sets/lists/debug/mi: revision 1.403
	tests/libexec/ld.elf_so/helper_symver_dso0/Makefile: revision 1.2
	libexec/ld.elf_so/arch/x86_64/mdreloc.c: revision 1.48
	distrib/sets/lists/debug/mi: revision 1.406
	tests/libexec/ld.elf_so/helper_use_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_use_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_ifunc_dso/Makefile: revision 1.2
	libexec/ld.elf_so/arch/sparc64/mdreloc.c: revision 1.70
	libexec/ld.elf_so/arch/aarch64/mdreloc.c: revision 1.18
	tests/libexec/ld.elf_so/helper_abuse_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_abuse_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/Makefile: revision 1.13
	libexec/ld.elf_so/arch/arm/mdreloc.c: revision 1.46
	libexec/ld.elf_so/rtld.h: revision 1.146
	tests/libexec/ld.elf_so/Makefile: revision 1.14
	distrib/sets/lists/debug/shl.mi: revision 1.306
	tests/libexec/ld.elf_so/Makefile: revision 1.15
	tests/libexec/ld.elf_so/helper_abuse_static/Makefile: revision 1.1
	distrib/sets/lists/debug/shl.mi: revision 1.307
	tests/libexec/ld.elf_so/Makefile: revision 1.16
	tests/libexec/ld.elf_so/helper_abuse_static/Makefile: revision 1.2
	distrib/sets/lists/debug/shl.mi: revision 1.308
	tests/libexec/ld.elf_so/Makefile: revision 1.17
	distrib/sets/lists/debug/shl.mi: revision 1.309
	tests/libexec/ld.elf_so/Makefile: revision 1.18
	tests/libexec/ld.elf_so/Makefile: revision 1.19
	libexec/ld.elf_so/tls.c: revision 1.16
	libexec/ld.elf_so/tls.c: revision 1.17
	libexec/ld.elf_so/tls.c: revision 1.18
	libexec/ld.elf_so/tls.c: revision 1.19
	tests/libexec/ld.elf_so/helper_onlydef_static/h_onlydef_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_use_static/h_use_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_use_static/h_use_static.c: revision 1.2
	tests/libexec/ld.elf_so/helper_def_static/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_def_static/Makefile: revision 1.2
	libexec/ld.elf_so/arch/hppa/hppa_reloc.c: revision 1.50
	distrib/sets/lists/debug/shl.mi: revision 1.310
	libexec/ld.elf_so/README.TLS: revision 1.6
	distrib/sets/lists/debug/shl.mi: revision 1.311
	distrib/sets/lists/debug/shl.mi: revision 1.314
	tests/libexec/ld.elf_so/helper_dso3/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_symver_dso1/Makefile: revision 1.4
	libexec/ld.elf_so/arch/powerpc/ppc_reloc.c: revision 1.63
	tests/libexec/ld.elf_so/helper_def_dynamic/h_def_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlydef/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_onlydef/Makefile: revision 1.2
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.10
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.11
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.12
	libexec/ld.elf_so/map_object.c: revision 1.66
	tests/libexec/ld.elf_so/helper.mk: revision 1.1
	libexec/ld.elf_so/arch/sparc/mdreloc.c: revision 1.57
	libexec/ld.elf_so/map_object.c: revision 1.67
	tests/libexec/ld.elf_so/helper_onlydef/h_onlydef.c: revision 1.1
	tests/libexec/ld.elf_so/helper_symver_dso2/Makefile: revision 1.4
	tests/libexec/ld.elf_so/helper_use_static/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_use_static/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_use_static/Makefile: revision 1.3
	tests/libexec/ld.elf_so/helper_use_dynamic/h_use_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_abuse_static/h_abuse_static.c: revision 1.1
	libexec/ld.elf_so/arch/riscv/mdreloc.c: revision 1.9
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.1
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.2
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.3
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.4
	tests/libexec/ld.elf_so/helper_onlyctor_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.5
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.6
	libexec/ld.elf_so/arch/m68k/mdreloc.c: revision 1.34
	tests/libexec/ld.elf_so/helper_onlyctor_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.7
	libexec/ld.elf_so/arch/i386/mdreloc.c: revision 1.42
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.8
	libexec/ld.elf_so/arch/i386/mdreloc.c: revision 1.43
	libexec/ld.elf_so/arch/or1k/mdreloc.c: revision 1.4
	tests/libexec/ld.elf_so/t_tls_extern.c: revision 1.9
	tests/libexec/ld.elf_so/helper_onlyuse_dynamic/Makefile: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_dynamic/Makefile: revision 1.2
	tests/libexec/ld.elf_so/helper_abuse_dynamic/h_abuse_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyctor_dynamic/h_onlyctor_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_static/h_onlyuse_static.c: revision 1.1
	tests/libexec/ld.elf_so/helper_onlyuse_dynamic/h_onlyuse_dynamic.c: revision 1.1
	tests/libexec/ld.elf_so/helper_dso1/Makefile: revision 1.2
	distrib/sets/lists/tests/shl.mi: revision 1.12
	distrib/sets/lists/tests/shl.mi: revision 1.13
	libexec/ld.elf_so/arch/alpha/alpha_reloc.c: revision 1.44

ld.elf_so: New test for extern initial-exec TLS, PR toolchain/50277.

ld.elf_so: Fix extern TLS test to match PR toolchain/50277.
Now it's actually testing the problem.
ld.elf_so: Nix inadvertently committed private test program.
ld.elf_so: Fix set lists for MKDEBUG=yes builds with t_tls_extern.

ld.elf_so: Sprinkle tls debug messages.

ld.elf_so: Make tls alloc debug messages more detailed and greppable.

ld.elf_so: Test variations on PR toolchain/50277.

ld.elf_so: Test extern dynamic TLS too.

ld.elf_so: Factor out logic in TLS tests to make writing more easier.
No functional change intended.

ld.elf_so: Test TLS abuse of static def, dynamic use and vice versa.

ld.elf_so: Shorter test names.
No functional non-cosmetic change intended.

ld.elf_so: Separately test eager and lazy resolution of def tls ptr.
eager: before loading use library
lazy: after loading use library

Add recent ld.elf_so test helpers debug info
ld.elf_so: Add new files to debug/shl.mi.

ld.elf_so: tls_extern dynamic_defabuse_eager must xfail differently.
If a symbol has already been resolved as dynamic TLS, any library
that tries to use it as static TLS cannot be dlopened.

ld.elf_so: Test another edge case of mismatched TLS models.
One library defines a symbol and _doesn't_ use it, so it has no
indication of whether the symbol is for static TLS or dynamic TLS,
and then two other libraries use it in different ways.

ld.elf_so: Test dynamic-then-static abuse via ctor.

ld.elf_so: Fix missing tab in debug/shl.mi in last change.

Fix interactions of initial-exec TLS model and dlopen

(1) If an initial-exec relocation was used for a non-local symbol
(i.e. the definition of the symbol is in a different DSO), the
computation of the static TLS offset used the wrong DSO.

This would effectively mean the wrong address was computed
(PR toolchain/50277, PR pkg/57445).
Fix this by forcing the computation of the correct DSO (the one defining
the symbol).
This code uses __UNCONST to avoid the vast interface changes for this
special case.

(2) If symbols from a DSO loaded via dlopen are used with both
global-dynamic/local-dynamic and initial-exec relocations AND
a initial-exec relocation was resolved first in a thread, a split brain
situation could exist where the dynamic relocations would use one memory
block (separate allocation) and the initial-exec relocations the static
per-thread TLS space.

(3) If the initial-exec relocation in (2) is seen after any thread has
already used a GD/LD allocation, bail out. Since IE relocations are used
only in the GOT, this will prevent the dlopen. This is a bit more
aggressive than necessary, but a full blown reference counting doesn't
seem to be justified.
Avoid using uninitialized variable "symnum" when building with DEBUG
enabled by borrowing the rdbg_symname() macro from arch/x86_64.
ld.elf_so: Sprinkle more debug messages on dlopen and error.

PR pkg/57445

Fix MKDEBUGLIB build by adding these installed files to the debug
set list.

One could argue that these files are not of any use, so why install
them?  I don't have a good argument either way, and this is (for
now) a simple work-around for PR bin/57455   Please feel free to
commit a different fix to avoid installing these files at all.

Fix markup of libh_ MKDEBUGLIB=yes only files

TLS variant I archs need to fudge the offset by the size of the TCB.
tests/libexec/ld.elf_so: Fix helper library makefiles.
1. Consolidate logic into a single helper.mk to reduce duplication.
2. Set NO* variables, not MK* variables which are reserved for user.
3. Avoid eager X!= in favour of lazy ${X:sh}.
4. Mark _g.a set list entries obsolete.  Never should've been built!
PR misc/57462
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $");
d160 2
a161 2
	if (defobj->tls_static) {
		/* Variable is in initially allocated TLS segment */
d295 2
a296 2
			if (!defobj->tls_static &&
			    _rtld_tls_offset_allocate(__UNCONST(defobj)))
@


1.13.2.2
log
@Pull up following revision(s) (requested by riastradh in ticket #1862):

	libexec/ld.elf_so/arch/arm/mdreloc.c: revision 1.45
	libexec/ld.elf_so/arch/aarch64/mdreloc.c: revision 1.14

Honor addend for R_AARCH64_TLS_TPREL relocation.

R_ARM_TLS_TPOFF32 needs to adjust the existing value, not blindly
overwrite it.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.13.2.1 2023/08/04 12:55:46 martin Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.13.2.1 2023/08/04 12:55:46 martin Exp $");
d299 2
a300 3
			*where = (Elf_Addr)(def->st_value + defobj->tlsoffset +
			    rela->r_addend + sizeof(struct tls_tcb));

@


1.12
log
@Fix RTLD_DEBUG_RELOC build
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.11 2018/11/23 10:59:20 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.11 2018/11/23 10:59:20 skrll Exp $");
d73 2
a74 3
	int64_t index;
	Obj_Entry *obj;
	const Elf_Rela *rela;
d80 2
a81 1
void *_rtld_tlsdesc(void *);
a82 1
int64_t _rtld_tlsdesc_handle(struct tls_data *, u_int);
d119 1
a119 1
_rtld_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela)
d124 2
a125 3
	tlsdesc->index = -1;
	tlsdesc->obj = obj;
	tlsdesc->rela = rela;
d130 2
a131 2
static int64_t
_rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, u_int flags)
a132 1
	const Elf_Rela *rela;
d135 2
a136 1
	Obj_Entry *obj;
d138 9
a146 2
	rela = tlsdesc->rela;
	obj = tlsdesc->obj;
d148 3
a150 3
	def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags);
	if (def == NULL)
		_rtld_die();
d152 7
a158 2
	tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend +
	    sizeof(struct tls_tcb);
d160 5
a164 2
	return tlsdesc->index;
}
d166 2
a167 25
int64_t
_rtld_tlsdesc_handle(struct tls_data *tlsdesc, u_int flags)
{
	sigset_t mask;

	/* We have already found the index, return it */
	if (tlsdesc->index >= 0)
		return tlsdesc->index;

	_rtld_exclusive_enter(&mask);
	/* tlsdesc->index may have been set by another thread */
	if (tlsdesc->index == -1)
		_rtld_tlsdesc_handle_locked(tlsdesc, flags);
	_rtld_exclusive_exit(&mask);

	return tlsdesc->index;
}

static void
_rtld_tlsdesc_fill(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where)
{
	if (ELF_R_SYM(rela->r_info) == 0) {
		where[0] = (Elf_Addr)_rtld_tlsdesc;
		where[1] = obj->tlsoffset + rela->r_addend +
		    sizeof(struct tls_tcb);
d169 1
d171 5
a175 1
		where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(obj, rela);
d274 1
a274 1
			_rtld_tlsdesc_fill(obj, rela, where);
d342 1
a342 1
			_rtld_tlsdesc_fill(obj, rela, where);
d406 1
a406 5
		if (ELF_R_SYM(rela->r_info) != 0) {
			struct tls_data *tlsdesc = (struct tls_data *)where[1];
			if (tlsdesc->index == -1)
				_rtld_tlsdesc_handle_locked(tlsdesc, SYMLOOK_IN_PLT);
		}
@


1.11
log
@Trailing whitespace
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.10 2018/09/20 19:02:22 jakllsch Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.10 2018/09/20 19:02:22 jakllsch Exp $");
d218 1
a218 1
		unsigned long	symnum;
d313 1
a313 1
			    "addend = %p, contents = %p, symbol = %s",
d317 1
a317 2
			    (void *)*where,
			    obj->strtab + obj->symtab[symnum].st_name));
@


1.10
log
@Revise previous to not deadlock.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.9 2018/09/20 18:41:05 jakllsch Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.9 2018/09/20 18:41:05 jakllsch Exp $");
d442 1
a442 1
	
@


1.9
log
@Improve support for R_AARCH64_TLSDESC relocations.

In large part from FreeBSD.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.8 2018/07/16 00:29:37 christos Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.8 2018/07/16 00:29:37 christos Exp $");
d415 1
a415 1
				_rtld_tlsdesc_handle(tlsdesc, SYMLOOK_IN_PLT);
@


1.8
log
@Initialize new_value to account for bogus return from the function.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.7 2018/02/04 21:49:51 skrll Exp $ */
d32 29
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.7 2018/02/04 21:49:51 skrll Exp $");
d72 6
d82 2
d119 65
d278 4
d348 1
a348 5
			assert(ELF_R_SYM(rela->r_info) == 0);	/* XXX */
			if (ELF_R_SYM(rela->r_info) == 0) {
				where[0] = (Elf_Addr)_rtld_tlsdesc;
				where[1] = obj->tlsoffset + rela->r_addend + sizeof(struct tls_tcb);
			}
a384 1
	unsigned long info = rela->r_info;
d386 8
a393 1
	assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));
d395 23
a417 12
	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
	if (__predict_false(def == NULL))
		return -1;
	if (__predict_false(def == &_rtld_sym_zero))
		return 0;

	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
		if (tp == NULL)
			return 0;
		new_value = _rtld_resolve_ifunc(defobj, def);
	} else {
		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
a418 6
	rdbg(("bind now/fixup in %s --> old=%p new=%p",
	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
	if (*where != new_value)
		*where = new_value;
	if (tp)
		*tp = new_value;
@


1.7
log
@Various fixes / changes from Ryo Shimizu / Toru Nishimura to make this
work.

_rtld_call_ifunc copied from other rela platforms by me - not tested in
any way.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.6 2017/08/28 06:59:25 nisimura Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.6 2017/08/28 06:59:25 nisimura Exp $");
d314 1
a314 1
	Elf_Addr new_value;
@


1.7.4.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $ */
a31 29
/*-
 * Copyright (c) 2014-2015 The FreeBSD Foundation
 * All rights reserved.
 *
 * Portions of this software were developed by Andrew Turner
 * under sponsorship from the FreeBSD Foundation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $");
a42 5
struct tls_data {
	size_t		td_tlsindex;
	Elf_Addr	td_tlsoffs;
};

d46 1
a46 3
void *_rtld_tlsdesc_static(void *);
void *_rtld_tlsdesc_undef(void *);
void *_rtld_tlsdesc_dynamic(void *);
a81 61
static struct tls_data *
_rtld_tlsdesc_alloc(size_t tlsindex, Elf_Addr offs)
{
	struct tls_data *tlsdesc;

	tlsdesc = xmalloc(sizeof(*tlsdesc));
	tlsdesc->td_tlsindex = tlsindex;
	tlsdesc->td_tlsoffs = offs;

	return tlsdesc;
}

static void
_rtld_tlsdesc_fill(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where, u_int flags)
{
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Elf_Addr offs = 0;
	unsigned long symnum = ELF_R_SYM(rela->r_info);

	if (symnum != 0) {
		def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags);
		if (def == NULL)
			_rtld_die();
		if (def == &_rtld_sym_zero) {
			/* Weak undefined thread variable */
			where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
			where[1] = rela->r_addend;

			rdbg(("TLSDESC %s (weak) in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)where[1]));

			return;
		}
		offs = def->st_value;
	} else {
		defobj = obj;
	}
	offs += rela->r_addend;

	if (defobj->tls_done) {
		/* Variable is in initialy allocated TLS segment */
		where[0] = (Elf_Addr)_rtld_tlsdesc_static;
		where[1] = defobj->tlsoffset + offs +
		    sizeof(struct tls_tcb);

		rdbg(("TLSDESC %s --> %p static",
		    obj->path, (void *)where[1]));
	} else {
		/* TLS offset is unknown at load time, use dynamic resolving */
		where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
		where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(defobj->tlsindex, offs);

		rdbg(("TLSDESC %s in %s --> %p dynamic (%zu, %p)",
		    obj->strtab + obj->symtab[symnum].st_name,
		    obj->path, (void *)where[1], defobj->tlsindex, (void *)offs));
	}
}

d116 1
a116 1
		unsigned long	symnum = ULONG_MAX;
a175 4
		case R_TYPE(TLSDESC):
			_rtld_tlsdesc_fill(obj, rela, where, 0);
			break;

d207 1
a207 1
			    "addend = %p, contents = %p",
d211 2
a212 1
			    (void *)*where));
d242 5
a246 1
			_rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT);
d283 9
d293 2
a294 7
	switch (ELF_R_TYPE(rela->r_info)) {
	case R_TYPE(JUMP_SLOT):
		def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj,
		    &defobj, tp != NULL);
		if (__predict_false(def == NULL))
			return -1;
		if (__predict_false(def == &_rtld_sym_zero))
d296 3
a298 20

		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
			if (tp == NULL)
				return 0;
			new_value = _rtld_resolve_ifunc(defobj, def);
		} else {
			new_value = (Elf_Addr)(defobj->relocbase +
			     def->st_value);
		}
		rdbg(("bind now/fixup in %s --> old=%p new=%p",
		    defobj->strtab + def->st_name, (void *)*where,
		    (void *)new_value));
		if (*where != new_value)
			*where = new_value;
		if (tp)
			*tp = new_value;
		break;
	case R_TYPE(TLSDESC):
		_rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT);
		break;
d300 6
d314 1
a314 1
	Elf_Addr new_value = 0;
d329 1
a329 1

@


1.7.2.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.8 2018/07/16 00:29:37 christos Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.8 2018/07/16 00:29:37 christos Exp $");
d314 1
a314 1
	Elf_Addr new_value = 0;
@


1.7.2.2
log
@Ssync with HEAD
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.10 2018/09/20 19:02:22 jakllsch Exp $ */
a31 29
/*-
 * Copyright (c) 2014-2015 The FreeBSD Foundation
 * All rights reserved.
 *
 * Portions of this software were developed by Andrew Turner
 * under sponsorship from the FreeBSD Foundation.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.10 2018/09/20 19:02:22 jakllsch Exp $");
a42 6
struct tls_data {
	int64_t index;
	Obj_Entry *obj;
	const Elf_Rela *rela;
};

a46 2
void *_rtld_tlsdesc_dynamic(void *);
int64_t _rtld_tlsdesc_handle(struct tls_data *, u_int);
a81 65
static struct tls_data *
_rtld_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela)
{
	struct tls_data *tlsdesc;

	tlsdesc = xmalloc(sizeof(*tlsdesc));
	tlsdesc->index = -1;
	tlsdesc->obj = obj;
	tlsdesc->rela = rela;

	return tlsdesc;
}

static int64_t
_rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, u_int flags)
{
	const Elf_Rela *rela;
	const Elf_Sym *def;
	const Obj_Entry *defobj;
	Obj_Entry *obj;

	rela = tlsdesc->rela;
	obj = tlsdesc->obj;

	def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags);
	if (def == NULL)
		_rtld_die();

	tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend +
	    sizeof(struct tls_tcb);

	return tlsdesc->index;
}

int64_t
_rtld_tlsdesc_handle(struct tls_data *tlsdesc, u_int flags)
{
	sigset_t mask;

	/* We have already found the index, return it */
	if (tlsdesc->index >= 0)
		return tlsdesc->index;

	_rtld_exclusive_enter(&mask);
	/* tlsdesc->index may have been set by another thread */
	if (tlsdesc->index == -1)
		_rtld_tlsdesc_handle_locked(tlsdesc, flags);
	_rtld_exclusive_exit(&mask);

	return tlsdesc->index;
}

static void
_rtld_tlsdesc_fill(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where)
{
	if (ELF_R_SYM(rela->r_info) == 0) {
		where[0] = (Elf_Addr)_rtld_tlsdesc;
		where[1] = obj->tlsoffset + rela->r_addend +
		    sizeof(struct tls_tcb);
	} else {
		where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
		where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(obj, rela);
	}
}

a175 4
		case R_TYPE(TLSDESC):
			_rtld_tlsdesc_fill(obj, rela, where);
			break;

d242 5
a246 1
			_rtld_tlsdesc_fill(obj, rela, where);
d283 3
d287 8
a294 7
	switch (ELF_R_TYPE(rela->r_info)) {
	case R_TYPE(JUMP_SLOT):
		def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj,
		    &defobj, tp != NULL);
		if (__predict_false(def == NULL))
			return -1;
		if (__predict_false(def == &_rtld_sym_zero))
d296 3
a298 24

		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
			if (tp == NULL)
				return 0;
			new_value = _rtld_resolve_ifunc(defobj, def);
		} else {
			new_value = (Elf_Addr)(defobj->relocbase +
			     def->st_value);
		}
		rdbg(("bind now/fixup in %s --> old=%p new=%p",
		    defobj->strtab + def->st_name, (void *)*where,
		    (void *)new_value));
		if (*where != new_value)
			*where = new_value;
		if (tp)
			*tp = new_value;
		break;
	case R_TYPE(TLSDESC):
		if (ELF_R_SYM(rela->r_info) != 0) {
			struct tls_data *tlsdesc = (struct tls_data *)where[1];
			if (tlsdesc->index == -1)
				_rtld_tlsdesc_handle_locked(tlsdesc, SYMLOOK_IN_PLT);
		}
		break;
d300 6
@


1.7.2.3
log
@Sync with HEAD, resolve a couple of conflicts
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.12 2018/11/23 11:26:05 skrll Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.12 2018/11/23 11:26:05 skrll Exp $");
d218 1
a218 1
		unsigned long	symnum = ULONG_MAX;
d313 1
a313 1
			    "addend = %p, contents = %p",
d317 2
a318 1
			    (void *)*where));
d442 1
a442 1

@


1.7.2.4
log
@Sync with HEAD
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.7.2.3 2018/11/26 01:52:13 pgoyette Exp $ */
d63 1
a63 1
__RCSID("$NetBSD: mdreloc.c,v 1.7.2.3 2018/11/26 01:52:13 pgoyette Exp $");
d73 3
a75 2
	size_t		td_tlsindex;
	Elf_Addr	td_tlsoffs;
d81 1
a81 2
void *_rtld_tlsdesc_static(void *);
void *_rtld_tlsdesc_undef(void *);
d83 1
d120 1
a120 1
_rtld_tlsdesc_alloc(size_t tlsindex, Elf_Addr offs)
d125 3
a127 2
	tlsdesc->td_tlsindex = tlsindex;
	tlsdesc->td_tlsoffs = offs;
d132 2
a133 2
static void
_rtld_tlsdesc_fill(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where, u_int flags)
d135 1
d138 11
a148 2
	Elf_Addr offs = 0;
	unsigned long symnum = ELF_R_SYM(rela->r_info);
d150 7
a156 9
	if (symnum != 0) {
		def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
		    flags);
		if (def == NULL)
			_rtld_die();
		if (def == &_rtld_sym_zero) {
			/* Weak undefined thread variable */
			where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
			where[1] = rela->r_addend;
d158 9
a166 3
			rdbg(("TLSDESC %s (weak) in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)where[1]));
d168 2
a169 7
			return;
		}
		offs = def->st_value;
	} else {
		defobj = obj;
	}
	offs += rela->r_addend;
d171 6
a176 4
	if (defobj->tls_done) {
		/* Variable is in initialy allocated TLS segment */
		where[0] = (Elf_Addr)_rtld_tlsdesc_static;
		where[1] = defobj->tlsoffset + offs +
a177 3

		rdbg(("TLSDESC %s --> %p static",
		    obj->path, (void *)where[1]));
a178 1
		/* TLS offset is unknown at load time, use dynamic resolving */
d180 1
a180 5
		where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(defobj->tlsindex, offs);

		rdbg(("TLSDESC %s in %s --> %p dynamic (%zu, %p)",
		    obj->strtab + obj->symtab[symnum].st_name,
		    obj->path, (void *)where[1], defobj->tlsindex, (void *)offs));
d279 1
a279 1
			_rtld_tlsdesc_fill(obj, rela, where, 0);
d347 1
a347 1
			_rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT);
d411 5
a415 1
		_rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT);
@


1.6
log
@explain AARCH64 PLT design
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.5 2017/08/23 09:17:48 nisimura Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.5 2017/08/23 09:17:48 nisimura Exp $");
d46 1
d85 2
a86 2
	const Elf_Rel *rel = 0, *rellim;
	Elf_Addr relsz = 0;
d91 2
a92 2
		case DT_REL:
			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
d94 2
a95 2
		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
d99 3
a101 3
	rellim = (const Elf_Rel *)((const uint8_t *)rel + relsz);
	for (; rel < rellim; rel++) {
		where = (Elf_Addr *)(relocbase + rel->r_offset);
d121 2
a122 2
		case R_TYPE(ABS64):	/* word B + S + A */
		case R_TYPE(GLOB_DAT):	/* word B + S */
d143 2
a144 2
		case R_TYPE(ABS64):	/* word B + S + A */
		case R_TYPE(GLOB_DAT):	/* word B + S */
d229 2
a230 2
	for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) {
		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
d232 2
a233 1
		assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT));
d235 14
a248 3
		/* Just relocate the GOT slots pointing into the PLT */
		*where += (Elf_Addr)obj->relocbase;
		rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
d254 21
d276 1
a276 1
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
d279 1
a279 1
	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
d283 1
a283 1
	unsigned long info = rel->r_info;
d311 1
a311 1
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
d313 2
a314 2
	const Elf_Rel *rel = obj->pltrel + reloff;
	Elf_Addr new_value = 0;	/* XXX gcc */
d317 1
a317 1
	int err = _rtld_relocate_plt_object(obj, rel, &new_value);
d327 1
a327 1
	const Elf_Rel *rel;
d330 2
a331 2
	for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
		err = _rtld_relocate_plt_object(obj, rel, NULL);
@


1.5
log
@
- avoid caddr_t. use Elf_Addr instead.
- iron out rdbg() errors.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.4 2017/08/10 19:03:25 joerg Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.4 2017/08/10 19:03:25 joerg Exp $");
d47 26
d76 1
@


1.4
log
@Add IRELATIVE support for ARM, X86 and PowerPC.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.3 2017/06/19 11:57:01 joerg Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.3 2017/06/19 11:57:01 joerg Exp $");
d45 1
a45 1
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
d87 2
a88 2
		unsigned long	 symnum;
		Elf_Addr	 addend;
a90 1
		addend = rela->r_addend;
d117 4
a120 2
			*where = addend + (Elf_Addr)defobj->relocbase +
			    def->st_value;
d127 1
a127 1
			*where = addend + (Elf_Addr)obj->relocbase;
d129 1
a129 1
			    (void *)tmp));
d149 1
a149 1
			*where = addend + (Elf_Addr)(def->st_value);
d151 1
a151 1
			rdbg(("TLS_DTPOFF32 %s in %s --> %p",
d153 1
a153 1
			    obj->path, (void *)tmp));
d161 1
a161 1
			    obj->path, (void *)tmp));
d172 1
a172 1
			rdbg(("TLS_TPOFF32 %s in %s --> %p",
d174 1
a174 1
			    obj->path, (void *)tmp));
d179 1
a179 1
			    "contents = %p, symbol = %s",
d182 2
a183 1
			    (void *)rela->r_offset, *where,
d249 1
a249 1
caddr_t
d261 1
a261 1
	return (caddr_t)new_value;
@


1.3
log
@Replace COMBREL with just-in-time check in _rtld_relocate_nonplt_objects.

The COMBREL logic predates thread-safety of the dynamic linker and
breaks the use of shared locks for the common symbol lookup case. It is
unlikely to provide any benefit for lazy binding or PLT lookups, so
provide equivalent functionality in the non-PLT relocation handling loop
by checking if the symbol used by the current relocation is the same as
the one used during the last lookup. No inter-object cachine is done as
it is also unlikely to be benefical.

Testing with Firefox startup on AMD64 shows a small performance gain by
the new method.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $");
d193 1
a193 1
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
@


1.2
log
@Add basic support for indirect functions. It allows providing a public
function symbol with an implementation choosen at run time.
Refactor calls to functions by address in ld.elf_so to create temporary
function descriptors on the stack, if the address is not leaked outside.

Limitations:
- no support for initialising static storage with function pointers
- no support for unnamed resolver functions

Inspired by FreeBSD's r228435 by kib@@freebsd.org.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.1 2014/08/10 05:47:37 matt Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.1 2014/08/10 05:47:37 matt Exp $");
d81 4
a84 1
	
a86 2
		const Elf_Sym   *def;
		const Obj_Entry *defobj;
a90 1
		symnum = ELF_R_SYM(rela->r_info);
d94 19
a117 3
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;
a147 4
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

a155 4
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

a164 4
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

d179 2
a180 1
			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
@


1.2.8.1
log
@Pull up following revision(s) (requested by joerg in ticket #64):
	libexec/ld.elf_so/arch/arm/mdreloc.c: revision 1.40
	libexec/ld.elf_so/arch/arm/mdreloc.c: revision 1.41
	libexec/ld.elf_so/arch/hppa/hppa_reloc.c: revision 1.44
	libexec/ld.elf_so/arch/riscv/mdreloc.c: revision 1.3
	libexec/ld.elf_so/arch/aarch64/mdreloc.c: revision 1.3
	libexec/ld.elf_so/arch/sparc64/mdreloc.c: revision 1.60
	libexec/ld.elf_so/arch/m68k/mdreloc.c: revision 1.32
	libexec/ld.elf_so/arch/sparc64/mdreloc.c: revision 1.61
	libexec/ld.elf_so/arch/or1k/mdreloc.c: revision 1.2
	libexec/ld.elf_so/arch/sparc/mdreloc.c: revision 1.50
	libexec/ld.elf_so/arch/sh3/mdreloc.c: revision 1.33
	libexec/ld.elf_so/arch/sh3/mdreloc.c: revision 1.34
	libexec/ld.elf_so/arch/arm/mdreloc.c: revision 1.39
	libexec/ld.elf_so/symbol.c: revision 1.68
	libexec/ld.elf_so/arch/mips/mips_reloc.c: revision 1.66
	libexec/ld.elf_so/arch/mips/mips_reloc.c: revision 1.67
	libexec/ld.elf_so/arch/mips/mips_reloc.c: revision 1.68
	libexec/ld.elf_so/arch/x86_64/mdreloc.c: revision 1.42
	libexec/ld.elf_so/arch/powerpc/ppc_reloc.c: revision 1.54
	libexec/ld.elf_so/Makefile: revision 1.137
	libexec/ld.elf_so/arch/vax/mdreloc.c: revision 1.32
	libexec/ld.elf_so/rtld.h: revision 1.127
	libexec/ld.elf_so/arch/vax/mdreloc.c: revision 1.33
	libexec/ld.elf_so/arch/i386/mdreloc.c: revision 1.38
	libexec/ld.elf_so/arch/alpha/alpha_reloc.c: revision 1.42
	libexec/ld.elf_so/map_object.c: revision 1.58
	libexec/ld.elf_so/arch/sparc/mdreloc.c: revision 1.49
Replace COMBREL with just-in-time check in _rtld_relocate_nonplt_objects.
The COMBREL logic predates thread-safety of the dynamic linker and
breaks the use of shared locks for the common symbol lookup case. It is
unlikely to provide any benefit for lazy binding or PLT lookups, so
provide equivalent functionality in the non-PLT relocation handling loop
by checking if the symbol used by the current relocation is the same as
the one used during the last lookup. No inter-object cachine is done as
it is also unlikely to be benefical.
Testing with Firefox startup on AMD64 shows a small performance gain by
the new method.
Drop symbol number from default branch diagnostic, it isn't set at this
point and most likely not valid either.
Expand symnum, GCC's uninitialized used tracking is too imprecise.
Fix C&P bug. Deal with more MIPS hacks overriding def.
Add last_symnum, move up def and defobj.
Add back symnum, fix debug print.
Replace last use of r_type.
Fix indentation.
Fix indentation.
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $");
d81 1
a81 4
	const Elf_Sym *def = NULL;
	const Obj_Entry *defobj = NULL;
	unsigned long last_symnum = ULONG_MAX;

d84 2
d90 1
a93 19
		case R_TYPE(ABS64):	/* word B + S + A */
		case R_TYPE(GLOB_DAT):	/* word B + S */
		case R_TLS_TYPE(TLS_DTPREL):
		case R_TLS_TYPE(TLS_DTPMOD):
		case R_TLS_TYPE(TLS_TPREL):
			symnum = ELF_R_SYM(rela->r_info);
			if (last_symnum != symnum) {
				last_symnum = symnum;
				def = _rtld_find_symdef(symnum, obj, &defobj,
				    false);
				if (def == NULL)
					return -1;
			}

		default:
			break;
		}

		switch (ELF_R_TYPE(rela->r_info)) {
d99 3
d132 4
d144 4
d157 4
d175 1
a175 2
			    (u_long)ELF_R_SYM(rela->r_info),
			    (u_long)ELF_R_TYPE(rela->r_info),
@


1.1
log
@Preliminary files for AARCH64 (64-bit ARM) support.
Enough for a distribution build.
@
text
@d1 1
a1 1
/* $NetBSD$ */
d34 1
a34 1
__RCSID("$NetBSD$");
d225 7
a231 1
	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
@


1.1.2.1
log
@Catch up to -current, via patch, requested by christos in ticket #1126:
@
text
@d1 1
a1 1
/* $NetBSD: mdreloc.c,v 1.1 2014/08/10 05:47:37 matt Exp $ */
d34 1
a34 1
__RCSID("$NetBSD: mdreloc.c,v 1.1 2014/08/10 05:47:37 matt Exp $");
d225 1
a225 7
	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
		if (tp == NULL)
			return 0;
		new_value = _rtld_resolve_ifunc(defobj, def);
	} else {
		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
	}
@


1.1.4.1
log
@file mdreloc.c was added on branch tls-maxphys on 2014-08-20 00:02:22 +0000
@
text
@d1 263
@


1.1.4.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 263
/* $NetBSD$ */

/*-
 * Copyright (c) 2014 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Matt Thomas of 3am Software Foundry.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD$");
#endif /* not lint */

#include <sys/types.h>
#include <string.h>

#include "debug.h"
#include "rtld.h"

void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);

void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
	obj->pltgot[1] = (Elf_Addr) obj;
	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}

void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
	const Elf_Rel *rel = 0, *rellim;
	Elf_Addr relsz = 0;
	Elf_Addr *where;

	for (; dynp->d_tag != DT_NULL; dynp++) {
		switch (dynp->d_tag) {
		case DT_REL:
			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
			break;
		case DT_RELSZ:
			relsz = dynp->d_un.d_val;
			break;
		}
	}
	rellim = (const Elf_Rel *)((const uint8_t *)rel + relsz);
	for (; rel < rellim; rel++) {
		where = (Elf_Addr *)(relocbase + rel->r_offset);
		*where += (Elf_Addr)relocbase;
	}
}

int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
	
	for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) {
		Elf_Addr        *where;
		const Elf_Sym   *def;
		const Obj_Entry *defobj;
		unsigned long	 symnum;
		Elf_Addr	 addend;

		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
		symnum = ELF_R_SYM(rela->r_info);
		addend = rela->r_addend;

		switch (ELF_R_TYPE(rela->r_info)) {
		case R_TYPE(NONE):
			break;

		case R_TYPE(ABS64):	/* word B + S + A */
		case R_TYPE(GLOB_DAT):	/* word B + S */
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;
			*where = addend + (Elf_Addr)defobj->relocbase +
			    def->st_value;
			rdbg(("ABS64/GLOB_DAT %s in %s --> %p @@ %p in %s",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp, where, defobj->path));
			break;

		case R_TYPE(RELATIVE):	/* word B + A */
			*where = addend + (Elf_Addr)obj->relocbase;
			rdbg(("RELATIVE in %s --> %p", obj->path,
			    (void *)tmp));
			break;

		case R_TYPE(COPY):
			/*
			 * These are deferred until all other relocations have
			 * been done.  All we do here is make sure that the
			 * COPY relocation is not in a shared library.  They
			 * are allowed only in executable files.
			 */
			if (obj->isdynamic) {
				_rtld_error(
			"%s: Unexpected R_COPY relocation in shared library",
				    obj->path);
				return -1;
			}
			rdbg(("COPY (avoid in main)"));
			break;

		case R_TLS_TYPE(TLS_DTPREL):
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			*where = addend + (Elf_Addr)(def->st_value);

			rdbg(("TLS_DTPOFF32 %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp));

			break;
		case R_TLS_TYPE(TLS_DTPMOD):
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			*where = (Elf_Addr)(defobj->tlsindex);

			rdbg(("TLS_DTPMOD %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp));

			break;

		case R_TLS_TYPE(TLS_TPREL):
			def = _rtld_find_symdef(symnum, obj, &defobj, false);
			if (def == NULL)
				return -1;

			if (!defobj->tls_done &&
			    _rtld_tls_offset_allocate(obj))
				return -1;

			*where = (Elf_Addr)def->st_value + defobj->tlsoffset +
			    sizeof(struct tls_tcb);
			rdbg(("TLS_TPOFF32 %s in %s --> %p",
			    obj->strtab + obj->symtab[symnum].st_name,
			    obj->path, (void *)tmp));
			break;

		default:
			rdbg(("sym = %lu, type = %lu, offset = %p, "
			    "contents = %p, symbol = %s",
			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
			    (void *)rela->r_offset, *where,
			    obj->strtab + obj->symtab[symnum].st_name));
			_rtld_error("%s: Unsupported relocation type %ld "
			    "in non-PLT relocations",
			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
			return -1;
		}
	}
	return 0;
}

int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{

	if (!obj->relocbase)
		return 0;

	for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) {
		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);

		assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT));

		/* Just relocate the GOT slots pointing into the PLT */
		*where += (Elf_Addr)obj->relocbase;
		rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
	}

	return 0;
}

static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
	Elf_Addr *tp)
{
	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
	Elf_Addr new_value;
	const Elf_Sym  *def;
	const Obj_Entry *defobj;
	unsigned long info = rel->r_info;

	assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));

	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
	if (__predict_false(def == NULL))
		return -1;
	if (__predict_false(def == &_rtld_sym_zero))
		return 0;

	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
	rdbg(("bind now/fixup in %s --> old=%p new=%p",
	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
	if (*where != new_value)
		*where = new_value;
	if (tp)
		*tp = new_value;

	return 0;
}

caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
	const Elf_Rel *rel = obj->pltrel + reloff;
	Elf_Addr new_value = 0;	/* XXX gcc */

	_rtld_shared_enter();
	int err = _rtld_relocate_plt_object(obj, rel, &new_value);
	if (err)
		_rtld_die();
	_rtld_shared_exit();

	return (caddr_t)new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
	const Elf_Rel *rel;
	int err = 0;
	
	for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
		err = _rtld_relocate_plt_object(obj, rel, NULL);
		if (err)
			break;
	}

	return err;
}
@


