From d546b5052bb71ad90230fa572101730d4c0246a3 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 7 Jun 2019 13:24:34 +0000 Subject: llvm-lib: Disallow mixing object files with different machine types lib.exe doesn't allow creating .lib files with object files that have differing machine types. Update llvm-lib to match. The motivation is to make it possible to infer the machine type of a .lib file in lld, so that it can warn when e.g. a 32-bit .lib file is passed to a 64-bit link (PR38965). Fixes PR38782. Differential Revision: https://reviews.llvm.org/D62913 llvm-svn: 362798 --- llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp') diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp index 2d44686..0b58c54 100644 --- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -13,8 +13,11 @@ #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/Magic.h" +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFF.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -137,6 +140,21 @@ static void doList(opt::InputArgList& Args) { fatalOpenError(std::move(Err), B->getBufferIdentifier()); } +static StringRef machineToStr(COFF::MachineTypes MT) { + switch (MT) { + case COFF::IMAGE_FILE_MACHINE_ARMNT: + return "arm"; + case COFF::IMAGE_FILE_MACHINE_ARM64: + return "arm64"; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return "x64"; + case COFF::IMAGE_FILE_MACHINE_I386: + return "x86"; + default: + llvm_unreachable("unknown machine type"); + } +} + int llvm::libDriverMain(ArrayRef ArgsArr) { BumpPtrAllocator Alloc; StringSaver Saver(Alloc); @@ -180,6 +198,7 @@ int llvm::libDriverMain(ArrayRef ArgsArr) { // Create a NewArchiveMember for each input file. std::vector Members; + COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; for (auto *Arg : Args.filtered(OPT_INPUT)) { std::string Path = findInputFile(Arg->getValue(), SearchPaths); if (Path.empty()) { @@ -203,6 +222,72 @@ int llvm::libDriverMain(ArrayRef ArgsArr) { << ": not a COFF object, bitcode or resource file\n"; return 1; } + + // Check that all input files have the same machine type. + // Mixing normal objects and LTO bitcode files is fine as long as they + // have the same machine type. + // Doing this here duplicates the header parsing work that writeArchive() + // below does, but it's not a lot of work and it's a bit awkward to do + // in writeArchive() which needs to support many tools, can't assume the + // input is COFF, and doesn't have a good way to report errors. + COFF::MachineTypes FileMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; + if (Magic == file_magic::coff_object) { + std::error_code EC; + object::COFFObjectFile Obj(*MOrErr->Buf, EC); + if (EC) { + llvm::errs() << Arg->getValue() << ": failed to open: " << EC.message() + << '\n'; + return 1; + } + uint16_t Machine = Obj.getMachine(); + if (Machine != COFF::IMAGE_FILE_MACHINE_I386 && + Machine != COFF::IMAGE_FILE_MACHINE_AMD64 && + Machine != COFF::IMAGE_FILE_MACHINE_ARMNT && + Machine != COFF::IMAGE_FILE_MACHINE_ARM64) { + llvm::errs() << Arg->getValue() << ": unknown machine: " << Machine + << '\n'; + return 1; + } + FileMachine = static_cast(Machine); + } else if (Magic == file_magic::bitcode) { + Expected TripleStr = getBitcodeTargetTriple(*MOrErr->Buf); + if (!TripleStr) { + llvm::errs() << Arg->getValue() + << ": failed to get target triple from bitcode\n"; + return 1; + } + switch (Triple(*TripleStr).getArch()) { + case Triple::x86: + FileMachine = COFF::IMAGE_FILE_MACHINE_I386; + break; + case Triple::x86_64: + FileMachine = COFF::IMAGE_FILE_MACHINE_AMD64; + break; + case Triple::arm: + FileMachine = COFF::IMAGE_FILE_MACHINE_ARMNT; + break; + case Triple::aarch64: + FileMachine = COFF::IMAGE_FILE_MACHINE_ARM64; + break; + default: + llvm::errs() << Arg->getValue() << ": unknown arch in target triple " + << *TripleStr << '\n'; + return 1; + } + } + + if (FileMachine != COFF::IMAGE_FILE_MACHINE_UNKNOWN) { + if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) + LibMachine = FileMachine; + else if (LibMachine != FileMachine) { + llvm::errs() << Arg->getValue() << ": file machine type " + << machineToStr(FileMachine) + << " conflicts with library machine type " + << machineToStr(LibMachine) << '\n'; + return 1; + } + } + Members.emplace_back(std::move(*MOrErr)); } -- cgit v1.1