2015-06-08 04:32:01 +02:00
|
|
|
//===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-06-08 04:32:01 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the writeArchive function.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Object/ArchiveWriter.h"
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2020-03-11 23:30:04 +01:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2015-06-08 04:32:01 +02:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2017-06-07 05:48:56 +02:00
|
|
|
#include "llvm/BinaryFormat/Magic.h"
|
2015-06-08 04:32:01 +02:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/Object/Archive.h"
|
2019-07-23 16:44:21 +02:00
|
|
|
#include "llvm/Object/Error.h"
|
2015-06-08 04:32:01 +02:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
|
|
|
#include "llvm/Object/SymbolicFile.h"
|
[Alignment] Move OffsetToAlignment to Alignment.h
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet, JDevlieghere, alexshap, rupprecht, jhenderson
Subscribers: sdardis, nemanjai, hiraditya, kbarton, jakehehrlich, jrtc27, MaskRay, atanasyan, jsji, seiya, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D67499
llvm-svn: 371742
2019-09-12 17:20:36 +02:00
|
|
|
#include "llvm/Support/Alignment.h"
|
2015-06-17 18:02:56 +02:00
|
|
|
#include "llvm/Support/EndianStream.h"
|
2015-06-13 19:23:04 +02:00
|
|
|
#include "llvm/Support/Errc.h"
|
2015-06-08 04:32:01 +02:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2020-07-29 16:40:11 +02:00
|
|
|
#include "llvm/Support/SmallVectorMemoryBuffer.h"
|
2015-06-08 04:32:01 +02:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
2018-10-04 20:49:21 +02:00
|
|
|
#include <map>
|
|
|
|
|
2015-06-08 04:43:32 +02:00
|
|
|
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
2015-06-08 04:32:01 +02:00
|
|
|
#include <unistd.h>
|
2015-06-08 04:43:32 +02:00
|
|
|
#else
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
2015-06-08 04:32:01 +02:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2016-06-30 00:27:42 +02:00
|
|
|
NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
|
2017-06-12 21:45:35 +02:00
|
|
|
: Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
|
|
|
|
MemberName(BufRef.getBufferIdentifier()) {}
|
2016-06-30 00:27:42 +02:00
|
|
|
|
|
|
|
Expected<NewArchiveMember>
|
|
|
|
NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
|
|
|
|
bool Deterministic) {
|
2016-07-29 19:44:13 +02:00
|
|
|
Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
|
2016-06-30 00:27:42 +02:00
|
|
|
if (!BufOrErr)
|
2016-07-29 19:44:13 +02:00
|
|
|
return BufOrErr.takeError();
|
2016-06-30 00:27:42 +02:00
|
|
|
|
|
|
|
NewArchiveMember M;
|
|
|
|
M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
|
2017-06-12 21:45:35 +02:00
|
|
|
M.MemberName = M.Buf->getBufferIdentifier();
|
2016-06-30 00:27:42 +02:00
|
|
|
if (!Deterministic) {
|
2016-10-24 15:38:27 +02:00
|
|
|
auto ModTimeOrErr = OldMember.getLastModified();
|
2016-08-03 21:02:50 +02:00
|
|
|
if (!ModTimeOrErr)
|
|
|
|
return ModTimeOrErr.takeError();
|
|
|
|
M.ModTime = ModTimeOrErr.get();
|
|
|
|
Expected<unsigned> UIDOrErr = OldMember.getUID();
|
|
|
|
if (!UIDOrErr)
|
|
|
|
return UIDOrErr.takeError();
|
|
|
|
M.UID = UIDOrErr.get();
|
|
|
|
Expected<unsigned> GIDOrErr = OldMember.getGID();
|
|
|
|
if (!GIDOrErr)
|
|
|
|
return GIDOrErr.takeError();
|
|
|
|
M.GID = GIDOrErr.get();
|
|
|
|
Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
|
|
|
|
if (!AccessModeOrErr)
|
|
|
|
return AccessModeOrErr.takeError();
|
|
|
|
M.Perms = AccessModeOrErr.get();
|
2016-06-30 00:27:42 +02:00
|
|
|
}
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(M);
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:27:42 +02:00
|
|
|
Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
|
|
|
|
bool Deterministic) {
|
|
|
|
sys::fs::file_status Status;
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 02:34:13 +02:00
|
|
|
auto FDOrErr = sys::fs::openNativeFileForRead(FileName);
|
|
|
|
if (!FDOrErr)
|
|
|
|
return FDOrErr.takeError();
|
|
|
|
sys::fs::file_t FD = *FDOrErr;
|
|
|
|
assert(FD != sys::fs::kInvalidFile);
|
2015-06-08 04:32:01 +02:00
|
|
|
|
2016-06-30 00:27:42 +02:00
|
|
|
if (auto EC = sys::fs::status(FD, Status))
|
|
|
|
return errorCodeToError(EC);
|
2015-06-08 04:32:01 +02:00
|
|
|
|
|
|
|
// Opening a directory doesn't make sense. Let it fail.
|
|
|
|
// Linux cannot open directories with open(2), although
|
|
|
|
// cygwin and *bsd can.
|
2016-06-30 00:27:42 +02:00
|
|
|
if (Status.type() == sys::fs::file_type::directory_file)
|
|
|
|
return errorCodeToError(make_error_code(errc::is_a_directory));
|
|
|
|
|
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
|
|
|
|
MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
|
|
|
|
if (!MemberBufferOrErr)
|
|
|
|
return errorCodeToError(MemberBufferOrErr.getError());
|
|
|
|
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 02:34:13 +02:00
|
|
|
if (auto EC = sys::fs::closeFile(FD))
|
|
|
|
return errorCodeToError(EC);
|
2016-06-30 00:27:42 +02:00
|
|
|
|
|
|
|
NewArchiveMember M;
|
|
|
|
M.Buf = std::move(*MemberBufferOrErr);
|
2017-06-12 21:45:35 +02:00
|
|
|
M.MemberName = M.Buf->getBufferIdentifier();
|
2016-06-30 00:27:42 +02:00
|
|
|
if (!Deterministic) {
|
2016-10-24 15:38:27 +02:00
|
|
|
M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
|
|
|
|
Status.getLastModificationTime());
|
2016-06-30 00:27:42 +02:00
|
|
|
M.UID = Status.getUser();
|
|
|
|
M.GID = Status.getGroup();
|
|
|
|
M.Perms = Status.permissions();
|
|
|
|
}
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(M);
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2017-09-22 01:06:23 +02:00
|
|
|
static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
|
2015-06-08 04:32:01 +02:00
|
|
|
uint64_t OldPos = OS.tell();
|
|
|
|
OS << Data;
|
|
|
|
unsigned SizeSoFar = OS.tell() - OldPos;
|
2017-09-22 01:00:55 +02:00
|
|
|
assert(SizeSoFar <= Size && "Data doesn't fit in Size");
|
|
|
|
OS.indent(Size - SizeSoFar);
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
|
|
|
|
2018-10-10 23:07:02 +02:00
|
|
|
static bool isDarwin(object::Archive::Kind Kind) {
|
|
|
|
return Kind == object::Archive::K_DARWIN ||
|
|
|
|
Kind == object::Archive::K_DARWIN64;
|
|
|
|
}
|
|
|
|
|
2017-02-21 21:40:54 +01:00
|
|
|
static bool isBSDLike(object::Archive::Kind Kind) {
|
|
|
|
switch (Kind) {
|
|
|
|
case object::Archive::K_GNU:
|
2017-11-03 20:15:06 +01:00
|
|
|
case object::Archive::K_GNU64:
|
2017-02-21 21:40:54 +01:00
|
|
|
return false;
|
|
|
|
case object::Archive::K_BSD:
|
|
|
|
case object::Archive::K_DARWIN:
|
2017-02-22 20:42:14 +01:00
|
|
|
case object::Archive::K_DARWIN64:
|
2018-10-10 23:07:02 +02:00
|
|
|
return true;
|
2017-02-22 20:42:14 +01:00
|
|
|
case object::Archive::K_COFF:
|
|
|
|
break;
|
2017-02-21 21:40:54 +01:00
|
|
|
}
|
2017-02-22 20:42:14 +01:00
|
|
|
llvm_unreachable("not supported for writting");
|
2017-02-21 21:40:54 +01:00
|
|
|
}
|
|
|
|
|
2017-11-03 20:15:06 +01:00
|
|
|
template <class T>
|
|
|
|
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
|
2018-05-18 21:46:24 +02:00
|
|
|
support::endian::write(Out, Val,
|
|
|
|
isBSDLike(Kind) ? support::little : support::big);
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
|
|
|
|
2016-10-24 15:38:27 +02:00
|
|
|
static void printRestOfMemberHeader(
|
2017-09-22 01:06:23 +02:00
|
|
|
raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
|
2019-07-23 16:44:21 +02:00
|
|
|
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
|
2016-10-24 15:38:27 +02:00
|
|
|
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
|
2017-09-22 01:00:55 +02:00
|
|
|
|
|
|
|
// The format has only 6 chars for uid and gid. Truncate if the provided
|
|
|
|
// values don't fit.
|
|
|
|
printWithSpacePadding(Out, UID % 1000000, 6);
|
|
|
|
printWithSpacePadding(Out, GID % 1000000, 6);
|
|
|
|
|
2015-06-08 04:32:01 +02:00
|
|
|
printWithSpacePadding(Out, format("%o", Perms), 8);
|
|
|
|
printWithSpacePadding(Out, Size, 10);
|
|
|
|
Out << "`\n";
|
|
|
|
}
|
|
|
|
|
2016-10-24 15:38:27 +02:00
|
|
|
static void
|
2017-09-22 01:06:23 +02:00
|
|
|
printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
|
2016-10-24 15:38:27 +02:00
|
|
|
const sys::TimePoint<std::chrono::seconds> &ModTime,
|
|
|
|
unsigned UID, unsigned GID, unsigned Perms,
|
2019-07-23 16:44:21 +02:00
|
|
|
uint64_t Size) {
|
2015-06-08 04:32:01 +02:00
|
|
|
printWithSpacePadding(Out, Twine(Name) + "/", 16);
|
|
|
|
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
|
|
|
|
}
|
|
|
|
|
2016-10-24 15:38:27 +02:00
|
|
|
static void
|
2017-10-03 22:59:43 +02:00
|
|
|
printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
|
2016-10-24 15:38:27 +02:00
|
|
|
const sys::TimePoint<std::chrono::seconds> &ModTime,
|
2019-07-23 16:44:21 +02:00
|
|
|
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
|
2017-10-03 22:59:43 +02:00
|
|
|
uint64_t PosAfterHeader = Pos + 60 + Name.size();
|
2015-07-09 16:54:12 +02:00
|
|
|
// Pad so that even 64 bit object files are aligned.
|
2019-09-27 14:54:21 +02:00
|
|
|
unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
|
2015-07-09 16:54:12 +02:00
|
|
|
unsigned NameWithPadding = Name.size() + Pad;
|
|
|
|
printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
|
|
|
|
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
|
|
|
|
NameWithPadding + Size);
|
|
|
|
Out << Name;
|
|
|
|
while (Pad--)
|
|
|
|
Out.write(uint8_t(0));
|
|
|
|
}
|
|
|
|
|
2015-07-15 07:47:46 +02:00
|
|
|
static bool useStringTable(bool Thin, StringRef Name) {
|
2017-06-12 21:45:35 +02:00
|
|
|
return Thin || Name.size() >= 16 || Name.contains('/');
|
2015-07-15 07:47:46 +02:00
|
|
|
}
|
|
|
|
|
2017-11-03 20:15:06 +01:00
|
|
|
static bool is64BitKind(object::Archive::Kind Kind) {
|
|
|
|
switch (Kind) {
|
|
|
|
case object::Archive::K_GNU:
|
|
|
|
case object::Archive::K_BSD:
|
|
|
|
case object::Archive::K_DARWIN:
|
|
|
|
case object::Archive::K_COFF:
|
|
|
|
return false;
|
|
|
|
case object::Archive::K_DARWIN64:
|
|
|
|
case object::Archive::K_GNU64:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("not supported for writting");
|
|
|
|
}
|
|
|
|
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
static void
|
|
|
|
printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
|
|
|
|
StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
|
|
|
|
bool Thin, const NewArchiveMember &M,
|
2019-07-23 16:44:21 +02:00
|
|
|
sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
|
2017-10-03 22:59:43 +02:00
|
|
|
if (isBSDLike(Kind))
|
2018-10-04 20:49:21 +02:00
|
|
|
return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
|
2017-10-03 22:59:43 +02:00
|
|
|
M.Perms, Size);
|
|
|
|
if (!useStringTable(Thin, M.MemberName))
|
2018-10-04 20:49:21 +02:00
|
|
|
return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
|
2017-10-03 22:59:43 +02:00
|
|
|
M.Perms, Size);
|
|
|
|
Out << '/';
|
2018-12-19 17:15:05 +01:00
|
|
|
uint64_t NamePos;
|
|
|
|
if (Thin) {
|
|
|
|
NamePos = StringTable.tell();
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
StringTable << M.MemberName << "/\n";
|
2018-12-19 17:15:05 +01:00
|
|
|
} else {
|
2018-12-19 21:54:06 +01:00
|
|
|
auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
|
|
|
|
if (Insertion.second) {
|
|
|
|
Insertion.first->second = StringTable.tell();
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
StringTable << M.MemberName << "/\n";
|
2018-12-19 17:15:05 +01:00
|
|
|
}
|
2018-12-19 21:54:06 +01:00
|
|
|
NamePos = Insertion.first->second;
|
2018-12-19 17:15:05 +01:00
|
|
|
}
|
2017-10-03 22:59:43 +02:00
|
|
|
printWithSpacePadding(Out, NamePos, 15);
|
2018-10-04 20:49:21 +02:00
|
|
|
printRestOfMemberHeader(Out, ModTime, M.UID, M.GID, M.Perms, Size);
|
2017-10-03 22:59:43 +02:00
|
|
|
}
|
2015-07-16 02:14:49 +02:00
|
|
|
|
2017-10-03 22:59:43 +02:00
|
|
|
namespace {
|
|
|
|
struct MemberData {
|
|
|
|
std::vector<unsigned> Symbols;
|
|
|
|
std::string Header;
|
|
|
|
StringRef Data;
|
|
|
|
StringRef Padding;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
static MemberData computeStringTable(StringRef Names) {
|
|
|
|
unsigned Size = Names.size();
|
2019-09-27 14:54:21 +02:00
|
|
|
unsigned Pad = offsetToAlignment(Size, Align(2));
|
2017-10-03 22:59:43 +02:00
|
|
|
std::string Header;
|
|
|
|
raw_string_ostream Out(Header);
|
|
|
|
printWithSpacePadding(Out, "//", 48);
|
|
|
|
printWithSpacePadding(Out, Size + Pad, 10);
|
|
|
|
Out << "`\n";
|
|
|
|
Out.flush();
|
|
|
|
return {{}, std::move(Header), Names, Pad ? "\n" : ""};
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
|
|
|
|
2016-10-24 15:38:27 +02:00
|
|
|
static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) {
|
|
|
|
using namespace std::chrono;
|
|
|
|
|
2015-07-13 22:38:09 +02:00
|
|
|
if (!Deterministic)
|
2016-10-24 15:38:27 +02:00
|
|
|
return time_point_cast<seconds>(system_clock::now());
|
|
|
|
return sys::TimePoint<seconds>();
|
2015-07-13 22:38:09 +02:00
|
|
|
}
|
|
|
|
|
2017-09-22 20:40:14 +02:00
|
|
|
static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
|
2020-04-10 14:24:21 +02:00
|
|
|
Expected<uint32_t> SymFlagsOrErr = S.getFlags();
|
|
|
|
if (!SymFlagsOrErr)
|
|
|
|
// TODO: Actually report errors helpfully.
|
|
|
|
report_fatal_error(SymFlagsOrErr.takeError());
|
|
|
|
if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
|
2017-09-22 20:40:14 +02:00
|
|
|
return false;
|
2020-04-10 14:24:21 +02:00
|
|
|
if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
|
2017-09-22 20:40:14 +02:00
|
|
|
return false;
|
2020-04-10 14:24:21 +02:00
|
|
|
if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
|
2017-09-22 20:40:14 +02:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-03 20:15:06 +01:00
|
|
|
static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
|
|
|
|
uint64_t Val) {
|
|
|
|
if (is64BitKind(Kind))
|
|
|
|
print<uint64_t>(Out, Kind, Val);
|
|
|
|
else
|
|
|
|
print<uint32_t>(Out, Kind, Val);
|
|
|
|
}
|
|
|
|
|
2020-10-21 17:11:50 +02:00
|
|
|
static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
|
|
|
|
uint64_t NumSyms, uint64_t OffsetSize,
|
|
|
|
StringRef StringTable,
|
|
|
|
uint32_t *Padding = nullptr) {
|
|
|
|
assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize");
|
|
|
|
uint64_t Size = OffsetSize; // Number of entries
|
2017-02-21 21:40:54 +01:00
|
|
|
if (isBSDLike(Kind))
|
2018-10-10 23:07:02 +02:00
|
|
|
Size += NumSyms * OffsetSize * 2; // Table
|
2017-10-03 22:59:43 +02:00
|
|
|
else
|
2018-10-10 23:07:02 +02:00
|
|
|
Size += NumSyms * OffsetSize; // Table
|
2017-02-21 21:40:54 +01:00
|
|
|
if (isBSDLike(Kind))
|
2018-10-10 23:07:02 +02:00
|
|
|
Size += OffsetSize; // byte count
|
2017-10-03 22:59:43 +02:00
|
|
|
Size += StringTable.size();
|
2017-09-22 20:36:00 +02:00
|
|
|
// ld64 expects the members to be 8-byte aligned for 64-bit content and at
|
|
|
|
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
|
|
|
|
// uniformly.
|
|
|
|
// We do this for all bsd formats because it simplifies aligning members.
|
2020-10-21 17:11:50 +02:00
|
|
|
uint32_t Pad = offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
|
2017-10-03 22:59:43 +02:00
|
|
|
Size += Pad;
|
2020-10-21 17:11:50 +02:00
|
|
|
if (Padding)
|
|
|
|
*Padding = Pad;
|
|
|
|
return Size;
|
|
|
|
}
|
2017-10-03 22:59:43 +02:00
|
|
|
|
2020-10-21 17:11:50 +02:00
|
|
|
static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
|
|
|
|
bool Deterministic, uint64_t Size) {
|
2018-10-10 23:07:02 +02:00
|
|
|
if (isBSDLike(Kind)) {
|
|
|
|
const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
|
|
|
|
printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
|
|
|
|
Size);
|
|
|
|
} else {
|
|
|
|
const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
|
|
|
|
printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
|
|
|
|
}
|
2020-10-21 17:11:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
|
|
|
|
bool Deterministic, ArrayRef<MemberData> Members,
|
|
|
|
StringRef StringTable) {
|
|
|
|
// We don't write a symbol table on an archive with no members -- except on
|
|
|
|
// Darwin, where the linker will abort unless the archive has a symbol table.
|
|
|
|
if (StringTable.empty() && !isDarwin(Kind))
|
|
|
|
return;
|
|
|
|
|
|
|
|
unsigned NumSyms = 0;
|
|
|
|
for (const MemberData &M : Members)
|
|
|
|
NumSyms += M.Symbols.size();
|
|
|
|
|
|
|
|
uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
|
|
|
|
uint32_t Pad;
|
|
|
|
uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad);
|
|
|
|
writeSymbolTableHeader(Out, Kind, Deterministic, Size);
|
2015-06-08 04:32:01 +02:00
|
|
|
|
2017-10-03 22:59:43 +02:00
|
|
|
uint64_t Pos = Out.tell() + Size;
|
2015-07-09 17:56:23 +02:00
|
|
|
|
2017-02-21 21:40:54 +01:00
|
|
|
if (isBSDLike(Kind))
|
2018-10-10 23:07:02 +02:00
|
|
|
printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
|
2017-02-21 21:40:54 +01:00
|
|
|
else
|
2017-11-03 20:15:06 +01:00
|
|
|
printNBits(Out, Kind, NumSyms);
|
2015-07-09 17:56:23 +02:00
|
|
|
|
2017-10-03 22:59:43 +02:00
|
|
|
for (const MemberData &M : Members) {
|
|
|
|
for (unsigned StringOffset : M.Symbols) {
|
|
|
|
if (isBSDLike(Kind))
|
2018-10-10 23:07:02 +02:00
|
|
|
printNBits(Out, Kind, StringOffset);
|
2017-11-03 20:15:06 +01:00
|
|
|
printNBits(Out, Kind, Pos); // member offset
|
2017-10-03 22:59:43 +02:00
|
|
|
}
|
|
|
|
Pos += M.Header.size() + M.Data.size() + M.Padding.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isBSDLike(Kind))
|
2017-11-03 20:15:06 +01:00
|
|
|
// byte count of the string table
|
2018-10-10 23:07:02 +02:00
|
|
|
printNBits(Out, Kind, StringTable.size());
|
2017-10-03 22:59:43 +02:00
|
|
|
Out << StringTable;
|
|
|
|
|
|
|
|
while (Pad--)
|
|
|
|
Out.write(uint8_t(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static Expected<std::vector<unsigned>>
|
|
|
|
getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
|
|
|
|
std::vector<unsigned> Ret;
|
|
|
|
|
2018-09-12 00:00:47 +02:00
|
|
|
// In the scenario when LLVMContext is populated SymbolicFile will contain a
|
|
|
|
// reference to it, thus SymbolicFile should be destroyed first.
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<object::SymbolicFile> Obj;
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
|
|
|
|
const file_magic Type = identify_magic(Buf.getBuffer());
|
|
|
|
// Treat unsupported file types as having no symbols.
|
|
|
|
if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
|
|
|
|
return Ret;
|
|
|
|
if (Type == file_magic::bitcode) {
|
2018-09-12 00:00:47 +02:00
|
|
|
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
|
|
|
|
Buf, file_magic::bitcode, &Context);
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
if (!ObjOrErr)
|
|
|
|
return ObjOrErr.takeError();
|
2018-09-12 00:00:47 +02:00
|
|
|
Obj = std::move(*ObjOrErr);
|
|
|
|
} else {
|
|
|
|
auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
if (!ObjOrErr)
|
|
|
|
return ObjOrErr.takeError();
|
2018-09-12 00:00:47 +02:00
|
|
|
Obj = std::move(*ObjOrErr);
|
2017-10-03 22:59:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
HasObject = true;
|
2018-09-12 00:00:47 +02:00
|
|
|
for (const object::BasicSymbolRef &S : Obj->symbols()) {
|
2017-10-03 22:59:43 +02:00
|
|
|
if (!isArchiveSymbol(S))
|
|
|
|
continue;
|
|
|
|
Ret.push_back(SymNames.tell());
|
2019-05-10 11:59:04 +02:00
|
|
|
if (Error E = S.printName(SymNames))
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(E);
|
2017-10-03 22:59:43 +02:00
|
|
|
SymNames << '\0';
|
|
|
|
}
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Expected<std::vector<MemberData>>
|
|
|
|
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
object::Archive::Kind Kind, bool Thin, bool Deterministic,
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
|
2017-10-03 22:59:43 +02:00
|
|
|
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
|
|
|
|
|
|
|
|
// This ignores the symbol table, but we only need the value mod 8 and the
|
|
|
|
// symbol table is aligned to be a multiple of 8 bytes
|
|
|
|
uint64_t Pos = 0;
|
|
|
|
|
|
|
|
std::vector<MemberData> Ret;
|
|
|
|
bool HasObject = false;
|
2018-10-04 20:49:21 +02:00
|
|
|
|
2018-12-19 17:15:05 +01:00
|
|
|
// Deduplicate long member names in the string table and reuse earlier name
|
|
|
|
// offsets. This especially saves space for COFF Import libraries where all
|
|
|
|
// members have the same name.
|
|
|
|
StringMap<uint64_t> MemberNames;
|
|
|
|
|
2018-10-04 20:49:21 +02:00
|
|
|
// UniqueTimestamps is a special case to improve debugging on Darwin:
|
|
|
|
//
|
|
|
|
// The Darwin linker does not link debug info into the final
|
|
|
|
// binary. Instead, it emits entries of type N_OSO in in the output
|
|
|
|
// binary's symbol table, containing references to the linked-in
|
|
|
|
// object files. Using that reference, the debugger can read the
|
|
|
|
// debug data directly from the object files. Alternatively, an
|
|
|
|
// invocation of 'dsymutil' will link the debug data from the object
|
|
|
|
// files into a dSYM bundle, which can be loaded by the debugger,
|
|
|
|
// instead of the object files.
|
|
|
|
//
|
|
|
|
// For an object file, the N_OSO entries contain the absolute path
|
|
|
|
// path to the file, and the file's timestamp. For an object
|
|
|
|
// included in an archive, the path is formatted like
|
|
|
|
// "/absolute/path/to/archive.a(member.o)", and the timestamp is the
|
|
|
|
// archive member's timestamp, rather than the archive's timestamp.
|
|
|
|
//
|
|
|
|
// However, this doesn't always uniquely identify an object within
|
|
|
|
// an archive -- an archive file can have multiple entries with the
|
|
|
|
// same filename. (This will happen commonly if the original object
|
|
|
|
// files started in different directories.) The only way they get
|
|
|
|
// distinguished, then, is via the timestamp. But this process is
|
|
|
|
// unable to find the correct object file in the archive when there
|
|
|
|
// are two files of the same name and timestamp.
|
|
|
|
//
|
|
|
|
// Additionally, timestamp==0 is treated specially, and causes the
|
|
|
|
// timestamp to be ignored as a match criteria.
|
|
|
|
//
|
|
|
|
// That will "usually" work out okay when creating an archive not in
|
|
|
|
// deterministic timestamp mode, because the objects will probably
|
|
|
|
// have been created at different timestamps.
|
|
|
|
//
|
|
|
|
// To ameliorate this problem, in deterministic archive mode (which
|
|
|
|
// is the default), on Darwin we will emit a unique non-zero
|
|
|
|
// timestamp for each entry with a duplicated name. This is still
|
|
|
|
// deterministic: the only thing affecting that timestamp is the
|
|
|
|
// order of the files in the resultant archive.
|
|
|
|
//
|
|
|
|
// See also the functions that handle the lookup:
|
|
|
|
// in lldb: ObjectContainerBSDArchive::Archive::FindObject()
|
|
|
|
// in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
|
2018-10-10 23:07:02 +02:00
|
|
|
bool UniqueTimestamps = Deterministic && isDarwin(Kind);
|
2018-10-04 20:49:21 +02:00
|
|
|
std::map<StringRef, unsigned> FilenameCount;
|
|
|
|
if (UniqueTimestamps) {
|
|
|
|
for (const NewArchiveMember &M : NewMembers)
|
|
|
|
FilenameCount[M.MemberName]++;
|
|
|
|
for (auto &Entry : FilenameCount)
|
|
|
|
Entry.second = Entry.second > 1 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2017-10-03 22:59:43 +02:00
|
|
|
for (const NewArchiveMember &M : NewMembers) {
|
|
|
|
std::string Header;
|
|
|
|
raw_string_ostream Out(Header);
|
|
|
|
|
|
|
|
MemoryBufferRef Buf = M.Buf->getMemBufferRef();
|
|
|
|
StringRef Data = Thin ? "" : Buf.getBuffer();
|
|
|
|
|
|
|
|
// ld64 expects the members to be 8-byte aligned for 64-bit content and at
|
|
|
|
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
|
|
|
|
// uniformly. This matches the behaviour with cctools and ensures that ld64
|
|
|
|
// is happy with archives that we generate.
|
2018-10-10 23:07:02 +02:00
|
|
|
unsigned MemberPadding =
|
2019-09-27 14:54:21 +02:00
|
|
|
isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
|
[Alignment] Move OffsetToAlignment to Alignment.h
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet, JDevlieghere, alexshap, rupprecht, jhenderson
Subscribers: sdardis, nemanjai, hiraditya, kbarton, jakehehrlich, jrtc27, MaskRay, atanasyan, jsji, seiya, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D67499
llvm-svn: 371742
2019-09-12 17:20:36 +02:00
|
|
|
unsigned TailPadding =
|
2019-09-27 14:54:21 +02:00
|
|
|
offsetToAlignment(Data.size() + MemberPadding, Align(2));
|
2017-10-03 22:59:43 +02:00
|
|
|
StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
|
|
|
|
|
2018-10-04 20:49:21 +02:00
|
|
|
sys::TimePoint<std::chrono::seconds> ModTime;
|
|
|
|
if (UniqueTimestamps)
|
|
|
|
// Increment timestamp for each file of a given name.
|
|
|
|
ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
|
|
|
|
else
|
|
|
|
ModTime = M.ModTime;
|
2019-07-23 16:44:21 +02:00
|
|
|
|
|
|
|
uint64_t Size = Buf.getBufferSize() + MemberPadding;
|
|
|
|
if (Size > object::Archive::MaxMemberSize) {
|
|
|
|
std::string StringMsg =
|
|
|
|
"File " + M.MemberName.str() + " exceeds size limit";
|
|
|
|
return make_error<object::GenericBinaryError>(
|
|
|
|
std::move(StringMsg), object::object_error::parse_failed);
|
|
|
|
}
|
|
|
|
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
|
2019-07-23 16:44:21 +02:00
|
|
|
ModTime, Size);
|
2017-10-03 22:59:43 +02:00
|
|
|
Out.flush();
|
|
|
|
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
std::vector<unsigned> Symbols;
|
|
|
|
if (NeedSymbols) {
|
|
|
|
Expected<std::vector<unsigned>> SymbolsOrErr =
|
|
|
|
getSymbols(Buf, SymNames, HasObject);
|
|
|
|
if (auto E = SymbolsOrErr.takeError())
|
|
|
|
return std::move(E);
|
|
|
|
Symbols = std::move(*SymbolsOrErr);
|
|
|
|
}
|
2017-10-03 22:59:43 +02:00
|
|
|
|
|
|
|
Pos += Header.size() + Data.size() + Padding.size();
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
Ret.push_back({std::move(Symbols), std::move(Header), Data, Padding});
|
2017-10-03 22:59:43 +02:00
|
|
|
}
|
|
|
|
// If there are no symbols, emit an empty symbol table, to satisfy Solaris
|
|
|
|
// tools, older versions of which expect a symbol table in a non-empty
|
|
|
|
// archive, regardless of whether there are any symbols in it.
|
|
|
|
if (HasObject && SymNames.tell() == 0)
|
|
|
|
SymNames << '\0' << '\0' << '\0';
|
|
|
|
return Ret;
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
|
|
|
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
namespace llvm {
|
2019-06-04 12:13:03 +02:00
|
|
|
|
|
|
|
static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
|
|
|
|
SmallString<128> Ret = P;
|
|
|
|
std::error_code Err = sys::fs::make_absolute(Ret);
|
|
|
|
if (Err)
|
|
|
|
return Err;
|
|
|
|
sys::path::remove_dots(Ret, /*removedotdot*/ true);
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
// Compute the relative path from From to To.
|
2019-06-04 12:13:03 +02:00
|
|
|
Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
|
|
|
|
ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
|
|
|
|
ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
|
|
|
|
if (!PathToOrErr || !DirFromOrErr)
|
|
|
|
return errorCodeToError(std::error_code(errno, std::generic_category()));
|
|
|
|
|
|
|
|
const SmallString<128> &PathTo = *PathToOrErr;
|
|
|
|
const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
|
|
|
|
|
|
|
|
// Can't construct a relative path between different roots
|
|
|
|
if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
|
|
|
|
return sys::path::convert_to_slash(PathTo);
|
|
|
|
|
|
|
|
// Skip common prefixes
|
|
|
|
auto FromTo =
|
|
|
|
std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
|
|
|
|
sys::path::begin(PathTo));
|
|
|
|
auto FromI = FromTo.first;
|
|
|
|
auto ToI = FromTo.second;
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
|
2019-06-04 12:13:03 +02:00
|
|
|
// Construct relative path
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
SmallString<128> Relative;
|
|
|
|
for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
|
2019-06-04 12:13:03 +02:00
|
|
|
sys::path::append(Relative, sys::path::Style::posix, "..");
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
|
2019-06-04 12:13:03 +02:00
|
|
|
for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
|
|
|
|
sys::path::append(Relative, sys::path::Style::posix, *ToI);
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
|
2020-01-28 20:23:46 +01:00
|
|
|
return std::string(Relative.str());
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
}
|
|
|
|
|
2020-07-29 16:40:11 +02:00
|
|
|
static Error writeArchiveToStream(raw_ostream &Out,
|
|
|
|
ArrayRef<NewArchiveMember> NewMembers,
|
|
|
|
bool WriteSymtab, object::Archive::Kind Kind,
|
|
|
|
bool Deterministic, bool Thin) {
|
2017-02-21 21:40:54 +01:00
|
|
|
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
|
2017-10-03 22:59:43 +02:00
|
|
|
|
|
|
|
SmallString<0> SymNamesBuf;
|
|
|
|
raw_svector_ostream SymNames(SymNamesBuf);
|
|
|
|
SmallString<0> StringTableBuf;
|
|
|
|
raw_svector_ostream StringTable(StringTableBuf);
|
|
|
|
|
[Archive] Don't throw away errors for malformed archive members
When adding an archive member with a problem, e.g. a new bitcode with an
old archiver, containing an unsupported attribute, or an ELF file with a
malformed symbol table, the archiver would throw away the error and
simply add the member to the archive without any symbol entries. This
meant that the resultant archive could be silently unusable when not
using --whole-archive, and result in unexpected undefined symbols.
This change fixes this issue by addressing two FIXMEs and only throwing
away not-an-object errors. However, this meant that some LLD tests which
didn't need symbol tables and were using invalid members deliberately to
test the linker's malformed input handling no longer worked, so this
patch also stops the archiver from looking for symbols in an object if
it doesn't require a symbol table, and updates the tests accordingly.
Differential Revision: https://reviews.llvm.org/D88288
Reviewed by: grimar, rupprecht, MaskRay
2020-09-25 11:21:39 +02:00
|
|
|
Expected<std::vector<MemberData>> DataOrErr =
|
|
|
|
computeMemberData(StringTable, SymNames, Kind, Thin, Deterministic,
|
|
|
|
WriteSymtab, NewMembers);
|
2017-10-03 22:59:43 +02:00
|
|
|
if (Error E = DataOrErr.takeError())
|
|
|
|
return E;
|
|
|
|
std::vector<MemberData> &Data = *DataOrErr;
|
|
|
|
|
|
|
|
if (!StringTableBuf.empty())
|
|
|
|
Data.insert(Data.begin(), computeStringTable(StringTableBuf));
|
|
|
|
|
2017-11-03 20:15:06 +01:00
|
|
|
// We would like to detect if we need to switch to a 64-bit symbol table.
|
|
|
|
if (WriteSymtab) {
|
2020-10-21 17:11:50 +02:00
|
|
|
uint64_t MaxOffset = 8; // For the file signature.
|
2017-11-03 20:15:06 +01:00
|
|
|
uint64_t LastOffset = MaxOffset;
|
2020-10-21 17:11:50 +02:00
|
|
|
uint64_t NumSyms = 0;
|
2018-09-12 00:00:47 +02:00
|
|
|
for (const auto &M : Data) {
|
2017-11-03 20:15:06 +01:00
|
|
|
// Record the start of the member's offset
|
|
|
|
LastOffset = MaxOffset;
|
|
|
|
// Account for the size of each part associated with the member.
|
|
|
|
MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
|
2020-10-21 17:11:50 +02:00
|
|
|
NumSyms += M.Symbols.size();
|
2017-11-03 20:15:06 +01:00
|
|
|
}
|
2018-03-28 19:21:14 +02:00
|
|
|
|
2020-10-21 17:11:50 +02:00
|
|
|
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
|
|
|
|
uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf);
|
|
|
|
auto computeSymbolTableHeaderSize =
|
|
|
|
[=] {
|
|
|
|
SmallString<0> TmpBuf;
|
|
|
|
raw_svector_ostream Tmp(TmpBuf);
|
|
|
|
writeSymbolTableHeader(Tmp, Kind, Deterministic, SymtabSize);
|
|
|
|
return TmpBuf.size();
|
|
|
|
};
|
|
|
|
LastOffset += computeSymbolTableHeaderSize() + SymtabSize;
|
|
|
|
|
2018-03-28 19:21:14 +02:00
|
|
|
// The SYM64 format is used when an archive's member offsets are larger than
|
|
|
|
// 32-bits can hold. The need for this shift in format is detected by
|
|
|
|
// writeArchive. To test this we need to generate a file with a member that
|
|
|
|
// has an offset larger than 32-bits but this demands a very slow test. To
|
|
|
|
// speed the test up we use this environment variable to pretend like the
|
|
|
|
// cutoff happens before 32-bits and instead happens at some much smaller
|
|
|
|
// value.
|
2020-10-21 17:11:50 +02:00
|
|
|
uint64_t Sym64Threshold = 1ULL << 32;
|
2018-03-28 19:21:14 +02:00
|
|
|
const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
|
|
|
|
if (Sym64Env)
|
|
|
|
StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
|
|
|
|
|
2017-11-03 20:15:06 +01:00
|
|
|
// If LastOffset isn't going to fit in a 32-bit varible we need to switch
|
|
|
|
// to 64-bit. Note that the file can be larger than 4GB as long as the last
|
|
|
|
// member starts before the 4GB offset.
|
2020-10-21 17:11:50 +02:00
|
|
|
if (LastOffset >= Sym64Threshold) {
|
2018-10-10 23:07:02 +02:00
|
|
|
if (Kind == object::Archive::K_DARWIN)
|
|
|
|
Kind = object::Archive::K_DARWIN64;
|
|
|
|
else
|
|
|
|
Kind = object::Archive::K_GNU64;
|
|
|
|
}
|
2017-11-03 20:15:06 +01:00
|
|
|
}
|
|
|
|
|
2015-07-15 07:47:46 +02:00
|
|
|
if (Thin)
|
|
|
|
Out << "!<thin>\n";
|
|
|
|
else
|
|
|
|
Out << "!<arch>\n";
|
2015-06-08 04:32:01 +02:00
|
|
|
|
2017-10-03 22:59:43 +02:00
|
|
|
if (WriteSymtab)
|
|
|
|
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
|
2015-06-08 04:32:01 +02:00
|
|
|
|
2017-10-03 22:59:43 +02:00
|
|
|
for (const MemberData &M : Data)
|
|
|
|
Out << M.Header << M.Data << M.Padding;
|
2015-06-08 04:32:01 +02:00
|
|
|
|
2017-11-14 02:21:15 +01:00
|
|
|
Out.flush();
|
2020-07-29 16:40:11 +02:00
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
|
|
|
|
bool WriteSymtab, object::Archive::Kind Kind,
|
|
|
|
bool Deterministic, bool Thin,
|
|
|
|
std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
|
|
|
|
Expected<sys::fs::TempFile> Temp =
|
|
|
|
sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
|
|
|
|
if (!Temp)
|
|
|
|
return Temp.takeError();
|
|
|
|
raw_fd_ostream Out(Temp->FD, false);
|
|
|
|
|
|
|
|
if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind,
|
|
|
|
Deterministic, Thin)) {
|
|
|
|
if (Error DiscardError = Temp->discard())
|
|
|
|
return joinErrors(std::move(E), std::move(DiscardError));
|
|
|
|
return E;
|
|
|
|
}
|
2016-05-09 15:31:11 +02:00
|
|
|
|
|
|
|
// At this point, we no longer need whatever backing memory
|
|
|
|
// was used to generate the NewMembers. On Windows, this buffer
|
|
|
|
// could be a mapped view of the file we want to replace (if
|
|
|
|
// we're updating an existing archive, say). In that case, the
|
|
|
|
// rename would still succeed, but it would leave behind a
|
|
|
|
// temporary file (actually the original file renamed) because
|
|
|
|
// a file cannot be deleted while there's a handle open on it,
|
|
|
|
// only renamed. So by freeing this buffer, this ensures that
|
|
|
|
// the last open handle on the destination file, if any, is
|
|
|
|
// closed before we attempt to rename.
|
|
|
|
OldArchiveBuf.reset();
|
|
|
|
|
2017-11-14 02:21:15 +01:00
|
|
|
return Temp->keep(ArcName);
|
2015-06-08 04:32:01 +02:00
|
|
|
}
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
|
2020-07-29 16:40:11 +02:00
|
|
|
Expected<std::unique_ptr<MemoryBuffer>>
|
|
|
|
writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab,
|
|
|
|
object::Archive::Kind Kind, bool Deterministic,
|
|
|
|
bool Thin) {
|
|
|
|
SmallVector<char, 0> ArchiveBufferVector;
|
|
|
|
raw_svector_ostream ArchiveStream(ArchiveBufferVector);
|
|
|
|
|
|
|
|
if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab,
|
|
|
|
Kind, Deterministic, Thin))
|
|
|
|
return std::move(E);
|
|
|
|
|
|
|
|
return std::make_unique<SmallVectorMemoryBuffer>(
|
|
|
|
std::move(ArchiveBufferVector));
|
|
|
|
}
|
|
|
|
|
[llvm-ar][libObject] Fix relative paths when nesting thin archives.
Summary:
When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist).
As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes.
This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point).
Reviewers: mstorsjo, pcc, ruiu, davide, david2050, inglorion
Reviewed By: ruiu
Subscribers: void, jdoerfert, tpimh, mgorny, hans, nickdesaulniers, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D57842
llvm-svn: 353995
2019-02-14 00:39:41 +01:00
|
|
|
} // namespace llvm
|