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 const StringMap<MachineInfo> OutputFormatMap{
193 // Name, {EMachine, 64bit, LittleEndian}
194 {"elf32-i386", {ELF::EM_386, false, true}},
195 {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
196 {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
197 {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
198 {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
201 static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
202 auto Iter = OutputFormatMap.find(Format);
203 if (Iter == std::end(OutputFormatMap))
204 error("Invalid output format: '" + Format + "'");
205 return Iter->getValue();
208 static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
209 StringRef Filename) {
210 SmallVector<StringRef, 16> Lines;
211 auto BufOrErr = MemoryBuffer::getFile(Filename);
213 reportError(Filename, BufOrErr.getError());
215 BufOrErr.get()->getBuffer().split(Lines, '\n');
216 for (StringRef Line : Lines) {
217 // Ignore everything after '#', trim whitespace, and only add the symbol if
219 auto TrimmedLine = Line.split('#').first.trim();
220 if (!TrimmedLine.empty())
221 Symbols.push_back(TrimmedLine.str());
225 // ParseObjcopyOptions returns the config and sets the input arguments. If a
226 // help flag is set then ParseObjcopyOptions will print the help messege and
228 DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
230 unsigned MissingArgumentIndex, MissingArgumentCount;
231 llvm::opt::InputArgList InputArgs =
232 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
234 if (InputArgs.size() == 0) {
235 T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
239 if (InputArgs.hasArg(OBJCOPY_help)) {
240 T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
244 if (InputArgs.hasArg(OBJCOPY_version)) {
245 outs() << "llvm-objcopy, compatible with GNU objcopy\n";
246 cl::PrintVersionMessage();
250 SmallVector<const char *, 2> Positional;
252 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
253 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
255 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
256 Positional.push_back(Arg->getValue());
258 if (Positional.empty())
259 error("No input file specified");
261 if (Positional.size() > 2)
262 error("Too many positional arguments");
265 Config.InputFilename = Positional[0];
266 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
267 if (InputArgs.hasArg(OBJCOPY_target) &&
268 (InputArgs.hasArg(OBJCOPY_input_target) ||
269 InputArgs.hasArg(OBJCOPY_output_target)))
270 error("--target cannot be used with --input-target or --output-target");
272 if (InputArgs.hasArg(OBJCOPY_target)) {
273 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
274 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
276 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
277 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
279 if (Config.InputFormat == "binary") {
280 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
281 if (BinaryArch.empty())
282 error("Specified binary input without specifiying an architecture");
283 Config.BinaryArch = getMachineInfo(BinaryArch);
285 if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
286 Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
288 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
289 OBJCOPY_compress_debug_sections_eq)) {
290 Config.CompressionType = DebugCompressionType::Z;
292 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
293 Config.CompressionType =
294 StringSwitch<DebugCompressionType>(
295 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
296 .Case("zlib-gnu", DebugCompressionType::GNU)
297 .Case("zlib", DebugCompressionType::Z)
298 .Default(DebugCompressionType::None);
299 if (Config.CompressionType == DebugCompressionType::None)
300 error("Invalid or unsupported --compress-debug-sections format: " +
301 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
302 if (!zlib::isAvailable())
303 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
307 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
308 Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
309 if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
310 Config.BuildIdLinkInput =
311 InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
312 if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
313 Config.BuildIdLinkOutput =
314 InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
315 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
316 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
318 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
319 if (!StringRef(Arg->getValue()).contains('='))
320 error("Bad format for --redefine-sym");
321 auto Old2New = StringRef(Arg->getValue()).split('=');
322 if (!Config.SymbolsToRename.insert(Old2New).second)
323 error("Multiple redefinition of symbol " + Old2New.first);
326 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
327 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
328 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
329 error("Multiple renames of section " + SR.OriginalName);
332 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
333 Config.ToRemove.push_back(Arg->getValue());
334 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
335 Config.KeepSection.push_back(Arg->getValue());
336 for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
337 Config.OnlySection.push_back(Arg->getValue());
338 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
339 Config.AddSection.push_back(Arg->getValue());
340 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
341 Config.DumpSection.push_back(Arg->getValue());
342 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
343 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
344 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
345 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
346 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
347 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
348 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
349 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
350 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
351 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
352 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
353 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
354 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
355 Config.DecompressDebugSections =
356 InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
357 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
358 Config.SymbolsToLocalize.push_back(Arg->getValue());
359 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
360 Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
361 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
362 addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
363 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
364 Config.SymbolsToGlobalize.push_back(Arg->getValue());
365 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
366 Config.SymbolsToWeaken.push_back(Arg->getValue());
367 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
368 Config.SymbolsToRemove.push_back(Arg->getValue());
369 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
370 Config.SymbolsToKeep.push_back(Arg->getValue());
372 Config.DeterministicArchives = InputArgs.hasFlag(
373 OBJCOPY_enable_deterministic_archives,
374 OBJCOPY_disable_deterministic_archives, /*default=*/true);
376 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
378 if (Config.DecompressDebugSections &&
379 Config.CompressionType != DebugCompressionType::None) {
380 error("Cannot specify --compress-debug-sections at the same time as "
381 "--decompress-debug-sections at the same time");
384 if (Config.DecompressDebugSections && !zlib::isAvailable())
385 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
388 DC.CopyConfigs.push_back(std::move(Config));
392 // ParseStripOptions returns the config and sets the input arguments. If a
393 // help flag is set then ParseStripOptions will print the help messege and
395 DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
397 unsigned MissingArgumentIndex, MissingArgumentCount;
398 llvm::opt::InputArgList InputArgs =
399 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
401 if (InputArgs.size() == 0) {
402 T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
406 if (InputArgs.hasArg(STRIP_help)) {
407 T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
411 if (InputArgs.hasArg(STRIP_version)) {
412 outs() << "llvm-strip, compatible with GNU strip\n";
413 cl::PrintVersionMessage();
417 SmallVector<const char *, 2> Positional;
418 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
419 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
420 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
421 Positional.push_back(Arg->getValue());
423 if (Positional.empty())
424 error("No input file specified");
426 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
427 error("Multiple input files cannot be used in combination with -o");
430 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
432 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
433 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
434 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
435 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
437 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll &&
439 Config.StripAll = true;
441 for (auto Arg : InputArgs.filtered(STRIP_keep_section))
442 Config.KeepSection.push_back(Arg->getValue());
444 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
445 Config.ToRemove.push_back(Arg->getValue());
447 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
448 Config.SymbolsToKeep.push_back(Arg->getValue());
450 Config.DeterministicArchives =
451 InputArgs.hasFlag(STRIP_enable_deterministic_archives,
452 STRIP_disable_deterministic_archives, /*default=*/true);
454 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
457 if (Positional.size() == 1) {
458 Config.InputFilename = Positional[0];
459 Config.OutputFilename =
460 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
461 DC.CopyConfigs.push_back(std::move(Config));
463 for (const char *Filename : Positional) {
464 Config.InputFilename = Filename;
465 Config.OutputFilename = Filename;
466 DC.CopyConfigs.push_back(Config);
473 } // namespace objcopy