Skip to content
Snippets Groups Projects
Commit 7d34220d authored by Simon McVittie's avatar Simon McVittie
Browse files

Provide _ext_dlsym(), etc. via headers capsule/_ext_dlsym.h etc.


This lets library users override them via the usual compiler include
path.

Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
parent 6147d675
Branches
Tags
1 merge request!311Build capsule-capture-libs from a bundled copy of libcapsule
......@@ -34,7 +34,10 @@ nobase_include_HEADERS = capsule/capsule.h
dist_doc_DATA = $(foreach doc,$(static_docs),doc/$(doc).txt)
# Headers to be included by shim libraries
nobase_include_HEADERS += capsule/capsule-shim.h
nobase_include_HEADERS += capsule/capsule-shim.h \
capsule/_ext_dlopen.h \
capsule/_ext_dlsym.h \
capsule/_int_dlopen.h
# demo program - keep this hanging around as it's a useful PoC
noinst_PROGRAMS = elf-dump
......@@ -132,8 +135,6 @@ nobase_dist_insttests_DATA += tests/notgl.h \
tests/notgl-helper-green.c \
tests/notgl-helper-red.c \
tests/notgl-helper-ref.c \
tests/shim/libnotgl.so.c.dlopen \
tests/shim/libnotgl.so.c.dlsym \
tests/shim/libnotgl.so.c.excluded \
tests/shim/libnotgl.so.c.shared \
tests/shim/libnotgl.so.c.symbols
......@@ -178,13 +179,13 @@ nodist_tests_shim_libnotgl_la_SOURCES = tests/shim/libnotgl.so.c
tests_shim_libnotgl_la_LIBADD = libcapsule.la
tests_shim_libnotgl_la_LDFLAGS = -shared -version-number 0:0:0
tests/shim/lib%.so.c: tests/shim/lib%.so.c.excluded tests/shim/lib%.so.c.dlopen tests/shim/lib%.so.c.dlsym tests/shim/lib%.so.c.shared tests/shim/lib%.so.c.symbols data/capsule-mkstublib Makefile
tests/shim/lib%.so.c: tests/shim/lib%.so.c.excluded tests/shim/lib%.so.c.shared tests/shim/lib%.so.c.symbols data/capsule-mkstublib Makefile
$(AM_V_GEN)\
PKG_CONFIG_PATH=$(abs_builddir)/data \
V=$V \
$(top_srcdir)/data/capsule-mkstublib \
--dlopen-implementation=$(srcdir)/$@.dlopen \
--dlsym-implementation=$(srcdir)/$@.dlsym \
--ext-dlopen \
--ext-dlsym \
--symbols-from=$(srcdir)/$@.symbols \
--no-update-symbols \
--runtime-tree=/host \
......
// Copyright © 2017 Collabora Ltd
//
// This file is part of libcapsule.
//
// libcapsule is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// libcapsule is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
// Standard implementation of _ext_dlopen(), the implementation used
// when a library outside the capsule calls dlopen(). To override this
// implementation, copy this file to shim/capsule/_ext_dlopen.h in
// your shim library and modify as needed.
static void *_ext_dlopen (const char *filename, int flag)
{
return capsule_external_dlopen( cap, filename, flag );
}
// Copyright © 2017 Collabora Ltd
//
// This file is part of libcapsule.
//
// libcapsule is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// libcapsule is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
// Standard implementation of _ext_sym(), the implementation used
// when a library outside the capsule calls dlsym(). To override this
// implementation, copy this file to shim/capsule/_ext_dlsym.h in
// your shim library and modify as needed.
//
// This allows symbols inside the capsule to be found by dlopen calls from
// outside the capsule iff they are in one of the exported DSOs.
//
......@@ -6,7 +28,7 @@
// bizarre dlopen()/dlsym() dance instead of referring to a symbol
// directly (and we may be missing those symbols from our static
// export list even if the target libGL has them)
static void *_dlsym (void *handle, const char *symbol)
static void *_ext_dlsym (void *handle, const char *symbol)
{
return capsule_external_dlsym( cap, handle, symbol );
}
// Copyright © 2017 Collabora Ltd
//
// This file is part of libcapsule.
//
// libcapsule is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// libcapsule is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
// Standard implementation of _int_dlopen(), the implementation used
// when a library inside the capsule calls dlopen(). To override this
// implementation, copy this file to shim/capsule/_int_dlopen.h in
// your shim library and modify as needed.
static void *
_int_dlopen (const char *filename, int flag)
{
if( flag & RTLD_GLOBAL )
{
fprintf( stderr, "Warning: libcapsule dlopen wrapper cannot pass "
"RTLD_GLOBAL to underlying dlmopen(%s...) call\n",
filename );
flag = (flag & ~RTLD_GLOBAL) & 0xfffff;
}
return capsule_shim_dlopen( cap, filename, flag );
}
......@@ -123,52 +123,6 @@ echo Extracting dynamic symbols from $tree : $target;
echo Preparing proxy source files
touch shim/$base.so.c.{shared,excluded};
cat - <<EOF > shim/$base.so.c.dlopen
static void *_int_dlopen (const char *filename, int flag)
{
if( flag & RTLD_GLOBAL )
{
fprintf( stderr, "Warning: libcapsule dlopen wrapper cannot pass "
"RTLD_GLOBAL to underlying dlmopen(%s...) call\\n",
filename );
flag = (flag & ~RTLD_GLOBAL) & 0xfffff;
}
return capsule_shim_dlopen( cap, filename, flag );
}
static void *_ext_dlopen (const char *filename, int flag)
{
char *capsule_error = NULL;
void *handle = capsule_external_dlopen( cap, filename, flag );
capsule_relocate_except( cap, dl_relocs,
&invalid_dl_reloc_targets[0],
&capsule_error );
if( capsule_error )
{
fprintf( stderr, "post-dlopen hook secondary relocate failed: %s\n",
capsule_error );
free( capsule_error );
capsule_error = NULL;
}
return handle;
}
EOF
cat - <<EOF > shim/$base.so.c.dlsym
// This allows symbols inside the capsule to be found by dlopen calls from
// outside the capsule iff they are in one of the exported DSOs.
//
// This is useful in libGL shims as libGL has an ‘interesting’ history
// of symbols appearing and disappearing so its users often do a
// bizarre dlopen()/dlsym() dance instead of referring to a symbol
// directly (and we may be missing those symbols from our static
// export list even if the target libGL has them)
static void *_dlsym (void *handle, const char *symbol)
{
return capsule_external_dlsym( cap, handle, symbol );
}
EOF
echo Initialising configure.ac;
cat - <<EOF > configure.ac
......@@ -201,6 +155,7 @@ CAPSULE_LIBRARY := $name
CAPSULE_VERSION := $ver
CAPSULE_TREE := $tree
CAPSULE_MAJOR := $maj
#AM_CAPSULE_MKSTUBLIB_FLAGS := --ext-dlopen --ext-dlsym
include @CAPSULE_MKINC@/disabled.mk
##include capsule-shim.mk##
......
......@@ -32,14 +32,12 @@ Usage: $me [OPTIONS] TARGET EXCLUDES EXPORTS OUTPUT [DSO-VERSION [TREE]]"
Options:
--capsule-symbols-tool=PATH
Use replacement capsule-symbols(1)
--dlopen-implementation=PATH
An implementation of _dlopen()
[default: OUTPUT.dlopen]
--dlsym-implementation=PATH
An implementation of _dlsym()
[default: OUTPUT.dlsym, if it exists]
--symbols-from=PATH Use symbols from this file
[default: \${OUTPUT%.c}.symbols]
--[no-]ext-dlopen Do or don't override dlopen() for
callers outside the capsule [default: don't]
--[no-]ext-dlsym Do or don't override dlsym() for
callers outside the capsule [default: don't]
--[no-]update-symbols Do or don't update symbols list if EXPORTS
is newer than it [default: do]
--search-tree=PATH Find libraries to be proxied in this
......@@ -70,10 +68,12 @@ EOF
exit "${1:-0}"
}
ext_dlopen=
ext_dlsym=
update_symbols=
getopt_temp="$(getopt -o 'h' \
-l 'capsule-symbols-tool:,search-tree:,runtime-tree:,dlopen-implementation:,dlsym-implementation:,symbols-from:,update-symbols,no-update-symbols,help' \
-l 'capsule-symbols-tool:,ext-dlsym,no-ext-dlsym,ext-dlopen,no-ext-dlopen,search-tree:,runtime-tree:,symbols-from:,update-symbols,no-update-symbols,help' \
-n "$me" -- "$@")"
eval set -- "$getopt_temp"
......@@ -86,15 +86,27 @@ do
continue;
;;
(--dlopen-implementation)
dlopen_file="$2";
shift 2;
(--ext-dlopen)
ext_dlopen=yes;
shift;
continue;
;;
(--dlsym-implementation)
dlsym_file="$2";
shift 2;
(--no-ext-dlopen)
ext_dlopen=;
shift;
continue;
;;
(--ext-dlsym)
ext_dlsym=yes;
shift;
continue;
;;
(--no-ext-dlsym)
ext_dlsym=;
shift;
continue;
;;
......@@ -190,17 +202,6 @@ then
symbol_file=${proxy_src%.c}.symbols;
fi
if [ -z "${dlopen_file:-}" ];
then
# This is mandatory, so no test -f here
dlopen_file=${proxy_src}.dlopen;
fi
if [ -z "${dlsym_file:-}" ] && [ -f "${proxy_src}.dlsym" ];
then
dlsym_file="${proxy_src}.dlsym";
fi
sharedir=$(pkg-config --variable=makeinc capsule)
exec >$proxy_src.tmp;
......@@ -248,8 +249,35 @@ done < $symbol_file;
cat - <<EOF
static capsule cap;
static void *_dlsym (void *handle, const char *symbol);
static void *_ext_dlopen (const char *filename, int flag);
// _int_dlopen() from libcapsule or a locally overridden version
#include "capsule/_int_dlopen.h"
EOF
if [ -n "$ext_dlopen" ]
then
echo '// _ext_dlopen() from libcapsule or a locally overridden version'
echo '#include "capsule/_ext_dlopen.h"'
echo '#define HAVE_EXT_DLOPEN'
else
echo '// Disabled by capsule-mkstublib --no-ext-dlopen'
echo '//#include "capsule/_ext_dlopen.h"'
echo '//#define HAVE_EXT_DLOPEN'
fi
if [ -n "$ext_dlsym" ]
then
echo '// _ext_dlsym() from libcapsule or a locally overridden version'
echo '#include "capsule/_ext_dlsym.h"'
echo '#define HAVE_EXT_DLSYM'
else
echo '// Disabled by capsule-mkstublib --no-ext-dlsym'
echo '//#include "capsule/_ext_dlsym.h"'
echo '//#define HAVE_EXT_DLSYM'
fi
cat - <<EOF
// should we exclude libpthread here?
// in any case, these are DSOs we do _not_ want to isolate
......@@ -279,14 +307,10 @@ do
EOF
done < $symbol_file;
if [ -n "$dlsym_file" ];
then
cat - <<EOF
{ "dlsym", (capsule_addr) _dlsym },
EOF
fi;
cat - <<EOF
#ifdef HAVE_EXT_DLSYM
{ "dlsym", (capsule_addr) _ext_dlsym },
#endif
{ NULL }
};
......@@ -321,51 +345,15 @@ cat - <<EOF
};
EOF
if [ -f ${dlopen_file} ];
then
cat - <<EOF
cat - <<EOF
static capsule_item dl_relocs[] =
{
#ifdef HAVE_EXT_DLOPEN
{ "dlopen", (capsule_addr) _ext_dlopen, (capsule_addr) _ext_dlopen },
#endif
{ NULL }
};
EOF
else
cat - <<EOF
static capsule_item dl_relocs[] =
{
{ NULL }
};
EOF
fi;
if [ -n "${dlsym_file}" ];
then
cat - <<EOF
// -------------------------------------------------------------
// start of ${proxy_src%.c} dlsym wrapper
EOF
cat $dlsym_file;
cat - <<EOF
// end of ${proxy_src%.c} dlsym wrapper
// -------------------------------------------------------------
EOF
fi
if [ -f ${dlopen_file} ];
then
cat - <<EOF
// -------------------------------------------------------------
// start of ${proxy_src%.c} dlopen wrapper
EOF
cat $dlopen_file;
cat - <<EOF
// end of ${proxy_src%.c} dlopen wrapper
// -------------------------------------------------------------
EOF
fi
cat - <<EOF
static void __attribute__ ((constructor)) _capsule_init (void)
{
int capsule_errno = 0;
......
......@@ -25,8 +25,17 @@ GENSTUB_V0 = @echo " GENSTUB " $(subst $(word 1, $(basename $(filter shim/lib%,
GENSTUB = $(GENSTUB_V$(V))
# regenerate if any dependencies get updated:
shim/lib%.so.c: shim/lib%.so.c.excluded shim/lib%.so.c.dlopen shim/lib%.so.c.dlsym shim/lib%.so.symbols
$(GENSTUB)V=$V $(CAPSULE_MKSTUBLIB_TOOL) $$(basename $@ .c) $@.excluded $@.shared $@ $(ltver) $(CAPSULE_TREE)
shim/lib%.so.c: shim/lib%.so.c.excluded shim/lib%.so.symbols
$(GENSTUB)V=$V \
$(CAPSULE_MKSTUBLIB_TOOL) \
$(AM_CAPSULE_MKSTUBLIB_FLAGS) \
$(CAPSULE_MKSTUBLIB_FLAGS) \
$$(basename $@ .c) \
$@.excluded \
$@.shared \
$@ \
$(ltver) \
$(CAPSULE_TREE)
# regenerate the exportable symbols list
shim/lib%.so.symbols: shim/lib%.so.c.shared
......
......@@ -19,3 +19,15 @@ of the excluded library to shim/lib@LIB@.so.c.excluded and rebuild.
The generated library will have the same name as the main proxy target
(@TARGET@). You can control the exact version number (cf libfoo.x.y.z)
by setting CAPSULE_VERSION in Makefile.am
To make the generated library override dlopen() and/or dlsym() for
callers outside the capsule, pass --ext-dlopen and/or --ext-dlsym to
capsule-mkstublib by setting the AM_CAPSULE_MKSTUBLIB_FLAGS variable in
Makefile.am. If libcapsule's standard implementations of those functions
are not suitable, copy capsule/_ext_dlopen.h, capsule/_ext_dlsym.h
from libcapsule's development files into shim/capsule/, modify them
as necessary, and add them to EXTRA_DIST in Makefile.am.
Similarly, if libcapsule's standard implementation of dlopen() for
callers inside the capsule is not suitable, copy and modify
capsule/_int_dlopen.h.
......@@ -148,28 +148,31 @@ shim/libGL.so.c.shared
libX11.so
----------------------------------------------------------------------------
shim/libfoo.so.c.dlopen
shim/capsule/_int_dlopen.h
If your library needs any special handling of dlopen() calls you will
need to implement functions with the following signature and names:
This file is not created by default.
static void *_ext_dlopen (const char *filename, int flags)
{
}
The _int_dlopen wrapper is installed inside the capsule and takes
care of any /host path prefixing so that the encapsulated libraries
get their native targets with dlmopen (and don't break encapsulation
by calling dlopen).
A default implementation provided by libcapsule is normally used.
See libcapsule's <capsule/_int_dlopen.h> for that implementation.
To use a custom implementation, create the file and implement a
function with the same signature:
static void *_int_dlopen (const char *filename, int flags)
{
}
and put them in this file. Default wrappers which work for most
libraries are generated here by the capsule-init-project tool.
The _int_dlopen wrapper is installed inside the capsule and takes
care of any /host path prefixing so that the encapsulated libraries
get their native targets with dlmopen (and don't break encapsulation
by calling dlopen).
----------------------------------------------------------------------------
shim/capsule/_ext_dlopen.h
This file is not created or used by default. It can be enabled by
adding --ext-dlopen to AM_CAPSULE_MKSTUBLIB_FLAGS in Makefile.am.
The _ext_dlopen wrapper is installed in _most_ libraries outside the
capsule (notably not in the shim itself, libcapsule.so, libc.so and
......@@ -177,23 +180,45 @@ shim/libfoo.so.c.dlopen
capsule's manual symbol relocation when a library outside the capsule
is dlopen()ed.
If this is enabled by --ext-dlopen but the file is not present,
a default implementation provided by libcapsule is used.
See libcapsule's <capsule/_ext_dlopen.h> for that implementation.
To use a custom implementation, create the file and implement a
function with the same signature:
static void *_ext_dlopen (const char *filename, int flags)
{
}
----------------------------------------------------------------------------
shim/libfoo.so.c.dlsym
shim/capsule/_ext_dlsym.h
This file is not created or used by default. It can be enabled by
adding --ext-dlsym to AM_CAPSULE_MKSTUBLIB_FLAGS in Makefile.am.
When external DSOs call dlsym() they may expect to find symbols
which haven't explicitly been exported by the capsule. The wrapper in
this file should take care of exposing only the subset of symbols
you want to make available in this way:
you want to make available in this way.
static void *_dlsym (void *handle, const char *symbol)
{
return capsule_external_dlsym( cap, handle, symbol );
}
If this is enabled by --ext-dlsym but the file is not present,
a default implementation provided by libcapsule is used:
See libcapsule's <capsule/_ext_dlsym.h> for that implementation:
The default implementation above takes care of exposing only those
symbols located in the libraries explicitly listed in .shared (or
the main target library).
To use a custom implementation, create the file and implement a
function with the same signature:
static void *_ext_dlsym (void *handle, const char *symbol)
{
}
----------------------------------------------------------------------------
That's it - you should be ready to:
......
static void *_int_dlopen (const char *filename, int flag)
{
if( flag & RTLD_GLOBAL )
{
fprintf( stderr, "Warning: libcapsule dlopen wrapper cannot pass "
"RTLD_GLOBAL to underlying dlmopen(%s...) call\n",
filename );
flag = (flag & ~RTLD_GLOBAL) & 0xfffff;
}
return capsule_shim_dlopen( cap, filename, flag );
}
static void *_ext_dlopen (const char *filename, int flag)
{
return capsule_external_dlopen( cap, filename, flag );
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment