"-fsanitize-coverage=trace-pc-guard" dynamic linking

Hello. I have a project where I want to build readelf with “-fsanitize-coverage=trace-pc-guard”. Due to the project structure I need to build readelf with “-fsanitize-coverage=trace-pc-guard” into a complete binary and then compile target_instrumentation.c where I will define

void __sanitizer_cov_trace_pc_guard_init(uint32_t *s, uint32_t *e)
void __sanitizer_cov_trace_pc_guard(uint32_t *g)

I tried and seem to be stuck. Do you see how this needs to be done? The Dockerfile to reproduce my approach is this

# From 2025. Contains important tools like git, wget, and make.
FROM buildpack-deps:bookworm@sha256:8c30a94b4fb5caf5bd7d24f45791b590a56c1260191876b06404692a507f366a
# Clang is not fixed but it probably doesn't matter all too much.
RUN apt-get update && apt-get install -y clang lld
# This binutils version is also from 2025. It is used to build the readelf tool.
WORKDIR /home
RUN wget https://ftp.gnu.org/gnu/binutils/binutils-2.44.tar.xz && tar xf binutils-2.44.tar.xz && rm binutils-2.44.tar.xz

WORKDIR /home/binutils-2.44
ENV CC=clang
ENV CXX=clang++
# 1) Make plain readelf
RUN mkdir build-plain 
WORKDIR /home/binutils-2.44/build-plain
RUN ../configure --disable-shared --disable-gas --disable-ld --disable-nls --disable-doc
RUN make -j"$(nproc)" && make -C binutils readelf

# 2) Make fuzz readelf
RUN mkdir build-fuzz 
WORKDIR /home/binutils-2.44/build-fuzz
ENV CFLAGS="-fsanitize-coverage=trace-pc-guard"
ENV CXXFLAGS="-fsanitize-coverage=trace-pc-guard"
RUN ../configure --disable-shared --disable-gas --disable-ld --disable-nls --disable-doc
RUN make -j"$(nproc)" && make -C binutils readelf

# 3) Conveniently put both in home
RUN cp /home/binutils-2.44/build-fuzz/binutils/readelf /home/readelf-fuzz
RUN cp /home/binutils-2.44/build-plain/binutils/readelf /home/readelf-plain

WORKDIR /home/instrumentation
COPY target_instrumentation.c .
RUN clang -shared -fPIC  target_instrumentation.c -o libtarget_instrumentation.so

WORKDIR /home/binutils-2.44

The target instrumentation is this

// target_instrumentation.c
#include <stdint.h>
#include <stdio.h>

void __sanitizer_cov_trace_pc_guard_init(uint32_t *s, uint32_t *e) {
  fprintf(stderr, "INIT detected\n");
}

void __sanitizer_cov_trace_pc_guard(uint32_t *g) {
  fprintf(stderr, "EDGE detected\n");
}

I want to execute
LD_PRELOAD=/home/instrumentation/libtarget_instrumentation.so /home/readelf-fuzz -h /bin/ls

and see that the edges and init were detected but it doesn’t work

Going blindly off of what you’ve sent, I’d reckon its an issue with linking to the sanitizer runtime.
Try adding -Wl,--export-dynamic to the LDFLAGS.
Beyond that you’d need to share more about how you’re stuck.

Unfortunately this did not work. The idea is that the two definitions from __sanitizer_cov_trace_pc_guard_init and __sanitizer_cov_trace_pc_guard are loaded during runtime and give me some feedback, i.e. by printing. However they seem to be never called. Perhaps because they are already defined and LD_PRELOAD doesn’t do anything after they have been defined already