./unlink path/to/binary
out/run
to call it
#!/bin/bash | |
set -e | |
set -u | |
set -o pipefail | |
ELF=$1 | |
TGT=$PWD/${2:-out} | |
rm -rf "$TGT" | |
mkdir -p "$TGT" | |
interpreter=$(readelf -l "$ELF" | grep "Requesting program interpreter") | |
interpreter=${interpreter#*[:]} | |
interpreter=${interpreter:1} | |
interpreter=${interpreter::-1} | |
resolveelf() { | |
local lib | |
local needed | |
mapfile -t needed <<<"$(readelf -d "$1" | grep "(NEEDED)" | sed -r 's/.*\[(.*)\]/\1/')" | |
for lib in "${needed[@]}"; do | |
if [ -z "$lib" ]; then | |
continue | |
fi | |
echo "-> $lib" | |
libname=$(basename "$lib") | |
if [ "$libname" = "$(basename "$interpreter")" ]; then | |
continue | |
fi | |
if [ -f "$TGT/$lib" ]; then | |
continue | |
fi | |
if ! [ -f "$lib" ]; then | |
# relative path | |
lib=$(ldconfig -p | grep -F "$lib" | head -1) | |
lib=${lib//* => /} | |
if ! [ "$libname" = "$(basename "$lib")" ]; then | |
echo "library name mismatch: $libname -> $lib" # happens with version mismatch, don't know how to handle this | |
lib="$(dirname "$lib")/$libname" | |
fi | |
fi | |
resolveelf "$lib" | |
done | |
cp "$1" "$TGT" | |
echo "patching $1" | |
for lib in "${needed[@]}"; do | |
patchelf --replace-needed "$lib" "./$(basename "$lib")" "$TGT/$(basename "$1")" | |
done | |
} | |
resolveelf "$ELF" | |
cp "$interpreter" "$TGT" | |
patchelf --set-interpreter "./$(basename "$interpreter")" "$TGT/$(basename "$ELF")" | |
cat <<EOF >"$TGT/run" | |
#!/bin/sh | |
cd "\$(dirname "\$0")" | |
exec "$(basename "$ELF")" "\$@" | |
EOF | |
chmod +x "$TGT/run" |