[llvm-objcopy][NFC] Move core implementation of llvm-objcopy into separate library.
This patch moves core implementation of llvm-objcopy into Object library
(http://lists.llvm.org/pipermail/llvm-dev/2020-September/145075.html).
The functionality for parsing input options is left inside tools/llvm-objcopy.
The interface of ObjCopy library:
ObjCopy/ELF/ELFObjcopy.h
```
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::ELFObjectFileBase &In, Buffer &Out);
```
ObjCopy/COFF/COFFObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::COFFObjectFile &In, Buffer &Out);
```
ObjCopy/MachO/MachOObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::MachOObjectFile &In, Buffer &Out);
```
ObjCopy/wasm/WasmObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::WasmObjectFile &In, Buffer &Out);
```
Differential Revision: https://reviews.llvm.org/D88827
2022-02-11 21:42:40 +03:00
|
|
|
//===- Archive.cpp --------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Archive.h"
|
|
|
|
#include "llvm/ObjCopy/CommonConfig.h"
|
|
|
|
#include "llvm/ObjCopy/MultiFormatConfig.h"
|
|
|
|
#include "llvm/ObjCopy/ObjCopy.h"
|
|
|
|
#include "llvm/Object/Error.h"
|
[Object] Fix updating darwin archives
When creating an archive, llvm-ar looks at the host to determine the
archive format to use, on Apple platforms this means it uses the
K_DARWIN format. K_DARWIN is _virtually_ equivalent to K_BSD, expect for
some very slight differences around padding, timestamps in deterministic
mode, and 64 bit formats. When updating an archive using llvm-ar, or
llvm-objcopy, Archive would try to determine the kind, but it was not
possible to get K_DARWIN in the initialization of the archive, because
they're virtually inciting usable from K_BSD, especially since the
slight differences only apply in very specific cases. This leads to
linker failures when the alignment workaround is not applied to an
archive copied with llvm-objcopy. This change teaches Archive to infer
the K_DARWIN type in the cases where it's possible and the first object
in the archive is a macho object. This avoids using the host triple to
determine this to not affect cross compiling.
Ideally we would eliminate the separate K_DARWIN type entirely since
it's not a truly separate archive type, but then we'd have to force the
macho workarounds on the BSD format generally. This might be acceptable
but then it would be unclear how to handle this case without forcing the
K_DARWIN64 format on all BSD users:
```
if (LastOffset >= Sym64Threshold) {
if (Kind == object::Archive::K_DARWIN)
Kind = object::Archive::K_DARWIN64;
else
Kind = object::Archive::K_GNU64;
}
```
The logic used to determine if the object is macho is derived from the
logic llvm-ar uses.
Previous context:
- 111cd669e90e5b2132187d36f8b141b11a671a8b
- 23a76be5adcaa768ba538f8a4514a7afccf61988
Differential Revision: https://reviews.llvm.org/D124895
2022-05-03 18:43:46 -07:00
|
|
|
#include "llvm/Object/MachO.h"
|
[llvm-objcopy][NFC] Move core implementation of llvm-objcopy into separate library.
This patch moves core implementation of llvm-objcopy into Object library
(http://lists.llvm.org/pipermail/llvm-dev/2020-September/145075.html).
The functionality for parsing input options is left inside tools/llvm-objcopy.
The interface of ObjCopy library:
ObjCopy/ELF/ELFObjcopy.h
```
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::ELFObjectFileBase &In, Buffer &Out);
```
ObjCopy/COFF/COFFObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::COFFObjectFile &In, Buffer &Out);
```
ObjCopy/MachO/MachOObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::MachOObjectFile &In, Buffer &Out);
```
ObjCopy/wasm/WasmObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::WasmObjectFile &In, Buffer &Out);
```
Differential Revision: https://reviews.llvm.org/D88827
2022-02-11 21:42:40 +03:00
|
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
|
|
|
#include "llvm/Support/SmallVectorMemoryBuffer.h"
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace objcopy {
|
|
|
|
|
|
|
|
using namespace llvm::object;
|
|
|
|
|
|
|
|
Expected<std::vector<NewArchiveMember>>
|
|
|
|
createNewArchiveMembers(const MultiFormatConfig &Config, const Archive &Ar) {
|
|
|
|
std::vector<NewArchiveMember> NewArchiveMembers;
|
|
|
|
Error Err = Error::success();
|
|
|
|
for (const Archive::Child &Child : Ar.children(Err)) {
|
|
|
|
Expected<StringRef> ChildNameOrErr = Child.getName();
|
|
|
|
if (!ChildNameOrErr)
|
|
|
|
return createFileError(Ar.getFileName(), ChildNameOrErr.takeError());
|
|
|
|
|
|
|
|
Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
|
|
|
|
if (!ChildOrErr)
|
|
|
|
return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
|
|
|
|
ChildOrErr.takeError());
|
|
|
|
|
|
|
|
SmallVector<char, 0> Buffer;
|
|
|
|
raw_svector_ostream MemStream(Buffer);
|
|
|
|
|
|
|
|
if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream))
|
|
|
|
return std::move(E);
|
|
|
|
|
|
|
|
Expected<NewArchiveMember> Member = NewArchiveMember::getOldMember(
|
|
|
|
Child, Config.getCommonConfig().DeterministicArchives);
|
|
|
|
if (!Member)
|
|
|
|
return createFileError(Ar.getFileName(), Member.takeError());
|
|
|
|
|
|
|
|
Member->Buf = std::make_unique<SmallVectorMemoryBuffer>(
|
|
|
|
std::move(Buffer), ChildNameOrErr.get());
|
|
|
|
Member->MemberName = Member->Buf->getBufferIdentifier();
|
|
|
|
NewArchiveMembers.push_back(std::move(*Member));
|
|
|
|
}
|
|
|
|
if (Err)
|
|
|
|
return createFileError(Config.getCommonConfig().InputFilename,
|
|
|
|
std::move(Err));
|
|
|
|
return std::move(NewArchiveMembers);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For regular archives this function simply calls llvm::writeArchive,
|
|
|
|
// For thin archives it writes the archive file itself as well as its members.
|
|
|
|
static Error deepWriteArchive(StringRef ArcName,
|
|
|
|
ArrayRef<NewArchiveMember> NewMembers,
|
2023-08-22 09:41:33 -04:00
|
|
|
SymtabWritingMode WriteSymtab,
|
|
|
|
object::Archive::Kind Kind, bool Deterministic,
|
|
|
|
bool Thin) {
|
[Object] Fix updating darwin archives
When creating an archive, llvm-ar looks at the host to determine the
archive format to use, on Apple platforms this means it uses the
K_DARWIN format. K_DARWIN is _virtually_ equivalent to K_BSD, expect for
some very slight differences around padding, timestamps in deterministic
mode, and 64 bit formats. When updating an archive using llvm-ar, or
llvm-objcopy, Archive would try to determine the kind, but it was not
possible to get K_DARWIN in the initialization of the archive, because
they're virtually inciting usable from K_BSD, especially since the
slight differences only apply in very specific cases. This leads to
linker failures when the alignment workaround is not applied to an
archive copied with llvm-objcopy. This change teaches Archive to infer
the K_DARWIN type in the cases where it's possible and the first object
in the archive is a macho object. This avoids using the host triple to
determine this to not affect cross compiling.
Ideally we would eliminate the separate K_DARWIN type entirely since
it's not a truly separate archive type, but then we'd have to force the
macho workarounds on the BSD format generally. This might be acceptable
but then it would be unclear how to handle this case without forcing the
K_DARWIN64 format on all BSD users:
```
if (LastOffset >= Sym64Threshold) {
if (Kind == object::Archive::K_DARWIN)
Kind = object::Archive::K_DARWIN64;
else
Kind = object::Archive::K_GNU64;
}
```
The logic used to determine if the object is macho is derived from the
logic llvm-ar uses.
Previous context:
- 111cd669e90e5b2132187d36f8b141b11a671a8b
- 23a76be5adcaa768ba538f8a4514a7afccf61988
Differential Revision: https://reviews.llvm.org/D124895
2022-05-03 18:43:46 -07:00
|
|
|
if (Kind == object::Archive::K_BSD && !NewMembers.empty() &&
|
|
|
|
NewMembers.front().detectKindFromObject() == object::Archive::K_DARWIN)
|
|
|
|
Kind = object::Archive::K_DARWIN;
|
|
|
|
|
[llvm-objcopy][NFC] Move core implementation of llvm-objcopy into separate library.
This patch moves core implementation of llvm-objcopy into Object library
(http://lists.llvm.org/pipermail/llvm-dev/2020-September/145075.html).
The functionality for parsing input options is left inside tools/llvm-objcopy.
The interface of ObjCopy library:
ObjCopy/ELF/ELFObjcopy.h
```
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::ELFObjectFileBase &In, Buffer &Out);
```
ObjCopy/COFF/COFFObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::COFFObjectFile &In, Buffer &Out);
```
ObjCopy/MachO/MachOObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::MachOObjectFile &In, Buffer &Out);
```
ObjCopy/wasm/WasmObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::WasmObjectFile &In, Buffer &Out);
```
Differential Revision: https://reviews.llvm.org/D88827
2022-02-11 21:42:40 +03:00
|
|
|
if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind,
|
|
|
|
Deterministic, Thin))
|
|
|
|
return createFileError(ArcName, std::move(E));
|
|
|
|
|
|
|
|
if (!Thin)
|
|
|
|
return Error::success();
|
|
|
|
|
|
|
|
for (const NewArchiveMember &Member : NewMembers) {
|
|
|
|
// For regular files (as is the case for deepWriteArchive),
|
|
|
|
// FileOutputBuffer::create will return OnDiskBuffer.
|
|
|
|
// OnDiskBuffer uses a temporary file and then renames it. So in reality
|
|
|
|
// there is no inefficiency / duplicated in-memory buffers in this case. For
|
|
|
|
// now in-memory buffers can not be completely avoided since
|
|
|
|
// NewArchiveMember still requires them even though writeArchive does not
|
|
|
|
// write them on disk.
|
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> FB =
|
|
|
|
FileOutputBuffer::create(Member.MemberName, Member.Buf->getBufferSize(),
|
|
|
|
FileOutputBuffer::F_executable);
|
|
|
|
if (!FB)
|
|
|
|
return FB.takeError();
|
|
|
|
std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
|
|
|
|
(*FB)->getBufferStart());
|
|
|
|
if (Error E = (*FB)->commit())
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Error executeObjcopyOnArchive(const MultiFormatConfig &Config,
|
|
|
|
const object::Archive &Ar) {
|
|
|
|
Expected<std::vector<NewArchiveMember>> NewArchiveMembersOrErr =
|
|
|
|
createNewArchiveMembers(Config, Ar);
|
|
|
|
if (!NewArchiveMembersOrErr)
|
|
|
|
return NewArchiveMembersOrErr.takeError();
|
|
|
|
const CommonConfig &CommonConfig = Config.getCommonConfig();
|
|
|
|
return deepWriteArchive(CommonConfig.OutputFilename, *NewArchiveMembersOrErr,
|
2023-08-22 09:41:33 -04:00
|
|
|
Ar.hasSymbolTable() ? SymtabWritingMode::NormalSymtab
|
|
|
|
: SymtabWritingMode::NoSymtab,
|
|
|
|
Ar.kind(), CommonConfig.DeterministicArchives,
|
|
|
|
Ar.isThin());
|
[llvm-objcopy][NFC] Move core implementation of llvm-objcopy into separate library.
This patch moves core implementation of llvm-objcopy into Object library
(http://lists.llvm.org/pipermail/llvm-dev/2020-September/145075.html).
The functionality for parsing input options is left inside tools/llvm-objcopy.
The interface of ObjCopy library:
ObjCopy/ELF/ELFObjcopy.h
```
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
Buffer &Out);
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::ELFObjectFileBase &In, Buffer &Out);
```
ObjCopy/COFF/COFFObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::COFFObjectFile &In, Buffer &Out);
```
ObjCopy/MachO/MachOObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::MachOObjectFile &In, Buffer &Out);
```
ObjCopy/wasm/WasmObjcopy.h
```
Error executeObjcopyOnBinary(const CopyConfig &Config,
object::WasmObjectFile &In, Buffer &Out);
```
Differential Revision: https://reviews.llvm.org/D88827
2022-02-11 21:42:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace objcopy
|
|
|
|
} // end namespace llvm
|