1

For what I understand, if there are more than one program using a shared library, the shared library won't get unloaded untill all program finishes.

I am reading The Linux Programming Interface:

42.4 Initialization and Finalization Functions It is possible to define one or more functions that are executed automatically when a

shared library is loaded and unloaded. This allows us to perform initialization and finalization actions when working with shared libraries. Initialization and finalization functions are executed regardless of whether the library is loaded automatically or loaded explicitly using the dlopen interface (Section 42.1).

Initialization and finalization functions are defined using the gcc constructor and destructor attributes. Each function that is to be executed when the library is loaded should be defined as follows:

void __attribute__ ((constructor)) some_name_load(void)
{
 /* Initialization code */
}

Unload functions are similarly defined:

void __attribute__ ((destructor)) some_name_unload(void)
{
 /* Finalization code */
} The function names `some_name_load()` and `some_name_unload()` can be replaced by any desired names. ....

Then I wrote 3 files to test:

foo.c

#include <stdio.h>

void __attribute__((constructor)) call_me_when_load(void){
    printf("Loading....\n");
}
void __attribute__((destructor)) call_me_when_unload(void){
    printf("Unloading...\n");
}
int xyz(int a ){
    return a + 3;
}

main.c

#include <stdio.h>
#include <unistd.h>

int main(){
    int xyz(int);
    int b;
    for(int i = 0;i < 1; i++){
         b = xyz(i);
             printf("xyz(i) is: %d\n", b);
    }
}

main_while_sleep.c

#include <stdio.h>
#include <unistd.h>

int main(){
    int xyz(int);
    int b;
    for(int i = 0;i < 10; i++){
         b = xyz(i);
             sleep(1);
             printf("xyz(i) is: %d\n", b);
    }
}

Then I compile a shared library and 2 executables:

gcc -g -Wall -fPIC -shared -o libdemo.so foo.c
gcc -g -Wall -o main main.c libdemo.so
gcc -g -Wall -o main_while_sleep main_while_sleep.c libdemo.so

finally run LD_LIBRARY_PATH=. ./main_while_sleep in a shell and run LD_LIBRARY_PATH=. ./main in another:

main_while_sleep output:

Loading....
xyz(i) is: 3
xyz(i) is: 4
xyz(i) is: 5
xyz(i) is: 6
xyz(i) is: 7
xyz(i) is: 8
xyz(i) is: 9
xyz(i) is: 10
xyz(i) is: 11
xyz(i) is: 12
Unloading...

main output:

Loading....
xyz(i) is: 3
Unloading...

My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!

Do I get something wrong?

Rick
  • 7,007
  • 2
  • 49
  • 79
  • 4
    The initialization and finalization actions are per process. The system won't unload the library completely while a process is using it, but a process may unload the library, or terminate. – Jonathan Leffler Jun 20 '22 at 15:29
  • @JonathanLeffler I don't get it. :( Could you elaborate? – Rick Jun 20 '22 at 15:40
  • The library is loaded per process, not per system. Every process has its own separate instance of loaded library. Let's say a copy. – KamilCuk Jun 20 '22 at 16:13
  • @KamilCuk Ok I see. 1 copy per process, so 10 copies for 10 processes, but only 1 copy in physical memory, do I get this right? – Rick Jun 20 '22 at 16:16
  • If what I say above is correct, is there anyway I can observe the "shared library is not unloaded till all programs using it terminate" behaviour in physical memory? I mean, I would like to see when `main` is terminated while `main_while_sleep`, the system-wide **1 copy** is still there. – Rick Jun 20 '22 at 16:18
  • @Rick yes, it is like each process has its own copy, but with less physical memory. – user253751 Jun 20 '22 at 16:20
  • `do I get this right?` Yes, "as-if". `I can observe the "shared library is not unloaded till all programs using it terminate" behaviour in physical memory?` I do not know what you mean by "observe". `lsof` gives you for example all open files on the system. – KamilCuk Jun 20 '22 at 16:38
  • If you're on Linux, you can probably deduce from information in the `/proc` file system which shared libraries are loaded — though you'll quite likely need elevated privileges (`root` privileges) to do so. Otherwise, the may be specialized system calls to tell you what's loaded — you'll need to scrutinize the manual (section 2, system calls). – Jonathan Leffler Jun 20 '22 at 16:41

1 Answers1

0

My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!

You are confusing/conflating initialization/deinitialization with load/unload.

A constructor is an initialization function that is called after a shared library has been mapped into a given process's memory.

It does not affect any other process (which is in a separate, per-process address space).

Likewise, the mapping (or unmapping) of a shared library in a given process does not affect any other process.

When a process maps a library, nothing is "loaded". When the process tries to access a memory page that is part of the shared library, it receives a page fault and the given page is mapped, the page is marked resident, and the faulting instruction is restarted.

There is much more detail in my answers:

  1. How does mmap improve file reading speed?
  2. Which segments are affected by a copy-on-write?
  3. read line by line in the most efficient way *platform specific*
  4. Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?
  5. Malloc is using 10x the amount of memory necessary
Craig Estey
  • 30,627
  • 4
  • 24
  • 48