1 //===- CopyConfig.cpp -----------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "CopyConfig.h"
11 #include "llvm-objcopy.h"
13 #include "llvm/ADT/BitmaskEnum.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Object/ELFTypes.h"
18 #include "llvm/Option/Arg.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Support/CommandLine.h"
21 #include "llvm/Support/Compression.h"
22 #include "llvm/Support/MemoryBuffer.h"
31 OBJCOPY_INVALID
= 0, // This is not an option ID.
32 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
33 HELPTEXT, METAVAR, VALUES) \
35 #include "ObjcopyOpts.inc"
39 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
40 #include "ObjcopyOpts.inc"
43 static const opt::OptTable::Info ObjcopyInfoTable
[] = {
44 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
45 HELPTEXT, METAVAR, VALUES) \
51 opt::Option::KIND##Class, \
58 #include "ObjcopyOpts.inc"
62 class ObjcopyOptTable
: public opt::OptTable
{
64 ObjcopyOptTable() : OptTable(ObjcopyInfoTable
) {}
68 STRIP_INVALID
= 0, // This is not an option ID.
69 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
70 HELPTEXT, METAVAR, VALUES) \
72 #include "StripOpts.inc"
76 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
77 #include "StripOpts.inc"
80 static const opt::OptTable::Info StripInfoTable
[] = {
81 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
82 HELPTEXT, METAVAR, VALUES) \
83 {STRIP_##PREFIX, NAME, HELPTEXT, \
84 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
85 PARAM, FLAGS, STRIP_##GROUP, \
86 STRIP_##ALIAS, ALIASARGS, VALUES},
87 #include "StripOpts.inc"
91 class StripOptTable
: public opt::OptTable
{
93 StripOptTable() : OptTable(StripInfoTable
) {}
101 SecReadonly
= 1 << 3,
108 SecContents
= 1 << 10,
110 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare
)
115 static SectionFlag
parseSectionRenameFlag(StringRef SectionName
) {
116 return llvm::StringSwitch
<SectionFlag
>(SectionName
)
117 .Case("alloc", SectionFlag::SecAlloc
)
118 .Case("load", SectionFlag::SecLoad
)
119 .Case("noload", SectionFlag::SecNoload
)
120 .Case("readonly", SectionFlag::SecReadonly
)
121 .Case("debug", SectionFlag::SecDebug
)
122 .Case("code", SectionFlag::SecCode
)
123 .Case("data", SectionFlag::SecData
)
124 .Case("rom", SectionFlag::SecRom
)
125 .Case("merge", SectionFlag::SecMerge
)
126 .Case("strings", SectionFlag::SecStrings
)
127 .Case("contents", SectionFlag::SecContents
)
128 .Case("share", SectionFlag::SecShare
)
129 .Default(SectionFlag::SecNone
);
132 static SectionRename
parseRenameSectionValue(StringRef FlagValue
) {
133 if (!FlagValue
.contains('='))
134 error("Bad format for --rename-section: missing '='");
136 // Initial split: ".foo" = ".bar,f1,f2,..."
137 auto Old2New
= FlagValue
.split('=');
139 SR
.OriginalName
= Old2New
.first
;
141 // Flags split: ".bar" "f1" "f2" ...
142 SmallVector
<StringRef
, 6> NameAndFlags
;
143 Old2New
.second
.split(NameAndFlags
, ',');
144 SR
.NewName
= NameAndFlags
[0];
146 if (NameAndFlags
.size() > 1) {
147 SectionFlag Flags
= SectionFlag::SecNone
;
148 for (size_t I
= 1, Size
= NameAndFlags
.size(); I
< Size
; ++I
) {
149 SectionFlag Flag
= parseSectionRenameFlag(NameAndFlags
[I
]);
150 if (Flag
== SectionFlag::SecNone
)
151 error("Unrecognized section flag '" + NameAndFlags
[I
] +
152 "'. Flags supported for GNU compatibility: alloc, load, noload, "
153 "readonly, debug, code, data, rom, share, contents, merge, "
159 if (Flags
& SectionFlag::SecAlloc
)
160 *SR
.NewFlags
|= ELF::SHF_ALLOC
;
161 if (!(Flags
& SectionFlag::SecReadonly
))
162 *SR
.NewFlags
|= ELF::SHF_WRITE
;
163 if (Flags
& SectionFlag::SecCode
)
164 *SR
.NewFlags
|= ELF::SHF_EXECINSTR
;
165 if (Flags
& SectionFlag::SecMerge
)
166 *SR
.NewFlags
|= ELF::SHF_MERGE
;
167 if (Flags
& SectionFlag::SecStrings
)
168 *SR
.NewFlags
|= ELF::SHF_STRINGS
;
174 static const StringMap
<MachineInfo
> ArchMap
{
175 // Name, {EMachine, 64bit, LittleEndian}
176 {"aarch64", {ELF::EM_AARCH64
, true, true}},
177 {"arm", {ELF::EM_ARM
, false, true}},
178 {"i386", {ELF::EM_386
, false, true}},
179 {"i386:x86-64", {ELF::EM_X86_64
, true, true}},
180 {"powerpc:common64", {ELF::EM_PPC64
, true, true}},
181 {"sparc", {ELF::EM_SPARC
, false, true}},
182 {"x86-64", {ELF::EM_X86_64
, true, true}},
185 static const MachineInfo
&getMachineInfo(StringRef Arch
) {
186 auto Iter
= ArchMap
.find(Arch
);
187 if (Iter
== std::end(ArchMap
))
188 error("Invalid architecture: '" + Arch
+ "'");
189 return Iter
->getValue();
192 static void addGlobalSymbolsFromFile(std::vector
<std::string
> &Symbols
,
193 StringRef Filename
) {
194 SmallVector
<StringRef
, 16> Lines
;
195 auto BufOrErr
= MemoryBuffer::getFile(Filename
);
197 reportError(Filename
, BufOrErr
.getError());
199 BufOrErr
.get()->getBuffer().split(Lines
, '\n');
200 for (StringRef Line
: Lines
) {
201 // Ignore everything after '#', trim whitespace, and only add the symbol if
203 auto TrimmedLine
= Line
.split('#').first
.trim();
204 if (!TrimmedLine
.empty())
205 Symbols
.push_back(TrimmedLine
.str());
209 // ParseObjcopyOptions returns the config and sets the input arguments. If a
210 // help flag is set then ParseObjcopyOptions will print the help messege and
212 DriverConfig
parseObjcopyOptions(ArrayRef
<const char *> ArgsArr
) {
214 unsigned MissingArgumentIndex
, MissingArgumentCount
;
215 llvm::opt::InputArgList InputArgs
=
216 T
.ParseArgs(ArgsArr
, MissingArgumentIndex
, MissingArgumentCount
);
218 if (InputArgs
.size() == 0) {
219 T
.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
223 if (InputArgs
.hasArg(OBJCOPY_help
)) {
224 T
.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
228 if (InputArgs
.hasArg(OBJCOPY_version
)) {
229 outs() << "llvm-objcopy, compatible with GNU objcopy\n";
230 cl::PrintVersionMessage();
234 SmallVector
<const char *, 2> Positional
;
236 for (auto Arg
: InputArgs
.filtered(OBJCOPY_UNKNOWN
))
237 error("unknown argument '" + Arg
->getAsString(InputArgs
) + "'");
239 for (auto Arg
: InputArgs
.filtered(OBJCOPY_INPUT
))
240 Positional
.push_back(Arg
->getValue());
242 if (Positional
.empty())
243 error("No input file specified");
245 if (Positional
.size() > 2)
246 error("Too many positional arguments");
249 Config
.InputFilename
= Positional
[0];
250 Config
.OutputFilename
= Positional
[Positional
.size() == 1 ? 0 : 1];
251 if (InputArgs
.hasArg(OBJCOPY_target
) &&
252 (InputArgs
.hasArg(OBJCOPY_input_target
) ||
253 InputArgs
.hasArg(OBJCOPY_output_target
)))
254 error("--target cannot be used with --input-target or --output-target");
256 if (InputArgs
.hasArg(OBJCOPY_target
)) {
257 Config
.InputFormat
= InputArgs
.getLastArgValue(OBJCOPY_target
);
258 Config
.OutputFormat
= InputArgs
.getLastArgValue(OBJCOPY_target
);
260 Config
.InputFormat
= InputArgs
.getLastArgValue(OBJCOPY_input_target
);
261 Config
.OutputFormat
= InputArgs
.getLastArgValue(OBJCOPY_output_target
);
263 if (Config
.InputFormat
== "binary") {
264 auto BinaryArch
= InputArgs
.getLastArgValue(OBJCOPY_binary_architecture
);
265 if (BinaryArch
.empty())
266 error("Specified binary input without specifiying an architecture");
267 Config
.BinaryArch
= getMachineInfo(BinaryArch
);
270 if (auto Arg
= InputArgs
.getLastArg(OBJCOPY_compress_debug_sections
,
271 OBJCOPY_compress_debug_sections_eq
)) {
272 Config
.CompressionType
= DebugCompressionType::Z
;
274 if (Arg
->getOption().getID() == OBJCOPY_compress_debug_sections_eq
) {
275 Config
.CompressionType
=
276 StringSwitch
<DebugCompressionType
>(
277 InputArgs
.getLastArgValue(OBJCOPY_compress_debug_sections_eq
))
278 .Case("zlib-gnu", DebugCompressionType::GNU
)
279 .Case("zlib", DebugCompressionType::Z
)
280 .Default(DebugCompressionType::None
);
281 if (Config
.CompressionType
== DebugCompressionType::None
)
282 error("Invalid or unsupported --compress-debug-sections format: " +
283 InputArgs
.getLastArgValue(OBJCOPY_compress_debug_sections_eq
));
284 if (!zlib::isAvailable())
285 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
289 Config
.SplitDWO
= InputArgs
.getLastArgValue(OBJCOPY_split_dwo
);
290 Config
.AddGnuDebugLink
= InputArgs
.getLastArgValue(OBJCOPY_add_gnu_debuglink
);
291 Config
.SymbolsPrefix
= InputArgs
.getLastArgValue(OBJCOPY_prefix_symbols
);
293 for (auto Arg
: InputArgs
.filtered(OBJCOPY_redefine_symbol
)) {
294 if (!StringRef(Arg
->getValue()).contains('='))
295 error("Bad format for --redefine-sym");
296 auto Old2New
= StringRef(Arg
->getValue()).split('=');
297 if (!Config
.SymbolsToRename
.insert(Old2New
).second
)
298 error("Multiple redefinition of symbol " + Old2New
.first
);
301 for (auto Arg
: InputArgs
.filtered(OBJCOPY_rename_section
)) {
302 SectionRename SR
= parseRenameSectionValue(StringRef(Arg
->getValue()));
303 if (!Config
.SectionsToRename
.try_emplace(SR
.OriginalName
, SR
).second
)
304 error("Multiple renames of section " + SR
.OriginalName
);
307 for (auto Arg
: InputArgs
.filtered(OBJCOPY_remove_section
))
308 Config
.ToRemove
.push_back(Arg
->getValue());
309 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_section
))
310 Config
.KeepSection
.push_back(Arg
->getValue());
311 for (auto Arg
: InputArgs
.filtered(OBJCOPY_only_keep
))
312 Config
.OnlyKeep
.push_back(Arg
->getValue());
313 for (auto Arg
: InputArgs
.filtered(OBJCOPY_add_section
))
314 Config
.AddSection
.push_back(Arg
->getValue());
315 for (auto Arg
: InputArgs
.filtered(OBJCOPY_dump_section
))
316 Config
.DumpSection
.push_back(Arg
->getValue());
317 Config
.StripAll
= InputArgs
.hasArg(OBJCOPY_strip_all
);
318 Config
.StripAllGNU
= InputArgs
.hasArg(OBJCOPY_strip_all_gnu
);
319 Config
.StripDebug
= InputArgs
.hasArg(OBJCOPY_strip_debug
);
320 Config
.StripDWO
= InputArgs
.hasArg(OBJCOPY_strip_dwo
);
321 Config
.StripSections
= InputArgs
.hasArg(OBJCOPY_strip_sections
);
322 Config
.StripNonAlloc
= InputArgs
.hasArg(OBJCOPY_strip_non_alloc
);
323 Config
.StripUnneeded
= InputArgs
.hasArg(OBJCOPY_strip_unneeded
);
324 Config
.ExtractDWO
= InputArgs
.hasArg(OBJCOPY_extract_dwo
);
325 Config
.LocalizeHidden
= InputArgs
.hasArg(OBJCOPY_localize_hidden
);
326 Config
.Weaken
= InputArgs
.hasArg(OBJCOPY_weaken
);
327 Config
.DiscardAll
= InputArgs
.hasArg(OBJCOPY_discard_all
);
328 Config
.OnlyKeepDebug
= InputArgs
.hasArg(OBJCOPY_only_keep_debug
);
329 Config
.KeepFileSymbols
= InputArgs
.hasArg(OBJCOPY_keep_file_symbols
);
330 Config
.DecompressDebugSections
=
331 InputArgs
.hasArg(OBJCOPY_decompress_debug_sections
);
332 for (auto Arg
: InputArgs
.filtered(OBJCOPY_localize_symbol
))
333 Config
.SymbolsToLocalize
.push_back(Arg
->getValue());
334 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_global_symbol
))
335 Config
.SymbolsToKeepGlobal
.push_back(Arg
->getValue());
336 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_global_symbols
))
337 addGlobalSymbolsFromFile(Config
.SymbolsToKeepGlobal
, Arg
->getValue());
338 for (auto Arg
: InputArgs
.filtered(OBJCOPY_globalize_symbol
))
339 Config
.SymbolsToGlobalize
.push_back(Arg
->getValue());
340 for (auto Arg
: InputArgs
.filtered(OBJCOPY_weaken_symbol
))
341 Config
.SymbolsToWeaken
.push_back(Arg
->getValue());
342 for (auto Arg
: InputArgs
.filtered(OBJCOPY_strip_symbol
))
343 Config
.SymbolsToRemove
.push_back(Arg
->getValue());
344 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_symbol
))
345 Config
.SymbolsToKeep
.push_back(Arg
->getValue());
347 Config
.DeterministicArchives
= InputArgs
.hasFlag(
348 OBJCOPY_enable_deterministic_archives
,
349 OBJCOPY_disable_deterministic_archives
, /*default=*/true);
351 Config
.PreserveDates
= InputArgs
.hasArg(OBJCOPY_preserve_dates
);
353 if (Config
.DecompressDebugSections
&&
354 Config
.CompressionType
!= DebugCompressionType::None
) {
355 error("Cannot specify --compress-debug-sections at the same time as "
356 "--decompress-debug-sections at the same time");
359 if (Config
.DecompressDebugSections
&& !zlib::isAvailable())
360 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
363 DC
.CopyConfigs
.push_back(std::move(Config
));
367 // ParseStripOptions returns the config and sets the input arguments. If a
368 // help flag is set then ParseStripOptions will print the help messege and
370 DriverConfig
parseStripOptions(ArrayRef
<const char *> ArgsArr
) {
372 unsigned MissingArgumentIndex
, MissingArgumentCount
;
373 llvm::opt::InputArgList InputArgs
=
374 T
.ParseArgs(ArgsArr
, MissingArgumentIndex
, MissingArgumentCount
);
376 if (InputArgs
.size() == 0) {
377 T
.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
381 if (InputArgs
.hasArg(STRIP_help
)) {
382 T
.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
386 if (InputArgs
.hasArg(STRIP_version
)) {
387 outs() << "llvm-strip, compatible with GNU strip\n";
388 cl::PrintVersionMessage();
392 SmallVector
<const char *, 2> Positional
;
393 for (auto Arg
: InputArgs
.filtered(STRIP_UNKNOWN
))
394 error("unknown argument '" + Arg
->getAsString(InputArgs
) + "'");
395 for (auto Arg
: InputArgs
.filtered(STRIP_INPUT
))
396 Positional
.push_back(Arg
->getValue());
398 if (Positional
.empty())
399 error("No input file specified");
401 if (Positional
.size() > 1 && InputArgs
.hasArg(STRIP_output
))
402 error("Multiple input files cannot be used in combination with -o");
405 Config
.StripDebug
= InputArgs
.hasArg(STRIP_strip_debug
);
407 Config
.DiscardAll
= InputArgs
.hasArg(STRIP_discard_all
);
408 Config
.StripUnneeded
= InputArgs
.hasArg(STRIP_strip_unneeded
);
409 Config
.StripAll
= InputArgs
.hasArg(STRIP_strip_all
);
410 Config
.StripAllGNU
= InputArgs
.hasArg(STRIP_strip_all_gnu
);
412 if (!Config
.StripDebug
&& !Config
.StripUnneeded
&& !Config
.DiscardAll
&&
414 Config
.StripAll
= true;
416 for (auto Arg
: InputArgs
.filtered(STRIP_keep_section
))
417 Config
.KeepSection
.push_back(Arg
->getValue());
419 for (auto Arg
: InputArgs
.filtered(STRIP_remove_section
))
420 Config
.ToRemove
.push_back(Arg
->getValue());
422 for (auto Arg
: InputArgs
.filtered(STRIP_keep_symbol
))
423 Config
.SymbolsToKeep
.push_back(Arg
->getValue());
425 Config
.DeterministicArchives
=
426 InputArgs
.hasFlag(STRIP_enable_deterministic_archives
,
427 STRIP_disable_deterministic_archives
, /*default=*/true);
429 Config
.PreserveDates
= InputArgs
.hasArg(STRIP_preserve_dates
);
432 if (Positional
.size() == 1) {
433 Config
.InputFilename
= Positional
[0];
434 Config
.OutputFilename
=
435 InputArgs
.getLastArgValue(STRIP_output
, Positional
[0]);
436 DC
.CopyConfigs
.push_back(std::move(Config
));
438 for (const char *Filename
: Positional
) {
439 Config
.InputFilename
= Filename
;
440 Config
.OutputFilename
= Filename
;
441 DC
.CopyConfigs
.push_back(Config
);
448 } // namespace objcopy