summaryrefslogtreecommitdiffstats
path: root/llvm/tools/lto/LTOCodeGenerator.cpp
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2012-04-05 21:26:44 +0000
committerBill Wendling <isanbard@gmail.com>2012-04-05 21:26:44 +0000
commit4f60125dd866d3552d58c04cdb7ce2b5496b9bd3 (patch)
tree4467b4ec670b3a9a703aa92e31fcaa7c05b22e2f /llvm/tools/lto/LTOCodeGenerator.cpp
parent930f2f66e7fc9bcd796b6edf18ee1914702b6da4 (diff)
downloadbcm5719-llvm-4f60125dd866d3552d58c04cdb7ce2b5496b9bd3.tar.gz
bcm5719-llvm-4f60125dd866d3552d58c04cdb7ce2b5496b9bd3.zip
The internalize pass can be dangerous for LTO.
Consider the following program: $ cat main.c void foo(void) { } int main(int argc, char *argv[]) { foo(); return 0; } $ cat bundle.c extern void foo(void); void bar(void) { foo(); } $ clang -o main main.c $ clang -o bundle.so bundle.c -bundle -bundle_loader ./main $ nm -m bundle.so 0000000000000f40 (__TEXT,__text) external _bar (undefined) external _foo (from executable) (undefined) external dyld_stub_binder (from libSystem) $ clang -o main main.c -O4 $ clang -o bundle.so bundle.c -bundle -bundle_loader ./main Undefined symbols for architecture x86_64: "_foo", referenced from: _bar in bundle-elQN6d.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) The linker was told that the 'foo' in 'main' was 'internal' and had no uses, so it was dead stripped. Another situation is something like: define void @foo() { ret void } define void @bar() { call asm volatile "call _foo" ... ret void } The only use of 'foo' is inside of an inline ASM call. Since we don't look inside those for uses of functions, we don't specify this as a "use." Get around this by not invoking the 'internalize' pass by default. This is an admitted hack for LTO correctness. <rdar://problem/11185386> llvm-svn: 154124
Diffstat (limited to 'llvm/tools/lto/LTOCodeGenerator.cpp')
-rw-r--r--llvm/tools/lto/LTOCodeGenerator.cpp15
1 files changed, 13 insertions, 2 deletions
diff --git a/llvm/tools/lto/LTOCodeGenerator.cpp b/llvm/tools/lto/LTOCodeGenerator.cpp
index f0640c22063..0e61c2fb2a5 100644
--- a/llvm/tools/lto/LTOCodeGenerator.cpp
+++ b/llvm/tools/lto/LTOCodeGenerator.cpp
@@ -46,10 +46,13 @@
#include "llvm/ADT/StringExtras.h"
using namespace llvm;
-static cl::opt<bool> DisableInline("disable-inlining",
+static cl::opt<bool> EnableInternalizing("enable-internalizing", cl::init(false),
+ cl::desc("Internalize functions during LTO"));
+
+static cl::opt<bool> DisableInline("disable-inlining", cl::init(false),
cl::desc("Do not run the inliner pass"));
-static cl::opt<bool> DisableGVNLoadPRE("disable-gvn-loadpre",
+static cl::opt<bool> DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
cl::desc("Do not run the GVN load PRE pass"));
const char* LTOCodeGenerator::getVersionString() {
@@ -275,6 +278,14 @@ static void findUsedValues(GlobalVariable *LLVMUsed,
}
void LTOCodeGenerator::applyScopeRestrictions() {
+ // Internalize only if specifically asked for. Otherwise, global symbols which
+ // exist in the final image, but which are used outside of that image
+ // (e.g. bundling) may be removed. This also happens when a function is used
+ // only in inline asm. LLVM doesn't recognize that as a "use", so it could be
+ // stripped.
+ if (!EnableInternalizing)
+ return;
+
if (_scopeRestrictionsDone) return;
Module *mergedModule = _linker.getModule();
OpenPOWER on IntegriCloud