Commit 6e8d3fae by John Porto

Subzero. Uses fixups to calculate addend to relocations.

This CL modifies the ELF emission so the addends are calculated during object file creation, and not during function code emission. BUG= R=kschimpf@google.com, stichnot@chromium.org Review URL: https://codereview.chromium.org/1669443002 .
parent 8347abda
......@@ -293,6 +293,10 @@ public:
return Buffer.load<T>(Position);
}
template <typename T> void store(intptr_t Position, T Value) {
Buffer.store(Position, Value);
}
/// Emit a fixup at the current location.
void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); }
......
......@@ -501,9 +501,23 @@ EncodedOperand encodeAddress(const Operand *Opnd, IValueT &Value,
}
// Checks that Offset can fit in imm24 constant of branch (b) instruction.
bool canEncodeBranchOffset(IOffsetT Offset) {
return Utils::IsAligned(Offset, 4) &&
Utils::IsInt(kBranchOffsetBits, Offset >> 2);
void assertCanEncodeBranchOffset(IOffsetT Offset) {
(void)Offset;
(void)kBranchOffsetBits;
assert(Utils::IsAligned(Offset, 4) &&
Utils::IsInt(kBranchOffsetBits, Offset >> 2));
}
IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst) {
// Adjust offset to the way ARM CPUs read PC.
Offset -= kPCReadOffset;
assertCanEncodeBranchOffset(Offset);
// Properly preserve only the bits supported in the instruction.
Offset >>= 2;
Offset &= kBranchOffsetMask;
return (Inst & ~kBranchOffsetMask) | Offset;
}
IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
......@@ -595,6 +609,19 @@ size_t MoveRelocatableFixup::emit(GlobalContext *Ctx,
return InstARM32::InstSize;
}
// This fixup points to an ARM32 instruction with the following format:
void MoveRelocatableFixup::emitOffset(Assembler *Asm) const {
// cccc00110T00iiiiddddiiiiiiiiiiii where cccc=Cond, dddd=Rd,
// iiiiiiiiiiiiiiii = Imm16, and T=1 for movt.
const IValueT Inst = Asm->load<IValueT>(position());
constexpr IValueT Imm16Mask = 0x000F0FFF;
const IValueT Imm16 =
offset() >> (kind() == llvm::ELF::R_ARM_MOVW_ABS_NC ? 0 : 16) & 0xffff;
Asm->store(position(),
(Inst & ~Imm16Mask) | ((Imm16 >> 12) << 16) | (Imm16 & 0xfff));
}
MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW,
const Constant *Value) {
MoveRelocatableFixup *F =
......@@ -618,6 +645,15 @@ size_t BlRelocatableFixup::emit(GlobalContext *Ctx,
return InstARM32::InstSize;
}
void BlRelocatableFixup::emitOffset(Assembler *Asm) const {
// cccc101liiiiiiiiiiiiiiiiiiiiiiii where cccc=Cond, l=Link, and
// iiiiiiiiiiiiiiiiiiiiiiii=
// EncodedBranchOffset(cccc101l000000000000000000000000, Offset);
const IValueT Inst = Asm->load<IValueT>(position());
constexpr IValueT OffsetMask = 0x00FFFFFF;
Asm->store(position(), encodeBranchOffset(offset(), Inst & ~OffsetMask));
}
void AssemblerARM32::padWithNop(intptr_t Padding) {
constexpr intptr_t InstWidth = sizeof(IValueT);
assert(Padding % InstWidth == 0 &&
......@@ -667,20 +703,6 @@ Label *AssemblerARM32::getOrCreateLabel(SizeT Number, LabelVector &Labels) {
return L;
}
IValueT AssemblerARM32::encodeBranchOffset(IOffsetT Offset, IValueT Inst) {
// Adjust offset to the way ARM CPUs read PC.
Offset -= kPCReadOffset;
bool IsGoodOffset = canEncodeBranchOffset(Offset);
assert(IsGoodOffset);
(void)IsGoodOffset;
// Properly preserve only the bits supported in the instruction.
Offset >>= 2;
Offset &= kBranchOffsetMask;
return (Inst & ~kBranchOffsetMask) | Offset;
}
// Pull out offset from branch Inst.
IOffsetT AssemblerARM32::decodeBranchOffset(IValueT Inst) {
// Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC.
......
......@@ -46,6 +46,7 @@ class MoveRelocatableFixup final : public AssemblerFixup {
public:
MoveRelocatableFixup() = default;
size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
void emitOffset(Assembler *Asm) const;
};
/// Handles encoding of branch and link to global location.
......@@ -56,6 +57,7 @@ class BlRelocatableFixup final : public AssemblerFixup {
public:
BlRelocatableFixup() = default;
size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
void emitOffset(Assembler *Asm) const;
};
class AssemblerARM32 : public Assembler {
......@@ -645,9 +647,6 @@ private:
void emitBranch(Label *L, CondARM32::Cond, bool Link);
// Encodes the given Offset into the branch instruction Inst.
IValueT encodeBranchOffset(IOffsetT Offset, IValueT Inst);
// Returns the offset encoded in the branch instruction Inst.
static IOffsetT decodeBranchOffset(IValueT Inst);
......
......@@ -73,11 +73,7 @@ public:
public:
explicit Immediate(int32_t value) : value_(value) {}
Immediate(RelocOffsetT offset, AssemblerFixup *fixup)
: value_(offset), fixup_(fixup) {
// Use the Offset in the "value" for now. If we decide to process fixups,
// we'll need to patch that offset with the true value.
}
explicit Immediate(AssemblerFixup *fixup) : fixup_(fixup) {}
int32_t value() const { return value_; }
AssemblerFixup *fixup() const { return fixup_; }
......@@ -95,7 +91,7 @@ public:
}
private:
const int32_t value_;
const int32_t value_ = 0;
AssemblerFixup *fixup_ = nullptr;
};
......
......@@ -134,8 +134,10 @@ void AssemblerX86Base<TraitsType>::call(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
intptr_t call_start = Buffer.getPosition();
emitUint8(0xE8);
emitFixup(this->createFixup(Traits::FK_PcRel, label));
emitInt32(-4);
auto *Fixup = this->createFixup(Traits::FK_PcRel, label);
Fixup->set_addend(-4);
emitFixup(Fixup);
emitInt32(0);
assert((Buffer.getPosition() - call_start) == kCallExternalLabelSize);
(void)call_start;
}
......@@ -145,8 +147,10 @@ void AssemblerX86Base<TraitsType>::call(const Immediate &abs_address) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
intptr_t call_start = Buffer.getPosition();
emitUint8(0xE8);
emitFixup(this->createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol));
emitInt32(abs_address.value() - 4);
auto *Fixup = this->createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol);
Fixup->set_addend(abs_address.value() - 4);
emitFixup(Fixup);
emitInt32(0);
assert((Buffer.getPosition() - call_start) == kCallExternalLabelSize);
(void)call_start;
}
......@@ -3140,8 +3144,10 @@ void AssemblerX86Base<TraitsType>::j(BrCond condition,
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitUint8(0x0F);
emitUint8(0x80 + condition);
emitFixup(this->createFixup(Traits::FK_PcRel, label));
emitInt32(-4);
auto *Fixup = this->createFixup(Traits::FK_PcRel, label);
Fixup->set_addend(-4);
emitFixup(Fixup);
emitInt32(0);
}
template <typename TraitsType>
......@@ -3180,8 +3186,10 @@ template <typename TraitsType>
void AssemblerX86Base<TraitsType>::jmp(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitUint8(0xE9);
emitFixup(this->createFixup(Traits::FK_PcRel, label));
emitInt32(-4);
auto *Fixup = this->createFixup(Traits::FK_PcRel, label);
Fixup->set_addend(-4);
emitFixup(Fixup);
emitInt32(0);
}
template <typename TraitsType>
......@@ -3189,10 +3197,10 @@ void AssemblerX86Base<TraitsType>::jmp(const Immediate &abs_address) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitUint8(0xE9);
AssemblerFixup *Fixup =
this->createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol);
Fixup->set_addend(abs_address.value());
createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol);
Fixup->set_addend(abs_address.value() - 4);
emitFixup(Fixup);
emitInt32(abs_address.value() - 4);
emitInt32(0);
}
template <typename TraitsType> void AssemblerX86Base<TraitsType>::mfence() {
......@@ -3391,23 +3399,26 @@ void AssemblerX86Base<TraitsType>::emitOperand(int rm, const Operand &operand,
emitUint8(operand.encoding_[1]);
displacement_start = 2;
}
// Emit the displacement and the fixup that affects it, if any.
AssemblerFixup *Fixup = operand.fixup();
if (Fixup != nullptr) {
emitFixup(Fixup);
assert(length - displacement_start == 4);
if (fixupIsPCRel(Fixup->kind())) {
Fixup->set_addend(-Addend);
int32_t Offset;
memmove(&Offset, &operand.encoding_[displacement_start], sizeof(Offset));
Offset -= Addend;
emitInt32(Offset);
return;
}
}
if (Fixup == nullptr) {
for (intptr_t i = displacement_start; i < length; i++) {
emitUint8(operand.encoding_[i]);
}
return;
}
// Emit the fixup, and a dummy 4-byte immediate. Note that the Disp32 in
// operand.encoding_[i, i+1, i+2, i+3] is part of the constant relocatable
// used to create the fixup, so there's no need to add it to the addend.
assert(length - displacement_start == 4);
if (fixupIsPCRel(Fixup->kind())) {
Fixup->set_addend(Fixup->get_addend() - Addend);
} else {
Fixup->set_addend(Fixup->get_addend());
}
emitFixup(Fixup);
emitInt32(0);
}
template <typename TraitsType>
......@@ -3420,10 +3431,14 @@ void AssemblerX86Base<TraitsType>::emitImmediate(Type Ty,
return;
}
if (Fixup != nullptr) {
emitFixup(Fixup);
}
if (Fixup == nullptr) {
emitInt32(imm.value());
return;
}
Fixup->set_addend(Fixup->get_addend() + imm.value());
emitFixup(Fixup);
emitInt32(0);
}
template <typename TraitsType>
......
......@@ -74,6 +74,8 @@ class Variable;
class VariableDeclaration;
class VariablesMetadata;
constexpr char GlobalOffsetTable[] = "_GLOBAL_OFFSET_TABLE_";
template <size_t SlabSize = 1024 * 1024>
using ArenaAllocator =
llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, SlabSize>;
......
......@@ -217,7 +217,7 @@ Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
}
void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
bool IsInternal, const Assembler *Asm) {
bool IsInternal, Assembler *Asm) {
assert(!SectionNumbersAssigned);
ELFTextSection *Section = nullptr;
ELFRelocationSection *RelSection = nullptr;
......@@ -243,7 +243,6 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
// Function symbols are set to 0 size in the symbol table, in contrast to
// data symbols which have a proper size.
constexpr SizeT SymbolSize = 0;
Section->appendData(Str, Asm->getBufferView());
uint8_t SymbolType;
uint8_t SymbolBinding;
if (IsInternal && !Ctx.getFlags().getDisableInternal()) {
......@@ -259,9 +258,18 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
// Copy the fixup information from per-function Assembler memory to the
// object writer's memory, for writing later.
if (!Asm->fixups().empty()) {
const auto &Fixups = Asm->fixups();
if (!Fixups.empty()) {
if (!RelSection->isRela()) {
// This is a non-rela section, so we need to update the instruction stream
// with the relocation addends.
for (const auto *Fixup : Fixups) {
Fixup->emitOffset(Asm);
}
}
RelSection->addRelocations(OffsetInSection, Asm->fixups());
}
Section->appendData(Str, Asm->getBufferView());
}
namespace {
......
......@@ -69,7 +69,7 @@ public:
/// after all functions are written. The text buffer and fixups are extracted
/// from the Assembler object.
void writeFunctionCode(const IceString &FuncName, bool IsInternal,
const Assembler *Asm);
Assembler *Asm);
/// Queries the GlobalContext for constant pools of the given type and writes
/// out read-only data sections for those constants. This also fills the
......
......@@ -367,13 +367,6 @@ void ELFRelocationSection::writeData(const GlobalContext &Ctx, ELFStreamer &Str,
Rela.r_offset = Fixup.position();
Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
Rela.r_addend = Fixup.offset();
if (Fixup.kind() == llvm::ELF::R_X86_64_PC32) {
// In ELF64, PC-relative relocations' addends need to account for the
// immediate size. For now, this is always 4 (because x86-64 sandboxed
// is the only ELF64 target currently implemented.)
constexpr int32_t RelocImmediateSize = 4;
Rela.r_addend -= RelocImmediateSize;
}
Str.writeAddrOrOffset<IsELF64>(Rela.r_offset);
Str.writeELFXword<IsELF64>(Rela.r_info);
Str.writeELFXword<IsELF64>(Rela.r_addend);
......
......@@ -40,7 +40,9 @@ IceString AssemblerFixup::symbol(const GlobalContext *Ctx,
Str << CR->getName();
else
Str << Ctx->mangleName(CR->getName());
if (Asm && !Asm->fixupIsPCRel(kind()) && Ctx->getFlags().getUseNonsfi()) {
if (Asm && !Asm->fixupIsPCRel(kind()) && Ctx->getFlags().getUseNonsfi() &&
CR->getName() != GlobalOffsetTable) {
// TODO(jpp): remove the special GOT test.
Str << "@GOTOFF";
}
} else {
......@@ -58,23 +60,39 @@ size_t AssemblerFixup::emit(GlobalContext *Ctx, const Assembler &Asm) const {
return FixupSize;
Ostream &Str = Ctx->getStrEmit();
Str << "\t.long ";
if (isNullSymbol())
IceString Symbol;
if (isNullSymbol()) {
Str << "__Sz_AbsoluteZero";
else
Str << symbol(Ctx, &Asm);
RelocOffsetT Offset = Asm.load<RelocOffsetT>(position());
if (Offset)
} else {
Symbol = symbol(Ctx, &Asm);
Str << Symbol;
}
assert(Asm.load<RelocOffsetT>(position()) == 0);
RelocOffsetT Offset = offset();
if (Offset != 0) {
if (Offset > 0) {
Str << " + " << Offset;
// For PCRel fixups, we write the pc-offset from a symbol into the Buffer
// (e.g., -4), but we don't represent that in the fixup's offset. Otherwise
// the fixup holds the true offset, and so does the Buffer. Just load the
// offset from the buffer.
if (Asm.fixupIsPCRel(kind()))
} else {
assert(Offset != std::numeric_limits<RelocOffsetT>::lowest());
Str << " - " << -Offset;
}
}
// We need to emit the '- .' for PCRel fixups. Even if the relocation kind()
// is not PCRel, we emit the '- .' for the _GLOBAL_OFFSET_TABLE_.
// TODO(jpp): create fixups wrt the GOT with the right fixup kind.
if (Asm.fixupIsPCRel(kind()) || Symbol == GlobalOffsetTable)
Str << " - .";
Str << "\n";
return FixupSize;
}
void AssemblerFixup::emitOffset(Assembler *Asm) const {
Asm->store(position(), offset());
}
size_t AssemblerTextFixup::emit(GlobalContext *Ctx, const Assembler &) const {
Ctx->getStrEmit() << Message << "\n";
return NumBytes;
......
......@@ -54,10 +54,15 @@ public:
void set_value(const Constant *Value) { value_ = Value; }
void set_addend(RelocOffsetT Addend) { addend_ = Addend; }
RelocOffsetT get_addend() const { return addend_; }
/// Emits fixup, then returns the number of bytes to skip.
virtual size_t emit(GlobalContext *Ctx, const Assembler &Asm) const;
/// Emits offset() (little endian) in position_. If your fixup requires
/// something smarter, you must create your own fixup type.
virtual void emitOffset(Assembler *Asm) const;
private:
bool position_was_set_ = false;
intptr_t position_ = 0;
......
......@@ -268,14 +268,14 @@ TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress(
Disp += static_cast<int32_t>(CI->getValue());
} else if (const auto *CR =
llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
RelocOffsetT DispAdjustment = 0;
if (CR->getName() != "") {
const auto FixupKind =
(getBase() != nullptr || getIndex() != nullptr) ? FK_Abs : FK_PcRel;
DispAdjustment = FixupKind == FK_PcRel ? 4 : 0;
const RelocOffsetT DispAdjustment = FixupKind == FK_PcRel ? 4 : 0;
Fixup = Asm->createFixup(FixupKind, CR);
Fixup->set_addend(-DispAdjustment);
}
Disp = CR->getOffset() - DispAdjustment;
Disp = CR->getOffset();
} else {
llvm_unreachable("Unexpected offset type");
}
......
......@@ -403,40 +403,23 @@ template <typename TraitsType>
void InstImpl<TraitsType>::InstX86GetIP::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
const auto *Dest = this->getDest();
assert(Dest->hasReg());
Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getDest()->hasReg());
Str << "\t"
"addl\t$_GLOBAL_OFFSET_TABLE_, ";
this->getDest()->emit(Func);
"call"
"\t";
auto *Target = static_cast<TargetLowering *>(Func->getTarget());
Target->emitWithoutPrefix(Target->createGetIPForRegister(Dest));
}
template <typename TraitsType>
void InstImpl<TraitsType>::InstX86GetIP::emitIAS(const Cfg *Func) const {
if (Func->getContext()->getFlags().getOutFileType() == FT_Iasm) {
// TODO(stichnot): Find a workaround for llvm-mc's inability to handle
// something like ".long _GLOBAL_OFFSET_TABLE_ + ." . One possibility is to
// just use hybrid iasm output for this add instruction.
llvm::report_fatal_error(
"Iasm support for _GLOBAL_OFFSET_TABLE_ not implemented");
}
const auto *Dest = this->getDest();
Assembler *Asm = Func->getAssembler<Assembler>();
assert(this->getDest()->hasReg());
GPRRegister Reg = Traits::getEncodedGPR(this->getDest()->getRegNum());
Constant *GlobalOffsetTable =
Func->getContext()->getConstantExternSym("_GLOBAL_OFFSET_TABLE_");
AssemblerFixup *Fixup = Asm->createFixup(Traits::FK_GotPC, GlobalOffsetTable);
intptr_t OrigPos = Asm->getBufferSize();
constexpr int32_t TempDisp = 0;
constexpr int32_t ImmediateWidth = 4;
// Emit the add instruction once, in a preliminary fashion, to find its total
// size. TODO(stichnot): IceType_i32 should really be something that
// represents the target's pointer type.
Asm->add(IceType_i32, Reg, AssemblerImmediate(TempDisp, Fixup));
const int32_t Disp = Asm->getBufferSize() - OrigPos - ImmediateWidth;
// Now roll back and emit the add instruction again, this time with the
// correct displacement.
Asm->setBufferSize(OrigPos);
Asm->add(IceType_i32, Reg, AssemblerImmediate(Disp, Fixup));
assert(Dest->hasReg());
Asm->call(static_cast<TargetLowering *>(Func->getTarget())
->createGetIPForRegister(Dest));
}
template <typename TraitsType>
......@@ -595,7 +578,6 @@ void InstImpl<TraitsType>::InstX86Jmp::emitIAS(const Cfg *Func) const {
assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
llvm::report_fatal_error("Assembler can't jmp to memory operand");
} else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Target)) {
assert(CR->getOffset() == 0 && "We only support jumping to a function");
Asm->jmp(CR);
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
// NaCl trampoline calls refer to an address within the sandbox directly.
......@@ -653,7 +635,6 @@ void InstImpl<TraitsType>::InstX86Call::emitIAS(const Cfg *Func) const {
assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
Asm->call(Mem->toAsmAddress(Asm, Target));
} else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
assert(CR->getOffset() == 0 && "We only support calling a function");
Asm->call(CR);
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
Asm->call(AssemblerImmediate(Imm->getValue()));
......@@ -748,10 +729,11 @@ void InstImpl<TraitsType>::emitIASRegOpTyGPR(const Cfg *Func, bool IsLea,
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
} else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
AssemblerFixup *Fixup =
Asm->createFixup(Traits::TargetLowering::getAbsFixup(), Reloc);
(Asm->*(Emitter.GPRImm))(Ty, VarReg,
AssemblerImmediate(Reloc->getOffset(), Fixup));
const auto FixupKind = Reloc->getName() == GlobalOffsetTable
? Traits::FK_GotPC
: Traits::TargetLowering::getAbsFixup();
AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc);
(Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Fixup));
} else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Src)) {
(Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func));
} else {
......@@ -773,10 +755,11 @@ void InstImpl<TraitsType>::emitIASAddrOpTyGPR(const Cfg *Func, Type Ty,
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue()));
} else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
AssemblerFixup *Fixup =
Asm->createFixup(Traits::TargetLowering::getAbsFixup(), Reloc);
(Asm->*(Emitter.AddrImm))(Ty, Addr,
AssemblerImmediate(Reloc->getOffset(), Fixup));
const auto FixupKind = Reloc->getName() == GlobalOffsetTable
? Traits::FK_GotPC
: Traits::TargetLowering::getAbsFixup();
AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc);
(Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Fixup));
} else {
llvm_unreachable("Unexpected operand type");
}
......
......@@ -265,6 +265,7 @@ public:
return new (Ctx->allocate<RelocOffset>()) RelocOffset(Value);
}
void setSubtract(bool Value) { Subtract = Value; }
bool hasOffset() const { return HasOffset; }
RelocOffsetT getOffset() const {
......@@ -274,7 +275,12 @@ public:
void setOffset(const RelocOffsetT Value) {
assert(!HasOffset);
if (Subtract) {
assert(Value != std::numeric_limits<RelocOffsetT>::lowest());
Offset = -Value;
} else {
Offset = Value;
}
HasOffset = true;
}
......@@ -282,6 +288,7 @@ private:
RelocOffset() = default;
explicit RelocOffset(RelocOffsetT Offset) { setOffset(Offset); }
bool Subtract = false;
bool HasOffset = false;
RelocOffsetT Offset;
};
......
......@@ -35,6 +35,14 @@ createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
void staticInit(::Ice::GlobalContext *Ctx) {
::Ice::X8632::TargetX8632::staticInit(Ctx);
if (Ctx->getFlags().getUseNonsfi()) {
// In nonsfi, we need to reference the _GLOBAL_OFFSET_TABLE_ for accessing
// globals. The GOT is an external symbol (i.e., it is not defined in the
// pexe) so we need to register it as such so that ELF emission won't barf
// on an "unknown" symbol. The GOT is added to the External symbols list
// here because staticInit() is invoked in a single-thread context.
Ctx->getConstantExternSym(::Ice::GlobalOffsetTable);
}
}
} // end of namespace X8632
......@@ -233,14 +241,30 @@ void TargetX8632::emitGetIP(CfgNode *Node) {
Variable *CallDest =
Dest->hasReg() ? Dest
: getPhysicalRegister(Traits::RegisterSet::Reg_eax);
// Call the getIP_<reg> helper.
IceString RegName = Traits::getRegName(CallDest->getRegNum());
Constant *CallTarget = Ctx->getConstantExternSym(H_getIP_prefix + RegName);
Context.insert<Traits::Insts::Call>(CallDest, CallTarget);
auto *BeforeAddReloc = RelocOffset::create(Ctx);
BeforeAddReloc->setSubtract(true);
auto *BeforeAdd = InstX86Label::create(Func, this);
BeforeAdd->setRelocOffset(BeforeAddReloc);
auto *AfterAddReloc = RelocOffset::create(Ctx);
auto *AfterAdd = InstX86Label::create(Func, this);
AfterAdd->setRelocOffset(AfterAddReloc);
auto *ImmSize = RelocOffset::create(Ctx, -typeWidthInBytes(IceType_i32));
auto *GotFromPc = llvm::cast<ConstantRelocatable>(
Ctx->getConstantSym({AfterAddReloc, BeforeAddReloc, ImmSize},
GlobalOffsetTable, GlobalOffsetTable, true));
// Insert a new version of InstX86GetIP.
Context.insert<Traits::Insts::GetIP>(CallDest);
Context.insert(BeforeAdd);
_add(CallDest, GotFromPc);
Context.insert(AfterAdd);
// Spill the register to its home stack location if necessary.
if (!Dest->hasReg()) {
if (Dest != CallDest) {
_mov(Dest, CallDest);
}
}
......
......@@ -172,6 +172,13 @@ public:
return Traits::Is64Bit ? false : Ty == IceType_i64;
}
ConstantRelocatable *createGetIPForRegister(const Variable *Dest) {
assert(Dest->hasReg());
const IceString RegName = Traits::getRegName(Dest->getRegNum());
return llvm::cast<ConstantRelocatable>(
Ctx->getConstantExternSym(H_getIP_prefix + RegName));
}
SizeT getMinJumpTableSize() const override { return 4; }
void emitVariable(const Variable *Var) const override;
......
......@@ -7097,7 +7097,7 @@ template <class Machine>
void TargetX86Base<Machine>::emit(const ConstantRelocatable *C) const {
if (!BuildDefs::dump())
return;
assert(!Ctx->getFlags().getUseNonsfi());
assert(!Ctx->getFlags().getUseNonsfi() || C->getName() == GlobalOffsetTable);
Ostream &Str = Ctx->getStrEmit();
Str << "$";
emitWithoutPrefix(C);
......
......@@ -729,8 +729,12 @@ protected:
if (NeedsEpilogue) {
addEpilogue();
}
NeedsEpilogue = false;
for (const auto *Fixup : assembler()->fixups()) {
Fixup->emitOffset(assembler());
}
return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords);
}
......
......@@ -222,7 +222,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseDisp(r6, 0x60000Fu, Disp, r7);
TestLeaBaseDisp(r7, 0x11000Fu, Disp, r8);
TestLeaBaseDisp(r8, 0x11200Fu, Disp, r10);
TestLeaBaseDisp(r9, 0x000000u, Disp, r10);
TestLeaBaseDisp(r9, 0x220400u, Disp, r10);
TestLeaBaseDisp(r10, 0x22000Fu, Disp, r11);
TestLeaBaseDisp(r11, 0x22030Fu, Disp, r12);
TestLeaBaseDisp(r12, 0x22040Fu, Disp, r13);
......@@ -242,7 +242,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaIndex32bitDisp(r6, 0xA040u, Disp, r7, r5, r10, r1);
TestLeaIndex32bitDisp(r7, 0xC050u, Disp, r5, r10, r1, r11);
TestLeaIndex32bitDisp(r8, 0xC060u, Disp, r10, r1, r11, r12);
TestLeaIndex32bitDisp(r9, 0x0000u, Disp, r1, r11, r12, r13);
TestLeaIndex32bitDisp(r9, 0xC100u, Disp, r1, r11, r12, r13);
TestLeaIndex32bitDisp(r10, 0xC008u, Disp, r11, r12, r13, r14);
TestLeaIndex32bitDisp(r11, 0xC009u, Disp, r12, r13, r14, r15);
TestLeaIndex32bitDisp(r12, 0xC00Au, Disp, r13, r14, r15, r1);
......@@ -260,7 +260,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r6, 0x500000u, r7, 0x200u, Disp, r8, r5, r10, r11);
TestLeaBaseIndexDisp(r7, 0x600000u, r8, 0x100u, Disp, r5, r10, r11, r12);
TestLeaBaseIndexDisp(r8, 0x600000u, r9, 0x1A0u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r9, 0x000000u, r10, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r9, 0x600050u, r10, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r10, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r11, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1);
TestLeaBaseIndexDisp(r12, 0x604000u, r13, 0x1E0u, Disp, r14, r15, r1, r2);
......@@ -274,7 +274,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r0, 0, r6, 0x300u, Disp, r7, r8, r5, r10);
TestLeaBaseIndexDisp(r0, 0, r7, 0x200u, Disp, r8, r5, r10, r11);
TestLeaBaseIndexDisp(r0, 0, r8, 0x100u, Disp, r5, r10, r11, r12);
TestLeaBaseIndexDisp(r0, 0, r9, 0x000u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r0, 0, r9, 0x1000u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r0, 0, r10, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r0, 0, r11, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r0, 0, r12, 0x1D0u, Disp, r13, r14, r15, r1);
......@@ -289,7 +289,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r5, 0x400000u, r6, 0x300u, Disp, r7, r8, r1, r10);
TestLeaBaseIndexDisp(r5, 0x500000u, r7, 0x200u, Disp, r8, r1, r10, r11);
TestLeaBaseIndexDisp(r5, 0x600000u, r8, 0x100u, Disp, r1, r10, r11, r12);
TestLeaBaseIndexDisp(r5, 0x600000u, r9, 0x000u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r5, 0x600000u, r9, 0x1A00u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r5, 0x601000u, r10, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r5, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r5, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1);
......@@ -304,7 +304,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r6, 0x400000u, r5, 0x300u, Disp, r7, r8, r1, r10);
TestLeaBaseIndexDisp(r7, 0x500000u, r5, 0x200u, Disp, r8, r1, r10, r11);
TestLeaBaseIndexDisp(r8, 0x600000u, r5, 0x100u, Disp, r1, r10, r11, r12);
TestLeaBaseIndexDisp(r9, 0x000000u, r5, 0x1A0u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r9, 0x660000u, r5, 0x1A0u, Disp, r10, r11, r12, r13);
TestLeaBaseIndexDisp(r10, 0x601000u, r5, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r11, 0x602000u, r5, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r12, 0x603000u, r5, 0x1D0u, Disp, r13, r14, r15, r1);
......
......@@ -913,8 +913,12 @@ protected:
if (NeedsEpilogue) {
addEpilogue();
}
NeedsEpilogue = false;
for (const auto *Fixup : assembler()->fixups()) {
Fixup->emitOffset(assembler());
}
return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment