freebsd-nq/lib/libc/gen/dlfcn.c
Konstantin Belousov 99ac8154ff Provide libdl.
Create libdl.so.1 as a filter for libc.so.7 which exports public dl*
functions. The functions are resolved from the rtld instead, the goal
of creating library is to avoid errors from the static linker due to
missed libdl. For static binaries, an empty .o is compiled into
libdl.a so that static binaries still get dl stubs from libc.a.

Right now lld cannot create filter objects, disable libdl on arm64
when binutils are not used.

Reviewed by:	bdrewery, dim (previos version); emaste
Exp run:	PR 220525, done by antoine
Sponsored by:	The FreeBSD Foundation
MFC after:	1 month
Differential revision:	https://reviews.freebsd.org/D11504
2017-07-10 14:59:21 +00:00

264 lines
5.7 KiB
C

/*-
* Copyright (c) 1998 John D. Polstra
* All rights reserved.
*
* 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>
__FBSDID("$FreeBSD$");
#if !defined(IN_LIBDL) || defined(PIC)
/*
* Linkage to services provided by the dynamic linker.
*/
#include <sys/mman.h>
#include <dlfcn.h>
#include <link.h>
#include <stddef.h>
#include "namespace.h"
#include <pthread.h>
#include "un-namespace.h"
#include "libc_private.h"
static char sorry[] = "Service unavailable";
void _rtld_thread_init(void *);
void _rtld_atfork_pre(int *);
void _rtld_atfork_post(int *);
/*
* For ELF, the dynamic linker directly resolves references to its
* services to functions inside the dynamic linker itself. These
* weak-symbol stubs are necessary so that "ld" won't complain about
* undefined symbols. The stubs are executed only when the program is
* linked statically, or when a given service isn't implemented in the
* dynamic linker. They must return an error if called, and they must
* be weak symbols so that the dynamic linker can override them.
*/
#pragma weak _rtld_error
void
_rtld_error(const char *fmt __unused, ...)
{
}
#pragma weak dladdr
int
dladdr(const void *addr __unused, Dl_info *dlip __unused)
{
_rtld_error(sorry);
return (0);
}
#pragma weak dlclose
int
dlclose(void *handle __unused)
{
_rtld_error(sorry);
return (-1);
}
#pragma weak dlerror
char *
dlerror(void)
{
return (sorry);
}
#pragma weak dllockinit
void
dllockinit(void *context,
void *(*lock_create)(void *context) __unused,
void (*rlock_acquire)(void *lock) __unused,
void (*wlock_acquire)(void *lock) __unused,
void (*lock_release)(void *lock) __unused,
void (*lock_destroy)(void *lock) __unused,
void (*context_destroy)(void *context) __unused)
{
if (context_destroy != NULL)
context_destroy(context);
}
#pragma weak dlopen
void *
dlopen(const char *name __unused, int mode __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlsym
void *
dlsym(void * __restrict handle __unused, const char * __restrict name __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlfunc
dlfunc_t
dlfunc(void * __restrict handle __unused, const char * __restrict name __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlvsym
void *
dlvsym(void * __restrict handle __unused, const char * __restrict name __unused,
const char * __restrict version __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlinfo
int
dlinfo(void * __restrict handle __unused, int request __unused,
void * __restrict p __unused)
{
_rtld_error(sorry);
return (0);
}
#pragma weak _rtld_thread_init
void
_rtld_thread_init(void *li __unused)
{
_rtld_error(sorry);
}
#ifndef IN_LIBDL
static pthread_once_t dl_phdr_info_once = PTHREAD_ONCE_INIT;
static struct dl_phdr_info phdr_info;
static void
dl_init_phdr_info(void)
{
Elf_Auxinfo *auxp;
unsigned int i;
for (auxp = __elf_aux_vector; auxp->a_type != AT_NULL; auxp++) {
switch (auxp->a_type) {
case AT_BASE:
phdr_info.dlpi_addr = (Elf_Addr)auxp->a_un.a_ptr;
break;
case AT_EXECPATH:
phdr_info.dlpi_name = (const char *)auxp->a_un.a_ptr;
break;
case AT_PHDR:
phdr_info.dlpi_phdr =
(const Elf_Phdr *)auxp->a_un.a_ptr;
break;
case AT_PHNUM:
phdr_info.dlpi_phnum = (Elf_Half)auxp->a_un.a_val;
break;
}
}
for (i = 0; i < phdr_info.dlpi_phnum; i++) {
if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) {
phdr_info.dlpi_tls_modid = 1;
phdr_info.dlpi_tls_data =
(void*)phdr_info.dlpi_phdr[i].p_vaddr;
}
}
phdr_info.dlpi_adds = 1;
}
#endif
#pragma weak dl_iterate_phdr
int
dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
void *data __unused)
{
#ifndef IN_LIBDL
__init_elf_aux_vector();
if (__elf_aux_vector == NULL)
return (1);
_once(&dl_phdr_info_once, dl_init_phdr_info);
return (callback(&phdr_info, sizeof(phdr_info), data));
#else
return (0);
#endif
}
#pragma weak fdlopen
void *
fdlopen(int fd __unused, int mode __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak _rtld_atfork_pre
void
_rtld_atfork_pre(int *locks __unused)
{
}
#pragma weak _rtld_atfork_post
void
_rtld_atfork_post(int *locks __unused)
{
}
#pragma weak _rtld_addr_phdr
int
_rtld_addr_phdr(const void *addr __unused,
struct dl_phdr_info *phdr_info_a __unused)
{
return (0);
}
#pragma weak _rtld_get_stack_prot
int
_rtld_get_stack_prot(void)
{
return (PROT_EXEC | PROT_READ | PROT_WRITE);
}
#pragma weak _rtld_is_dlopened
int
_rtld_is_dlopened(void *arg __unused)
{
return (0);
}
#endif /* !defined(IN_LIBDL) || defined(PIC) */