1 //===- CopyConfig.cpp -----------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "CopyConfig.h" 11 #include "llvm-objcopy.h" 12 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" 23 #include <memory> 24 #include <string> 25 26 namespace llvm { 27 namespace objcopy { 28 29 namespace { 30 enum ObjcopyID { 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) \ 34 OBJCOPY_##ID, 35 #include "ObjcopyOpts.inc" 36 #undef OPTION 37 }; 38 39 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE; 40 #include "ObjcopyOpts.inc" 41 #undef PREFIX 42 43 static const opt::OptTable::Info ObjcopyInfoTable[] = { 44 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 45 HELPTEXT, METAVAR, VALUES) \ 46 {OBJCOPY_##PREFIX, \ 47 NAME, \ 48 HELPTEXT, \ 49 METAVAR, \ 50 OBJCOPY_##ID, \ 51 opt::Option::KIND##Class, \ 52 PARAM, \ 53 FLAGS, \ 54 OBJCOPY_##GROUP, \ 55 OBJCOPY_##ALIAS, \ 56 ALIASARGS, \ 57 VALUES}, 58 #include "ObjcopyOpts.inc" 59 #undef OPTION 60 }; 61 62 class ObjcopyOptTable : public opt::OptTable { 63 public: 64 ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {} 65 }; 66 67 enum StripID { 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) \ 71 STRIP_##ID, 72 #include "StripOpts.inc" 73 #undef OPTION 74 }; 75 76 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE; 77 #include "StripOpts.inc" 78 #undef PREFIX 79 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" 88 #undef OPTION 89 }; 90 91 class StripOptTable : public opt::OptTable { 92 public: 93 StripOptTable() : OptTable(StripInfoTable) {} 94 }; 95 96 enum SectionFlag { 97 SecNone = 0, 98 SecAlloc = 1 << 0, 99 SecLoad = 1 << 1, 100 SecNoload = 1 << 2, 101 SecReadonly = 1 << 3, 102 SecDebug = 1 << 4, 103 SecCode = 1 << 5, 104 SecData = 1 << 6, 105 SecRom = 1 << 7, 106 SecMerge = 1 << 8, 107 SecStrings = 1 << 9, 108 SecContents = 1 << 10, 109 SecShare = 1 << 11, 110 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare) 111 }; 112 113 } // namespace 114 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); 130 } 131 132 static SectionRename parseRenameSectionValue(StringRef FlagValue) { 133 if (!FlagValue.contains('=')) 134 error("Bad format for --rename-section: missing '='"); 135 136 // Initial split: ".foo" = ".bar,f1,f2,..." 137 auto Old2New = FlagValue.split('='); 138 SectionRename SR; 139 SR.OriginalName = Old2New.first; 140 141 // Flags split: ".bar" "f1" "f2" ... 142 SmallVector<StringRef, 6> NameAndFlags; 143 Old2New.second.split(NameAndFlags, ','); 144 SR.NewName = NameAndFlags[0]; 145 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, " 154 "strings."); 155 Flags |= Flag; 156 } 157 158 SR.NewFlags = 0; 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; 169 } 170 171 return SR; 172 } 173 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}}, 183 }; 184 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(); 190 } 191 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}}, 199 }; 200 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(); 206 } 207 208 static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols, 209 StringRef Filename) { 210 SmallVector<StringRef, 16> Lines; 211 auto BufOrErr = MemoryBuffer::getFile(Filename); 212 if (!BufOrErr) 213 reportError(Filename, BufOrErr.getError()); 214 215 BufOrErr.get()->getBuffer().split(Lines, '\n'); 216 for (StringRef Line : Lines) { 217 // Ignore everything after '#', trim whitespace, and only add the symbol if 218 // it's not empty. 219 auto TrimmedLine = Line.split('#').first.trim(); 220 if (!TrimmedLine.empty()) 221 Symbols.push_back(TrimmedLine.str()); 222 } 223 } 224 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 227 // exit. 228 DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) { 229 ObjcopyOptTable T; 230 unsigned MissingArgumentIndex, MissingArgumentCount; 231 llvm::opt::InputArgList InputArgs = 232 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 233 234 if (InputArgs.size() == 0) { 235 T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool"); 236 exit(1); 237 } 238 239 if (InputArgs.hasArg(OBJCOPY_help)) { 240 T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool"); 241 exit(0); 242 } 243 244 if (InputArgs.hasArg(OBJCOPY_version)) { 245 outs() << "llvm-objcopy, compatible with GNU objcopy\n"; 246 cl::PrintVersionMessage(); 247 exit(0); 248 } 249 250 SmallVector<const char *, 2> Positional; 251 252 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 253 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 254 255 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) 256 Positional.push_back(Arg->getValue()); 257 258 if (Positional.empty()) 259 error("No input file specified"); 260 261 if (Positional.size() > 2) 262 error("Too many positional arguments"); 263 264 CopyConfig Config; 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"); 271 272 if (InputArgs.hasArg(OBJCOPY_target)) { 273 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); 274 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target); 275 } else { 276 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 277 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 278 } 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); 284 } 285 if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary") 286 Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat); 287 288 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, 289 OBJCOPY_compress_debug_sections_eq)) { 290 Config.CompressionType = DebugCompressionType::Z; 291 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."); 304 } 305 } 306 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); 317 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); 324 } 325 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); 330 } 331 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()); 371 372 Config.DeterministicArchives = InputArgs.hasFlag( 373 OBJCOPY_enable_deterministic_archives, 374 OBJCOPY_disable_deterministic_archives, /*default=*/true); 375 376 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); 377 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"); 382 } 383 384 if (Config.DecompressDebugSections && !zlib::isAvailable()) 385 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress."); 386 387 DriverConfig DC; 388 DC.CopyConfigs.push_back(std::move(Config)); 389 return DC; 390 } 391 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 394 // exit. 395 DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) { 396 StripOptTable T; 397 unsigned MissingArgumentIndex, MissingArgumentCount; 398 llvm::opt::InputArgList InputArgs = 399 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 400 401 if (InputArgs.size() == 0) { 402 T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool"); 403 exit(1); 404 } 405 406 if (InputArgs.hasArg(STRIP_help)) { 407 T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool"); 408 exit(0); 409 } 410 411 if (InputArgs.hasArg(STRIP_version)) { 412 outs() << "llvm-strip, compatible with GNU strip\n"; 413 cl::PrintVersionMessage(); 414 exit(0); 415 } 416 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()); 422 423 if (Positional.empty()) 424 error("No input file specified"); 425 426 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) 427 error("Multiple input files cannot be used in combination with -o"); 428 429 CopyConfig Config; 430 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); 431 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); 436 437 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll && 438 !Config.StripAllGNU) 439 Config.StripAll = true; 440 441 for (auto Arg : InputArgs.filtered(STRIP_keep_section)) 442 Config.KeepSection.push_back(Arg->getValue()); 443 444 for (auto Arg : InputArgs.filtered(STRIP_remove_section)) 445 Config.ToRemove.push_back(Arg->getValue()); 446 447 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) 448 Config.SymbolsToKeep.push_back(Arg->getValue()); 449 450 Config.DeterministicArchives = 451 InputArgs.hasFlag(STRIP_enable_deterministic_archives, 452 STRIP_disable_deterministic_archives, /*default=*/true); 453 454 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); 455 456 DriverConfig DC; 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)); 462 } else { 463 for (const char *Filename : Positional) { 464 Config.InputFilename = Filename; 465 Config.OutputFilename = Filename; 466 DC.CopyConfigs.push_back(Config); 467 } 468 } 469 470 return DC; 471 } 472 473 } // namespace objcopy 474 } // namespace llvm 475