This is an archive of the discontinued LLVM Phabricator instance.

[ELF] - Implement extern "c++" version script tag
ClosedPublic

Authored by grimar on Jul 1 2016, 9:26 AM.

Diff Detail

Repository
rL LLVM

Event Timeline

grimar updated this revision to Diff 62501.Jul 1 2016, 9:26 AM
grimar retitled this revision from to [ELF] - Implement extern "c++" version script tag.
grimar updated this object.
grimar added reviewers: ruiu, rafael.
grimar added subscribers: llvm-commits, grimar.
ruiu edited edge metadata.Jul 2 2016, 1:03 AM

The new code seems to be a copy of the existing code with a small change to demangle symbols. Can you make it smaller?

ELF/SymbolTable.cpp
564 ↗(On Diff #62501)

We already have elf::demangle function.

grimar added inline comments.Jul 4 2016, 1:46 AM
ELF/SymbolTable.cpp
564 ↗(On Diff #62501)

Sure we have it, but it will not work here I think. At least it has 2 conditions that we don't want to see here:

if (!Config->Demangle)
  return Name;
// __cxa_demangle can be used to demangle strings other than symbol
// names which do not necessarily start with "_Z". Name can be
// either a C or C++ symbol. Don't call __cxa_demangle if the name
// does not look like a C++ symbol name to avoid getting unexpected
// result for a C symbol that happens to match a mangled type name.
if (!Name.startswith("_Z"))
  return Name;
grimar added a comment.Jul 4 2016, 4:24 AM
In D21930#473140, @ruiu wrote:

The new code seems to be a copy of the existing code with a small change to demangle symbols. Can you make it smaller?

I'll try to do something. Let's land dependency D21894 first.

emaste added a subscriber: emaste.Jul 4 2016, 6:42 AM
if (!Name.startswith("_Z"))
   return Name;

This one is needed, otherwise a symbol f would be demangled to float. We want only mangled symbol names (which start with _Z), not types etc.

grimar added a comment.Jul 4 2016, 6:47 AM
if (!Name.startswith("_Z"))
   return Name;

This one is needed, otherwise a symbol f would be demangled to float. We want only mangled symbol names (which start with _Z), not types etc.

Ah, oh. I was misunderstanding meaning of "_Z" then.

ruiu added inline comments.Jul 6 2016, 2:41 PM
ELF/Config.h
38 ↗(On Diff #62501)

SymbolVersion is probably better?

ELF/SymbolTable.cpp
564 ↗(On Diff #62501)

You can remove if (!Config->Demangle) from the function and check the condition on caller side. As to the second condition, you actually want it, no?

grimar updated this revision to Diff 63045.Jul 7 2016, 3:03 AM
grimar edited edge metadata.
grimar marked an inline comment as done.
  • Addressed review comments.
ELF/Config.h
38 ↗(On Diff #62501)

Done.

ELF/SymbolTable.cpp
564 ↗(On Diff #62501)

Right.

ruiu added inline comments.Jul 7 2016, 3:31 PM
ELF/SymbolTable.cpp
560 ↗(On Diff #63045)

I'd name this setVersionId. Also rename Entry -> Name.

601–607 ↗(On Diff #63045)

I do not understand the exact logic. Can this handle C++ mangled name patterns that contain glob meta characters?

grimar added inline comments.Jul 8 2016, 2:05 AM
ELF/SymbolTable.cpp
601–607 ↗(On Diff #63045)

This patch handles only exact matches.
According to rules of processing version script files described in Ian Lance Taylor article,
handling of wildcards is the last step and the same should be applied for wildcarded
externs. So handling wildcards in externs is a job for following patches I think.

Speaking about exactly this piece of code - it just builds association map to map [extern name -> its version].
That is done to simplify and accelerate the pass to handle externs (lines 621-628). Without that map I would
need to iterate over all versions and all externs after demangle() call to find which version to use.
It would be something like next without this map (pseudocode):

for (auto I = Symtab.begin(); I != Symtab.end(); ++I) {
  StringRef Demangled = demangle(I->first.Val);

  for (size_t J = 0, E = Config->SymbolVersions.size(); J < E; ++J) {
    Version &V = Config->SymbolVersions[I];
    for (SymbolVersion Sym : V.Globals) {
        if (!Sym.IsExternCpp)
          continue;
      
        if (Sym.Name == Demangled) {
          overrideSymbolVersion(SymVector[I->second], Sym.Name, J + 2);
          return;
        }
      }
    }
}
ruiu added a comment.Jul 8 2016, 2:06 PM

What I was trying to say is that the code did not look very straightforward. I think you have no choice other than demangle all symbols if "extern" directive is used, so why don't you create a map from demangled names to symbolbodies?

ELF/SymbolTable.cpp
591 ↗(On Diff #63045)

Add

DenseMap<StringRef, SymbolBody *> Demangled;
if (hasExternCpp())
  Demangled = getDemangledSyms();

here and then

609 ↗(On Diff #63045)

replace this line with

SymbolBody *B = Sym.IsExternCpp ? Demangled[Sym.Name] : find(Sym.Name);
grimar updated this revision to Diff 63497.Jul 11 2016, 6:04 AM
  • Addressed review comments.
ELF/SymbolTable.cpp
560 ↗(On Diff #63045)

Done.

560 ↗(On Diff #63045)

Done.

591 ↗(On Diff #63045)

I implemented the close way below. I can't use StringRef as a key as demangle() returns string.
DenseMapInfo does not have specialization for std::strings.
And so I had to use std::map instead with std::string as a key.

609 ↗(On Diff #63045)

This just will not work I think..
Ian Lance Taylor wrote about current rules in gold (http://www.airs.com/blog/archives/300):

Here are the current rules for gold:

If there is an exact match for the mangled name, we use it.

...

Otherwise, we look for an extern C++ or an extern Java exact match. If we find an exact match, we use it.

...

So externs matching should be done after common case matching, according to that rules we probably want to follow.

ruiu added inline comments.Jul 11 2016, 1:50 PM
ELF/SymbolTable.cpp
572 ↗(On Diff #63497)

If you pass a SymbolBody, do you have to pass Name? I think you can obtain it by Body->getName().

589 ↗(On Diff #63497)

Why don't you use a range-based for?

627–628 ↗(On Diff #63497)

I'd disagree -- that rule doesn't make sense to me. If you specify a mangled name (that contains no wildcards), then that is as specific/strict as demangled names. I don't see a reason to look for extern C++ names after non-extern-C++ names.

grimar updated this revision to Diff 63666.Jul 12 2016, 4:39 AM
  • Addressed review comments.
ELF/SymbolTable.cpp
572 ↗(On Diff #63497)

Here Name is the how it is written in linkerscript. It is SymbolVersion::Name.
So if we have demangled name under extern tag,
it will show it instead of mangled symbol name we can obtain from Body->getName() for example.
That is btw was why I named argument as Entry initially, because Name is a bit confusing in that case,
though it is still a name.

589 ↗(On Diff #63497)

Fixed.

627–628 ↗(On Diff #63497)

Ok. I agree here, implemented that just because I thought we want to follow the existent rules to prevent possible conflicts in existent software. Lets see how it works.

grimar updated this revision to Diff 63667.Jul 12 2016, 4:42 AM
  • Updated comment.
ruiu accepted this revision.Jul 12 2016, 12:27 PM
ruiu edited edge metadata.

LGTM

This revision is now accepted and ready to land.Jul 12 2016, 12:27 PM
grimar updated this object.Jul 13 2016, 12:51 AM
grimar edited edge metadata.
This revision was automatically updated to reflect the committed changes.

I had to revert this.
It broke 2 build bots:

  1. http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/8204/steps/test/logs/stdio

I have no idea why it failed because I specified XFAIL: win32 in testcase, so it was expected fails, though bot errors out.

  1. http://lab.llvm.org:8011/builders/lld-x86_64-freebsd/builds/19432/steps/test_lld/logs/stdio

Has the same error message. I guess it does not have HAVE_CXXABI_H.

So I am goint to rework the testcase and recommit later. Though I am curious why windows bot reports error when XFAIL is set ?

Recommitted as rL275682 + rL275683, FreeBSD bot is happy how. Thanks to Ed, Rafael and Rui for help in solving this.