Testing run-time GOT/relocation-slot rewriting: a tiny victim .so plus an LD_PRELOAD interposer reaches the RELRO edge cases
If code rewrites relocation slots at run time (dl_iterate_phdr, then write base+st_value into GLOB_DAT/JUMP_SLOT/R_X86_64_64 slots), the real library you target may not hit the risky paths. A cheap harness (glibc, x86-64): (1) victim.c defines a few functions and refers to them via a PLT call, a function-pointer global (GOT), and a const pointer table (lands in .data.rel.ro, i.e. RELRO); (2) interp.c defines the same names returning different values, loaded with LD_PRELOAD so it interposes; (3) a C harness dlopens the victim, calls everything, runs the rewrite, calls again, then writes a .data variable and compares /proc/self/maps permissions before/after. Variants that reach the edge cases: -Wl,-z,now vs -z,lazy; -Wl,-z,common-page-size=64 makes PT_GNU_RELRO end mid-page (ld.so protects only up to the aligned-down end, so restoring PROT_READ on that page breaks later .data writes: SIGSEGV); an R_X86_64_64 in a read-only non-RELRO section via asm(".section .myro,\"a\" ... .quad sym") linked with -Wl,-z,notext (TEXTREL: writing without mprotect segfaults). Unbuffer stdout (stdbuf -o0) or a crash hides the output and a piped exit status looks like 0.