[PATCH] D44543: [AsmPrinter] Emit .weak directive for weak linkage on COFF

Martin Storsjö via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 11 07:24:44 PDT 2020


mstorsjo added a reviewer: mstorsjo.
mstorsjo added a comment.
Herald added a project: LLVM.

I keep running into this issue in various places, that `__attribute__((weak))` doesn't work on COFF in clang.

In D44543#1041998 <https://reviews.llvm.org/D44543#1041998>, @espindola wrote:

> In D44543#1039750 <https://reviews.llvm.org/D44543#1039750>, @smeenai wrote:
>
> > @rnk, does that make sense to you?
> >
> > I'm not very familiar with this part of LLVM; I ran into this issue because an internal user needed `__attribute__((weak))` semantics on COFF, and having inline assembly with a manual `.weak` directive for a gigantic mangled C++ name isn't the greatest workaround (though it does work). I'm happy to follow through if there's agreement on how to proceed here though.
> >
> > I do have a question though. `linkonce` doesn't appear to do anything by itself on COFF right now. E.g. if I have
> >
> >   define linkonce void @f() {
> >     ret void
> >   }
> >
> >
> > and run `bin/llc -mtriple=x86_64-windows-msvc` on it, the object file produced is the same both with and without the `linkonce`.
>
>
> This is almost certainly an oversight. I don't think I have ever seen a plain linkonce used in practice, so it was probably never implemented.


If I've understood things correctly, this is the norm, see e.g. D71572 <https://reviews.llvm.org/D71572> for needing to add a comdat to make linkonce behave as intended.

In D44543#1046298 <https://reviews.llvm.org/D44543#1046298>, @rnk wrote:

> One way that we could make forward progress without rewriting LLVM's linkage is to not apply .weak for `weak_odr` linkages. Then we'd say, `weak_odr` is exactly like `linkonce_odr` except it is non-discardable, pending a cleanup to make discardability a separate bit (probably along with a separate "odr" bit that informs the inliner and constant propagation). `weak` linkage would be reserved for things that truly use `__attribute__((weak))`.


I'm also hesitant to adjusting the generic rules for how this behaves on a whim (even though the current `hasLinkOnceDirective` case essentially is COFF only), but some change like the one above (in one form or another) does seem to be needed. As the current code only checks for `hasLinkOnceDirective`, it does decide that it can use `.globl` as the platform in general should be able to describe linkonce semantics, while it only can describe linkonce semantics if there's a comdat.

One way of handling it, which seems to run fine without regression in a larger set of code, is this:

       if (MAI->hasWeakDefDirective()) {
         // .globl _foo
         OutStreamer->emitSymbolAttribute(GVSym, MCSA_Global);
   
         if (!canBeHidden(GV, *MAI))
           // .weak_definition _foo
           OutStreamer->emitSymbolAttribute(GVSym, MCSA_WeakDefinition); 
         else
           OutStreamer->emitSymbolAttribute(GVSym, MCSA_WeakDefAutoPrivate);
  +    } else if (TT.isOSWindows() && TT.isOSBinFormatCOFF() &&
  +               GlobalValue::isWeakLinkage(Linkage) && !GV->hasComdat()) {
  +      // .weak _foo
  +      OutStreamer->emitSymbolAttribute(GVSym, MCSA_Weak);
       } else if (MAI->hasLinkOnceDirective()) {
         // .globl _foo
         OutStreamer->emitSymbolAttribute(GVSym, MCSA_Global); 
         //NOTE: linkonce is handled by the section the symbol was assigned to.
       } else {
         // .weak _foo
         OutStreamer->emitSymbolAttribute(GVSym, MCSA_Weak);
       }

This retains the distinction between linkonce/linkonce_odr and weak/weak_odr that @smeenai was making so far.

Another way of doing it, with a much smaller diff, would be this:

       if (MAI->hasWeakDefDirective()) {
         // .globl _foo
         OutStreamer->emitSymbolAttribute(GVSym, MCSA_Global);
      
         if (!canBeHidden(GV, *MAI))
           // .weak_definition _foo
           OutStreamer->emitSymbolAttribute(GVSym, MCSA_WeakDefinition);
         else
           OutStreamer->emitSymbolAttribute(GVSym, MCSA_WeakDefAutoPrivate);
  -    } else if (MAI->hasLinkOnceDirective()) {
  +    } else if (MAI->hasLinkOnceDirective() && GV->hasComdat()) {
  +      // hasLinkOnceDirective() is essentially COFF-only, and COFF needs a comdat for expressing the linkonce semantics
         // .globl _foo
         OutStreamer->emitSymbolAttribute(GVSym, MCSA_Global);
         //NOTE: linkonce is handled by the section the symbol was assigned to.
       } else {
         // .weak _foo
         OutStreamer->emitSymbolAttribute(GVSym, MCSA_Weak);
       }

(This one I haven't testrun in the same way yet.)

If @smeenai doesn't have the same need for this one any longer, I could comandeer this revision, to start pestering people to get this finished.


Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D44543/new/

https://reviews.llvm.org/D44543





More information about the llvm-commits mailing list