Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lld 15] "duplicate symbol: guard variable" errors when mixing gcc and clang .o files #58232

Closed
Romain-Geissler-1A opened this issue Oct 7, 2022 · 2 comments
Labels

Comments

@Romain-Geissler-1A
Copy link
Member

Romain-Geissler-1A commented Oct 7, 2022

Hi,

After having upgraded from lld 13 to lld 15, it looks like in certain cases mixing gcc and clang object files doesn't seem to work anymore.

Here is a reduced reproducer from some code using initially Boost asio:

Content of test.h:

#pragma once

template <typename T> class tss_ptr
{   
    public:
        tss_ptr() {}
        
        static thread_local T* value_;
};

template <typename T> thread_local T* tss_ptr<T>::value_;

template <typename Value> class call_stack
{
    public:
        static tss_ptr<int> top_;
};      

template <typename Value> tss_ptr<int> call_stack<Value>::top_;

inline int top_of_thread_call_stack()
{
    return *call_stack<int>::top_.value_;
} 

Content of test.cpp:

#include "test.h"

And then try to compile: once with gcc, once with clang, and link both object together using lld (ok, this is silly, as there is no main, but this is a reduced scenario of something bigger to expose the error):

clang++ -fno-pie -fno-PIE -fno-pic -fno-PIC -o "clang.o" -c "test.cpp"
g++ -fno-pie -fno-PIE -fno-pic -fno-PIC -o "gcc.o" -c "test.cpp"
g++ -no-pie -fuse-ld=lld -o "test" clang.o gcc.o

which yields this error:

ld.lld: error: duplicate symbol: guard variable for call_stack<int>::top_
>>> defined at test.cpp
>>>            clang.o:(guard variable for call_stack<int>::top_)
>>> defined at test.cpp
>>>            gcc.o:(.bss._ZGVN10call_stackIiE4top_E+0x0)
collect2: error: ld returned 1 exit status
Makefile:6: recipe for target 'test' failed
make: *** [test] Error 1

It used to be ok with clang + lld 13.

Note: I used the release LLVM 15.0.2 compiled from source. clang is configured to target the gcc toolchain. gcc was also compiled from source, from a recent commit of the release branch of gcc 11.

If you cannot reproduce, I can provide the two .o files.

I don't know if it's linked, but on the gcc.o file, the guard variable is a "gnu unique symbol". It may (or may not, I don't know) be a problem similar to this mold issue: rui314/mold#524

Cheers,
Romain

@MaskRay
Copy link
Member

MaskRay commented Oct 20, 2022

https://reviews.llvm.org/D136381

Note that mixing GCC and Clang object files in this case looks fragile since they use different COMDATs, though I cannot think of an immediate problem. Both dynamic initializations will run, despite the COMDAT intention. It's benign because of the guard variable.

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 21, 2022

@llvm/issue-subscribers-lld-elf

llvmbot pushed a commit to llvm/llvm-project-release-prs that referenced this issue Oct 21, 2022
…_UNIQUE in different COMDATs

```
template <typename T> struct A {
  A() {}
  int value = 0;
};

template <typename Value> struct B {
  static A<int> a;
};

template <typename Value> A<int> B<Value>::a;

inline int foo() {
  return B<int>::a.value;
}
```

```
clang++ -c -fno-pic a.cc -o weak.o
g++ -c -fno-pic a.cc -o unique.o  # --enable-gnu-unique-object

# Duplicate symbol error. In postParse, we do not check `sym.binding`
ld.lld -e 0 weak.o unique.o
```

Mixing GCC and Clang object files in this case is not ideal. .bss._ZGVN1BIiE1aE
has different COMDAT groups. It appears to work in practice because the guard
variable prevents harm due to double initialization.

For the linker, we just stick with the rule that a weak binding does not cause
"duplicate symbol" errors.

Close llvm/llvm-project#58232

Differential Revision: https://reviews.llvm.org/D136381

(cherry picked from commit 0051b6b)
tru pushed a commit to llvm/llvm-project-release-prs that referenced this issue Oct 24, 2022
…_UNIQUE in different COMDATs

```
template <typename T> struct A {
  A() {}
  int value = 0;
};

template <typename Value> struct B {
  static A<int> a;
};

template <typename Value> A<int> B<Value>::a;

inline int foo() {
  return B<int>::a.value;
}
```

```
clang++ -c -fno-pic a.cc -o weak.o
g++ -c -fno-pic a.cc -o unique.o  # --enable-gnu-unique-object

# Duplicate symbol error. In postParse, we do not check `sym.binding`
ld.lld -e 0 weak.o unique.o
```

Mixing GCC and Clang object files in this case is not ideal. .bss._ZGVN1BIiE1aE
has different COMDAT groups. It appears to work in practice because the guard
variable prevents harm due to double initialization.

For the linker, we just stick with the rule that a weak binding does not cause
"duplicate symbol" errors.

Close llvm/llvm-project#58232

Differential Revision: https://reviews.llvm.org/D136381

(cherry picked from commit 0051b6b)
sid8123 pushed a commit to sid8123/llvm-project that referenced this issue Oct 25, 2022
…_UNIQUE in different COMDATs

```
template <typename T> struct A {
  A() {}
  int value = 0;
};

template <typename Value> struct B {
  static A<int> a;
};

template <typename Value> A<int> B<Value>::a;

inline int foo() {
  return B<int>::a.value;
}
```

```
clang++ -c -fno-pic a.cc -o weak.o
g++ -c -fno-pic a.cc -o unique.o  # --enable-gnu-unique-object

# Duplicate symbol error. In postParse, we do not check `sym.binding`
ld.lld -e 0 weak.o unique.o
```

Mixing GCC and Clang object files in this case is not ideal. .bss._ZGVN1BIiE1aE
has different COMDAT groups. It appears to work in practice because the guard
variable prevents harm due to double initialization.

For the linker, we just stick with the rule that a weak binding does not cause
"duplicate symbol" errors.

Close llvm#58232

Differential Revision: https://reviews.llvm.org/D136381
virnarula pushed a commit to virnarula/llvm-project that referenced this issue Nov 2, 2022
…_UNIQUE in different COMDATs

```
template <typename T> struct A {
  A() {}
  int value = 0;
};

template <typename Value> struct B {
  static A<int> a;
};

template <typename Value> A<int> B<Value>::a;

inline int foo() {
  return B<int>::a.value;
}
```

```
clang++ -c -fno-pic a.cc -o weak.o
g++ -c -fno-pic a.cc -o unique.o  # --enable-gnu-unique-object

# Duplicate symbol error. In postParse, we do not check `sym.binding`
ld.lld -e 0 weak.o unique.o
```

Mixing GCC and Clang object files in this case is not ideal. .bss._ZGVN1BIiE1aE
has different COMDAT groups. It appears to work in practice because the guard
variable prevents harm due to double initialization.

For the linker, we just stick with the rule that a weak binding does not cause
"duplicate symbol" errors.

Close llvm#58232

Differential Revision: https://reviews.llvm.org/D136381
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants