Skip to content

Instantly share code, notes, and snippets.

@maleadt
Created December 7, 2018 18:52
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 maleadt/ad63f04b1e8d64c0f7c9ff9e021a5a55 to your computer and use it in GitHub Desktop.
Save maleadt/ad63f04b1e8d64c0f7c9ff9e021a5a55 to your computer and use it in GitHub Desktop.
LLVM symbol renaming PoC

Compatibility with conflicting copies of LLVM

In some cases there can already by a visible copy of LLVM present in the address space, e.g., when a driver requires LLVM but doesn't hide its symbols. Depending on the platform, this may cause issues (reinitialization errors, silent use of the wrong library, etc). An abort due to doubly-registered passes when initializing the LLVM library is a common symptom for this.

It is possible to avoid this by renaming the symbols exported by the LLVM API wrapper (and the underlying LLVM library). You can do so by defining the LOCAL_NAMESPACE environment variable when configuring llvm_shared with CMake (note that this requires a statically-built LLVM, or rewriting will fail):

LOCAL_NAMESPACE=1 \
cmake ../
if(DEFINED ENV{LOCAL_NAMESPACE})
# NOTE: if localizing the namespace, by rewriting just before linking, we
# really do need to use static linking because we can't (easily)
# rewrite dynamic symbols
# NOTE: the directive below is copied from the Linux rules in
# CMakeDefaultMakeRuleVariables.cmake, and may have to be adjusted for
# your platform
set(CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_SOURCE_DIR}/rewrite_wrapper <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
endif()
#!/usr/bin/env perl
# This script rewrites the symbols in a static object or archive (.o or .a)
# using `objcopy`, prepending a tag to make it unique.
use strict;
use warnings;
use File::Temp qw/tempfile/;
use File::Basename;
my $input = shift || die;
die unless -r $input;
die unless $input =~ m/\.(o|a)$/i;
my $output = shift || die;
# list symbols
open(my $nm, "readelf --wide --syms $input |");
my @header;
my %symbols;
while (<$nm>) {
chomp;
s/^\s*//;
my @fields = split(/\s+/);
next unless @fields == 8;
if (@header == 0) {
@header = @fields;
} else {
my %data;
@data{@header} = @fields;
$symbols{$fields[-1]} = \%data;
# TODO: is overwriting multiply-defined symbols safe?
}
}
close($nm);
die if $?;
# create map
my ($fh, $filename) = tempfile();
foreach my $symbol (%symbols) {
# Add namespace to LLVM C++ API
if ($symbol =~ m/^_Z.*NK?4llvm/) {
my $orig = $symbol;
$symbol =~ s/(NK?)4llvm/${1}6foobar4llvm/;
print $fh "$orig $symbol\n";
}
# Add prefix to the LLVM C API
elsif ($symbol =~ m/^LLVM/) {
my $orig = $symbol;
$symbol = "Foobar$orig";
print $fh "$orig $symbol\n";
}
}
close($fh);
# rewrite
system("objcopy", "--redefine-syms=$filename", $input, $output) == 0 or die;
unlink $filename;
#!/usr/bin/env bash
set -ue
# This file is a wrapper to replace the compiler or linker at the final link
# step, processing each file argument by calling the `rewrite` script.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
declare -a FILES
handler() {
rm -f "${FILES[@]}"
exit 1
}
trap 'handler' ERR
declare -a ARGS
for i in "$@"; do
if [[ -f "$i" ]]; then
fn=$(basename "$i")
ext="${fn##*.}"
fn="${fn%.*}"
tmp=$(mktemp --tmpdir "$fn.XXXXXXXXXX" --suffix=".$ext")
FILES+=("$tmp")
$DIR/rewrite "$i" "$tmp"
ARGS+=("$tmp")
else
ARGS+=("$i")
fi
done
c++ "${ARGS[@]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment