Skip to content

Instantly share code, notes, and snippets.

@eth-p
Created October 17, 2019 23:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eth-p/283b5e232fc9af8e2a2c8ee9b95a9f1e to your computer and use it in GitHub Desktop.
Save eth-p/283b5e232fc9af8e2a2c8ee9b95a9f1e to your computer and use it in GitHub Desktop.
A quick bash script that tries to generate shims to allow Mach-O objects to link to assembly written for ELF objects.
#!/usr/bin/env bash
export CLANG_FORCE_COLOR_DIAGNOSTICS=0
SYMBOLS=()
OBJECTS=()
# Check for OSX.
if [[ "$(uname -s)" != "Darwin" ]]; then
printf "\x1B[31m%s\x1B[0m\n" "Mach-O demangle shim isn't needed on non-Darwin platforms."
exit 0
fi
# Determine the object files.
for file in *.s *.c; do
if [[ "$file" = "__shim.s" ]]; then continue; fi
OBJECTS+=("$(basename "$(basename "$file" .s)" .c)".o)
done
# Make the object files.
printf "Compiling objects...\n\x1B[2m"
COLOR=false make clean
COLOR=false make "${OBJECTS[@]}" 2>/dev/null
printf "\x1B[0m"
# Extract symbols from the object files.
printf "Extracting symbols...\n\x1B[2m"
for obj in *.o; do
while read -r encounter symbol; do
if [[ "$encounter" = "G" ]] && ! [[ "$symbol" =~ ^_ ]]; then
SYMBOLS+=("$symbol")
printf "%-30s %s\n" "$symbol" "[requires mangle]"
fi
done < <(objdump -t "$obj" | awk '
/ g / && !/__DATA/ { print "G "$NF }
/\*UND\*/ { print "U "$NF }
')
done
printf "\x1B[0m"
# Generate shim.
printf "Generating shim...\n\x1B[2m"
{
for symbol in "${SYMBOLS[@]}"; do
echo ".globl _$symbol"
echo "_$symbol: jmp $symbol"
done
} > "__shim.s"
cat __shim.s
printf "\x1B[0m"
# Patch makefile.
printf "Patching makefile...\n\x1B[2m"
if ! grep '__shim.s' < makefile &>/dev/null; then
echo "Finding targets..."
TARGETS=($(grep 'all:' < makefile | sed 's/^all://'))
if [[ -z "${TARGETS[*]}" ]]; then
printf "\x1B[31mFailed to patch makefile.\x1B[0m\n"
exit 1
fi
for target in "${TARGETS[@]}"; do
printf "Patching '%s'... " "$target"
found=false
while IFS='' read -r line; do
if ! $found; then
if ! grep "^$target:" <<< "$line" &>/dev/null; then
echo "$line"
continue;
fi
echo "$line __shim.s"
found=true;
continue
fi
if grep "^\s*gcc " <<< "$line" &>/dev/null; then
echo "$line __shim.s"
echo "OK" >&2
cat
mv makefile.tmp makefile
continue 2;
fi
done < makefile > makefile.tmp
# Couldn't automatically patch it.
printf "\x1B[31mFailed to patch makefile.\x1B[0m\n"
exit 1
done 2>&1
fi
printf "\x1B[0m"
# Done!
printf "\x1B[32mDone!\x1B[0m\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment