Chapter 24 Quiz: Dynamic Linking in Depth


Question 1

What is the primary purpose of the PLT (Procedure Linkage Table)?

A) To list all the procedures (functions) in a shared library for documentation B) To provide a fixed address that code can call, which then indirects through the GOT to reach the actual function — enabling lazy binding and position-independent function calls C) To link the program's symbol table with the library's symbol table at link time D) To store the addresses of all locally-defined functions for faster dispatch


Question 2

Before the first call to malloc (with lazy binding enabled), the GOT entry for malloc contains:

A) The actual address of malloc in libc B) The address of instruction 2 (push index) in the malloc@plt PLT stub — pointing back into the PLT itself C) Zero (null pointer) — the dynamic linker has not initialized it yet D) The address of _dl_runtime_resolve directly


Question 3

Why is the GOT placed in a writable memory segment?

A) The GOT contains function code that may be modified by the JIT compiler at runtime B) The dynamic linker must be able to write actual symbol addresses into GOT entries at runtime during lazy binding resolution C) GOT entries are initialized by the program at startup and require write access D) The GOT is writable because it is in the .bss segment, which is always writable


Question 4

LD_PRELOAD achieves function interposition because:

A) It directly patches the function addresses in the target binary's .text section B) Libraries listed in LD_PRELOAD are loaded before all others; since symbol resolution uses the first matching definition, the preloaded library's functions shadow the real library functions C) LD_PRELOAD modifies the GOT directly, redirecting all function calls D) The kernel intercepts system calls from the preloaded library and routes them to the target binary


Question 5

dlsym(RTLD_NEXT, "malloc") inside an LD_PRELOAD library returns:

A) The address of malloc in the current (preloaded) library B) The address of malloc in the next library in the search order after the calling library — typically the real malloc in libc C) NULL if malloc has not yet been called (lazy binding not complete) D) The PLT stub address for malloc


Question 6

Full RELRO (-Wl,-z,relro,-z,now) prevents GOT overwrite attacks by:

A) Randomizing the GOT addresses on each program run B) Disabling lazy binding (resolving all symbols at startup) and then marking the entire GOT (including .got.plt) as read-only with mprotect C) Encrypting GOT entries so attackers cannot read the function addresses D) Moving the GOT to kernel address space where user code cannot write to it


Question 7

What does the R_X86_64_JUMP_SLOT relocation type instruct the dynamic linker to do?

A) Jump to the specified symbol address unconditionally B) Write the resolved symbol's runtime address into the GOT slot at the specified offset C) Insert a PLT stub for the specified symbol D) Redirect a call instruction to use the PLT instead of a direct call


Question 8

A shared library function that is marked __attribute__((visibility("hidden"))):

A) Cannot be called by any code, even within the same library B) Is not exported in the library's dynamic symbol table; calls within the library bypass the PLT and GOT, using direct calls instead C) Is available but requires dlsym to access D) Is compiled into the .bss section rather than .text


Question 9

DT_INIT_ARRAY in the .dynamic section contains:

A) The ELF file version and architecture information B) An array of function pointers that are called (in order) before main — used for C++ global constructors and __attribute__((constructor)) functions C) The initialization code for the dynamic linker itself D) A list of shared libraries that must be initialized before this library


Question 10

Symbol versioning (e.g., printf@@GLIBC_2.2.5) allows:

A) Multiple programs to call different versions of printf simultaneously B) The same library file to export multiple versions of the same function with different ABIs, ensuring programs linked against old versions continue to work when the library is updated C) The linker to choose the most optimized version of a function based on CPU capabilities D) Weak symbol resolution when printf is not available on the system


Question 11

The difference between DT_RPATH and DT_RUNPATH is:

A) RPATH is for runtime libraries; RUNPATH is for compile-time libraries B) RPATH takes precedence over LD_LIBRARY_PATH and cannot be overridden; RUNPATH has lower priority than LD_LIBRARY_PATH C) RPATH is deprecated and treated as RUNPATH by modern dynamic linkers D) RPATH is searched recursively; RUNPATH is searched only in the specified directory


