[llvm] Add llvm-objcopy option --set-visibility-sym (PR #80872)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 6 08:53:20 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-binary-utilities

Author: Ilia Kuklin (kuilpd)

<details>
<summary>Changes</summary>

Add an option to manually set the visibility of symbols.

There is already an option to set the visibility of newly added symbols via --add-symbol and --new-symbol-visibility. This option will allow to change the visibility of already existing symbols.

---
Full diff: https://github.com/llvm/llvm-project/pull/80872.diff


5 Files Affected:

- (modified) llvm/include/llvm/ObjCopy/ELF/ELFConfig.h (+4) 
- (modified) llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp (+3) 
- (added) llvm/test/tools/llvm-objcopy/ELF/set-visibility.test (+139) 
- (modified) llvm/tools/llvm-objcopy/ObjcopyOptions.cpp (+43) 
- (modified) llvm/tools/llvm-objcopy/ObjcopyOpts.td (+11) 


``````````diff
diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
index d77cb69b159db..b3efa3205e376 100644
--- a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
+++ b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_OBJCOPY_ELF_ELFCONFIG_H
 #define LLVM_OBJCOPY_ELF_ELFCONFIG_H
 
+#include "llvm/ObjCopy/CommonConfig.h"
 #include "llvm/Object/ELFTypes.h"
 
 namespace llvm {
@@ -18,6 +19,9 @@ namespace objcopy {
 struct ELFConfig {
   uint8_t NewSymbolVisibility = (uint8_t)ELF::STV_DEFAULT;
 
+  NameMatcher SymbolsToSetVisibility;
+  uint8_t SetVisibilityType = ELF::STV_DEFAULT;
+
   // ELF entry point address expression. The input parameter is an entry point
   // address in the input ELF file. The entry address in the output file is
   // calculated with EntryExpr(input_address), when either --set-start or
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index b6d77d17bae36..b768b7c5d05d7 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -290,6 +290,9 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config,
     return Error::success();
 
   Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
+    if (ELFConfig.SymbolsToSetVisibility.matches(Sym.Name) &&
+        Sym.getShndx() != SHN_UNDEF)
+      Sym.Visibility = ELFConfig.SetVisibilityType;
     // Common and undefined symbols don't make sense as local symbols, and can
     // even cause crashes if we localize those, so skip them.
     if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-visibility.test b/llvm/test/tools/llvm-objcopy/ELF/set-visibility.test
new file mode 100644
index 0000000000000..bc1c92021c4fe
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/set-visibility.test
@@ -0,0 +1,139 @@
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '.*' > %t.symbols.regex
+
+# RUN: cp %t.o %t0.o
+# RUN: llvm-objcopy %t0.o --set-visibility-syms=%t.symbols.regex=default --regex
+# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=DEF
+# DEF-DAG: LOCAL  DEFAULT     1 default_local
+# DEF-DAG: LOCAL  DEFAULT     1 internal_local
+# DEF-DAG: LOCAL  DEFAULT     1 hidden_local
+# DEF-DAG: LOCAL  DEFAULT     1 protected_local
+# DEF-DAG: GLOBAL DEFAULT     1 default_global
+# DEF-DAG: WEAK   DEFAULT     1 default_weak
+# DEF-DAG: GLOBAL DEFAULT     1 internal_global
+# DEF-DAG: WEAK   DEFAULT     1 internal_weak
+# DEF-DAG: GLOBAL DEFAULT     1 hidden_global
+# DEF-DAG: WEAK   DEFAULT     1 hidden_weak
+# DEF-DAG: GLOBAL DEFAULT     1 protected_global
+# DEF-DAG: WEAK   DEFAULT     1 protected_weak
+
+# RUN: cp %t.o %t0.o
+# RUN: llvm-objcopy %t0.o --set-visibility-syms=%t.symbols.regex=hidden --regex
+# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=HID
+# HID-DAG: LOCAL  HIDDEN      1 default_local
+# HID-DAG: LOCAL  HIDDEN      1 internal_local
+# HID-DAG: LOCAL  HIDDEN      1 hidden_local
+# HID-DAG: LOCAL  HIDDEN      1 protected_local
+# HID-DAG: GLOBAL HIDDEN      1 default_global
+# HID-DAG: WEAK   HIDDEN      1 default_weak
+# HID-DAG: GLOBAL HIDDEN      1 internal_global
+# HID-DAG: WEAK   HIDDEN      1 internal_weak
+# HID-DAG: GLOBAL HIDDEN      1 hidden_global
+# HID-DAG: WEAK   HIDDEN      1 hidden_weak
+# HID-DAG: GLOBAL HIDDEN      1 protected_global
+# HID-DAG: WEAK   HIDDEN      1 protected_weak
+
+# RUN: cp %t.o %t0.o
+# RUN: llvm-objcopy %t0.o --set-visibility-syms=%t.symbols.regex=protected --regex
+# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=PRO
+# PRO-DAG: LOCAL  PROTECTED   1 default_local
+# PRO-DAG: LOCAL  PROTECTED   1 internal_local
+# PRO-DAG: LOCAL  PROTECTED   1 hidden_local
+# PRO-DAG: LOCAL  PROTECTED   1 protected_local
+# PRO-DAG: GLOBAL PROTECTED   1 default_global
+# PRO-DAG: WEAK   PROTECTED   1 default_weak
+# PRO-DAG: GLOBAL PROTECTED   1 internal_global
+# PRO-DAG: WEAK   PROTECTED   1 internal_weak
+# PRO-DAG: GLOBAL PROTECTED   1 hidden_global
+# PRO-DAG: WEAK   PROTECTED   1 hidden_weak
+# PRO-DAG: GLOBAL PROTECTED   1 protected_global
+# PRO-DAG: WEAK   PROTECTED   1 protected_weak
+
+# RUN: cp %t.o %t0.o
+# RUN: llvm-objcopy %t0.o --set-visibility-syms=%t.symbols.regex=internal --regex
+# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=INT
+# INT-DAG: LOCAL  INTERNAL    1 default_local
+# INT-DAG: LOCAL  INTERNAL    1 internal_local
+# INT-DAG: LOCAL  INTERNAL    1 hidden_local
+# INT-DAG: LOCAL  INTERNAL    1 protected_local
+# INT-DAG: GLOBAL INTERNAL    1 default_global
+# INT-DAG: WEAK   INTERNAL    1 default_weak
+# INT-DAG: GLOBAL INTERNAL    1 internal_global
+# INT-DAG: WEAK   INTERNAL    1 internal_weak
+# INT-DAG: GLOBAL INTERNAL    1 hidden_global
+# INT-DAG: WEAK   INTERNAL    1 hidden_weak
+# INT-DAG: GLOBAL INTERNAL    1 protected_global
+# INT-DAG: WEAK   INTERNAL    1 protected_weak
+
+# RUN: cp %t.o %t0.o
+# RUN: llvm-objcopy %t0.o --set-visibility-sym=hidden_global=default
+# RUN: llvm-objcopy %t0.o --set-visibility-sym=default_global=hidden
+# RUN: llvm-objcopy %t0.o --set-visibility-sym=default_local=protected
+# RUN: llvm-objcopy %t0.o --set-visibility-sym=protected_global=internal
+# RUN: llvm-readelf -s %t0.o | FileCheck %s --check-prefix=SYM
+# SYM-DAG: LOCAL  PROTECTED   1 default_local
+# SYM-DAG: GLOBAL HIDDEN      1 default_global
+# SYM-DAG: GLOBAL DEFAULT     1 hidden_global
+# SYM-DAG: GLOBAL INTERNAL    1 protected_global
+
+!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:
+  - Name:    default_local
+    Section: .text
+    Binding:  STB_LOCAL
+  - Name:    default_global
+    Section: .text
+    Binding:  STB_GLOBAL
+  - Name:    default_weak
+    Section: .text
+    Binding:  STB_WEAK
+  - Name:    internal_local
+    Section: .text
+    Binding:  STB_LOCAL
+    Other:    [ STV_INTERNAL ]
+  - Name:    internal_global
+    Section: .text
+    Binding:  STB_GLOBAL
+    Other:    [ STV_INTERNAL ]
+  - Name:    internal_weak
+    Section: .text
+    Binding:  STB_WEAK
+    Other:    [ STV_INTERNAL ]
+  - Name:    hidden_local
+    Section: .text
+    Binding:  STB_LOCAL
+    Other:    [ STV_HIDDEN ]
+  - Name:    hidden_global
+    Section: .text
+    Binding:  STB_GLOBAL
+    Other:    [ STV_HIDDEN ]
+  - Name:    hidden_weak
+    Section: .text
+    Binding:  STB_WEAK
+    Other:    [ STV_HIDDEN ]
+  - Name:    protected_local
+    Section: .text
+    Binding:  STB_LOCAL
+    Other:    [ STV_PROTECTED ]
+  - Name:    protected_global
+    Section: .text
+    Binding:  STB_GLOBAL
+    Other:    [ STV_PROTECTED ]
+  - Name:    protected_weak
+    Section: .text
+    Binding:  STB_WEAK
+    Other:    [ STV_PROTECTED ]
+  - Name:    ignored_name
+    Section: .text
+    Binding:  STB_GLOBAL
+    Other:    [ STV_INTERNAL ]
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index f15307181fad6..9fb7d3997039e 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -254,6 +254,21 @@ parseSetSectionFlagValue(StringRef FlagValue) {
   return SFU;
 }
 
+static Expected<uint8_t> parseVisibilityType(StringRef VisType) {
+  const uint8_t Invalid = 0xff;
+  uint8_t type = StringSwitch<uint8_t>(VisType)
+                     .Case("default", ELF::STV_DEFAULT)
+                     .Case("hidden", ELF::STV_HIDDEN)
+                     .Case("internal", ELF::STV_INTERNAL)
+                     .Case("protected", ELF::STV_PROTECTED)
+                     .Default(Invalid);
+  if (type == Invalid)
+    return createStringError(errc::invalid_argument,
+                             "'%s' is not a valid symbol visibility",
+                             VisType.str().c_str());
+  return type;
+}
+
 namespace {
 struct TargetInfo {
   FileFormat Format;
@@ -962,6 +977,34 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
 
     Config.SymbolsToAdd.push_back(*SymInfo);
   }
+  for (auto *Arg : InputArgs.filtered(OBJCOPY_set_visibility_sym)) {
+    if (!StringRef(Arg->getValue()).contains('='))
+      return createStringError(errc::invalid_argument,
+                               "bad format for --set-visibility-sym");
+    auto SymAndVis = StringRef(Arg->getValue()).split('=');
+    Expected<uint8_t> Type = parseVisibilityType(SymAndVis.second);
+    if (!Type)
+      return Type.takeError();
+    ELFConfig.SetVisibilityType = Type.get();
+    if (Error E =
+            ELFConfig.SymbolsToSetVisibility.addMatcher(NameOrPattern::create(
+                SymAndVis.first, SymbolMatchStyle, ErrorCallback)))
+      return std::move(E);
+  }
+  for (auto *Arg : InputArgs.filtered(OBJCOPY_set_visibility_syms)) {
+    if (!StringRef(Arg->getValue()).contains('='))
+      return createStringError(errc::invalid_argument,
+                               "bad format for --set-visibility-syms");
+    auto FileAndVis = StringRef(Arg->getValue()).split('=');
+    Expected<uint8_t> Type = parseVisibilityType(FileAndVis.second);
+    if (!Type)
+      return Type.takeError();
+    ELFConfig.SetVisibilityType = Type.get();
+    if (Error E = addSymbolsFromFile(ELFConfig.SymbolsToSetVisibility, DC.Alloc,
+                                     FileAndVis.first, SymbolMatchStyle,
+                                     ErrorCallback))
+      return std::move(E);
+  }
 
   ELFConfig.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
 
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index ead8cd28d3877..d872316df5190 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -93,6 +93,17 @@ defm set_section_type
          "Set the type of section <section> to the integer <type>">,
       MetaVarName<"section=type">;
 
+defm set_visibility_sym
+    : Eq<"set-visibility-sym",
+         "Change the visibility of a symbol to the specified type">,
+      MetaVarName<"symbol=visibility_type">;
+defm set_visibility_syms
+    : Eq<"set-visibility-syms",
+         "Reads a list of symbols from <filename> and changes their "
+         "visibility to the specified type. Visibility types: default, "
+         "internal, hidden, protected">,
+      MetaVarName<"filename=visibility_type">;
+
 def S : Flag<["-"], "S">,
         Alias<strip_all>,
         HelpText<"Alias for --strip-all">;

``````````

</details>


https://github.com/llvm/llvm-project/pull/80872


More information about the llvm-commits mailing list