LLD doesn't handle globals with appending linkage

Hello.

I’m posting this question here, because there seem to be no LLD-specific mailing list. Sorry in advance if this is wrong one.

I compile two C source with following command:

clang -flto -o %name.bc %name.c

LLVM is augmented with my custom pass, which amongst other things create a global with appending linkage:

@myvar = appending constant [1 x [1 x i8]*] …

I also have another pass plugged into LTO pipeline, which turns this global into internal one in the final module. I was hoping that LLD would first link bitcodes like llvm-link, appending @myvar’s from both modules into a single one, then run my pass, and only then perform linking at object level.

However, LLD complains about duplicated symbol “myvar” and doesn’t even run any passes.

I’ve tracked the problem down to BitcodeFile::parse() function from https://github.com/llvm/llvm-project/blob/master/lld/COFF/InputFiles.cpp#L918 - it doesn’t take linkage type into account.

Can anything be done about this problem? Or was my approach broken from the beginning?

Thanks in advance.

I’m /guessing/ this might be related to the COFF support specifically (perhaps COFF has no appending linkage support - in some cases LLVM IR supports the union of all semantics so that different formats can be fully expressed - but it means when targeting certain formats, some features are inherently unusable because they don’t map to anything on that platform)

If I were you I’d go see if there are any examples of appending linkage being used when targeting the COFF platform (eg: go look at places where Clang generates IR with appending linkage, see if any of them apply to COFF, if they do see how they work through LTO - if there are no such examples, look for non-COFF Examples of appending linkage and see what the IR targeting COFF looks like in those examples, perhaps a different linkage mechanism is used that you can use too)

(added Reid for familiarity with the COFF format & Ray for familiarity with LLD)

Actually, I experience the same problem with ELF on FreeBSD.

I'm /guessing/ this might be related to the COFF support specifically
(perhaps COFF has no appending linkage support - in some cases LLVM IR
supports the union of all semantics so that different formats can be fully
expressed - but it means when targeting certain formats, some features are
inherently unusable because they don't map to anything on that platform)

Actually, I experience the same problem with ELF on FreeBSD.

https://llvm.org/docs/LangRef.html

Unfortunately this doesn’t correspond to any feature in .o files, so
it can only be used for variables like llvm.global_ctors which llvm
interprets specially.

I think appending can only be used by llvm.used llvm.compiler.used
llvm.global_ctors llvm.global_dtors. How did you end up with an
appending in the IR?

(Maybe we can add an verifier because it seems no object format supports it.)

I’m /guessing/ this might be related to the COFF support specifically
(perhaps COFF has no appending linkage support - in some cases LLVM IR
supports the union of all semantics so that different formats can be fully
expressed - but it means when targeting certain formats, some features are
inherently unusable because they don’t map to anything on that platform)

Actually, I experience the same problem with ELF on FreeBSD.

https://llvm.org/docs/LangRef.html

Unfortunately this doesn’t correspond to any feature in .o files, so
it can only be used for variables like llvm.global_ctors which llvm
interprets specially.

I think appending can only be used by llvm.used llvm.compiler.used
llvm.global_ctors llvm.global_dtors. How did you end up with an
appending in the IR?

(Maybe we can add an verifier because it seems no object format supports it.)

But these bitcode files aren’t linked to .o files yet, but into a single bitcode file. It should be perfectly fine to have appending globals at this stage.

The following patch has fixed the problem for me:

diff --git a/llvm/lib/Object/ModuleSymbolTable.cpp b/llvm/lib/Object/ModuleSymbolTable.cpp
index 33ce7d8109f…d1d74fa54bf 100644
— a/lib/Object/ModuleSymbolTable.cpp
+++ b/lib/Object/ModuleSymbolTable.cpp
@@ -201,7 +201,7 @@ uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S) const {
Res |= BasicSymbolRef::SF_Executable;
if (isa(GV))
Res |= BasicSymbolRef::SF_Indirect;

  • if (GV->hasPrivateLinkage())
  • if (GV->hasPrivateLinkage() || GV->hasAppendingLinkage())
    Res |= BasicSymbolRef::SF_FormatSpecific;
    if (!GV->hasLocalLinkage())
    Res |= BasicSymbolRef::SF_Global;

Is it a sane approach? Can it be upstreamed?

Can you paste the IR file for which you want AppendingLinkage to work?

From an earlier command you pasted `clang -flto -o %name.bc %name.c`, it
seems that you have some way to generate `appending` from a .c file.

Hello.

I’m posting this question here, because there seem to be no LLD-specific
mailing list. Sorry in advance if this is wrong one.

I compile two C source with following command:

clang -flto -o %name.bc %name.c

LLVM is augmented with my custom pass, which amongst other things create a
global with appending linkage:

@myvar = appending constant [1 x [1 x i8]*] …

I also have another pass plugged into LTO pipeline, which turns this
global into internal one in the final module. I was hoping that LLD would
first link bitcodes like llvm-link, appending @myvar’s from both modules
into a single one, then run my pass, and only then perform linking at
object level.

However, LLD complains about duplicated symbol “myvar” and doesn’t even
run any passes.

I’ve tracked the problem down to BitcodeFile::parse() function from
https://github.com/llvm/llvm-project/blob/master/lld/COFF/InputFiles.cpp#L918

  • it doesn’t take linkage type into account.

Can anything be done about this problem? Or was my approach broken from
the beginning?

Thanks in advance.

The following patch has fixed the problem for me:

diff --git a/llvm/lib/Object/ModuleSymbolTable.cpp
b/llvm/lib/Object/ModuleSymbolTable.cpp
index 33ce7d8109f…d1d74fa54bf 100644
— a/lib/Object/ModuleSymbolTable.cpp
+++ b/lib/Object/ModuleSymbolTable.cpp
@@ -201,7 +201,7 @@ uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S)
const {
Res |= BasicSymbolRef::SF_Executable;
if (isa(GV))
Res |= BasicSymbolRef::SF_Indirect;

  • if (GV->hasPrivateLinkage())
  • if (GV->hasPrivateLinkage() || GV->hasAppendingLinkage())
    Res |= BasicSymbolRef::SF_FormatSpecific;
    if (!GV->hasLocalLinkage())
    Res |= BasicSymbolRef::SF_Global;

Is it a sane approach? Can it be upstreamed?

Can you paste the IR file for which you want AppendingLinkage to work?

There is nothing special about it. It just has a GV with appending linkage like I wrote earlier:

@myvar = appending constant [1 x [1 x i8]*] …

From an earlier command you pasted clang -flto -o %name.bc %name.c, it
seems that you have some way to generate appending from a .c file.

I have my own custom pass plugged into Clang’s pass pipeline, which generates that @myvar. Of course, vanilla Clang doesn’t generate GVs with appending linkage.