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
bind_now_open(lt_user_data d,const char * fname,lt_dladvise advise)69 static 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
bind_now_close(lt_user_data d,lt_module m)83 static 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
bind_now_find_sym(lt_user_data d,lt_module m,const char * symbol)95 static 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
109 static lt_dlvtable *bindnow_loader = NULL;
110 #endif
111
pa_ltdl_init(void)112 void 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
pa_ltdl_done(void)151 void 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