[llvm-commits] [llvm] r154124 - /llvm/trunk/tools/lto/LTOCodeGenerator.cpp

Bill Wendling isanbard at gmail.com
Thu Apr 5 14:26:44 PDT 2012

Author: void
Date: Thu Apr  5 16:26:44 2012
New Revision: 154124

URL: http://llvm.org/viewvc/llvm-project?rev=154124&view=rev
The internalize pass can be dangerous for LTO.

Consider the following program:

$ cat main.c
void foo(void) { }

int main(int argc, char *argv[]) {
    return 0;
$ cat bundle.c 
extern void foo(void);

void bar(void) {
$ 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.


Modified: llvm/trunk/tools/lto/LTOCodeGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lto/LTOCodeGenerator.cpp?rev=154124&r1=154123&r2=154124&view=diff
--- llvm/trunk/tools/lto/LTOCodeGenerator.cpp (original)
+++ llvm/trunk/tools/lto/LTOCodeGenerator.cpp Thu Apr  5 16:26:44 2012
@@ -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 @@
 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();

More information about the llvm-commits mailing list