dlopen.3: An object opened with RTLD_LOCAL can be promoted to RTLD_GLOBAL

Verified by experiment:

$ cat prog.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
    printf("\tName = %s\n", info->dlpi_name);

    return 0;
}

int
main(int argc, char *argv[])
{
    void *x1Handle, *x2Handle, *yHandle;
    void (*funcp)(void);
    char *err;

    x1Handle = dlopen("./lib_x1.so", RTLD_NOW | RTLD_LOCAL);
    if (x1Handle == NULL) {
        fprintf(stderr, "dlopen: %s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    if (argc > 1) {
        x2Handle = dlopen("./lib_x2.so", RTLD_NOW | RTLD_GLOBAL);
        if (x2Handle == NULL) {
            fprintf(stderr, "dlopen: %s\n", dlerror());
            exit(EXIT_FAILURE);
        }
    }

    yHandle = dlopen("./lib_y1.so", RTLD_NOW | RTLD_LOCAL);
    if (yHandle == NULL) {
        fprintf(stderr, "dlopen: %s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    (void) dlerror();                           /* Clear dlerror() */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
    funcp = (void (*)(void)) dlsym(yHandle, "y1_enter");
#pragma GCC diagnostic pop
    err = dlerror();
    if (err != NULL) {
        fprintf(stderr, "dlsym: %s", err);
        exit(EXIT_FAILURE);
    }

    (*funcp)();

    exit(EXIT_SUCCESS);
}

$ cat lib_x1.c
#include <stdio.h>

void
x1_enter(void)
{
    printf("Called %s::%s\n", __FILE__, __func__);
}

$ cat lib_x2.c
#include <stdio.h>

void
testfunc(void)
{
    printf("Called %s::%s\n", __FILE__, __func__);
}

$ cat lib_y1.c
#include <stdio.h>

void
testfunc(void)
{
    printf("Called %s::%s\n", __FILE__, __func__);
}

void
y1_enter(void)
{
    extern void y2(void);

    printf("Called %s\n\n", __func__);

    testfunc();
}

$ cat Build.sh
#!/bin/sh

CFLAGS="-Wno-implicit-function-declaration -Wl,--no-as-needed"

cc $CFLAGS -g -fPIC -shared -o lib_x2.so lib_x2.c
cc $CFLAGS -g -fPIC -shared -o lib_x1.so lib_x1.c ./lib_x2.so
cc $CFLAGS -g -fPIC -shared -o lib_y1.so lib_y1.c

cc $CFLAGS -o prog prog.c -ldl

$ sh Build.sh

$ ./prog
Called y1_enter

Called lib_y1.c::testfunc
$ ./prog x
Called y1_enter

Called lib_x2.c::testfunc

Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Michael Kerrisk 2019-07-03 10:57:33 +02:00
parent da6b9a6172
commit 9bdbaa8ab2
1 changed files with 6 additions and 0 deletions

View File

@ -245,6 +245,12 @@ call that loads the same shared object with
.B RTLD_NOW
may force symbol resolution for a shared object earlier loaded with
.BR RTLD_LAZY .
Similarly, an object that was previously opened with
.BR RTLD_LOCAL
can be promoted to
.BR RTLD_GLOBAL
in a subsequent
.BR dlopen ().
.PP
If
.BR dlopen ()