Skip to content

Instantly share code, notes, and snippets.

@ling2yt
Forked from jerome-pouiller/cross-compile-ldd
Created August 31, 2023 05:39
Show Gist options
  • Save ling2yt/f8d5ab3aa36d65256d6ad1473c15536b to your computer and use it in GitHub Desktop.
Save ling2yt/f8d5ab3aa36d65256d6ad1473c15536b to your computer and use it in GitHub Desktop.
ldd drop-in replacement for cross-compilation toolchains.
#!/bin/bash
# ldd drop-in replacement for cross-compilation toolchains.
# This file is a slightly modified version of xldd.in from
# crosstool-ng 1.22.0
# In order to use it, copy it in same directory than other
# toolchain binaries and rename it with same tuple.
# (i.e. /opt/arm-sysmic-linux-gnueabihf/bin/arm-sysmic-linux-gnueabihf-ldd)
# Thus, this will automaticaly detect necessary information
# about your toolchain.
export LC_ALL=C
version="forked from crosstool-ng 1.22.0"
# Change it to 64 if necessary
bits="32"
sed="${SED:-sed}"
grep="${GREP:-grep}"
my_name="$( basename "${0}" )"
prefix="${0%-ldd}"
gcc="${GCC:-"${prefix}-gcc"}"
readelf="${READELF:-"${prefix}-readelf"}"
fake_load_addr_root="$((0xdeadbeef))"
fake_load_addr_rpath="$((0xdeadc0de))"
fake_load_addr_sysroot="$((0x8badf00d))"
ld_library_path="/lib:/usr/lib"
input_bin="${INPUT_BIN}"
root="${ROOT:-""}"
do_error() {
printf "%s: %s\n" "${my_name}" "$*" >&2
}
do_opt_error() {
do_error "$@"
printf "Try \`%s --help' for more information\n" "${my_name}" >&2
}
do_trace() {
local depth=0
[ -z "${CT_XLDD_VERBOSE}" ] && return 0
for((depth=0; "${#FUNCNAME[$((depth+1))]}" != 0; depth++)); do :; done
printf "%*s" $((4*(depth-1))) "" >&2
printf -- "$@" >&2
}
# Sanity checks
sysroot="$( "${gcc}" -print-sysroot 2>/dev/null )"
if [ -z "${sysroot}" ]; then
sysroot="$( "${gcc}" -print-file-name=libc.so 2>/dev/null \
|${sed} -r -e 's:/usr/lib/libc.so$::;' \
)"
fi
if [ -z "${sysroot}" ]; then
do_error "unable to find sysroot for \`${gcc}'"
fi
if [ -z "${root}" ]; then
root=${sysroot}
fi
if [ ! -d "${root}" ]; then
do_error "\`${root}': no such file or directory"
exit 1
fi
if [ ! -f "${input_bin}" ]; then
do_error "\'${input_bin}': no such file or directory"
exit 1
fi
do_report_needed_found() {
local needed="${1}"
local path="${2}"
local origin="${3}"
local loadaddr
local sys
case "${origin}" in
root)
loadaddr="${fake_load_addr_root}"
;;
rpath)
loadaddr="${fake_load_addr_rpath}"
if [ -n "${show_system}" ]; then
sys=" [+]"
fi
;;
sysroot)
loadaddr="${fake_load_addr_sysroot}"
if [ -n "${show_system}" ]; then
sys=" [*]"
fi
;;
esac
printf "%8s%s => %s (0x%0*x)%s\n" \
"" \
"${needed}" \
"${path}" \
"$((bits/4))" \
"${loadaddr}" \
"${sys}"
}
declare -A myMap=()
myMap["my03"]="03"
# Search a needed file, scanning ${lib_dir} in the root directory
do_find_needed() {
local needed="${1}"
local -a list
local -a dirs
local found
local where
local base
local d i
do_trace "Searching for '%s'\n" "${needed}"
# rpath shall come first!
list=( \
"rpath:${root}" \
"root:${root}" \
"sysroot:${sysroot}" \
)
for i in "${list[@]}"; do
where="${i%%:*}"
base="${i#*:}"
if [ "${where}" = "rpath" ]; then
dirs=( "${search_rpath[@]}" )
else
dirs=( "${needed_search_path[@]}" )
fi
for d in "${dirs[@]}"; do
do_trace "-> looking in '%s' '%s' '%s' (%s)\n" "${base}" "${d}" "${needed})" "${where}"
if echo "${base}/${d}/${needed}" | grep "\$ORIGIN" > /dev/null; then
findPath=$(echo "${base}/${d}/${needed}" | sed 's/\$ORIGIN//g')
else
findPath="${base}/${d}/${needed}"
fi
unset ORIGIN
if [ -f ${findPath} ]; then
found="${findPath}"
do_trace "---> found\n"
break 2
fi
done
done
if [ -n "${found}" ] && [ ! -n "${myMap[$findPath]}" ]; then
do_report_needed_found "${needed}" "${found}" "${where}"
do_process_file "${found}"
#myMap["$findPath"]="done"
elif [ ! -n "${found}" ]; then
printf "%8s%s not found\n" "" "${needed}"
fi
do_trace "Done searching for '%s'\n" "${needed}"
}
# Scan a file for all NEEDED tags
do_process_file() {
local file="${1}"
local -a save_search_rpath
local n m
local found
do_trace "Parsing file '%s'\n" "${file}"
save_search_rpath=( "${search_rpath[@]}" )
for n in $( "${readelf}" -d "${file}" \
|"${grep}" -E '\((RPATH|RUNPATH)\)' \
|"${sed}" -r -e 's/^.*Library r(|un)path:[[:space:]]+\[(.*)\]$/\2/;'\
); do
OIFS=$IFS;
IFS=":";
narray=($n)
for subn in "${narray[@]}"; do
do_trace "-> adding rpath '%s'\n" "${subn}"
search_rpath+=( "${subn}" )
done
IFS=$OIFS;
done
do_trace ": search path:\n"
for n in "${search_rpath[@]}" "${needed_search_path[@]}"; do
do_trace ": - '%s'\n" "${n}"
done
do_trace ": end search path\n"
for n in $( "${readelf}" -d "${file}" \
|"${grep}" -E '\(NEEDED\)' \
|"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[([^]]+)\].*/\1/;' \
); do
found=0
for m in "${needed_list[@]}"; do
[ "${n}" = "${m}" ] && found=1 && break
done
if [ ${found} -ne 0 ]; then
do_trace "-> skipping already known dependency '%s'\n" "${n}"
continue
fi
do_trace "-> handling new dependency '%s'\n" "${n}"
needed_list+=( "${n}" )
do_find_needed "${n}"
do_trace "-> done handling dependency '%s'\n" "${n}"
done
search_rpath=( "${save_search_rpath[@]}" )
do_trace "Finished parsing file '%s'\n" "${file}"
}
# Recursively scan a /etc/ld.so.conf file
do_scan_etc_ldsoconf() {
local ldsoconf="${1}"
local g
local f
[ -f "${ldsoconf}" ] || return 0
do_trace "Parsing ld.so.conf: '%s'\n" "${ldsoconf}"
while read line; do
case "${line}" in
include\ *)
g="${root}${line#include }"
do_trace "-> handling include directive '%s'\n" "${g}"
for f in ${g}; do
do_scan_etc_ldsoconf "${f}"
done
do_trace "-> finished handling include directive '%s'\n" "${g}"
;;
\#*|"")
;;
*)
do_trace "-> adding search dir '%s'\n" "${line}"
needed_search_path+=( "${line}" )
;;
esac
done <"${ldsoconf}"
do_trace "Finished parsing ld.so.conf: '%s'\n" "${ldsoconf}"
}
# Build up the full list of search directories
declare -a needed_search_path
do_trace "Adding basic lib dirs\n"
ld_library_path="${ld_library_path}:"
while [ -n "${ld_library_path}" ]; do
d="${ld_library_path%%:*}"
if [ -n "${d}" ]; then
do_trace "-> adding search dir '%s'\n" "${d}"
needed_search_path+=( "${d}" )
fi
ld_library_path="${ld_library_path#*:}"
done
do_trace "Done adding basic lib dirs\n"
do_trace "Scanning '/etc/ld.so.conf'\n"
do_scan_etc_ldsoconf "${root}/etc/ld.so.conf"
do_trace "Done scanning '/etc/ld.so.conf'\n"
do_trace "Search path:\n"
for p in "${needed_search_path[@]}"; do
do_trace "-> '%s'\n" "${p}"
done
declare -a needed_list
declare -a search_rpath
do_trace "Scanning file '%s'\n" "${input_bin}"
do_process_file "${input_bin}"
do_trace "Done scanning file '%s'\n" "${input_bin}"
@ling2yt
Copy link
Author

ling2yt commented Aug 31, 2023

usage:


1. copy it in same directory than other toolchain binaries and rename it with same tuple.
# (i.e. /opt/arm-sysmic-linux-gnueabihf/bin/arm-sysmic-linux-gnueabihf-ldd)
export ROOT=$(binary_directory)
export INPUT_BIN="${binary_path}"
$run script

2. 
export GCC=xxx
export READELF=xxx
export ROOT=$(binary_directory)
export INPUT_BIN="${binary_path}"
$run script

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment