LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 26674 - --start-lib/--end-lib broken with LTO
Summary: --start-lib/--end-lib broken with LTO
Status: RESOLVED FIXED
Alias: None
Product: libraries
Classification: Unclassified
Component: Linker (show other bugs)
Version: trunk
Hardware: PC Linux
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-19 17:30 PST by Evgenii Stepanov
Modified: 2016-03-03 18:26 PST (History)
2 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Evgenii Stepanov 2016-02-19 17:30:44 PST
$ cat bin.cc 
int main() {}

$ cat 1.cc
__attribute__((constructor(0))) void ctor() {}

$ ./bin/clang++ -flto bin.cc -c
$ ./bin/clang++ -flto 1.cc -c
$ ./bin/clang++ -fuse-ld=gold -flto  bin.o -Wl,--start-lib 1.o -Wl,--end-lib
/tmp/lto-llvm-2af7ce.o(.init_array.0+0x0): error: undefined reference to 'ctor()'
clang-3.9: error: linker command failed with exit code 1 (use -v to see invocation)

With -Wl,-plugin-opt,save-temps the merged IR (before link time optimizations) looks like this:

[...]
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @_Z4ctorv, i8* null }]

; Function Attrs: norecurse nounwind uwtable
define i32 @main() #0 {
entry:
  ret i32 0
}

; Function Attrs: nounwind uwtable
declare void @_Z4ctorv() #1
[...]


$ /usr/bin/ld.gold --version
GNU gold (GNU Binutils for Ubuntu 2.24) 1.11
Comment 1 Evgenii Stepanov 2016-02-19 19:03:39 PST
Gold says that ctor() is LDPR_PREEMPTED_REG.

I think we hit this code in get_symbol_resolution_info():
      // We never decided to include this object. We mark all symbols as
      // preempted.
      gold_assert(this->symbols_.size() == 0);
      for (int i = 0; i < nsyms; i++)
        syms[i].resolution = LDPR_PREEMPTED_REG;

Why are we still trying to add it then?
Comment 2 Rafael Ávila de Espíndola 2016-02-22 08:31:27 PST
This reduces to just

@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void \
()*, i8* } { i32 0, void ()* @foo, i8* null }]

define void @foo() {
  ret void
}

link with

$ ld -plugin LLVMgold.so -shared --start-lib 1.bc --end-lib -o t.so 

t.so will have an undefined reference to foo.

What is going on is

We see @foo is preemepted_reg and we *do not* include it.

The problem is that llvm.global_ctors is one of the magical llvm append variables and in handled by llvm directly. Gold doesn't know it exists. We then get an undefined reference to foo from it.

This would still be an issue even with a more direct representation of static constructors:

@ctor1 = private constant void()* @foo, section "llvm.metadata.ctros"

since it would be a private variable, it would still be unknown to gold.

The fundamental problem is that there is no way for the plugin api to distinguish two different cases

* The file was not included in the link.
* The file was included in the link, but every linker visible symbol is preemepted_reg

A possible way to extend it would be to add a LDPT_GET_SYMBOLS_V3 that returns a new LDPS_NOT_INCLUDED_IN_LINK for the first case.
Comment 3 Evgenii Stepanov 2016-03-03 18:26:42 PST
Fixed in http://reviews.llvm.org/rL262676 with ToT gold.