Index: test/tools/llvm-objcopy/keep-global-symbols-mix-globalize.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/keep-global-symbols-mix-globalize.test @@ -0,0 +1,51 @@ +# RUN: yaml2obj %s > %t.o + +# Tests --keep-global-symbol when used in combination with --globalize-symbol on +# a different symbol. + +# RUN: llvm-objcopy \ +# RUN: --globalize-symbol Local1 \ +# RUN: --keep-global-symbol Local2 \ +# RUN: --globalize-symbol Weak1 \ +# RUN: --keep-global-symbol Weak2 \ +# RUN: --globalize-symbol Global1 \ +# RUN: --keep-global-symbol Global2 \ +# RUN: %t.o %t.2.o +# RUN: llvm-readobj -elf-output-style=GNU -symbols %t.2.o | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] +Symbols: + Local: + - Name: Local1 + Section: .text + - Name: Local2 + Section: .text + Weak: + - Name: Weak1 + Section: .text + - Name: Weak2 + Section: .text + Global: + - Name: Global1 + Section: .text + - Name: Global2 + Section: .text + +# CHECK: Symbol table '.symtab' contains 7 entries: +# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name +# CHECK-NEXT: 0: {{.*}} LOCAL {{.*}} +# CHECK-NEXT: 1: {{.*}} LOCAL {{.*}} Local2 +# CHECK-NEXT: 2: {{.*}} GLOBAL {{.*}} Local1 +# CHECK-NEXT: 3: {{.*}} GLOBAL {{.*}} Global1 +# CHECK-NEXT: 4: {{.*}} GLOBAL {{.*}} Global2 +# CHECK-NEXT: 5: {{.*}} GLOBAL {{.*}} Weak1 +# CHECK-NEXT: 6: {{.*}} WEAK {{.*}} Weak2 Index: test/tools/llvm-objcopy/keep-global-symbols.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/keep-global-symbols.test @@ -0,0 +1,95 @@ +# RUN: yaml2obj %s > %t.o + +# Tests that only global symbols (via -G/--keep-global-symbols) are kept via +# the several different variants of -G/--keep-global-symbol(s). +# +# Local1: Local because "-G Local1" doesn't make symbols global. +# Local2: Global because of "--globalize-symbol Local2". +# Weak1: Weak because "-G Weak1" doesn't make symbols global. +# Weak2: Global because of "--globalize-symbol Weak2". +# Weak3: Local because no -G flag covers it. +# Global1: Global because of "-G Global1". +# Global2: Global because of "--keep-global-symbol Global2". +# Global3: Global because of "--keep-global-symbols %t-globals1.txt". +# Global4: Global because of "--keep-global-symbols %t-globals2.txt". +# Global5: Local, it appears in %t-globals2.txt but only in comments and as +# part of another symbol +# Global6: Local, it appears in %t-globals2.txt but only part of another symbol +# "Global5 Global6": Global, because it appears in %t-globals2.txt, but we only +# trim leading and trailing whitespace. We don't just take the first chunk +# that looks like a symbol. + +# RUN: echo Global2 > %t-globals1.txt +# RUN: echo " Global3 " > %t-globals2.txt +# RUN: echo "Global4 # Global5" >> %t-globals2.txt +# RUN: echo " Global5 Global6 " >> %t-globals2.txt +# RUN: echo "Unknown" >> %t-globals2.txt +# RUN: echo " " >> %t-globals2.txt +# RUN: echo "# File with no symbols" > %t-globals3.txt + +# RUN: llvm-objcopy \ +# RUN: -G Global1 \ +# RUN: --keep-global-symbol Global2 \ +# RUN: --keep-global-symbols %t-globals1.txt \ +# RUN: --keep-global-symbols %t-globals2.txt \ +# RUN: -G Local1 \ +# RUN: --globalize-symbol Local2 \ +# RUN: -G Weak1 \ +# RUN: --globalize-symbol Weak2 \ +# RUN: %t.o %t.2.o +# RUN: llvm-readobj -elf-output-style=GNU -symbols %t.2.o | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] +Symbols: + Local: + - Name: Local1 + Section: .text + - Name: Local2 + Section: .text + Weak: + - Name: Weak1 + Section: .text + - Name: Weak2 + Section: .text + - Name: Weak3 + Section: .text + Global: + - Name: Global1 + Section: .text + - Name: Global2 + Section: .text + - Name: Global3 + Section: .text + - Name: Global4 + Section: .text + - Name: Global5 + Section: .text + - Name: Global6 + Section: .text + - Name: "Global5 Global6" + Section: .text + +# CHECK: Symbol table '.symtab' contains 13 entries: +# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name +# CHECK-NEXT: 0: {{.*}} LOCAL {{.*}} +# CHECK-NEXT: 1: {{.*}} LOCAL {{.*}} Local1 +# CHECK-NEXT: 2: {{.*}} LOCAL {{.*}} Global5 +# CHECK-NEXT: 3: {{.*}} LOCAL {{.*}} Global6 +# CHECK-NEXT: 4: {{.*}} LOCAL {{.*}} Weak3 +# CHECK-NEXT: 5: {{.*}} GLOBAL {{.*}} Local2 +# CHECK-NEXT: 6: {{.*}} GLOBAL {{.*}} Global1 +# CHECK-NEXT: 7: {{.*}} GLOBAL {{.*}} Global2 +# CHECK-NEXT: 8: {{.*}} GLOBAL {{.*}} Global3 +# CHECK-NEXT: 9: {{.*}} GLOBAL {{.*}} Global4 +# CHECK-NEXT: 10: {{.*}} GLOBAL {{.*}} Global5 Global6 +# CHECK-NEXT: 11: {{.*}} WEAK {{.*}} Weak1 +# CHECK-NEXT: 12: {{.*}} GLOBAL {{.*}} Weak2 Index: tools/llvm-objcopy/ObjcopyOpts.td =================================================================== --- tools/llvm-objcopy/ObjcopyOpts.td +++ tools/llvm-objcopy/ObjcopyOpts.td @@ -75,6 +75,24 @@ defm globalize_symbol : Eq<"globalize-symbol">, MetaVarName<"symbol">, HelpText<"Mark as global">; + +defm keep_global_symbol + : Eq<"keep-global-symbol">, + MetaVarName<"symbol">, + HelpText<"Convert all symbols except to local. May be repeated " + "to convert all except a set of symbols to local.">; +def G : JoinedOrSeparate<[ "-" ], "G">, Alias; + +defm keep_global_symbols + : Eq<"keep-global-symbols">, + MetaVarName<"filename">, + HelpText< + "Reads a list of symbols from and runs as if " + "--keep-global-symbol= is set for each one. " + "contains one symbol per line and may contain comments beginning " + "with '#'. Leading and trailing whitespace is stripped from each " + "line. May be repeated to read symbols from many files.">; + defm weaken_symbol : Eq<"weaken-symbol">, MetaVarName<"symbol">, HelpText<"Mark as weak">; Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -146,6 +146,7 @@ std::vector SymbolsToWeaken; std::vector SymbolsToRemove; std::vector SymbolsToKeep; + std::vector SymbolsToKeepGlobal; StringMap SectionsToRename; StringMap SymbolsToRename; bool StripAll = false; @@ -376,6 +377,20 @@ is_contained(Config.SymbolsToLocalize, Sym.Name))) Sym.Binding = STB_LOCAL; + // Note: these two globalize flags have very similar names but different + // meanings: + // + // --globalize-symbol: promote a symbol to global + // --keep-global-symbol: all symbols except for these should be made local + // + // If --globalize-symbol is specified for a given symbol, it will be + // global in the output file even if it is not included via + // --keep-global-symbol. Because of that, make sure to check + // --globalize-symbol second. + if (!Config.SymbolsToKeepGlobal.empty() && + !is_contained(Config.SymbolsToKeepGlobal, Sym.Name)) + Sym.Binding = STB_LOCAL; + if (!Config.SymbolsToGlobalize.empty() && is_contained(Config.SymbolsToGlobalize, Sym.Name)) Sym.Binding = STB_GLOBAL; @@ -688,6 +703,23 @@ executeElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB); } +static void addGlobalSymbolsFromFile(std::vector &Symbols, + StringRef Filename) { + SmallVector Lines; + auto BufOrErr = MemoryBuffer::getFile(Filename); + if (!BufOrErr) + reportError(Filename, BufOrErr.getError()); + + BufOrErr.get()->getBuffer().split(Lines, '\n'); + for (StringRef Line : Lines) { + // Ignore everything after '#', trim whitespace, and only add the symbol if + // it's not empty. + auto TrimmedLine = Line.split('#').first.trim(); + if (!TrimmedLine.empty()) + Symbols.push_back(TrimmedLine.str()); + } +} + // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. @@ -771,6 +803,10 @@ Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) Config.SymbolsToLocalize.push_back(Arg->getValue()); + for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) + Config.SymbolsToKeepGlobal.push_back(Arg->getValue()); + for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) + addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue()); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) Config.SymbolsToGlobalize.push_back(Arg->getValue()); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))