Added user API to specify manually loaded library handle (gh-14).

This commit is contained in:
Yuri Gribov
2022-07-23 17:50:15 +03:00
parent 4a9ad29358
commit d78ba4e553
9 changed files with 177 additions and 33 deletions
+24 -9
View File
@@ -41,6 +41,7 @@ extern "C" {
#define LAZY_LOAD $lazy_load
static void *lib_handle;
static int do_dlclose;
static int is_lib_loading;
#if ! NO_DLOPEN
@@ -59,13 +60,14 @@ static void *load_library() {
CHECK(lib_handle, "failed to load library via dlopen: %s", dlerror());
#endif
do_dlclose = 1;
is_lib_loading = 0;
return lib_handle;
}
static void __attribute__((destructor)) unload_lib() {
if(lib_handle)
if(do_dlclose && lib_handle)
dlclose(lib_handle);
}
#endif
@@ -94,14 +96,20 @@ void _${lib_suffix}_tramp_resolve(int i) {
void *h = 0;
#if NO_DLOPEN
// Library with implementations has already been loaded.
// If shim symbols are hidden we should search for first available definition of symbol
// in library list, otherwise look for next available definition
# ifdef IMPLIB_HIDDEN_SHIMS
h = RTLD_DEFAULT;
# else
h = RTLD_NEXT;
# endif
// Library with implementations must have already been loaded.
if (lib_handle) {
// User has specified loaded library
h = lib_handle;
} else {
// User hasn't provided us the loaded library so search the global namespace.
// If shim symbols are hidden we should search for first available definition of symbol
// in library list, otherwise look for next available definition
# ifdef IMPLIB_HIDDEN_SHIMS
h = RTLD_DEFAULT;
# else
h = RTLD_NEXT;
# endif
}
#else
h = load_library();
CHECK(h, "failed to resolve symbol '%s', library failed to load", sym_names[i]);
@@ -119,11 +127,18 @@ void _${lib_suffix}_tramp_resolve_all(void) {
_${lib_suffix}_tramp_resolve(i);
}
// Allows user to specify manually loaded implementation library.
void _${lib_suffix}_tramp_set_handle(void *handle) {
lib_handle = handle;
do_dlclose = 0;
}
// Resets all resolved symbols. This is needed in case
// client code wants to reload interposed library multiple times.
void _${lib_suffix}_tramp_reset(void) {
memset(_${lib_suffix}_tramp_table, 0, SYM_COUNT * sizeof(_${lib_suffix}_tramp_table[0]));
lib_handle = 0;
do_dlclose = 0;
}
#ifdef __cplusplus
+1
View File
@@ -36,3 +36,4 @@ tests/verbose/run.sh $ARCH
tests/no_dlopen/run.sh $ARCH
tests/multiple-dlopens/run.sh $ARCH
tests/multiple-dlopens-2/run.sh $ARCH
tests/multiple-dlopens-3/run.sh $ARCH
+8 -13
View File
@@ -33,21 +33,16 @@ void *my_load_library(const char *name) {
return handle;
}
void my_unload_library() {
dlclose(handle);
handle = 0;
assert(dlopen("libinterposed.so", RTLD_NOLOAD) == 0);
extern void _libinterposed_so_tramp_reset(void);
_libinterposed_so_tramp_reset();
}
int main() {
test();
my_unload_library();
extern void _libinterposed_so_tramp_reset(void);
test();
my_unload_library();
for (int i = 0; i < 2; ++i) {
test();
dlclose(handle);
handle = 0;
assert(dlopen("libinterposed.so", RTLD_NOLOAD) == 0);
_libinterposed_so_tramp_reset();
}
return 0;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2022 Yury Gribov
*
* The MIT License (MIT)
*
* Use of this source code is governed by MIT license that can be
* found in the LICENSE.txt file.
*/
#include <stdio.h>
#include "interposed.h"
__attribute__((visibility("default")))
int foo(int x, float y) {
printf("Calling foo from libtest: %d %g\n", x, y);
return 0xf00;
}
__attribute__((visibility("default")))
int bar(int x, int y, int z) {
printf("Calling bar from libtest: %d %d %d\n", x, y, z);
return 0xba7;
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2022 Yury Gribov
*
* The MIT License (MIT)
*
* Use of this source code is governed by MIT license that can be
* found in the LICENSE.txt file.
*/
#ifndef INTERPOSED_H
#define INTERPOSED_H
extern int foo(int x, float y);
extern int bar(int x, int y, int z);
#endif
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright 2022 Yury Gribov
*
* The MIT License (MIT)
*
* Use of this source code is governed by MIT license that can be
* found in the LICENSE.txt file.
*/
#include <dlfcn.h>
#include <stdio.h>
#include <assert.h>
#include "interposed.h"
void test() {
int x, y;
// Slow path
x = foo(25, 0.5),
y = bar(11, 22, 33);
printf("Results: %x %x\n", x, y);
// Fast path
x = foo(35, 0.25);
y = bar(44, 55, 66);
printf("Results: %x %x\n", x, y);
}
int main() {
extern void _libinterposed_so_tramp_set_handle(void *handle);
extern void _libinterposed_so_tramp_reset(void);
for (int i = 0; i < 2; ++i) {
void *h = dlopen("libinterposed.so", RTLD_LOCAL | RTLD_LAZY);
_libinterposed_so_tramp_set_handle(h);
test();
dlclose(h);
assert(dlopen("libinterposed.so", RTLD_NOLOAD) == 0);
_libinterposed_so_tramp_reset();
}
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
#!/bin/sh
# Copyright 2022 Yury Gribov
#
# The MIT License (MIT)
#
# Use of this source code is governed by MIT license that can be
# found in the LICENSE.txt file.
# This is a test for manual loading of destination library (--no-dlopen flag).
# Run it like
# ./run.sh ARCH
# where ARCH stands for any supported arch (arm, x86_64, etc., see `implib-gen -h' for full list).
# Note that you may need to install qemu-user for respective platform
# (i386 also needs gcc-multilib).
set -eu
cd $(dirname $0)
if test -n "${1:-}"; then
ARCH="$1"
fi
. ../common.sh
CFLAGS="-g -O2 $CFLAGS"
LIBS='-ldl'
# Build shlib to test against
$CC $CFLAGS -shared -fPIC interposed.c -o libinterposed.so
# Prepare implib
${PYTHON:-} ../../implib-gen.py -q --target $TARGET --no-dlopen libinterposed.so
# Build app
$CC $CFLAGS -fPIE main.c libinterposed.so.tramp.S libinterposed.so.init.c $LIBS
LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH:-} $INTERP ./a.out > a.out.log
diff test.ref a.out.log
echo SUCCESS
+12
View File
@@ -0,0 +1,12 @@
Calling foo from libtest: 25 0.5
Calling bar from libtest: 11 22 33
Results: f00 ba7
Calling foo from libtest: 35 0.25
Calling bar from libtest: 44 55 66
Results: f00 ba7
Calling foo from libtest: 25 0.5
Calling bar from libtest: 11 22 33
Results: f00 ba7
Calling foo from libtest: 35 0.25
Calling bar from libtest: 44 55 66
Results: f00 ba7
+7 -11
View File
@@ -28,17 +28,13 @@ void test() {
extern void _libinterposed_so_tramp_reset(void);
int main() {
void *h = dlopen("libinterposed.so", RTLD_GLOBAL | RTLD_LAZY);
test();
dlclose(h);
assert(dlopen("libinterposed.so", RTLD_NOLOAD) == 0);
_libinterposed_so_tramp_reset();
h = dlopen("libinterposed.so", RTLD_GLOBAL | RTLD_LAZY);
test();
dlclose(h);
assert(dlopen("libinterposed.so", RTLD_NOLOAD) == 0);
_libinterposed_so_tramp_reset();
for (int i = 0; i < 2; ++i) {
void *h = dlopen("libinterposed.so", RTLD_GLOBAL | RTLD_LAZY);
test();
dlclose(h);
assert(dlopen("libinterposed.so", RTLD_NOLOAD) == 0);
_libinterposed_so_tramp_reset();
}
return 0;
}