[BACK]Return to tls.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / tls

File: [cvs.NetBSD.org] / src / lib / libc / tls / tls.c (download)

Revision 1.8, Sun Dec 14 23:49:17 2014 UTC (5 years, 7 months ago) by chs
Branch: MAIN
CVS Tags: prg-localcount2-base3, prg-localcount2-base2, prg-localcount2-base1, prg-localcount2-base, prg-localcount2, phil-wifi-base, pgoyette-localcount-base, pgoyette-localcount-20170426, pgoyette-localcount-20170320, pgoyette-localcount-20170107, pgoyette-localcount-20161104, pgoyette-localcount-20160806, pgoyette-localcount-20160726, pgoyette-localcount, pgoyette-compat-base, pgoyette-compat-0625, pgoyette-compat-0521, pgoyette-compat-0502, pgoyette-compat-0422, pgoyette-compat-0415, pgoyette-compat-0407, pgoyette-compat-0330, pgoyette-compat-0322, pgoyette-compat-0315, perseant-stdc-iso10646-base, perseant-stdc-iso10646, netbsd-8-base, netbsd-8-2-RELEASE, netbsd-8-1-RELEASE, netbsd-8-1-RC1, netbsd-8-0-RELEASE, netbsd-8-0-RC2, netbsd-8-0-RC1, netbsd-8, matt-nb8-mediatek-base, matt-nb8-mediatek, localcount-20160914, bouyer-socketcan-base1, bouyer-socketcan-base, bouyer-socketcan
Branch point for: phil-wifi, pgoyette-compat
Changes since 1.7: +2 -11 lines

fix powerpc TLS problems by removing the hacks for PPC EABI.
the kernel no longer treats R2 specially and its use as
the TLS register is now handled entirely in userland.

/*	$NetBSD: tls.c,v 1.8 2014/12/14 23:49:17 chs Exp $	*/

/*-
 * Copyright (c) 2011 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Joerg Sonnenberger.
 *
 * 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>
__RCSID("$NetBSD: tls.c,v 1.8 2014/12/14 23:49:17 chs Exp $");

#include "namespace.h"

#define	_rtld_tls_allocate	__libc_rtld_tls_allocate
#define	_rtld_tls_free		__libc_rtld_tls_free

#include <sys/tls.h>

#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)

#include <sys/param.h>
#include <sys/mman.h>
#include <link_elf.h>
#include <lwp.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

__dso_hidden void	__libc_static_tls_setup(void);

static const void *tls_initaddr;
static size_t tls_initsize;
static size_t tls_size;
static size_t tls_allocation;
static void *initial_thread_tcb;

void * __libc_tls_get_addr(void);

__weak_alias(__tls_get_addr, __libc_tls_get_addr)
#ifdef __i386__
__weak_alias(___tls_get_addr, __libc_tls_get_addr)
#endif

void *
__libc_tls_get_addr(void)
{

	abort();
	/* NOTREACHED */
}

__weak_alias(_rtld_tls_allocate, __libc_rtld_tls_allocate)

struct tls_tcb *
_rtld_tls_allocate(void)
{
	struct tls_tcb *tcb;
	uint8_t *p;

	if (initial_thread_tcb == NULL) {
#ifdef __HAVE_TLS_VARIANT_II
		tls_size = roundup2(tls_size, sizeof(void *));
#endif
		tls_allocation = tls_size + sizeof(*tcb);

		initial_thread_tcb = p = mmap(NULL, tls_allocation,
		    PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
	} else {
		p = calloc(1, tls_allocation);
	}
	if (p == NULL) {
		static const char msg[] =  "TLS allocation failed, terminating\n";
		write(STDERR_FILENO, msg, sizeof(msg));
		_exit(127);
	}
#ifdef __HAVE_TLS_VARIANT_I
	/* LINTED */
	tcb = (struct tls_tcb *)p;
	p += sizeof(struct tls_tcb);
#else
	/* LINTED tls_size is rounded above */
	tcb = (struct tls_tcb *)(p + tls_size);
	tcb->tcb_self = tcb;
#endif
	memcpy(p, tls_initaddr, tls_initsize);

	return tcb;
}

__weak_alias(_rtld_tls_free, __libc_rtld_tls_free)

void
_rtld_tls_free(struct tls_tcb *tcb)
{
	uint8_t *p;

#ifdef __HAVE_TLS_VARIANT_I
	/* LINTED */
	p = (uint8_t *)tcb;
#else
	/* LINTED */
	p = (uint8_t *)tcb - tls_size;
#endif
	if (p == initial_thread_tcb)
		munmap(p, tls_allocation);
	else
		free(p);
}

__weakref_visible int rtld_DYNAMIC __weak_reference(_DYNAMIC);

static int __section(".text.startup")
__libc_static_tls_setup_cb(struct dl_phdr_info *data, size_t len, void *cookie)
{
	const Elf_Phdr *phdr = data->dlpi_phdr;
	const Elf_Phdr *phlimit = data->dlpi_phdr + data->dlpi_phnum;

	for (; phdr < phlimit; ++phdr) {
		if (phdr->p_type != PT_TLS)
			continue;
		tls_initaddr = (void *)(phdr->p_vaddr + data->dlpi_addr);
		tls_initsize = phdr->p_filesz;
		tls_size = phdr->p_memsz;
	}
	return 0;
}

void
__libc_static_tls_setup(void)
{
	struct tls_tcb *tcb;

	if (&rtld_DYNAMIC != NULL) {
		return;
	}

	dl_iterate_phdr(__libc_static_tls_setup_cb, NULL);

	tcb = _rtld_tls_allocate();
#ifdef __HAVE___LWP_SETTCB
	__lwp_settcb(tcb);
#else
	_lwp_setprivate(tcb);
#endif
}

#endif /* __HAVE_TLS_VARIANT_I || __HAVE_TLS_VARIANT_II */