[llvm-link] use file magic when deciding if input should be loaded as archive

llvm-link should not rely on the '.a' file extension when deciding if input file
should be loaded as archive. Archives may have other extensions (f.e. .lib) or no
extensions at all. This patch changes llvm-link to use llvm::file_magic to check
if input file is an archive.

Reviewed By: RaviNarayanaswamy

Differential Revision: https://reviews.llvm.org/D92376
This commit is contained in:
Sergey Dmitriev 2020-12-02 16:19:31 -08:00
parent 9f6a612ccc
commit f1419e8887
3 changed files with 24 additions and 18 deletions

View File

@ -1,7 +1,7 @@
# RUN: cp %S/Inputs/f.ll %t.fg.a
# RUN: echo -e '!<arch>\nwith invalid contents' > %t.fg.a
# RUN: not llvm-link %S/Inputs/h.ll %t.fg.a -o %t.linked.bc 2>&1 | FileCheck %s
# RUN: rm -f %t.fg.a
# RUN: rm -f %t.linked.bc
# CHECK: file too small to be an archive
# CHECK: truncated or malformed archive

View File

@ -1,8 +1,8 @@
# RUN: llvm-as %S/Inputs/f.ll -o %t.f.bc
# RUN: llvm-as %S/Inputs/g.ll -o %t.g.bc
# RUN: llvm-ar cr %t.fg.a %t.f.bc %t.g.bc
# RUN: llvm-ar cr %t.empty.a
# RUN: llvm-link %S/Inputs/h.ll %t.fg.a %t.empty.a -o %t.linked.bc
# RUN: llvm-ar cr %t.empty.lib
# RUN: llvm-link %S/Inputs/h.ll %t.fg.a %t.empty.lib -o %t.linked.bc
# RUN: llvm-nm %t.linked.bc | FileCheck %s

View File

@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/Archive.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/AutoUpgrade.h"
@ -24,6 +24,7 @@
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Object/Archive.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
@ -115,17 +116,18 @@ static ExitOnError ExitOnErr;
// link path for the specified file to try to find it...
//
static std::unique_ptr<Module> loadFile(const char *argv0,
const std::string &FN,
std::unique_ptr<MemoryBuffer> Buffer,
LLVMContext &Context,
bool MaterializeMetadata = true) {
SMDiagnostic Err;
if (Verbose)
errs() << "Loading '" << FN << "'\n";
errs() << "Loading '" << Buffer->getBufferIdentifier() << "'\n";
std::unique_ptr<Module> Result;
if (DisableLazyLoad)
Result = parseIRFile(FN, Err, Context);
Result = parseIR(*Buffer, Err, Context);
else
Result = getLazyIRFileModule(FN, Err, Context, !MaterializeMetadata);
Result =
getLazyIRModule(std::move(Buffer), Err, Context, !MaterializeMetadata);
if (!Result) {
Err.print(argv0, errs());
@ -141,19 +143,17 @@ static std::unique_ptr<Module> loadFile(const char *argv0,
}
static std::unique_ptr<Module> loadArFile(const char *Argv0,
const std::string &ArchiveName,
std::unique_ptr<MemoryBuffer> Buffer,
LLVMContext &Context, Linker &L,
unsigned OrigFlags,
unsigned ApplicableFlags) {
std::unique_ptr<Module> Result(new Module("ArchiveModule", Context));
StringRef ArchiveName = Buffer->getBufferIdentifier();
if (Verbose)
errs() << "Reading library archive file '" << ArchiveName
<< "' to memory\n";
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
MemoryBuffer::getFile(ArchiveName, -1, false);
ExitOnErr(errorCodeToError(Buf.getError()));
Error Err = Error::success();
object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
object::Archive Archive(*Buffer, Err);
ExitOnErr(std::move(Err));
for (const object::Archive::Child &C : Archive.children(Err)) {
Expected<StringRef> Ename = C.getName();
@ -287,7 +287,9 @@ static bool importFunctions(const char *argv0, Module &DestModule) {
auto ModuleLoader = [&DestModule](const char *argv0,
const std::string &Identifier) {
return loadFile(argv0, Identifier, DestModule.getContext(), false);
std::unique_ptr<MemoryBuffer> Buffer =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Identifier)));
return loadFile(argv0, std::move(Buffer), DestModule.getContext(), false);
};
ModuleLazyLoaderCache ModuleLoaderCache(ModuleLoader);
@ -349,10 +351,14 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
// Similar to some flags, internalization doesn't apply to the first file.
bool InternalizeLinkedSymbols = false;
for (const auto &File : Files) {
std::unique_ptr<MemoryBuffer> Buffer =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(File)));
std::unique_ptr<Module> M =
(llvm::sys::path::extension(File) == ".a")
? loadArFile(argv0, File, Context, L, Flags, ApplicableFlags)
: loadFile(argv0, File, Context);
identify_magic(Buffer->getBuffer()) == file_magic::archive
? loadArFile(argv0, std::move(Buffer), Context, L, Flags,
ApplicableFlags)
: loadFile(argv0, std::move(Buffer), Context);
if (!M.get()) {
errs() << argv0 << ": ";
WithColor::error() << " loading file '" << File << "'\n";