forked from OSchip/llvm-project
Change the implementation of --dynamic-list to use linker script parsing.
The feature is documented as ----------------------------- The format of the dynamic list is the same as the version node without scope and node name. See *note VERSION:: for more information. -------------------------------- And indeed qt uses a dynamic list with an 'extern "C++"' in it. With this patch we support that The change to gc-sections-shared makes us match bfd. Just because we kept bar doesn't mean it has to be in the dynamic symbol table. The changes to invalid-dynamic-list.test and reproduce.s are because of the new parser. The changes to version-script.s are the only case where we change behavior with regards to bfd, but I would like to see a mix of --version-script and --dynamic-list used in the wild before complicating the code. llvm-svn: 289082
This commit is contained in:
parent
6f6d46d497
commit
d0ebd84c42
|
@ -87,7 +87,6 @@ struct Configuration {
|
|||
std::string RPath;
|
||||
std::vector<VersionDefinition> VersionDefinitions;
|
||||
std::vector<llvm::StringRef> AuxiliaryList;
|
||||
std::vector<llvm::StringRef> DynamicList;
|
||||
std::vector<llvm::StringRef> SearchPaths;
|
||||
std::vector<llvm::StringRef> Undefined;
|
||||
std::vector<SymbolVersion> VersionScriptGlobals;
|
||||
|
|
|
@ -627,14 +627,24 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
|||
|
||||
if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
|
||||
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
|
||||
parseDynamicList(*Buffer);
|
||||
readDynamicList(*Buffer);
|
||||
|
||||
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
|
||||
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
|
||||
parseSymbolOrderingList(*Buffer);
|
||||
|
||||
for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
|
||||
Config->DynamicList.push_back(Arg->getValue());
|
||||
Config->VersionScriptGlobals.push_back(
|
||||
{Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
|
||||
|
||||
// Dynamic lists are a simplified linker script that doesn't need the
|
||||
// "global:" and implicitly ends with a "local:*". Set the variables needed to
|
||||
// simulate that.
|
||||
if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) {
|
||||
Config->ExportDynamic = true;
|
||||
if (!Config->Shared)
|
||||
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
|
||||
}
|
||||
|
||||
if (auto *Arg = Args.getLastArg(OPT_version_script))
|
||||
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
|
||||
|
@ -793,7 +803,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
|
|||
|
||||
Symtab.scanUndefinedFlags();
|
||||
Symtab.scanShlibUndefined();
|
||||
Symtab.scanDynamicList();
|
||||
Symtab.scanVersionScript();
|
||||
|
||||
Symtab.addCombinedLTOObject();
|
||||
|
|
|
@ -69,7 +69,6 @@ enum {
|
|||
|
||||
void printHelp(const char *Argv0);
|
||||
std::vector<uint8_t> parseHexstring(StringRef S);
|
||||
void parseDynamicList(MemoryBufferRef MB);
|
||||
|
||||
std::string createResponseFile(const llvm::opt::InputArgList &Args);
|
||||
|
||||
|
|
|
@ -90,32 +90,6 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
|
|||
return Args;
|
||||
}
|
||||
|
||||
// Parse the --dynamic-list argument. A dynamic list is in the form
|
||||
//
|
||||
// { symbol1; symbol2; [...]; symbolN };
|
||||
//
|
||||
// Multiple groups can be defined in the same file, and they are merged
|
||||
// into a single group.
|
||||
void elf::parseDynamicList(MemoryBufferRef MB) {
|
||||
class Parser : public ScriptParserBase {
|
||||
public:
|
||||
Parser(MemoryBufferRef MB) : ScriptParserBase(MB) {}
|
||||
|
||||
void run() {
|
||||
while (!atEOF()) {
|
||||
expect("{");
|
||||
while (!Error && !consume("}")) {
|
||||
Config->DynamicList.push_back(unquote(next()));
|
||||
expect(";");
|
||||
}
|
||||
expect(";");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Parser(MB).run();
|
||||
}
|
||||
|
||||
void elf::printHelp(const char *Argv0) {
|
||||
ELFOptTable Table;
|
||||
Table.PrintHelp(outs(), Argv0, "lld", false);
|
||||
|
|
|
@ -987,6 +987,7 @@ public:
|
|||
|
||||
void readLinkerScript();
|
||||
void readVersionScript();
|
||||
void readDynamicList();
|
||||
|
||||
private:
|
||||
void addFile(StringRef Path);
|
||||
|
@ -1040,6 +1041,13 @@ private:
|
|||
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
|
||||
};
|
||||
|
||||
void ScriptParser::readDynamicList() {
|
||||
expect("{");
|
||||
readAnonymousDeclaration();
|
||||
if (!atEOF())
|
||||
setError("EOF expected, but got " + next());
|
||||
}
|
||||
|
||||
void ScriptParser::readVersionScript() {
|
||||
readVersionScriptCommand();
|
||||
if (!atEOF())
|
||||
|
@ -1932,7 +1940,7 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
|
|||
StringRef Tok = next();
|
||||
bool IsCXX = Tok == "\"C++\"";
|
||||
if (!IsCXX && Tok != "\"C\"")
|
||||
setError("Unknown Language");
|
||||
setError("Unknown language");
|
||||
expect("{");
|
||||
|
||||
std::vector<SymbolVersion> Ret;
|
||||
|
@ -1956,6 +1964,10 @@ void elf::readVersionScript(MemoryBufferRef MB) {
|
|||
ScriptParser(MB).readVersionScript();
|
||||
}
|
||||
|
||||
void elf::readDynamicList(MemoryBufferRef MB) {
|
||||
ScriptParser(MB).readDynamicList();
|
||||
}
|
||||
|
||||
template class elf::LinkerScript<ELF32LE>;
|
||||
template class elf::LinkerScript<ELF32BE>;
|
||||
template class elf::LinkerScript<ELF64LE>;
|
||||
|
|
|
@ -66,6 +66,8 @@ void readLinkerScript(MemoryBufferRef MB);
|
|||
// Parses a version script.
|
||||
void readVersionScript(MemoryBufferRef MB);
|
||||
|
||||
void readDynamicList(MemoryBufferRef MB);
|
||||
|
||||
// This enum is used to implement linker script SECTIONS command.
|
||||
// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
|
||||
enum SectionsCommandKind {
|
||||
|
|
|
@ -535,13 +535,6 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
|
|||
Sym->symbol()->ExportDynamic = true;
|
||||
}
|
||||
|
||||
// This function processes --export-dynamic-symbol and --dynamic-list.
|
||||
template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
|
||||
for (StringRef S : Config->DynamicList)
|
||||
if (SymbolBody *B = find(S))
|
||||
B->symbol()->ExportDynamic = true;
|
||||
}
|
||||
|
||||
// Initialize DemangledSyms with a map from demangled symbols to symbol
|
||||
// objects. Used to handle "extern C++" directive in version scripts.
|
||||
//
|
||||
|
|
|
@ -81,7 +81,6 @@ public:
|
|||
|
||||
void scanUndefinedFlags();
|
||||
void scanShlibUndefined();
|
||||
void scanDynamicList();
|
||||
void scanVersionScript();
|
||||
|
||||
SymbolBody *find(StringRef Name);
|
||||
|
|
|
@ -19,15 +19,6 @@
|
|||
# CHECK-NEXT: Section: Undefined (0x0)
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: bar
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
# CHECK-NEXT: Binding: Global
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Other:
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: bar2
|
||||
# CHECK-NEXT: Value:
|
||||
# CHECK-NEXT: Size:
|
||||
|
|
|
@ -34,4 +34,4 @@
|
|||
|
||||
# RUN: echo "{ extern \"BOGUS\" { test }; };" > %t1
|
||||
# RUN: not ld.lld --dynamic-list %t1 2>&1 | FileCheck -check-prefix=ERR6 %s
|
||||
# ERR6: {{.*}}:1: ; expected, but got "BOGUS"
|
||||
# ERR6: {{.*}}:1: Unknown language
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
# RUN: diff %t.dir/build2/foo.o repro/%:t.dir/build2/foo.o
|
||||
|
||||
# RUN: echo "{ local: *; };" > ver
|
||||
# RUN: echo > dyn
|
||||
# RUN: echo "{};" > dyn
|
||||
# RUN: echo > file
|
||||
# RUN: echo > file2
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o 'foo bar'
|
||||
|
|
|
@ -14,11 +14,6 @@
|
|||
# RUN: ld.lld --version-script %t3.script -shared %t.o %t2.so -o %t3.so
|
||||
# RUN: llvm-readobj -dyn-symbols %t3.so | FileCheck --check-prefix=DSO2 %s
|
||||
|
||||
# --version-script filters --dynamic-list.
|
||||
# RUN: echo "{ foo1; foo2; };" > %t.list
|
||||
# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t
|
||||
# RUN: llvm-readobj -dyn-symbols %t | FileCheck --check-prefix=EXE %s
|
||||
|
||||
# RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t4.script
|
||||
# RUN: echo "VERSION_2.0 { global: foo3; local: *; };" >> %t4.script
|
||||
# RUN: ld.lld --version-script %t4.script -shared %t.o %t2.so -o %t4.so
|
||||
|
@ -42,6 +37,7 @@
|
|||
# RUN: FileCheck -check-prefix=WARN2 %s
|
||||
# WARN2: duplicate symbol 'foo1' in version script
|
||||
|
||||
# RUN: echo "{ foo1; foo2; };" > %t.list
|
||||
# RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2
|
||||
# RUN: llvm-readobj %t2 > /dev/null
|
||||
|
||||
|
@ -105,36 +101,6 @@
|
|||
# DSO2-NEXT: }
|
||||
# DSO2-NEXT: ]
|
||||
|
||||
# EXE: DynamicSymbols [
|
||||
# EXE-NEXT: Symbol {
|
||||
# EXE-NEXT: Name: @
|
||||
# EXE-NEXT: Value: 0x0
|
||||
# EXE-NEXT: Size: 0
|
||||
# EXE-NEXT: Binding: Local (0x0)
|
||||
# EXE-NEXT: Type: None (0x0)
|
||||
# EXE-NEXT: Other: 0
|
||||
# EXE-NEXT: Section: Undefined (0x0)
|
||||
# EXE-NEXT: }
|
||||
# EXE-NEXT: Symbol {
|
||||
# EXE-NEXT: Name: bar@
|
||||
# EXE-NEXT: Value: 0x0
|
||||
# EXE-NEXT: Size: 0
|
||||
# EXE-NEXT: Binding: Global (0x1)
|
||||
# EXE-NEXT: Type: Function (0x2)
|
||||
# EXE-NEXT: Other: 0
|
||||
# EXE-NEXT: Section: Undefined (0x0)
|
||||
# EXE-NEXT: }
|
||||
# EXE-NEXT: Symbol {
|
||||
# EXE-NEXT: Name: foo1@
|
||||
# EXE-NEXT: Value: 0x201000
|
||||
# EXE-NEXT: Size: 0
|
||||
# EXE-NEXT: Binding: Global (0x1)
|
||||
# EXE-NEXT: Type: None (0x0)
|
||||
# EXE-NEXT: Other: 0
|
||||
# EXE-NEXT: Section: .text
|
||||
# EXE-NEXT: }
|
||||
# EXE-NEXT: ]
|
||||
|
||||
# VERDSO: DynamicSymbols [
|
||||
# VERDSO-NEXT: Symbol {
|
||||
# VERDSO-NEXT: Name: @
|
||||
|
|
Loading…
Reference in New Issue