1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
//===- ELFConfig.cpp ------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "CopyConfig.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace objcopy {
namespace elf {
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:
//
// <name>=[<section>:]<value>[,<flags>]
//
// where:
// <name> - symbol name, can be empty string
// <section> - optional section name. If not given ABS symbol is created
// <value> - symbol value, can be decimal or hexadecimal number prefixed
// with 0x.
// <flags> - optional flags affecting symbol type, binding or visibility:
// The following are currently supported:
//
// global, local, weak, default, hidden, file, section, object,
// indirect-function.
//
// The following flags are ignored and provided for GNU
// compatibility only:
//
// warning, debug, constructor, indirect, synthetic,
// unique-object, before=<symbol>.
NewSymbolInfo SI;
StringRef Value;
std::tie(SI.SymbolName, Value) = FlagValue.split('=');
if (Value.empty())
return createStringError(
errc::invalid_argument,
"bad format for --add-symbol, missing '=' after '%s'",
SI.SymbolName.str().c_str());
if (Value.contains(':')) {
std::tie(SI.SectionName, Value) = Value.split(':');
if (SI.SectionName.empty() || Value.empty())
return createStringError(
errc::invalid_argument,
"bad format for --add-symbol, missing section name or symbol value");
}
SmallVector<StringRef, 6> Flags;
Value.split(Flags, ',');
if (Flags[0].getAsInteger(0, SI.Value))
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)
static_cast<Functor>(
StringSwitch<Functor>(Flags[I])
.CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
.CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
.CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
.CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
.CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
.CaseLower("protected",
[&SI] { SI.Visibility = ELF::STV_PROTECTED; })
.CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
.CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
.CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
.CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
.CaseLower("indirect-function",
[&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
.CaseLower("debug", [] {})
.CaseLower("constructor", [] {})
.CaseLower("warning", [] {})
.CaseLower("indirect", [] {})
.CaseLower("synthetic", [] {})
.CaseLower("unique-object", [] {})
.StartsWithLower("before", [] {})
.Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
if (!UnsupportedFlags.empty())
return createStringError(errc::invalid_argument,
"unsupported flag%s for --add-symbol: '%s'",
UnsupportedFlags.size() > 1 ? "s" : "",
join(UnsupportedFlags, "', '").c_str());
return SI;
}
Expected<ELFCopyConfig> parseConfig(const CopyConfig &Config) {
ELFCopyConfig ELFConfig;
if (Config.NewSymbolVisibility) {
const uint8_t Invalid = 0xff;
ELFConfig.NewSymbolVisibility =
StringSwitch<uint8_t>(*Config.NewSymbolVisibility)
.Case("default", ELF::STV_DEFAULT)
.Case("hidden", ELF::STV_HIDDEN)
.Case("internal", ELF::STV_INTERNAL)
.Case("protected", ELF::STV_PROTECTED)
.Default(Invalid);
if (ELFConfig.NewSymbolVisibility == Invalid)
return createStringError(errc::invalid_argument,
"'%s' is not a valid symbol visibility",
Config.NewSymbolVisibility->str().c_str());
}
for (StringRef Arg : Config.SymbolsToAdd) {
Expected<elf::NewSymbolInfo> NSI = parseNewSymbolInfo(
Arg,
ELFConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
if (!NSI)
return NSI.takeError();
ELFConfig.SymbolsToAdd.push_back(*NSI);
}
return ELFConfig;
}
} // end namespace elf
} // end namespace objcopy
} // end namespace llvm
|