Skip to content

dlopen does not make symbols of dependencies visible #18264

Closed
@ryanking13

Description

@ryanking13

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.26 (8eaf19f)
clang version 16.0.0 (https://github.com/llvm/llvm-project f81f0cb75a2808a67d2662f044ad07628fc9d900)


loadDynamicLibrary, which is internally used in dlopen, loads a dynamic library and its dependencies.

When loading dependencies, loadDynamicLibrary propagates flags parameter as-is. So if a target library is loaded locally (e.g. loadDynamicLibrary(..., {global: false}) or dlopen(..., RTLD_NOW | RTLD_LOCAL)) it also loads its dependencies locally.

This is problematic because normally a shared library needs to use symbols from its dependencies.

Edited

The problem is that currently, a side module cannot see symbols of its dependencies if they are loaded locally. For example, when a.so depends on b.so, if we load a.so locally via dlopen("a.so", RTLD_LOCAL), a.so can't use symbols from b.so.

How to reproduce

main.c depends on dep.so and dep.so depends on dep2.so. In native (linux), this works fine.

#!/bin/bash

set -e

cat > dep2.h << EOF
int _add(int a);
EOF

cat > dep2.c << EOF
int _add(int a) { return a; }
EOF

cat > dep.h << EOF
int add(int a);
EOF

cat > dep.c << EOF
#include "dep2.h"
int add(int a) { return _add(a) + 1; }
EOF

cat > main.c << EOF
#include<dlfcn.h>
#include<stdio.h>
#include "dep.h"

int main() {
    void *lib_handle = dlopen("./dep.so", RTLD_NOW | RTLD_LOCAL);
    int (*add)(int) = (int (*)(int))dlsym(lib_handle, "add");

    printf("3 + 1 = %d\n", add(3));
}
EOF

rm -rf dep.o dep2.o dep.so dep2.so main
gcc dep2.c -shared -o dep2.so
gcc dep.c dep2.so -shared -o dep.so
gcc main.c -ldl -o main

LD_LIBRARY_PATH=$(pwd) ./main

While in emscripten, the same example raises error,

#!/bin/bash

set -e

cat > dep2.h << EOF
int _add(int a);
EOF

cat > dep2.c << EOF
int _add(int a) { return a; }
EOF

cat > dep.h << EOF
int add(int a);
EOF

cat > dep.c << EOF
#include "dep2.h"
int add(int a) { return _add(a) + 1; }
EOF

cat > main.c << EOF
#include<dlfcn.h>
#include<stdio.h>
#include "dep.h"

int main() {
    void *lib_handle = dlopen("./dep.so", RTLD_NOW | RTLD_LOCAL);
    int (*add)(int) = (int (*)(int))dlsym(lib_handle, "add");

    printf("3 + 1 = %d\n", add(3));
}
EOF

rm -rf dep.o dep2.o dep.so dep2.so main
emcc -c dep.c
emcc -c dep2.c
emcc dep2.o -shared -o dep2.so -sSIDE_MODULE
emcc dep.o dep2.so -shared -o dep.so -sSIDE_MODULE

emcc main.c -sMAIN_MODULE -o main

node main
Aborted(Assertion failed: undefined symbol `_add`. perhaps a side module was not linked in?
if this global was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions