dlfcn.c revision 34196
1135446Strhodes/*- 2224092Sdougb * Copyright (c) 1998 John D. Polstra 3135446Strhodes * All rights reserved. 4135446Strhodes * 5174187Sdougb * Redistribution and use in source and binary forms, with or without 6135446Strhodes * modification, are permitted provided that the following conditions 7135446Strhodes * are met: 8135446Strhodes * 1. Redistributions of source code must retain the above copyright 9135446Strhodes * notice, this list of conditions and the following disclaimer. 10135446Strhodes * 2. Redistributions in binary form must reproduce the above copyright 11135446Strhodes * notice, this list of conditions and the following disclaimer in the 12135446Strhodes * documentation and/or other materials provided with the distribution. 13135446Strhodes * 14135446Strhodes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15135446Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16135446Strhodes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17135446Strhodes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18225361Sdougb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19135446Strhodes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20170222Sdougb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21170222Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22135446Strhodes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23135446Strhodes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24135446Strhodes * SUCH DAMAGE. 25171577Sdougb * 26171577Sdougb * $Id: dlfcn.c,v 1.1 1998/02/09 06:05:24 jdp Exp $ 27186462Sdougb */ 28135446Strhodes 29135446Strhodes/* 30135446Strhodes * Linkage to services provided by the dynamic linker. These are 31135446Strhodes * implemented differently in ELF and a.out, because the dynamic 32186462Sdougb * linkers have different interfaces. 33135446Strhodes */ 34180477Sdougb 35193149Sdougb#ifdef __ELF__ 36135446Strhodes 37135446Strhodes#include <dlfcn.h> 38171577Sdougb#include <stddef.h> 39135446Strhodes 40135446Strhodesstatic const char sorry[] = "Service unavailable"; 41135446Strhodes 42135446Strhodes/* 43135446Strhodes * For ELF, the dynamic linker directly resolves references to its 44135446Strhodes * services to functions inside the dynamic linker itself. These 45135446Strhodes * weak-symbol stubs are necessary so that "ld" won't complain about 46135446Strhodes * undefined symbols. The stubs are executed only when the program is 47193149Sdougb * linked statically, or when a given service isn't implemented in the 48135446Strhodes * dynamic linker. They must return an error if called, and they must 49135446Strhodes * be weak symbols so that the dynamic linker can override them. 50135446Strhodes */ 51135446Strhodes 52135446Strhodes#pragma weak _rtld_error 53193149Sdougbvoid 54186462Sdougb_rtld_error(const char *fmt, ...) 55135446Strhodes{ 56193149Sdougb} 57193149Sdougb 58193149Sdougb#pragma weak dladdr 59180477Sdougbint 60180477Sdougbdladdr(const void *addr, Dl_info *dlip) 61180477Sdougb{ 62180477Sdougb _rtld_error(sorry); 63180477Sdougb return 0; 64180477Sdougb} 65186462Sdougb 66186462Sdougb#pragma weak dlclose 67180477Sdougbint 68180477Sdougbdlclose(void *handle) 69186462Sdougb{ 70186462Sdougb _rtld_error(sorry); 71186462Sdougb return -1; 72186462Sdougb} 73186462Sdougb 74186462Sdougb#pragma weak dlerror 75186462Sdougbconst char * 76186462Sdougbdlerror(void) 77186462Sdougb{ 78135446Strhodes return sorry; 79135446Strhodes} 80135446Strhodes 81135446Strhodes#pragma weak dlopen 82135446Strhodesvoid * 83135446Strhodesdlopen(const char *name, int mode) 84193149Sdougb{ 85186462Sdougb _rtld_error(sorry); 86135446Strhodes return NULL; 87135446Strhodes} 88135446Strhodes 89135446Strhodes#pragma weak dlsym 90135446Strhodesvoid * 91135446Strhodesdlsym(void *handle, const char *name) 92180477Sdougb{ 93180477Sdougb _rtld_error(sorry); 94180477Sdougb return NULL; 95180477Sdougb} 96135446Strhodes 97135446Strhodes#else /* a.out format */ 98135446Strhodes 99170222Sdougb#include <sys/types.h> 100170222Sdougb#include <nlist.h> /* XXX - Required by link.h */ 101170222Sdougb#include <dlfcn.h> 102135446Strhodes#include <link.h> 103135446Strhodes#include <stddef.h> 104135446Strhodes 105170222Sdougb/* 106170222Sdougb * For a.out, entry to the dynamic linker is via these trampolines. 107170222Sdougb * They enter the dynamic linker through the ld_entry struct that was 108170222Sdougb * passed back from the dynamic linker at startup time. 109186462Sdougb */ 110135446Strhodes 111186462Sdougb/* GCC is needed because we use its __builtin_return_address construct. */ 112186462Sdougb 113186462Sdougb#ifndef __GNUC__ 114186462Sdougb#error "GCC is needed to compile this file" 115186462Sdougb#endif 116186462Sdougb 117186462Sdougb/* 118186462Sdougb * These variables are set by code in crt0.o. For compatibility with 119186462Sdougb * old executables, they must be common, not extern. 120186462Sdougb */ 121186462Sdougbstruct ld_entry *__ldso_entry; /* Entry points to dynamic linker */ 122186462Sdougbint __ldso_version; /* Dynamic linker version number */ 123186462Sdougb 124186462Sdougbint 125186462Sdougbdladdr(const void *addr, Dl_info *dlip) 126186462Sdougb{ 127186462Sdougb if (__ldso_entry == NULL || __ldso_version < LDSO_VERSION_HAS_DLADDR) 128186462Sdougb return 0; 129186462Sdougb return (__ldso_entry->dladdr)(addr, dlip); 130135446Strhodes} 131135446Strhodes 132135446Strhodesint 133135446Strhodesdlclose(void *handle) 134135446Strhodes{ 135135446Strhodes if (__ldso_entry == NULL) 136135446Strhodes return -1; 137135446Strhodes return (__ldso_entry->dlclose)(handle); 138135446Strhodes} 139135446Strhodes 140135446Strhodesconst char * 141180477Sdougbdlerror(void) 142135446Strhodes{ 143135446Strhodes if (__ldso_entry == NULL) 144135446Strhodes return "Service unavailable"; 145135446Strhodes return (__ldso_entry->dlerror)(); 146135446Strhodes} 147135446Strhodes 148186462Sdougbvoid * 149135446Strhodesdlopen(const char *name, int mode) 150135446Strhodes{ 151135446Strhodes if (__ldso_entry == NULL) 152135446Strhodes return NULL; 153186462Sdougb return (__ldso_entry->dlopen)(name, mode); 154186462Sdougb} 155186462Sdougb 156186462Sdougbvoid * 157186462Sdougbdlsym(void *handle, const char *name) 158186462Sdougb{ 159186462Sdougb if (__ldso_entry == NULL) 160186462Sdougb return NULL; 161186462Sdougb if (__ldso_version >= LDSO_VERSION_HAS_DLSYM3) { 162186462Sdougb void *retaddr = __builtin_return_address(0); /* __GNUC__ only */ 163186462Sdougb return (__ldso_entry->dlsym3)(handle, name, retaddr); 164186462Sdougb } else 165186462Sdougb return (__ldso_entry->dlsym)(handle, name); 166186462Sdougb} 167186462Sdougb 168186462Sdougb#endif /* __ELF__ */ 169186462Sdougb