/
moon_dlfix.h
178 lines (156 loc) · 5.58 KB
/
moon_dlfix.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* Copyright 2013-2016 Philipp Janda <siffiejoe@gmx.net>
*
* You may do anything with this work that copyright law would normally
* restrict, so long as you retain the above notice(s) and this license
* in all redistributed copies and derived works. There is no warranty.
*/
#ifndef MOON_DLFIX_H_
#define MOON_DLFIX_H_
/* Provides a C function macro that tries to reopen the Lua library
* in global mode, so that C extension modules do not have to be
* relinked for Lua VMs in shared libraries.
*/
/* enable/disable debug output */
#if 0
#include <stdio.h>
#define MOON_DLFIX_DBG( _a ) (printf _a)
#else
#define MOON_DLFIX_DBG( _a ) ((void)0)
#endif
/* detect some form of UNIX, so that unistd.h can be included to
* use other feature macros */
#if defined( unix ) || defined( __unix ) || defined( __unix__ ) || \
defined( __TOS_AIX__ ) || defined( _SYSTYPE_BSD ) || \
(defined( __APPLE__ ) && defined( __MACH__ )) || \
defined( HAVE_UNISTD_H )
#include <unistd.h>
/* check for minimum POSIX version that specifies dlopen etc. */
#if (defined( _POSIX_VERSION ) && _POSIX_VERSION >= 200112L) || \
defined( HAVE_DLFCN_H )
#include <dlfcn.h>
/* check for the existence of the RTLD_NOLOAD flag
* - GLIBC has it (since 2.2)
* - FreeBSD has it
* - ...
*/
#ifdef RTLD_NOLOAD
/* Lua VM library names to try
* Most of them require the dev-package to be installed,
* but guessing the real library names for multiple distros
* is pretty difficult ...
* If the library is not in the default search path you can
* set LD_LIBRARY_PATH, or use MOON_DLFIX_LIBNAME to specify
* an absolute path to the library.
*/
static char const* const moon_dlfix_lib_names[] = {
/* you can define your own custom name via compiler define: */
#ifdef MOON_DLFIX_LIBNAME
MOON_DLFIX_LIBNAME,
#endif /* custom Lua library name */
"liblua5.4.so", /* Lua 5.4, Debian/Ubuntu naming */
"liblua5.4.so.0", /* same with common SONAME */
"liblua54.so",
"liblua5.3.so", /* Lua 5.3, Debian/Ubuntu naming */
"liblua5.3.so.0", /* same with common SONAME */
"liblua53.so",
"liblua5.2.so", /* Lua 5.2, Debian/Ubuntu naming */
"liblua5.2.so.0", /* same with common SONAME */
"liblua52.so",
"liblua.so", /* default name from Lua's makefile */
"liblua5.1.so", /* Lua 5.1, Debian/Ubuntu naming */
"liblua5.1.so.0", /* same with common SONAME */
"liblua51.so",
"libluajit-5.1.so", /* LuaJIT default name */
"libluajit-5.1.so.2", /* common SONAME */
};
/* On some OSes we can iterate over all loaded libraries to
* find the Lua shared object.
*/
#if defined( __linux__ ) && defined( _GNU_SOURCE )
#define MOON_DLFIX_DL_ITERATE_PHDR
#include <link.h>
#endif /* Linux with dl_iterate_phdr() function */
#if defined( __FreeBSD__ ) || defined( __DragonFly__ ) || \
defined( __NetBSD__ ) || defined( __OpenBSD__ )
#define MOON_DLFIX_DL_ITERATE_PHDR
#include <link.h>
#endif /* BSDs with dl_iterate_phdr() function */
#if !defined( MOON_DLFIX_FIND ) && \
defined( MOON_DLFIX_DL_ITERATE_PHDR )
#include <string.h>
#ifndef MOON_DLFIX_LIBPREFIX
#define MOON_DLFIX_LIBPREFIX "liblua"
#endif
static int moon_dlfix_cb( struct dl_phdr_info* info, size_t size,
void* data ) {
int* found = data;
void* dl = dlopen( info->dlpi_name, RTLD_LAZY );
(void)size;
MOON_DLFIX_DBG(("Checking ELF object '%s'.\n", info->dlpi_name));
if( dl ) {
if( dlsym( dl, "lua_gettop" ) ) {
MOON_DLFIX_DBG(("'%s' does have Lua symbols.\n", info->dlpi_name));
/* the Lua API could be in a dependency, so test the library
* name for "liblua" */
char const* libname = strrchr( info->dlpi_name, '/' );
if( libname )
++libname; /* skip slash */
else
libname = info->dlpi_name;
if( 0 == strncmp( libname, MOON_DLFIX_LIBPREFIX,
sizeof( MOON_DLFIX_LIBPREFIX )-1 ) ) {
void* dl2 = dlopen( info->dlpi_name,
RTLD_LAZY|RTLD_GLOBAL|RTLD_NOLOAD );
if( dl2 ) {
MOON_DLFIX_DBG(("Found and fixed Lua SO!\n"));
dlclose( dl2 );
*found = 1;
}
}
}
dlclose( dl );
}
return *found;
}
static int moon_dlfix_find( void ) {
int found = 0;
MOON_DLFIX_DBG(("Iterating all loaded ELF objects ...\n"));
return dl_iterate_phdr( moon_dlfix_cb, &found );
}
#define MOON_DLFIX_FIND() (moon_dlfix_find())
#endif /* has dl_iterate_phdr() function */
#if !defined( MOON_DLFIX_FIND )
/* dummy definition (always returns failure) */
# define MOON_DLFIX_FIND() (0)
#endif
/* Try to iterate all loaded shared libraries using a platform-
* specific way to find a loaded Lua shared library.
* If that fails, try a list of common library names.
* In all cases reopen the Lua library using RTLD_GLOBAL and
* RTLD_NOLOAD.
*/
#define MOON_DLFIX() \
do { \
if( !MOON_DLFIX_FIND() ) { \
unsigned i = 0; \
MOON_DLFIX_DBG(("Trying some common Lua library names ...\n")); \
for( ; i < sizeof( moon_dlfix_lib_names )/sizeof( *moon_dlfix_lib_names ); ++i ) { \
void* dl = dlopen( moon_dlfix_lib_names[ i ], RTLD_LAZY|RTLD_GLOBAL|RTLD_NOLOAD ); \
MOON_DLFIX_DBG(("Trying '%s'.\n", moon_dlfix_lib_names[ i ])); \
if( dl ) { \
MOON_DLFIX_DBG(("Fixed Lua SO.\n")); \
dlclose( dl ); \
break; \
} \
} \
} \
} while( 0 )
#endif /* has RTLD_NOLOAD */
#endif /* has dlfcn.h */
#endif /* has unistd.h */
/* define fallback */
#ifndef MOON_DLFIX
#define MOON_DLFIX() \
(MOON_DLFIX_DBG(("moon_dlfix functionality not available!\n")))
#endif
#endif /* MOON_DLFIX_H_ */