Master the fundamental concepts of linkers & loaders through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it works.so FilesShared libraries let many processes map one physical copy of libc. Compile with -fPIC, link with -shared. Export symbols with default visibility; hide internals. LD_LIBRARY_PATH and rpath control search paths at runtime.
Build the shared object first, then link the main program against it. The dynamic linker resolves libfoo.so at startup using DT_NEEDED entries and search paths baked into the executable.
bashLoading…
libfoo.so.1) supports versioned ABInm -D shows dynamic symbols-Wl,--export-dynamic exports symbols for dlsymProduction compilers embed this step inside a longer pipeline. GCC flows through cpp, cc1, assembly, and ld; Clang uses the driver, Sema, LLVM IR passes, and a target backend. LLVM bitcode, JVM bytecode, and WASM are other familiar IRs at the same layer. The exercise isolates one pass so you can test it alone before chaining it to the next stage.
You will create and use shared libraries. This exercise requires building a PIC shared object, exporting functions, and linking an executable that calls into the library at runtime.
Simulate the dynamic loader's run-time API: dlopen, dlsym, dlvsym and dlclose, including dependency loading, reference counting, symbol search order, global vs local scope, and symbol versioning: the machinery plugins and shared libraries rely on.
First the available libraries, then commands:
cLoading…
An export is sym (unversioned), sym@@VER (the default version) or sym@VER (an older version, reachable only through dlvsym).
dlopen of a library not yet loaded loads it and, recursively, the libraries it needs. Every library has a reference count: +1 for each dlopen of it, and +1 from each loaded library that needs it (counted once, when that library loads).dlopen of a library assigns it the next handle h1, h2, …; later dlopens of it return the same handle. A handle becomes invalid when its library is unloaded.dlsym hN searches the handle's library and then its dependencies, breadth-first in needs order. dlsym default searches only libraries opened global (and their dependencies), in load order.dlsym matches sym or sym@@VER; dlvsym matches sym@VER or sym@@VER for the given version.dlclose drops one reference; a library reaching 0 is unloaded and drops the references it held on its dependencies (which may unload them too).error: cannot open shared object file (naming the missing dependency when it's a dependency); unknown handle: error: invalid handle; no match: error: undefined symbol.cLoading…
Finish with loaded: LIB(R) ... in load order (or loaded: none).
Input:
cLoading…
Output:
cLoading…
dlsym default fails because libapp.so was opened local: its symbols are only reachable through its handle.
Hidden tests cover shared dependencies (one library needed by two), re-opening a loaded library, global scope, using a handle after it was closed, and a missing dependency.