1 //===- llvm-objcopy.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 "llvm-objcopy.h" 11 #include "Object.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/Twine.h" 15 #include "llvm/BinaryFormat/ELF.h" 16 #include "llvm/Object/Binary.h" 17 #include "llvm/Object/ELFObjectFile.h" 18 #include "llvm/Object/ELFTypes.h" 19 #include "llvm/Object/Error.h" 20 #include "llvm/Option/Arg.h" 21 #include "llvm/Option/ArgList.h" 22 #include "llvm/Option/Option.h" 23 #include "llvm/Support/Casting.h" 24 #include "llvm/Support/CommandLine.h" 25 #include "llvm/Support/Compiler.h" 26 #include "llvm/Support/Error.h" 27 #include "llvm/Support/ErrorHandling.h" 28 #include "llvm/Support/ErrorOr.h" 29 #include "llvm/Support/FileOutputBuffer.h" 30 #include "llvm/Support/InitLLVM.h" 31 #include "llvm/Support/raw_ostream.h" 32 #include <algorithm> 33 #include <cassert> 34 #include <cstdlib> 35 #include <functional> 36 #include <iterator> 37 #include <memory> 38 #include <string> 39 #include <system_error> 40 #include <utility> 41 42 using namespace llvm; 43 using namespace object; 44 using namespace ELF; 45 46 namespace { 47 48 enum ID { 49 OBJCOPY_INVALID = 0, // This is not an option ID. 50 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 51 HELPTEXT, METAVAR, VALUES) \ 52 OBJCOPY_##ID, 53 #include "Opts.inc" 54 #undef OPTION 55 }; 56 57 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 58 #include "Opts.inc" 59 #undef PREFIX 60 61 static const opt::OptTable::Info ObjcopyInfoTable[] = { 62 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 63 HELPTEXT, METAVAR, VALUES) \ 64 {PREFIX, NAME, HELPTEXT, \ 65 METAVAR, OBJCOPY_##ID, opt::Option::KIND##Class, \ 66 PARAM, FLAGS, OBJCOPY_##GROUP, \ 67 OBJCOPY_##ALIAS, ALIASARGS, VALUES}, 68 #include "Opts.inc" 69 #undef OPTION 70 }; 71 72 class ObjcopyOptTable : public opt::OptTable { 73 public: 74 ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {} 75 }; 76 77 } // namespace 78 79 // The name this program was invoked as. 80 static StringRef ToolName; 81 82 namespace llvm { 83 84 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 85 errs() << ToolName << ": " << Message << ".\n"; 86 errs().flush(); 87 exit(1); 88 } 89 90 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 91 assert(EC); 92 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; 93 exit(1); 94 } 95 96 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 97 assert(E); 98 std::string Buf; 99 raw_string_ostream OS(Buf); 100 logAllUnhandledErrors(std::move(E), OS, ""); 101 OS.flush(); 102 errs() << ToolName << ": '" << File << "': " << Buf; 103 exit(1); 104 } 105 106 } // end namespace llvm 107 108 struct CopyConfig { 109 StringRef OutputFilename; 110 StringRef InputFilename; 111 StringRef OutputFormat; 112 StringRef InputFormat; 113 StringRef BinaryArch; 114 115 StringRef SplitDWO; 116 StringRef AddGnuDebugLink; 117 std::vector<StringRef> ToRemove; 118 std::vector<StringRef> Keep; 119 std::vector<StringRef> OnlyKeep; 120 std::vector<StringRef> AddSection; 121 std::vector<StringRef> SymbolsToLocalize; 122 StringMap<StringRef> SymbolsToRename; 123 bool StripAll; 124 bool StripAllGNU; 125 bool StripDebug; 126 bool StripSections; 127 bool StripNonAlloc; 128 bool StripDWO; 129 bool ExtractDWO; 130 bool LocalizeHidden; 131 }; 132 133 using SectionPred = std::function<bool(const SectionBase &Sec)>; 134 135 bool IsDWOSection(const SectionBase &Sec) { return Sec.Name.endswith(".dwo"); } 136 137 bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { 138 // We can't remove the section header string table. 139 if (&Sec == Obj.SectionNames) 140 return false; 141 // Short of keeping the string table we want to keep everything that is a DWO 142 // section and remove everything else. 143 return !IsDWOSection(Sec); 144 } 145 146 std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config, Object &Obj, 147 StringRef File, ElfType OutputElfType) { 148 if (Config.OutputFormat == "binary") { 149 return llvm::make_unique<BinaryWriter>(File, Obj); 150 } 151 // Depending on the initial ELFT and OutputFormat we need a different Writer. 152 switch (OutputElfType) { 153 case ELFT_ELF32LE: 154 return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj, 155 !Config.StripSections); 156 case ELFT_ELF64LE: 157 return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj, 158 !Config.StripSections); 159 case ELFT_ELF32BE: 160 return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj, 161 !Config.StripSections); 162 case ELFT_ELF64BE: 163 return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj, 164 !Config.StripSections); 165 } 166 llvm_unreachable("Invalid output format"); 167 } 168 169 void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader, 170 StringRef File, ElfType OutputElfType) { 171 auto DWOFile = Reader.create(); 172 DWOFile->removeSections( 173 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); }); 174 auto Writer = CreateWriter(Config, *DWOFile, File, OutputElfType); 175 Writer->finalize(); 176 Writer->write(); 177 } 178 179 // This function handles the high level operations of GNU objcopy including 180 // handling command line options. It's important to outline certain properties 181 // we expect to hold of the command line operations. Any operation that "keeps" 182 // should keep regardless of a remove. Additionally any removal should respect 183 // any previous removals. Lastly whether or not something is removed shouldn't 184 // depend a) on the order the options occur in or b) on some opaque priority 185 // system. The only priority is that keeps/copies overrule removes. 186 void HandleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader, 187 ElfType OutputElfType) { 188 189 if (!Config.SplitDWO.empty()) { 190 SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); 191 } 192 193 SectionPred RemovePred = [](const SectionBase &) { return false; }; 194 195 // Removes: 196 if (!Config.ToRemove.empty()) { 197 RemovePred = [&Config](const SectionBase &Sec) { 198 return std::find(std::begin(Config.ToRemove), std::end(Config.ToRemove), 199 Sec.Name) != std::end(Config.ToRemove); 200 }; 201 } 202 203 if (Config.StripDWO || !Config.SplitDWO.empty()) 204 RemovePred = [RemovePred](const SectionBase &Sec) { 205 return IsDWOSection(Sec) || RemovePred(Sec); 206 }; 207 208 if (Config.ExtractDWO) 209 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 210 return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 211 }; 212 213 if (Config.StripAllGNU) 214 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 215 if (RemovePred(Sec)) 216 return true; 217 if ((Sec.Flags & SHF_ALLOC) != 0) 218 return false; 219 if (&Sec == Obj.SectionNames) 220 return false; 221 switch (Sec.Type) { 222 case SHT_SYMTAB: 223 case SHT_REL: 224 case SHT_RELA: 225 case SHT_STRTAB: 226 return true; 227 } 228 return Sec.Name.startswith(".debug"); 229 }; 230 231 if (Config.StripSections) { 232 RemovePred = [RemovePred](const SectionBase &Sec) { 233 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 234 }; 235 } 236 237 if (Config.StripDebug) { 238 RemovePred = [RemovePred](const SectionBase &Sec) { 239 return RemovePred(Sec) || Sec.Name.startswith(".debug"); 240 }; 241 } 242 243 if (Config.StripNonAlloc) 244 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 245 if (RemovePred(Sec)) 246 return true; 247 if (&Sec == Obj.SectionNames) 248 return false; 249 return (Sec.Flags & SHF_ALLOC) == 0; 250 }; 251 252 if (Config.StripAll) 253 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 254 if (RemovePred(Sec)) 255 return true; 256 if (&Sec == Obj.SectionNames) 257 return false; 258 if (Sec.Name.startswith(".gnu.warning")) 259 return false; 260 return (Sec.Flags & SHF_ALLOC) == 0; 261 }; 262 263 // Explicit copies: 264 if (!Config.OnlyKeep.empty()) { 265 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 266 // Explicitly keep these sections regardless of previous removes. 267 if (std::find(std::begin(Config.OnlyKeep), std::end(Config.OnlyKeep), 268 Sec.Name) != std::end(Config.OnlyKeep)) 269 return false; 270 271 // Allow all implicit removes. 272 if (RemovePred(Sec)) 273 return true; 274 275 // Keep special sections. 276 if (Obj.SectionNames == &Sec) 277 return false; 278 if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec) 279 return false; 280 281 // Remove everything else. 282 return true; 283 }; 284 } 285 286 if (!Config.Keep.empty()) { 287 RemovePred = [Config, RemovePred](const SectionBase &Sec) { 288 // Explicitly keep these sections regardless of previous removes. 289 if (std::find(std::begin(Config.Keep), std::end(Config.Keep), Sec.Name) != 290 std::end(Config.Keep)) 291 return false; 292 // Otherwise defer to RemovePred. 293 return RemovePred(Sec); 294 }; 295 } 296 297 Obj.removeSections(RemovePred); 298 299 if (!Config.AddSection.empty()) { 300 for (const auto &Flag : Config.AddSection) { 301 auto SecPair = Flag.split("="); 302 auto SecName = SecPair.first; 303 auto File = SecPair.second; 304 auto BufOrErr = MemoryBuffer::getFile(File); 305 if (!BufOrErr) 306 reportError(File, BufOrErr.getError()); 307 auto Buf = std::move(*BufOrErr); 308 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 309 auto BufSize = Buf->getBufferSize(); 310 Obj.addSection<OwnedDataSection>(SecName, 311 ArrayRef<uint8_t>(BufPtr, BufSize)); 312 } 313 } 314 315 if (!Config.AddGnuDebugLink.empty()) 316 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); 317 318 if (Obj.SymbolTable) { 319 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 320 if ((Config.LocalizeHidden && 321 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 322 (!Config.SymbolsToLocalize.empty() && 323 std::find(std::begin(Config.SymbolsToLocalize), 324 std::end(Config.SymbolsToLocalize), 325 Sym.Name) != std::end(Config.SymbolsToLocalize))) 326 Sym.Binding = STB_LOCAL; 327 328 const auto I = Config.SymbolsToRename.find(Sym.Name); 329 if (I != Config.SymbolsToRename.end()) 330 Sym.Name = I->getValue(); 331 }); 332 } 333 } 334 335 std::unique_ptr<Reader> CreateReader(StringRef InputFilename, 336 ElfType &OutputElfType) { 337 // Right now we can only read ELF files so there's only one reader; 338 auto Out = llvm::make_unique<ELFReader>(InputFilename); 339 // We need to set the default ElfType for output. 340 OutputElfType = Out->getElfType(); 341 return std::move(Out); 342 } 343 344 void ExecuteElfObjcopy(const CopyConfig &Config) { 345 ElfType OutputElfType; 346 auto Reader = CreateReader(Config.InputFilename, OutputElfType); 347 auto Obj = Reader->create(); 348 auto Writer = 349 CreateWriter(Config, *Obj, Config.OutputFilename, OutputElfType); 350 HandleArgs(Config, *Obj, *Reader, OutputElfType); 351 Writer->finalize(); 352 Writer->write(); 353 } 354 355 // ParseObjcopyOptions returns the config and sets the input arguments. If a 356 // help flag is set then ParseObjcopyOptions will print the help messege and 357 // exit. 358 CopyConfig ParseObjcopyOptions(ArrayRef<const char *> ArgsArr) { 359 ObjcopyOptTable T; 360 unsigned MissingArgumentIndex, MissingArgumentCount; 361 llvm::opt::InputArgList InputArgs = 362 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 363 364 if (InputArgs.size() == 0 || InputArgs.hasArg(OBJCOPY_help)) { 365 T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); 366 exit(0); 367 } 368 369 SmallVector<const char *, 2> Positional; 370 371 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 372 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 373 374 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) 375 Positional.push_back(Arg->getValue()); 376 377 if (Positional.empty()) 378 error("No input file specified"); 379 380 if (Positional.size() > 2) 381 error("Too many positional arguments"); 382 383 CopyConfig Config; 384 Config.InputFilename = Positional[0]; 385 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; 386 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 387 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 388 Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); 389 390 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); 391 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); 392 393 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { 394 if (!StringRef(Arg->getValue()).contains('=')) 395 error("Bad format for --redefine-sym"); 396 auto Old2New = StringRef(Arg->getValue()).split('='); 397 if (!Config.SymbolsToRename.insert(Old2New).second) 398 error("Multiple redefinition of symbol " + Old2New.first); 399 } 400 401 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) 402 Config.ToRemove.push_back(Arg->getValue()); 403 for (auto Arg : InputArgs.filtered(OBJCOPY_keep)) 404 Config.Keep.push_back(Arg->getValue()); 405 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep)) 406 Config.OnlyKeep.push_back(Arg->getValue()); 407 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) 408 Config.AddSection.push_back(Arg->getValue()); 409 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); 410 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); 411 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); 412 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); 413 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); 414 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); 415 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); 416 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); 417 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) 418 Config.SymbolsToLocalize.push_back(Arg->getValue()); 419 420 return Config; 421 } 422 423 int main(int argc, char **argv) { 424 InitLLVM X(argc, argv); 425 ToolName = argv[0]; 426 427 CopyConfig Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); 428 ExecuteElfObjcopy(Config); 429 } 430