represents a single symbol, with leading and trailing whitespace ignored, as is
anything following a '#'. Can be specified multiple times to read names from
multiple files.
+
+.. option:: --new-symbol-visibility <visibility>
+
+ Specify the visibility of the symbols automatically created when using binary
+ input or :option:`--add-symbol`. Valid options are:
+
+ - `default`
+ - `hidden`
+ - `internal`
+ - `protected`
+
+ The default is `default`.
.. option:: --output-target <format>, -O
--- /dev/null
+## Ensure that the visibility of symbols added with --add-symbol can be
+## specified with the --new-symbol-visibility switch.
+
+# RUN: yaml2obj %s -o %t.obj
+# RUN: llvm-objcopy --new-symbol-visibility protected --add-symbol symbol_protected=.text:42 \
+# RUN: --add-symbol symbol_hidden=.text:42,hidden %t.obj %t
+# RUN: llvm-readelf -s %t | FileCheck %s
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+
+# CHECK: PROTECTED {{.*}} symbol_protected
+# CHECK: HIDDEN {{.*}} symbol_hidden
--- /dev/null
+## Ensure that the visibility of the start, end and size symbols created when
+## using binary input can be specified with the --new-symbol-visibility switch.
+
+# RUN: llvm-objcopy -I binary -B i386:x86-64 %s %t.unspecified
+# RUN: llvm-readelf -s %t.unspecified | FileCheck %s --check-prefix=BINARY -DVISIBILITY=DEFAULT
+# RUN: llvm-objcopy --new-symbol-visibility default -I binary -B i386:x86-64 %s %t.default
+# RUN: llvm-readelf -s %t.default | FileCheck %s --check-prefix=BINARY -DVISIBILITY=DEFAULT
+# RUN: llvm-objcopy --new-symbol-visibility hidden -I binary -B i386:x86-64 %s %t.hidden
+# RUN: llvm-readelf -s %t.hidden | FileCheck %s --check-prefix=BINARY -DVISIBILITY=HIDDEN
+# RUN: llvm-objcopy --new-symbol-visibility protected -I binary -B i386:x86-64 %s %t.protected
+# RUN: llvm-readelf -s %t.protected | FileCheck %s --check-prefix=BINARY -DVISIBILITY=PROTECTED
+# RUN: llvm-objcopy --new-symbol-visibility internal -I binary -B i386:x86-64 %s %t.internal
+# RUN: llvm-readelf -s %t.internal | FileCheck %s --check-prefix=BINARY -DVISIBILITY=INTERNAL
+
+# BINARY: [[VISIBILITY]] {{.*}} _binary{{.*}}_start
+# BINARY-NEXT: [[VISIBILITY]] {{.*}} _binary{{.*}}_end
+# BINARY-NEXT: [[VISIBILITY]] {{.*}} _binary{{.*}}_size
+
+# RUN: not llvm-objcopy --new-symbol-visibility fluff -I binary -B i386:x86-64 %s %t.error 2>&1 \
+# RUN: | FileCheck %s --check-prefix=ERR
+
+# ERR: error: 'fluff' is not a valid symbol visibility
Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
!Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
!Config.AllocSectionsPrefix.empty() || !Config.DumpSection.empty() ||
- !Config.KeepSection.empty() || !Config.SymbolsToGlobalize.empty() ||
- !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
- !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
- !Config.SectionsToRename.empty() || !Config.SetSectionFlags.empty() ||
- !Config.SymbolsToRename.empty() || Config.ExtractDWO ||
- Config.KeepFileSymbols || Config.LocalizeHidden || Config.PreserveDates ||
- Config.StripDWO || Config.StripNonAlloc || Config.StripSections ||
- Config.Weaken || Config.DecompressDebugSections ||
+ !Config.KeepSection.empty() || Config.NewSymbolVisibility ||
+ !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
+ !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
+ !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
+ !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty() ||
+ Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden ||
+ Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc ||
+ Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
Config.DiscardMode == DiscardType::Locals ||
!Config.SymbolsToAdd.empty() || Config.EntryExpr) {
return createStringError(llvm::errc::invalid_argument,
return SFU;
}
-static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {
+static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
+ uint8_t DefaultVisibility) {
// Parse value given with --add-symbol option and create the
// new symbol if possible. The value format for --add-symbol is:
//
return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
Flags[0].str().c_str());
+ SI.Visibility = DefaultVisibility;
+
using Functor = std::function<void(void)>;
SmallVector<StringRef, 6> UnsupportedFlags;
for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
Config.BinaryArch = *MI;
}
+ if (opt::Arg *A = InputArgs.getLastArg(OBJCOPY_new_symbol_visibility)) {
+ const uint8_t Invalid = 0xff;
+ Config.NewSymbolVisibility = StringSwitch<uint8_t>(A->getValue())
+ .Case("default", ELF::STV_DEFAULT)
+ .Case("hidden", ELF::STV_HIDDEN)
+ .Case("internal", ELF::STV_INTERNAL)
+ .Case("protected", ELF::STV_PROTECTED)
+ .Default(Invalid);
+
+ if (Config.NewSymbolVisibility == Invalid)
+ return createStringError(
+ errc::invalid_argument, "'%s' is not a valid symbol visibility",
+ InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility).str().c_str());
+ }
+
Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
.Case("binary", FileFormat::Binary)
.Case("ihex", FileFormat::IHex)
Arg->getValue(), UseRegex))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {
- Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(Arg->getValue());
+ Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(
+ Arg->getValue(),
+ Config.NewSymbolVisibility.getValueOr(ELF::STV_DEFAULT));
if (!NSI)
return NSI.takeError();
Config.SymbolsToAdd.push_back(*NSI);
StringRef SymbolsPrefix;
StringRef AllocSectionsPrefix;
DiscardType DiscardMode = DiscardType::None;
+ Optional<uint8_t> NewSymbolVisibility;
// Repeated options
std::vector<StringRef> AddSection;
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out) {
- BinaryReader Reader(Config.BinaryArch, &In);
+ uint8_t NewSymbolVisibility =
+ Config.NewSymbolVisibility.getValueOr(ELF::STV_DEFAULT);
+ BinaryReader Reader(Config.BinaryArch, &In, NewSymbolVisibility);
std::unique_ptr<Object> Obj = Reader.create();
// Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
Twine Prefix = Twine("_binary_") + SanitizedFilename;
SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection,
- /*Value=*/0, STV_DEFAULT, 0, 0);
+ /*Value=*/0, NewSymbolVisibility, 0, 0);
SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection,
- /*Value=*/DataSection.Size, STV_DEFAULT, 0, 0);
+ /*Value=*/DataSection.Size, NewSymbolVisibility, 0, 0);
SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr,
- /*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0);
+ /*Value=*/DataSection.Size, NewSymbolVisibility, SHN_ABS,
+ 0);
}
std::unique_ptr<Object> BinaryELFBuilder::build() {
Reader::~Reader() {}
std::unique_ptr<Object> BinaryReader::create() const {
- return BinaryELFBuilder(MInfo.EMachine, MemBuf).build();
+ return BinaryELFBuilder(MInfo.EMachine, MemBuf, NewSymbolVisibility).build();
}
Expected<std::vector<IHexRecord>> IHexReader::parse() const {
class BinaryELFBuilder : public BasicELFBuilder {
MemoryBuffer *MemBuf;
+ uint8_t NewSymbolVisibility;
void addData(SymbolTableSection *SymTab);
public:
- BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB)
- : BasicELFBuilder(EM), MemBuf(MB) {}
+ BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB, uint8_t NewSymbolVisibility)
+ : BasicELFBuilder(EM), MemBuf(MB),
+ NewSymbolVisibility(NewSymbolVisibility) {}
std::unique_ptr<Object> build();
};
class BinaryReader : public Reader {
const MachineInfo &MInfo;
MemoryBuffer *MemBuf;
+ uint8_t NewSymbolVisibility;
public:
- BinaryReader(const MachineInfo &MI, MemoryBuffer *MB)
- : MInfo(MI), MemBuf(MB) {}
+ BinaryReader(const MachineInfo &MI, MemoryBuffer *MB,
+ const uint8_t NewSymbolVisibility)
+ : MInfo(MI), MemBuf(MB), NewSymbolVisibility(NewSymbolVisibility) {}
std::unique_ptr<Object> create() const override;
};
!Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
!Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() ||
!Config.DumpSection.empty() || !Config.KeepSection.empty() ||
- !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() ||
- !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
- !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
- !Config.SectionsToRename.empty() || !Config.SymbolsToRename.empty() ||
+ Config.NewSymbolVisibility || !Config.OnlySection.empty() ||
+ !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
+ !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
+ !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
+ !Config.SymbolsToRename.empty() ||
!Config.UnneededSymbolsToRemove.empty() ||
!Config.SetSectionFlags.empty() || !Config.ToRemove.empty() ||
Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden ||
Alias<output_target>,
HelpText<"Alias for --output-target">;
+defm new_symbol_visibility : Eq<"new-symbol-visibility", "Visibility of "
+ "symbols generated for binary input or added"
+ " with --add-symbol unless otherwise"
+ " specified. The default value is 'default'.">;
+
def compress_debug_sections : Flag<["--"], "compress-debug-sections">;
def compress_debug_sections_eq
: Joined<["--"], "compress-debug-sections=">,