1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2008 Lennart Poettering 5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#ifdef HAVE_DLFCN_H 26#include <dlfcn.h> 27#endif 28 29#ifdef HAVE_SYS_DL_H 30#include <sys/dl.h> 31#endif 32 33#include <string.h> 34 35#include <ltdl.h> 36 37#include <pulsecore/i18n.h> 38#include <pulsecore/macro.h> 39#include <pulsecore/log.h> 40 41#include "ltdl-bind-now.h" 42 43#ifdef RTLD_NOW 44#define PA_BIND_NOW RTLD_NOW 45#elif defined(DL_NOW) 46#define PA_BIND_NOW DL_NOW 47#else 48#undef PA_BIND_NOW 49#endif 50 51#ifdef OS_IS_WIN32 52#undef PA_BIND_NOW 53#endif 54 55#ifdef PA_BIND_NOW 56 57/* 58 To avoid lazy relocations during runtime in our RT threads we add 59 our own shared object loader with uses RTLD_NOW if it is 60 available. The standard ltdl loader prefers RTLD_LAZY. 61 62 Please note that this loader doesn't have any influence on 63 relocations on any libraries that are already loaded into our 64 process, i.e. because the pulseaudio binary links directly to 65 them. To disable lazy relocations for those libraries it is possible 66 to set $LT_BIND_NOW before starting the pulseaudio binary. 67*/ 68 69static lt_module bind_now_open(lt_user_data d, const char *fname, lt_dladvise advise) { 70 lt_module m; 71 72 pa_assert(fname); 73 74 if (!(m = dlopen(fname, PA_BIND_NOW))) { 75 pa_log(_("Failed to open module %s: %s"), fname, dlerror()); 76 lt_dlseterror(LT_ERROR_CANNOT_OPEN); 77 return NULL; 78 } 79 80 return m; 81} 82 83static int bind_now_close(lt_user_data d, lt_module m) { 84 85 pa_assert(m); 86 87 if (dlclose(m) != 0) { 88 lt_dlseterror(LT_ERROR_CANNOT_CLOSE); 89 return 1; 90 } 91 92 return 0; 93} 94 95static lt_ptr bind_now_find_sym(lt_user_data d, lt_module m, const char *symbol) { 96 lt_ptr ptr; 97 98 pa_assert(m); 99 pa_assert(symbol); 100 101 if (!(ptr = dlsym(m, symbol))) { 102 lt_dlseterror(LT_ERROR_SYMBOL_NOT_FOUND); 103 return NULL; 104 } 105 106 return ptr; 107} 108 109static lt_dlvtable *bindnow_loader = NULL; 110#endif 111 112void pa_ltdl_init(void) { 113 114#ifdef PA_BIND_NOW 115 const lt_dlvtable *dlopen_loader; 116#endif 117 118 pa_assert_se(lt_dlinit() == 0); 119 120#ifdef PA_BIND_NOW 121 /* Already initialised */ 122 if (bindnow_loader) 123 return; 124 125 if (!(dlopen_loader = lt_dlloader_find((char*) "lt_dlopen"))) { 126 pa_log_warn(_("Failed to find original lt_dlopen loader.")); 127 return; 128 } 129 130 if (!(bindnow_loader = malloc(sizeof(lt_dlvtable)))) { 131 pa_log_error(_("Failed to allocate new dl loader.")); 132 return; 133 } 134 135 memcpy(bindnow_loader, dlopen_loader, sizeof(*bindnow_loader)); 136 bindnow_loader->name = "bind-now-loader"; 137 bindnow_loader->module_open = bind_now_open; 138 bindnow_loader->module_close = bind_now_close; 139 bindnow_loader->find_sym = bind_now_find_sym; 140 bindnow_loader->priority = LT_DLLOADER_PREPEND; 141 142 /* Add our BIND_NOW loader as the default module loader. */ 143 if (lt_dlloader_add(bindnow_loader) != 0) { 144 pa_log_warn(_("Failed to add bind-now-loader.")); 145 free(bindnow_loader); 146 bindnow_loader = NULL; 147 } 148#endif 149} 150 151void pa_ltdl_done(void) { 152 pa_assert_se(lt_dlexit() == 0); 153 154#ifdef PA_BIND_NOW 155 /* lt_dlexit() will free our loader vtable, hence reset our 156 * pointer to it here */ 157 bindnow_loader = NULL; 158#endif 159} 160