diff --git a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test --- a/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test +++ b/llvm/test/tools/llvm-objcopy/MachO/install-name-tool-add-rpath.test @@ -22,6 +22,13 @@ # NO-INPUT: no input file specified +## Add same RPATH twice: +# RUN: not llvm-install-name-tool -add_rpath @executable_X \ +# RUN: -add_rpath @executable_X %t.i386 2>&1 \ +# RUN: | FileCheck --check-prefix=DOUBLE %s + +# DOUBLE: duplicate load command + ## Check that cmdsize accounts for NULL terminator. # RUN: yaml2obj %p/Inputs/x86_64.yaml -o %t.x86_64 # RUN: llvm-install-name-tool -add_rpath abcd %t.x86_64 diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" +#include namespace llvm { namespace objcopy { @@ -271,6 +272,14 @@ for (std::unique_ptr
&Sec : LC.Sections) Sec->Relocations.clear(); + std::set OriginalRPaths; + auto FindPair = + [](StringRef Old, + const std::vector> &Range) { + return find_if(Range, [=](const std::pair Pair) { + return Pair.first == Old; + }); + }; for (LoadCommand &LC : Obj.LoadCommands) { switch (LC.MachOLoadCommand.load_command_data.cmd) { case MachO::LC_ID_DYLIB: @@ -283,20 +292,38 @@ } break; + case MachO::LC_RPATH: { + StringRef CurrentRPath = getPayloadString(LC); + OriginalRPaths.insert(CurrentRPath.str()); + auto FoundArg = FindPair(CurrentRPath, Config.RPathsToUpdate); + if (FoundArg != Config.RPathsToUpdate.end()) + updateLoadCommandPayloadString(LC, + FoundArg->second); + } break; + case MachO::LC_LOAD_DYLIB: case MachO::LC_LOAD_WEAK_DYLIB: - StringRef Old, New; StringRef CurrentInstallName = getPayloadString(LC); - for (const auto &InstallNamePair : Config.InstallNamesToUpdate) { - std::tie(Old, New) = InstallNamePair; - if (CurrentInstallName == Old) { - updateLoadCommandPayloadString(LC, New); - break; - } - } + auto FoundArg = FindPair(CurrentInstallName, Config.InstallNamesToUpdate); + if (FoundArg != Config.InstallNamesToUpdate.end()) + updateLoadCommandPayloadString(LC, + FoundArg->second); + break; } } + StringRef Old, New; + for (const auto &OldNew : Config.RPathsToUpdate) { + std::tie(Old, New) = OldNew; + if (OriginalRPaths.count(Old.str()) == 0) + return createStringError(errc::invalid_argument, + "no LC_RPATH load command with path: " + Old); + if (OriginalRPaths.count(New.str()) != 0) + return createStringError(errc::invalid_argument, + "rpath " + New + + " would create a duplicate load command"); + } + for (const auto &Flag : Config.AddSection) { std::pair SecPair = Flag.split("="); StringRef SecName = SecPair.first; @@ -310,40 +337,12 @@ if (Error E = removeLoadCommands(Config, Obj)) return E; - StringRef Old, New; - for (const auto &OldNew : Config.RPathsToUpdate) { - std::tie(Old, New) = OldNew; - - auto FindRPathLC = [&Obj](StringRef RPath) { - return find_if(Obj.LoadCommands, [=](const LoadCommand &LC) { - return LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH && - getPayloadString(LC) == RPath; - }); - }; - - auto NewIt = FindRPathLC(New); - if (NewIt != Obj.LoadCommands.end()) + for (StringRef RPath : Config.RPathToAdd) { + if (OriginalRPaths.count(RPath.str()) != 0) return createStringError(errc::invalid_argument, - "rpath " + New + + "rpath " + RPath + " would create a duplicate load command"); - - auto OldIt = FindRPathLC(Old); - if (OldIt == Obj.LoadCommands.end()) - return createStringError(errc::invalid_argument, - "no LC_RPATH load command with path: " + Old); - - updateLoadCommandPayloadString(*OldIt, New); - } - - for (StringRef RPath : Config.RPathToAdd) { - for (LoadCommand &LC : Obj.LoadCommands) { - if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_RPATH && - RPath == getPayloadString(LC)) { - return createStringError(errc::invalid_argument, - "rpath " + RPath + - " would create a duplicate load command"); - } - } + OriginalRPaths.insert(RPath.str()); Obj.addLoadCommand(buildRPathLoadCommand(RPath)); } return Error::success();