Question 12

When dlopen is called with RTLD_GLOBAL:

A) The library is loaded into global memory (kernel address space) B) Symbols from the loaded library are made available for symbol resolution by subsequently loaded libraries (they can see each other's symbols) C) The library is loaded with global file permissions (world-readable) D) All symbols in the library are resolved immediately, regardless of whether RTLD_NOW or RTLD_LAZY is specified


Question 13

LD_PRELOAD is silently ignored for setuid/setgid programs because:

A) Setuid programs use a different dynamic linker that does not support LD_PRELOAD B) If honored, a non-privileged user could use LD_PRELOAD to inject code that runs with elevated privileges — a security vulnerability C) Setuid programs statically link all their libraries, so LD_PRELOAD has nothing to intercept D) Setuid programs explicitly unset LD_PRELOAD at startup before loading any libraries


Question 14

The $ORIGIN token in an RPATH or RUNPATH:

A) Is the virtual address of the program's origin (entry point) B) Expands at runtime to the directory containing the executable (or library) that has the embedded RPATH — enabling relocatable installations C) Is the hostname where the library was originally compiled D) Is a security token verified by the dynamic linker to prevent path injection


Question 15

What does ltrace do that strace does not?

A) ltrace shows CPU registers at each function call; strace shows only syscall arguments B) ltrace intercepts and logs shared library function calls (e.g., printf, malloc); strace intercepts only kernel system calls C) ltrace shows the complete call tree including inline functions; strace shows only top-level calls D) ltrace requires root privileges; strace can run as a normal user


Question 16

__attribute__((constructor(200))) and __attribute__((constructor(300))) — which runs first?

A) 300 (higher priority number = higher priority = runs first) B) 200 (lower priority number = runs first; priorities work like scheduling priorities where lower number = earlier) C) They run in parallel if the system has multiple CPU cores D) The order is unspecified for priorities in the range 200-300


Question 17

In the PLT, the first entry (PLT[0]) is special. What is its purpose?

A) It contains the address of main for use by the C runtime startup B) It is the resolver stub: it pushes the link_map pointer and jumps to _dl_runtime_resolve — used by all other PLT entries when their symbol is not yet resolved C) It is a padding entry that is never executed D) It contains the number of PLT entries for the dynamic linker's reference


Question 18

When a GOT overwrite attack replaces GOT[exit] with the address of shellcode, what happens when the program calls exit(0)?

A) Nothing — exit is a system call and cannot be intercepted via the GOT B) The PLT stub for exit reads the GOT entry, which now contains the shellcode address, and the jmp in the PLT stub redirects execution to the shellcode C) The shellcode runs but immediately crashes because it is not at a valid PLT entry address D) The dynamic linker detects the modified GOT entry and re-resolves it correctly


Question 19

checksec --file=program reports "Partial RELRO." This means:

A) The GOT is completely read-only; PLT entries remain writable B) .got (non-lazy relocations) is read-only after startup, but .got.plt (lazy-binding entries) remains writable C) Only 50% of the GOT entries have been protected; the rest are writable D) Full RELRO was attempted but failed due to missing library support


Question 20

dlclose(handle) decrements the reference count of the loaded library. The library is actually unloaded (unmapped) when:

A) dlclose is called exactly once for each dlopen B) The reference count reaches zero — which happens only when all dlopen calls (including transitive dependencies) have been matched by dlclose calls C) The calling program calls exit() D) The garbage collector in ld-linux.so determines the library is no longer referenced


Answer Key

  1. B
  2. B
  3. B
  4. B
  5. B
  6. B
  7. B
  8. B
  9. B
  10. B
  11. B
  12. B
  13. B
  14. B
  15. B
  16. B
  17. B
  18. B
  19. B
  20. B