blob: cb20907b3e30d6879b1c7685fd5e654f67cca1a0 [file] [log] [blame]
//===- lib/FileFormat/MachO/ArchHandler.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 "Atoms.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm::MachO;
using namespace lld::mach_o::normalized;
namespace lld {
namespace mach_o {
ArchHandler::ArchHandler() {
}
ArchHandler::~ArchHandler() {
}
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
MachOLinkingContext::Arch arch) {
switch (arch) {
case MachOLinkingContext::arch_x86_64:
return create_x86_64();
case MachOLinkingContext::arch_x86:
return create_x86();
case MachOLinkingContext::arch_armv6:
case MachOLinkingContext::arch_armv7:
case MachOLinkingContext::arch_armv7s:
return create_arm();
case MachOLinkingContext::arch_arm64:
return create_arm64();
default:
llvm_unreachable("Unknown arch");
}
}
bool ArchHandler::isLazyPointer(const Reference &ref) {
// A lazy bind entry is needed for a lazy pointer.
const StubInfo &info = stubInfo();
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return false;
if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch)
return false;
return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind);
}
ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
assert((reloc.type & 0xFFF0) == 0);
uint16_t result = reloc.type;
if (reloc.scattered)
result |= rScattered;
if (reloc.pcRel)
result |= rPcRel;
if (reloc.isExtern)
result |= rExtern;
switch(reloc.length) {
case 0:
break;
case 1:
result |= rLength2;
break;
case 2:
result |= rLength4;
break;
case 3:
result |= rLength8;
break;
default:
llvm_unreachable("bad r_length");
}
return result;
}
normalized::Relocation
ArchHandler::relocFromPattern(ArchHandler::RelocPattern pattern) {
normalized::Relocation result;
result.offset = 0;
result.scattered = (pattern & rScattered);
result.type = (RelocationInfoType)(pattern & 0xF);
result.pcRel = (pattern & rPcRel);
result.isExtern = (pattern & rExtern);
result.value = 0;
result.symbol = 0;
switch (pattern & 0x300) {
case rLength1:
result.length = 0;
break;
case rLength2:
result.length = 1;
break;
case rLength4:
result.length = 2;
break;
case rLength8:
result.length = 3;
break;
}
return result;
}
void ArchHandler::appendReloc(normalized::Relocations &relocs, uint32_t offset,
uint32_t symbol, uint32_t value,
RelocPattern pattern) {
normalized::Relocation reloc = relocFromPattern(pattern);
reloc.offset = offset;
reloc.symbol = symbol;
reloc.value = value;
relocs.push_back(reloc);
}
int16_t ArchHandler::readS16(const uint8_t *addr, bool isBig) {
return read16(addr, isBig);
}
int32_t ArchHandler::readS32(const uint8_t *addr, bool isBig) {
return read32(addr, isBig);
}
uint32_t ArchHandler::readU32(const uint8_t *addr, bool isBig) {
return read32(addr, isBig);
}
int64_t ArchHandler::readS64(const uint8_t *addr, bool isBig) {
return read64(addr, isBig);
}
bool ArchHandler::isDwarfCIE(bool isBig, const DefinedAtom *atom) {
assert(atom->contentType() == DefinedAtom::typeCFI);
if (atom->rawContent().size() < sizeof(uint32_t))
return false;
uint32_t size = read32(atom->rawContent().data(), isBig);
uint32_t idOffset = sizeof(uint32_t);
if (size == 0xffffffffU)
idOffset += sizeof(uint64_t);
return read32(atom->rawContent().data() + idOffset, isBig) == 0;
}
const Atom *ArchHandler::fdeTargetFunction(const DefinedAtom *fde) {
for (auto ref : *fde) {
if (ref->kindNamespace() == Reference::KindNamespace::mach_o &&
ref->kindValue() == unwindRefToFunctionKind()) {
assert(ref->kindArch() == kindArch() && "unexpected Reference arch");
return ref->target();
}
}
return nullptr;
}
} // namespace mach_o
} // namespace lld