Created
October 17, 2019 23:33
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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