//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "ArchHandler.h"
#include "File.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "MachOPasses.h"
#include "lld/Common/LLVM.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
#include "lld/Core/Simple.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
namespace lld {
namespace mach_o {
///
/// ObjC Image Info Atom created by the ObjC pass.
///
class ObjCImageInfoAtom : public SimpleDefinedAtom {
public:
ObjCImageInfoAtom(const File &file, bool isBig,
MachOLinkingContext::ObjCConstraint objCConstraint,
uint32_t swiftVersion)
: SimpleDefinedAtom(file) {
Data.info.version = 0;
switch (objCConstraint) {
case MachOLinkingContext::objc_unknown:
llvm_unreachable("Shouldn't run the objc pass without a constraint");
case MachOLinkingContext::objc_supports_gc:
case MachOLinkingContext::objc_gc_only:
llvm_unreachable("GC is not supported");
case MachOLinkingContext::objc_retainReleaseForSimulator:
// The retain/release for simulator flag is already the correct
// encoded value for the data so just set it here.
Data.info.flags = (uint32_t)objCConstraint;
break;
case MachOLinkingContext::objc_retainRelease:
// We don't need to encode this flag, so just leave the flags as 0.
Data.info.flags = 0;
break;
}
Data.info.flags |= (swiftVersion << 8);
normalized::write32(Data.bytes + 4, Data.info.flags, isBig);
}
~ObjCImageInfoAtom() override = default;
ContentType contentType() const override {
return DefinedAtom::typeObjCImageInfo;
}
Alignment alignment() const override {
return 4;
}
uint64_t size() const override {
return 8;
}
ContentPermissions permissions() const override {
return DefinedAtom::permR__;
}
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(Data.bytes, size());
}
private:
struct objc_image_info {
uint32_t version;
uint32_t flags;
};
union {
objc_image_info info;
uint8_t bytes[8];
} Data;
};
class ObjCPass : public Pass {
public:
ObjCPass(const MachOLinkingContext &context)
: _ctx(context),
_file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) {
_file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
}
llvm::Error perform(SimpleFile &mergedFile) override {
// Add the image info.
mergedFile.addAtom(*getImageInfo());
return llvm::Error::success();
}
private:
const DefinedAtom* getImageInfo() {
bool IsBig = MachOLinkingContext::isBigEndian(_ctx.arch());
return new (_file.allocator()) ObjCImageInfoAtom(_file, IsBig,
_ctx.objcConstraint(),
_ctx.swiftVersion());
}
const MachOLinkingContext &_ctx;
MachOFile &_file;
};
void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
pm.add(llvm::make_unique<ObjCPass>(ctx));
}
} // end namespace mach_o
} // end namespace lld