From 97d990323607d6eb50a84f672b2169ac4ba1697d Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 5 Apr 2012 21:26:44 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@154124 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/lto/LTOCodeGenerator.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index f0640c22063..0e61c2fb2a5 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -46,10 +46,13 @@ #include "llvm/ADT/StringExtras.h" using namespace llvm; -static cl::opt DisableInline("disable-inlining", +static cl::opt EnableInternalizing("enable-internalizing", cl::init(false), + cl::desc("Internalize functions during LTO")); + +static cl::opt DisableInline("disable-inlining", cl::init(false), cl::desc("Do not run the inliner pass")); -static cl::opt DisableGVNLoadPRE("disable-gvn-loadpre", +static cl::opt 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();