📝 Dynamic linking and shared libraries in Main memory (10 MCQs)
📖 From Operating System • 8. Main Memory • 10 questions available
What is Dynamic linking and shared libraries in Main memory?
Definition:
Dynamic linking resolves external library references at load or run time allowing multiple processes to share a single copy of common code in physical memory.
Example:
Ten running applications all reference but only one physical copy resides in RAM with each process having its own page table entry pointing to it.
Reason:
Sharing reduces overall memory consumption and disk usage while enabling library updates without recompiling dependent applications.
📝 All Dynamic linking and shared libraries in Main memory MCQs
Q1. A program is compiled to use a shared library libmath.so that provides a function add(). At runtime the library is missing. Which action should the operating system take?
📖 Explanation: The dynamic loader checks all required shared objects before the program begins execution. If libmath.so cannot be found, the loader reports a load‑time error and the program is refused to start, which is the expected behavior. Aborting with a segmentation fault would occur only after the program runs and accesses invalid memory, which is not the case here. Providing a stub or trying to link a static version would require additional logic that the loader does not perform automatically.
Q2. What is the primary benefit of using shared libraries instead of static linking?
📖 Explanation: Shared libraries are loaded into memory only once and the same physical pages can be mapped into the address spaces of all processes that use them. This sharing saves RAM because each process does not need its own copy of the code. Reducing compile time is a secondary effect, and shared libraries do not guarantee backward compatibility; they merely provide memory efficiency. Therefore the principal advantage is the reduction of overall memory consumption.
Q3. Which file extension is commonly used for shared libraries on Linux systems?
📖 Explanation: The standard naming convention on most Unix‑like systems uses the suffix “.so”, which stands for “shared object”. This convention distinguishes shared libraries from executables and static archives, which typically use no suffix or “.a”. Windows uses “.dll”, while macOS historically used “.dylib”. Recognizing the correct extension helps developers locate the appropriate file for dynamic linking and ensures the loader can identify the file type during program start‑up.
Q4. Two processes each load libutils.so version 1.2. Process A later loads version 1.3 of the same library. What can happen?
📖 Explanation: When a process loads a shared object, the dynamic linker creates a separate mapping for each distinct version that the process requests. If Process A later loads version 1.3 while Process B continues using version 1.2, the two processes may end up referencing different symbols with the same name. This can cause incompatibilities if the two versions expose different interfaces or data layouts, leading to unexpected behavior or crashes. The OS does not automatically unload or merge versions; each mapping remains isolated within the process's address space.
Q5. How does the dynamic linker resolve undefined symbols when a program starts?
📖 Explanation: The dynamic linker examines the executable’s import table, which lists symbols that are undefined in the program but required from external libraries. It then walks through the list of dependent shared objects, loading each one if it is not already present, and resolves each undefined symbol by locating the first definition that matches the symbol name. This process happens automatically at program start, unlike manual source‑code scanning or user prompts, ensuring that all needed functions are available before execution continues.
Q6. An embedded system uses position‑independent code (PIC) for its shared library to allow loading at any address. If the library is loaded at address and contains a function that accesses a global variable at offset from the library base, what is the actual runtime address of the variable?
📖 Explanation: In position‑independent code the address of a global variable is computed as the sum of the library’s load base and a fixed offset. Here the base address is and the offset is . Adding these values yields . Therefore the runtime address of the variable is . This calculation shows why PIC allows the same binary to function correctly regardless of where the operating system maps it in virtual memory.
Q7. Why must shared libraries be compiled as position‑independent code (PIC) for use with the dynamic linker?
📖 Explanation: Shared libraries must be compiled as position‑independent code because the dynamic loader may place them at any virtual address that is free in the process’s address space. PIC ensures that all internal references are expressed relative to the library’s own base address rather than an absolute address determined at link time. This eliminates the need for costly relocations each time the library is loaded, reduces startup overhead, and allows multiple processes to share the same physical pages without conflicts.
Q8. A program uses dlopen() to load plugin.so at runtime, then calls dlsym() to obtain a pointer to init_plugin(). If the plugin was compiled without the -fPIC flag, what is the most likely result?
📖 Explanation: dlopen() loads a shared object at runtime, and dlsym() retrieves the address of a symbol. If the library was built without the -fPIC flag, its code contains absolute addresses that assume a fixed load address. When the loader maps the library at a different virtual address, those absolute references become incorrect, causing the function pointer returned by dlsym() to point to an invalid location. Executing the function then typically results in a segmentation fault or other crash, making answer A the most likely outcome.
Q9. What system call is primarily responsible for loading shared libraries into a process's address space during program start on Unix-like systems?
📖 Explanation: The mmap system call creates a memory mapping between a file and a region of a process’s virtual address space. When a program starts, the dynamic loader uses mmap to map each required shared object file into memory, allowing the same physical pages to be shared among processes. Although execve initiates program execution and fork creates new processes, it is mmap that actually brings the shared library contents into the address space, making it the primary mechanism for loading.
Q10. A developer notices that after upgrading libcrypto.so, their application crashes when calling RSA_generate_key(). Investigation shows that the new library changed the size of an internal struct. Which linking strategy could have prevented this problem?
📖 Explanation: Versioned symbols allow a library to expose multiple implementations of the same API under different version tags. When a program is linked against a specific version, the dynamic linker resolves symbols to the exact version that the program was built for, preventing mismatches caused by changes in data structures or function signatures. By using symbol versioning, the developer ensures that upgrades to libcrypto.so will not break existing binaries, because the loader will continue to bind to the older versioned