diff --git a/llvm/lib/ToolDrivers/llvm-lib/CMakeLists.txt b/llvm/lib/ToolDrivers/llvm-lib/CMakeLists.txt --- a/llvm/lib/ToolDrivers/llvm-lib/CMakeLists.txt +++ b/llvm/lib/ToolDrivers/llvm-lib/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS BinaryFormat + BitReader Object Option Support diff --git a/llvm/lib/ToolDrivers/llvm-lib/LLVMBuild.txt b/llvm/lib/ToolDrivers/llvm-lib/LLVMBuild.txt --- a/llvm/lib/ToolDrivers/llvm-lib/LLVMBuild.txt +++ b/llvm/lib/ToolDrivers/llvm-lib/LLVMBuild.txt @@ -18,4 +18,4 @@ type = Library name = LibDriver parent = Libraries -required_libraries = BinaryFormat Object Option Support +required_libraries = BinaryFormat BitReader Object Option Support diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp --- 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 @@ 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 @@ // 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 @@ << ": 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)); } diff --git a/llvm/test/tools/llvm-lib/Inputs/arm64.ll b/llvm/test/tools/llvm-lib/Inputs/arm64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lib/Inputs/arm64.ll @@ -0,0 +1,18 @@ +; ModuleID = 'test2.cc' +source_filename = "test2.cc" +target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" +target triple = "arm64-pc-windows-msvc19.11.0" + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @"?f@@YAXXZ"() #0 { +entry: + ret void +} + +attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{!"clang version 9.0.0 "} diff --git a/llvm/test/tools/llvm-lib/Inputs/i386.ll b/llvm/test/tools/llvm-lib/Inputs/i386.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lib/Inputs/i386.ll @@ -0,0 +1,19 @@ +; ModuleID = 'test2.cc' +source_filename = "test2.cc" +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i386-pc-windows-msvc19.11.0" + +; Function Attrs: noinline nounwind optnone +define dso_local void @"?f@@YAXXZ"() #0 { +entry: + ret void +} + +attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"NumRegisterParameters", i32 0} +!1 = !{i32 1, !"wchar_size", i32 2} +!2 = !{!"clang version 9.0.0 "} diff --git a/llvm/test/tools/llvm-lib/Inputs/x86_64.ll b/llvm/test/tools/llvm-lib/Inputs/x86_64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lib/Inputs/x86_64.ll @@ -0,0 +1,19 @@ +; ModuleID = 'test2.cc' +source_filename = "test2.cc" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.11.0" + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @"?f@@YAXXZ"() #0 { +entry: + ret void +} + +attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 7, !"PIC Level", i32 2} +!2 = !{!"clang version 9.0.0 "} diff --git a/llvm/test/tools/llvm-lib/machine-mismatch.test b/llvm/test/tools/llvm-lib/machine-mismatch.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lib/machine-mismatch.test @@ -0,0 +1,38 @@ +Prepare inputs: + +RUN: rm -rf %t && mkdir -p %t +RUN: llvm-mc -triple=i386-pc-windows-msvc -filetype=obj -o %t/i386.obj %S/Inputs/a.s +RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t/x86_64.obj %S/Inputs/a.s +RUN: llvm-as -o %t/i386.bc %S/Inputs/i386.ll +RUN: llvm-as -o %t/x86_64.bc %S/Inputs/x86_64.ll +RUN: llvm-as -o %t/arm64.bc %S/Inputs/arm64.ll + + +Mixing bitcode and normal object files with the same machine type is ok: + +RUN: llvm-lib %t/i386.obj %t/i386.bc +RUN: llvm-lib %t/x86_64.obj %t/x86_64.bc + + +As is including resource files: + +RUN: llvm-lib %S/Inputs/resource.res %t/i386.obj %t/i386.bc +RUN: llvm-lib %t/x86_64.obj %S/Inputs/resource.res %t/x86_64.bc + + +Mixing object files with different machine type is not ok: + +RUN: not llvm-lib %t/x86_64.obj %t/i386.obj 2>&1 | \ +RUN: FileCheck --check-prefix=OBJ32 %s +OBJ32: i386.obj: file machine type x86 conflicts with library machine type x64 + + +Neither is mixing object and bitcode files with different machine type: + +RUN: not llvm-lib %t/x86_64.obj %t/i386.bc 2>&1 | \ +RUN: FileCheck --check-prefix=BC32 %s +BC32: i386.bc: file machine type x86 conflicts with library machine type x64 + +RUN: not llvm-lib %t/arm64.bc %t/x86_64.bc 2>&1 | \ +RUN: FileCheck --check-prefix=BC64 %s +BC64: x86_64.bc: file machine type x64 conflicts with library machine type arm64 diff --git a/llvm/utils/gn/secondary/llvm/lib/ToolDrivers/llvm-lib/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/ToolDrivers/llvm-lib/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/lib/ToolDrivers/llvm-lib/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/ToolDrivers/llvm-lib/BUILD.gn @@ -10,6 +10,7 @@ deps = [ ":Options", "//llvm/lib/BinaryFormat", + "//llvm/lib/Bitcode/Reader", "//llvm/lib/Object", "//llvm/lib/Option", "//llvm/lib/Support",