Skip to content

Commit c83eefc

Browse files
committedSep 24, 2019
[llvm-objcopy] Refactor ELF-specific config out to ELFCopyConfig. NFC.
Summary: This patch splits the command-line parsing into two phases: First, parse cross-platform options and leave ELF-specific options unparsed. Second, in the ELF implementation, parse ELF-specific options and construct ELFCopyConfig. Reviewers: espindola, alexshap, rupprecht, jhenderson, jakehehrlich, MaskRay Reviewed By: alexshap, jhenderson, jakehehrlich, MaskRay Subscribers: mgorny, emaste, arichardson, jakehehrlich, MaskRay, abrachet, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67139 llvm-svn: 372712
1 parent 168b3fb commit c83eefc

File tree

7 files changed

+220
-128
lines changed

7 files changed

+220
-128
lines changed
 

‎llvm/tools/llvm-objcopy/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_llvm_tool(llvm-objcopy
2121
COFF/Object.cpp
2222
COFF/Reader.cpp
2323
COFF/Writer.cpp
24+
ELF/ELFConfig.cpp
2425
ELF/ELFObjcopy.cpp
2526
ELF/Object.cpp
2627
MachO/MachOObjcopy.cpp

‎llvm/tools/llvm-objcopy/CopyConfig.cpp

Lines changed: 5 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -177,87 +177,6 @@ parseSetSectionFlagValue(StringRef FlagValue) {
177177
return SFU;
178178
}
179179

180-
static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
181-
uint8_t DefaultVisibility) {
182-
// Parse value given with --add-symbol option and create the
183-
// new symbol if possible. The value format for --add-symbol is:
184-
//
185-
// <name>=[<section>:]<value>[,<flags>]
186-
//
187-
// where:
188-
// <name> - symbol name, can be empty string
189-
// <section> - optional section name. If not given ABS symbol is created
190-
// <value> - symbol value, can be decimal or hexadecimal number prefixed
191-
// with 0x.
192-
// <flags> - optional flags affecting symbol type, binding or visibility:
193-
// The following are currently supported:
194-
//
195-
// global, local, weak, default, hidden, file, section, object,
196-
// indirect-function.
197-
//
198-
// The following flags are ignored and provided for GNU
199-
// compatibility only:
200-
//
201-
// warning, debug, constructor, indirect, synthetic,
202-
// unique-object, before=<symbol>.
203-
NewSymbolInfo SI;
204-
StringRef Value;
205-
std::tie(SI.SymbolName, Value) = FlagValue.split('=');
206-
if (Value.empty())
207-
return createStringError(
208-
errc::invalid_argument,
209-
"bad format for --add-symbol, missing '=' after '%s'",
210-
SI.SymbolName.str().c_str());
211-
212-
if (Value.contains(':')) {
213-
std::tie(SI.SectionName, Value) = Value.split(':');
214-
if (SI.SectionName.empty() || Value.empty())
215-
return createStringError(
216-
errc::invalid_argument,
217-
"bad format for --add-symbol, missing section name or symbol value");
218-
}
219-
220-
SmallVector<StringRef, 6> Flags;
221-
Value.split(Flags, ',');
222-
if (Flags[0].getAsInteger(0, SI.Value))
223-
return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
224-
Flags[0].str().c_str());
225-
226-
SI.Visibility = DefaultVisibility;
227-
228-
using Functor = std::function<void(void)>;
229-
SmallVector<StringRef, 6> UnsupportedFlags;
230-
for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
231-
static_cast<Functor>(
232-
StringSwitch<Functor>(Flags[I])
233-
.CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
234-
.CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
235-
.CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
236-
.CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
237-
.CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
238-
.CaseLower("protected", [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
239-
.CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
240-
.CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
241-
.CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
242-
.CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
243-
.CaseLower("indirect-function",
244-
[&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
245-
.CaseLower("debug", [] {})
246-
.CaseLower("constructor", [] {})
247-
.CaseLower("warning", [] {})
248-
.CaseLower("indirect", [] {})
249-
.CaseLower("synthetic", [] {})
250-
.CaseLower("unique-object", [] {})
251-
.StartsWithLower("before", [] {})
252-
.Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
253-
if (!UnsupportedFlags.empty())
254-
return createStringError(errc::invalid_argument,
255-
"unsupported flag%s for --add-symbol: '%s'",
256-
UnsupportedFlags.size() > 1 ? "s" : "",
257-
join(UnsupportedFlags, "', '").c_str());
258-
return SI;
259-
}
260-
261180
struct TargetInfo {
262181
FileFormat Format;
263182
MachineInfo Machine;
@@ -467,20 +386,9 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
467386
.Case("ihex", FileFormat::IHex)
468387
.Default(FileFormat::Unspecified);
469388

470-
if (opt::Arg *A = InputArgs.getLastArg(OBJCOPY_new_symbol_visibility)) {
471-
const uint8_t Invalid = 0xff;
472-
Config.NewSymbolVisibility = StringSwitch<uint8_t>(A->getValue())
473-
.Case("default", ELF::STV_DEFAULT)
474-
.Case("hidden", ELF::STV_HIDDEN)
475-
.Case("internal", ELF::STV_INTERNAL)
476-
.Case("protected", ELF::STV_PROTECTED)
477-
.Default(Invalid);
478-
479-
if (Config.NewSymbolVisibility == Invalid)
480-
return createStringError(
481-
errc::invalid_argument, "'%s' is not a valid symbol visibility",
482-
InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility).str().c_str());
483-
}
389+
if (opt::Arg *A = InputArgs.getLastArg(OBJCOPY_new_symbol_visibility))
390+
Config.NewSymbolVisibility =
391+
InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);
484392

485393
Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
486394
.Case("binary", FileFormat::Binary)
@@ -694,14 +602,8 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
694602
if (Error E = addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc,
695603
Arg->getValue(), UseRegex))
696604
return std::move(E);
697-
for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {
698-
Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(
699-
Arg->getValue(),
700-
Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
701-
if (!NSI)
702-
return NSI.takeError();
703-
Config.SymbolsToAdd.push_back(*NSI);
704-
}
605+
for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
606+
Config.SymbolsToAdd.push_back(Arg->getValue());
705607

706608
Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
707609

‎llvm/tools/llvm-objcopy/CopyConfig.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
1010
#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
1111

12+
#include "ELF/ELFConfig.h"
1213
#include "llvm/ADT/ArrayRef.h"
1314
#include "llvm/ADT/BitmaskEnum.h"
1415
#include "llvm/ADT/Optional.h"
@@ -111,17 +112,11 @@ class NameMatcher {
111112
bool empty() const { return Matchers.empty(); }
112113
};
113114

114-
struct NewSymbolInfo {
115-
StringRef SymbolName;
116-
StringRef SectionName;
117-
uint64_t Value = 0;
118-
uint8_t Type = ELF::STT_NOTYPE;
119-
uint8_t Bind = ELF::STB_GLOBAL;
120-
uint8_t Visibility = ELF::STV_DEFAULT;
121-
};
122-
123115
// Configuration for copying/stripping a single file.
124116
struct CopyConfig {
117+
// Format-specific options to be initialized lazily when needed.
118+
Optional<elf::ELFCopyConfig> ELF;
119+
125120
// Main input/output options
126121
StringRef InputFilename;
127122
FileFormat InputFormat;
@@ -143,12 +138,12 @@ struct CopyConfig {
143138
StringRef SymbolsPrefix;
144139
StringRef AllocSectionsPrefix;
145140
DiscardType DiscardMode = DiscardType::None;
146-
Optional<uint8_t> NewSymbolVisibility;
141+
Optional<StringRef> NewSymbolVisibility;
147142

148143
// Repeated options
149144
std::vector<StringRef> AddSection;
150145
std::vector<StringRef> DumpSection;
151-
std::vector<NewSymbolInfo> SymbolsToAdd;
146+
std::vector<StringRef> SymbolsToAdd;
152147

153148
// Section matchers
154149
NameMatcher KeepSection;
@@ -194,6 +189,18 @@ struct CopyConfig {
194189
bool Weaken = false;
195190
bool DecompressDebugSections = false;
196191
DebugCompressionType CompressionType = DebugCompressionType::None;
192+
193+
// parseELFConfig performs ELF-specific command-line parsing. Fills `ELF` on
194+
// success or returns an Error otherwise.
195+
Error parseELFConfig() {
196+
if (!ELF) {
197+
Expected<elf::ELFCopyConfig> ELFConfig = elf::parseConfig(*this);
198+
if (!ELFConfig)
199+
return ELFConfig.takeError();
200+
ELF = *ELFConfig;
201+
}
202+
return Error::success();
203+
}
197204
};
198205

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

‎llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,
710710
Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
711711
Config.GnuDebugLinkCRC32);
712712

713-
for (const NewSymbolInfo &SI : Config.SymbolsToAdd) {
713+
for (const NewSymbolInfo &SI : Config.ELF->SymbolsToAdd) {
714714
SectionBase *Sec = Obj.findSection(SI.SectionName);
715715
uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;
716716
Obj.SymbolTable->addSymbol(
@@ -746,7 +746,7 @@ Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
746746
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
747747
Buffer &Out) {
748748
uint8_t NewSymbolVisibility =
749-
Config.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
749+
Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
750750
BinaryReader Reader(&In, NewSymbolVisibility);
751751
std::unique_ptr<Object> Obj = Reader.create();
752752

0 commit comments

Comments
 (0)