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: ...@@ -293,6 +293,10 @@ public:
return Buffer.load<T>(Position); 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. /// Emit a fixup at the current location.
void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); } void emitFixup(AssemblerFixup *Fixup) { Buffer.emitFixup(Fixup); }
......
...@@ -501,9 +501,23 @@ EncodedOperand encodeAddress(const Operand *Opnd, IValueT &Value, ...@@ -501,9 +501,23 @@ EncodedOperand encodeAddress(const Operand *Opnd, IValueT &Value,
} }
// Checks that Offset can fit in imm24 constant of branch (b) instruction. // Checks that Offset can fit in imm24 constant of branch (b) instruction.
bool canEncodeBranchOffset(IOffsetT Offset) { void assertCanEncodeBranchOffset(IOffsetT Offset) {
return Utils::IsAligned(Offset, 4) && (void)Offset;
Utils::IsInt(kBranchOffsetBits, Offset >> 2); (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, IValueT encodeRegister(const Operand *OpReg, RegSetWanted WantedRegSet,
...@@ -595,6 +609,19 @@ size_t MoveRelocatableFixup::emit(GlobalContext *Ctx, ...@@ -595,6 +609,19 @@ size_t MoveRelocatableFixup::emit(GlobalContext *Ctx,
return InstARM32::InstSize; 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, MoveRelocatableFixup *AssemblerARM32::createMoveFixup(bool IsMovW,
const Constant *Value) { const Constant *Value) {
MoveRelocatableFixup *F = MoveRelocatableFixup *F =
...@@ -618,6 +645,15 @@ size_t BlRelocatableFixup::emit(GlobalContext *Ctx, ...@@ -618,6 +645,15 @@ size_t BlRelocatableFixup::emit(GlobalContext *Ctx,
return InstARM32::InstSize; 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) { void AssemblerARM32::padWithNop(intptr_t Padding) {
constexpr intptr_t InstWidth = sizeof(IValueT); constexpr intptr_t InstWidth = sizeof(IValueT);
assert(Padding % InstWidth == 0 && assert(Padding % InstWidth == 0 &&
...@@ -667,20 +703,6 @@ Label *AssemblerARM32::getOrCreateLabel(SizeT Number, LabelVector &Labels) { ...@@ -667,20 +703,6 @@ Label *AssemblerARM32::getOrCreateLabel(SizeT Number, LabelVector &Labels) {
return L; 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. // Pull out offset from branch Inst.
IOffsetT AssemblerARM32::decodeBranchOffset(IValueT Inst) { IOffsetT AssemblerARM32::decodeBranchOffset(IValueT Inst) {
// Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC. // Sign-extend, left-shift by 2, and adjust to the way ARM CPUs read PC.
......
...@@ -46,6 +46,7 @@ class MoveRelocatableFixup final : public AssemblerFixup { ...@@ -46,6 +46,7 @@ class MoveRelocatableFixup final : public AssemblerFixup {
public: public:
MoveRelocatableFixup() = default; MoveRelocatableFixup() = default;
size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
void emitOffset(Assembler *Asm) const;
}; };
/// Handles encoding of branch and link to global location. /// Handles encoding of branch and link to global location.
...@@ -56,6 +57,7 @@ class BlRelocatableFixup final : public AssemblerFixup { ...@@ -56,6 +57,7 @@ class BlRelocatableFixup final : public AssemblerFixup {
public: public:
BlRelocatableFixup() = default; BlRelocatableFixup() = default;
size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final; size_t emit(GlobalContext *Ctx, const Assembler &Asm) const final;
void emitOffset(Assembler *Asm) const;
}; };
class AssemblerARM32 : public Assembler { class AssemblerARM32 : public Assembler {
...@@ -645,9 +647,6 @@ private: ...@@ -645,9 +647,6 @@ private:
void emitBranch(Label *L, CondARM32::Cond, bool Link); 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. // Returns the offset encoded in the branch instruction Inst.
static IOffsetT decodeBranchOffset(IValueT Inst); static IOffsetT decodeBranchOffset(IValueT Inst);
......
...@@ -73,11 +73,7 @@ public: ...@@ -73,11 +73,7 @@ public:
public: public:
explicit Immediate(int32_t value) : value_(value) {} explicit Immediate(int32_t value) : value_(value) {}
Immediate(RelocOffsetT offset, AssemblerFixup *fixup) explicit Immediate(AssemblerFixup *fixup) : fixup_(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.
}
int32_t value() const { return value_; } int32_t value() const { return value_; }
AssemblerFixup *fixup() const { return fixup_; } AssemblerFixup *fixup() const { return fixup_; }
...@@ -95,7 +91,7 @@ public: ...@@ -95,7 +91,7 @@ public:
} }
private: private:
const int32_t value_; const int32_t value_ = 0;
AssemblerFixup *fixup_ = nullptr; AssemblerFixup *fixup_ = nullptr;
}; };
......
...@@ -134,8 +134,10 @@ void AssemblerX86Base<TraitsType>::call(const ConstantRelocatable *label) { ...@@ -134,8 +134,10 @@ void AssemblerX86Base<TraitsType>::call(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
intptr_t call_start = Buffer.getPosition(); intptr_t call_start = Buffer.getPosition();
emitUint8(0xE8); emitUint8(0xE8);
emitFixup(this->createFixup(Traits::FK_PcRel, label)); auto *Fixup = this->createFixup(Traits::FK_PcRel, label);
emitInt32(-4); Fixup->set_addend(-4);
emitFixup(Fixup);
emitInt32(0);
assert((Buffer.getPosition() - call_start) == kCallExternalLabelSize); assert((Buffer.getPosition() - call_start) == kCallExternalLabelSize);
(void)call_start; (void)call_start;
} }
...@@ -145,8 +147,10 @@ void AssemblerX86Base<TraitsType>::call(const Immediate &abs_address) { ...@@ -145,8 +147,10 @@ void AssemblerX86Base<TraitsType>::call(const Immediate &abs_address) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
intptr_t call_start = Buffer.getPosition(); intptr_t call_start = Buffer.getPosition();
emitUint8(0xE8); emitUint8(0xE8);
emitFixup(this->createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol)); auto *Fixup = this->createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol);
emitInt32(abs_address.value() - 4); Fixup->set_addend(abs_address.value() - 4);
emitFixup(Fixup);
emitInt32(0);
assert((Buffer.getPosition() - call_start) == kCallExternalLabelSize); assert((Buffer.getPosition() - call_start) == kCallExternalLabelSize);
(void)call_start; (void)call_start;
} }
...@@ -3140,8 +3144,10 @@ void AssemblerX86Base<TraitsType>::j(BrCond condition, ...@@ -3140,8 +3144,10 @@ void AssemblerX86Base<TraitsType>::j(BrCond condition,
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitUint8(0x0F); emitUint8(0x0F);
emitUint8(0x80 + condition); emitUint8(0x80 + condition);
emitFixup(this->createFixup(Traits::FK_PcRel, label)); auto *Fixup = this->createFixup(Traits::FK_PcRel, label);
emitInt32(-4); Fixup->set_addend(-4);
emitFixup(Fixup);
emitInt32(0);
} }
template <typename TraitsType> template <typename TraitsType>
...@@ -3180,8 +3186,10 @@ template <typename TraitsType> ...@@ -3180,8 +3186,10 @@ template <typename TraitsType>
void AssemblerX86Base<TraitsType>::jmp(const ConstantRelocatable *label) { void AssemblerX86Base<TraitsType>::jmp(const ConstantRelocatable *label) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitUint8(0xE9); emitUint8(0xE9);
emitFixup(this->createFixup(Traits::FK_PcRel, label)); auto *Fixup = this->createFixup(Traits::FK_PcRel, label);
emitInt32(-4); Fixup->set_addend(-4);
emitFixup(Fixup);
emitInt32(0);
} }
template <typename TraitsType> template <typename TraitsType>
...@@ -3189,10 +3197,10 @@ void AssemblerX86Base<TraitsType>::jmp(const Immediate &abs_address) { ...@@ -3189,10 +3197,10 @@ void AssemblerX86Base<TraitsType>::jmp(const Immediate &abs_address) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
emitUint8(0xE9); emitUint8(0xE9);
AssemblerFixup *Fixup = AssemblerFixup *Fixup =
this->createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol); createFixup(Traits::FK_PcRel, AssemblerFixup::NullSymbol);
Fixup->set_addend(abs_address.value()); Fixup->set_addend(abs_address.value() - 4);
emitFixup(Fixup); emitFixup(Fixup);
emitInt32(abs_address.value() - 4); emitInt32(0);
} }
template <typename TraitsType> void AssemblerX86Base<TraitsType>::mfence() { template <typename TraitsType> void AssemblerX86Base<TraitsType>::mfence() {
...@@ -3391,23 +3399,26 @@ void AssemblerX86Base<TraitsType>::emitOperand(int rm, const Operand &operand, ...@@ -3391,23 +3399,26 @@ void AssemblerX86Base<TraitsType>::emitOperand(int rm, const Operand &operand,
emitUint8(operand.encoding_[1]); emitUint8(operand.encoding_[1]);
displacement_start = 2; displacement_start = 2;
} }
// Emit the displacement and the fixup that affects it, if any.
AssemblerFixup *Fixup = operand.fixup(); AssemblerFixup *Fixup = operand.fixup();
if (Fixup != nullptr) { if (Fixup == nullptr) {
emitFixup(Fixup); for (intptr_t i = displacement_start; i < length; i++) {
assert(length - displacement_start == 4); emitUint8(operand.encoding_[i]);
if (fixupIsPCRel(Fixup->kind())) {
Fixup->set_addend(-Addend);
int32_t Offset;
memmove(&Offset, &operand.encoding_[displacement_start], sizeof(Offset));
Offset -= Addend;
emitInt32(Offset);
return;
} }
return;
} }
for (intptr_t i = displacement_start; i < length; i++) {
emitUint8(operand.encoding_[i]); // 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> template <typename TraitsType>
...@@ -3420,10 +3431,14 @@ void AssemblerX86Base<TraitsType>::emitImmediate(Type Ty, ...@@ -3420,10 +3431,14 @@ void AssemblerX86Base<TraitsType>::emitImmediate(Type Ty,
return; return;
} }
if (Fixup != nullptr) { if (Fixup == nullptr) {
emitFixup(Fixup); emitInt32(imm.value());
return;
} }
emitInt32(imm.value());
Fixup->set_addend(Fixup->get_addend() + imm.value());
emitFixup(Fixup);
emitInt32(0);
} }
template <typename TraitsType> template <typename TraitsType>
......
...@@ -74,6 +74,8 @@ class Variable; ...@@ -74,6 +74,8 @@ class Variable;
class VariableDeclaration; class VariableDeclaration;
class VariablesMetadata; class VariablesMetadata;
constexpr char GlobalOffsetTable[] = "_GLOBAL_OFFSET_TABLE_";
template <size_t SlabSize = 1024 * 1024> template <size_t SlabSize = 1024 * 1024>
using ArenaAllocator = using ArenaAllocator =
llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, SlabSize>; llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, SlabSize>;
......
...@@ -217,7 +217,7 @@ Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) { ...@@ -217,7 +217,7 @@ Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
} }
void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
bool IsInternal, const Assembler *Asm) { bool IsInternal, Assembler *Asm) {
assert(!SectionNumbersAssigned); assert(!SectionNumbersAssigned);
ELFTextSection *Section = nullptr; ELFTextSection *Section = nullptr;
ELFRelocationSection *RelSection = nullptr; ELFRelocationSection *RelSection = nullptr;
...@@ -243,7 +243,6 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -243,7 +243,6 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
// Function symbols are set to 0 size in the symbol table, in contrast to // Function symbols are set to 0 size in the symbol table, in contrast to
// data symbols which have a proper size. // data symbols which have a proper size.
constexpr SizeT SymbolSize = 0; constexpr SizeT SymbolSize = 0;
Section->appendData(Str, Asm->getBufferView());
uint8_t SymbolType; uint8_t SymbolType;
uint8_t SymbolBinding; uint8_t SymbolBinding;
if (IsInternal && !Ctx.getFlags().getDisableInternal()) { if (IsInternal && !Ctx.getFlags().getDisableInternal()) {
...@@ -259,9 +258,18 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, ...@@ -259,9 +258,18 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
// Copy the fixup information from per-function Assembler memory to the // Copy the fixup information from per-function Assembler memory to the
// object writer's memory, for writing later. // 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()); RelSection->addRelocations(OffsetInSection, Asm->fixups());
} }
Section->appendData(Str, Asm->getBufferView());
} }
namespace { namespace {
......
...@@ -69,7 +69,7 @@ public: ...@@ -69,7 +69,7 @@ public:
/// after all functions are written. The text buffer and fixups are extracted /// after all functions are written. The text buffer and fixups are extracted
/// from the Assembler object. /// from the Assembler object.
void writeFunctionCode(const IceString &FuncName, bool IsInternal, void writeFunctionCode(const IceString &FuncName, bool IsInternal,
const Assembler *Asm); Assembler *Asm);
/// Queries the GlobalContext for constant pools of the given type and writes /// Queries the GlobalContext for constant pools of the given type and writes
/// out read-only data sections for those constants. This also fills the /// out read-only data sections for those constants. This also fills the
......
...@@ -367,13 +367,6 @@ void ELFRelocationSection::writeData(const GlobalContext &Ctx, ELFStreamer &Str, ...@@ -367,13 +367,6 @@ void ELFRelocationSection::writeData(const GlobalContext &Ctx, ELFStreamer &Str,
Rela.r_offset = Fixup.position(); Rela.r_offset = Fixup.position();
Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind()); Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
Rela.r_addend = Fixup.offset(); 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.writeAddrOrOffset<IsELF64>(Rela.r_offset);
Str.writeELFXword<IsELF64>(Rela.r_info); Str.writeELFXword<IsELF64>(Rela.r_info);
Str.writeELFXword<IsELF64>(Rela.r_addend); Str.writeELFXword<IsELF64>(Rela.r_addend);
......
...@@ -40,7 +40,9 @@ IceString AssemblerFixup::symbol(const GlobalContext *Ctx, ...@@ -40,7 +40,9 @@ IceString AssemblerFixup::symbol(const GlobalContext *Ctx,
Str << CR->getName(); Str << CR->getName();
else else
Str << Ctx->mangleName(CR->getName()); 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"; Str << "@GOTOFF";
} }
} else { } else {
...@@ -58,23 +60,39 @@ size_t AssemblerFixup::emit(GlobalContext *Ctx, const Assembler &Asm) const { ...@@ -58,23 +60,39 @@ size_t AssemblerFixup::emit(GlobalContext *Ctx, const Assembler &Asm) const {
return FixupSize; return FixupSize;
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
Str << "\t.long "; Str << "\t.long ";
if (isNullSymbol()) IceString Symbol;
if (isNullSymbol()) {
Str << "__Sz_AbsoluteZero"; Str << "__Sz_AbsoluteZero";
else } else {
Str << symbol(Ctx, &Asm); Symbol = symbol(Ctx, &Asm);
RelocOffsetT Offset = Asm.load<RelocOffsetT>(position()); Str << Symbol;
if (Offset) }
Str << " + " << Offset;
// For PCRel fixups, we write the pc-offset from a symbol into the Buffer assert(Asm.load<RelocOffsetT>(position()) == 0);
// (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 RelocOffsetT Offset = offset();
// offset from the buffer. if (Offset != 0) {
if (Asm.fixupIsPCRel(kind())) if (Offset > 0) {
Str << " + " << Offset;
} 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 << " - .";
Str << "\n"; Str << "\n";
return FixupSize; return FixupSize;
} }
void AssemblerFixup::emitOffset(Assembler *Asm) const {
Asm->store(position(), offset());
}
size_t AssemblerTextFixup::emit(GlobalContext *Ctx, const Assembler &) const { size_t AssemblerTextFixup::emit(GlobalContext *Ctx, const Assembler &) const {
Ctx->getStrEmit() << Message << "\n"; Ctx->getStrEmit() << Message << "\n";
return NumBytes; return NumBytes;
......
...@@ -54,10 +54,15 @@ public: ...@@ -54,10 +54,15 @@ public:
void set_value(const Constant *Value) { value_ = Value; } void set_value(const Constant *Value) { value_ = Value; }
void set_addend(RelocOffsetT Addend) { addend_ = Addend; } void set_addend(RelocOffsetT Addend) { addend_ = Addend; }
RelocOffsetT get_addend() const { return addend_; }
/// Emits fixup, then returns the number of bytes to skip. /// Emits fixup, then returns the number of bytes to skip.
virtual size_t emit(GlobalContext *Ctx, const Assembler &Asm) const; 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: private:
bool position_was_set_ = false; bool position_was_set_ = false;
intptr_t position_ = 0; intptr_t position_ = 0;
......
...@@ -268,14 +268,14 @@ TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress( ...@@ -268,14 +268,14 @@ TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress(
Disp += static_cast<int32_t>(CI->getValue()); Disp += static_cast<int32_t>(CI->getValue());
} else if (const auto *CR = } else if (const auto *CR =
llvm::dyn_cast<ConstantRelocatable>(getOffset())) { llvm::dyn_cast<ConstantRelocatable>(getOffset())) {
RelocOffsetT DispAdjustment = 0;
if (CR->getName() != "") { if (CR->getName() != "") {
const auto FixupKind = const auto FixupKind =
(getBase() != nullptr || getIndex() != nullptr) ? FK_Abs : FK_PcRel; (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 = Asm->createFixup(FixupKind, CR);
Fixup->set_addend(-DispAdjustment);
} }
Disp = CR->getOffset() - DispAdjustment; Disp = CR->getOffset();
} else { } else {
llvm_unreachable("Unexpected offset type"); llvm_unreachable("Unexpected offset type");
} }
......
...@@ -403,40 +403,23 @@ template <typename TraitsType> ...@@ -403,40 +403,23 @@ template <typename TraitsType>
void InstImpl<TraitsType>::InstX86GetIP::emit(const Cfg *Func) const { void InstImpl<TraitsType>::InstX86GetIP::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
const auto *Dest = this->getDest();
assert(Dest->hasReg());
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(this->getDest()->hasReg());
Str << "\t" Str << "\t"
"addl\t$_GLOBAL_OFFSET_TABLE_, "; "call"
this->getDest()->emit(Func); "\t";
auto *Target = static_cast<TargetLowering *>(Func->getTarget());
Target->emitWithoutPrefix(Target->createGetIPForRegister(Dest));
} }
template <typename TraitsType> template <typename TraitsType>
void InstImpl<TraitsType>::InstX86GetIP::emitIAS(const Cfg *Func) const { void InstImpl<TraitsType>::InstX86GetIP::emitIAS(const Cfg *Func) const {
if (Func->getContext()->getFlags().getOutFileType() == FT_Iasm) { const auto *Dest = this->getDest();
// 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");
}
Assembler *Asm = Func->getAssembler<Assembler>(); Assembler *Asm = Func->getAssembler<Assembler>();
assert(this->getDest()->hasReg()); assert(Dest->hasReg());
GPRRegister Reg = Traits::getEncodedGPR(this->getDest()->getRegNum()); Asm->call(static_cast<TargetLowering *>(Func->getTarget())
Constant *GlobalOffsetTable = ->createGetIPForRegister(Dest));
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));
} }
template <typename TraitsType> template <typename TraitsType>
...@@ -595,7 +578,6 @@ void InstImpl<TraitsType>::InstX86Jmp::emitIAS(const Cfg *Func) const { ...@@ -595,7 +578,6 @@ void InstImpl<TraitsType>::InstX86Jmp::emitIAS(const Cfg *Func) const {
assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment); assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
llvm::report_fatal_error("Assembler can't jmp to memory operand"); llvm::report_fatal_error("Assembler can't jmp to memory operand");
} else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Target)) { } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Target)) {
assert(CR->getOffset() == 0 && "We only support jumping to a function");
Asm->jmp(CR); Asm->jmp(CR);
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Target)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
// NaCl trampoline calls refer to an address within the sandbox directly. // NaCl trampoline calls refer to an address within the sandbox directly.
...@@ -653,7 +635,6 @@ void InstImpl<TraitsType>::InstX86Call::emitIAS(const Cfg *Func) const { ...@@ -653,7 +635,6 @@ void InstImpl<TraitsType>::InstX86Call::emitIAS(const Cfg *Func) const {
assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment); assert(Mem->getSegmentRegister() == X86OperandMem::DefaultSegment);
Asm->call(Mem->toAsmAddress(Asm, Target)); Asm->call(Mem->toAsmAddress(Asm, Target));
} else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(CallTarget)) { } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
assert(CR->getOffset() == 0 && "We only support calling a function");
Asm->call(CR); Asm->call(CR);
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(CallTarget)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
Asm->call(AssemblerImmediate(Imm->getValue())); Asm->call(AssemblerImmediate(Imm->getValue()));
...@@ -748,10 +729,11 @@ void InstImpl<TraitsType>::emitIASRegOpTyGPR(const Cfg *Func, bool IsLea, ...@@ -748,10 +729,11 @@ void InstImpl<TraitsType>::emitIASRegOpTyGPR(const Cfg *Func, bool IsLea,
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue())); (Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Imm->getValue()));
} else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
AssemblerFixup *Fixup = const auto FixupKind = Reloc->getName() == GlobalOffsetTable
Asm->createFixup(Traits::TargetLowering::getAbsFixup(), Reloc); ? Traits::FK_GotPC
(Asm->*(Emitter.GPRImm))(Ty, VarReg, : Traits::TargetLowering::getAbsFixup();
AssemblerImmediate(Reloc->getOffset(), Fixup)); AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc);
(Asm->*(Emitter.GPRImm))(Ty, VarReg, AssemblerImmediate(Fixup));
} else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Src)) { } else if (const auto *Split = llvm::dyn_cast<VariableSplit>(Src)) {
(Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func)); (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func));
} else { } else {
...@@ -773,10 +755,11 @@ void InstImpl<TraitsType>::emitIASAddrOpTyGPR(const Cfg *Func, Type Ty, ...@@ -773,10 +755,11 @@ void InstImpl<TraitsType>::emitIASAddrOpTyGPR(const Cfg *Func, Type Ty,
} else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) { } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
(Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue())); (Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Imm->getValue()));
} else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) { } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
AssemblerFixup *Fixup = const auto FixupKind = Reloc->getName() == GlobalOffsetTable
Asm->createFixup(Traits::TargetLowering::getAbsFixup(), Reloc); ? Traits::FK_GotPC
(Asm->*(Emitter.AddrImm))(Ty, Addr, : Traits::TargetLowering::getAbsFixup();
AssemblerImmediate(Reloc->getOffset(), Fixup)); AssemblerFixup *Fixup = Asm->createFixup(FixupKind, Reloc);
(Asm->*(Emitter.AddrImm))(Ty, Addr, AssemblerImmediate(Fixup));
} else { } else {
llvm_unreachable("Unexpected operand type"); llvm_unreachable("Unexpected operand type");
} }
......
...@@ -265,6 +265,7 @@ public: ...@@ -265,6 +265,7 @@ public:
return new (Ctx->allocate<RelocOffset>()) RelocOffset(Value); return new (Ctx->allocate<RelocOffset>()) RelocOffset(Value);
} }
void setSubtract(bool Value) { Subtract = Value; }
bool hasOffset() const { return HasOffset; } bool hasOffset() const { return HasOffset; }
RelocOffsetT getOffset() const { RelocOffsetT getOffset() const {
...@@ -274,7 +275,12 @@ public: ...@@ -274,7 +275,12 @@ public:
void setOffset(const RelocOffsetT Value) { void setOffset(const RelocOffsetT Value) {
assert(!HasOffset); assert(!HasOffset);
Offset = Value; if (Subtract) {
assert(Value != std::numeric_limits<RelocOffsetT>::lowest());
Offset = -Value;
} else {
Offset = Value;
}
HasOffset = true; HasOffset = true;
} }
...@@ -282,6 +288,7 @@ private: ...@@ -282,6 +288,7 @@ private:
RelocOffset() = default; RelocOffset() = default;
explicit RelocOffset(RelocOffsetT Offset) { setOffset(Offset); } explicit RelocOffset(RelocOffsetT Offset) { setOffset(Offset); }
bool Subtract = false;
bool HasOffset = false; bool HasOffset = false;
RelocOffsetT Offset; RelocOffsetT Offset;
}; };
......
...@@ -35,6 +35,14 @@ createTargetHeaderLowering(::Ice::GlobalContext *Ctx) { ...@@ -35,6 +35,14 @@ createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
void staticInit(::Ice::GlobalContext *Ctx) { void staticInit(::Ice::GlobalContext *Ctx) {
::Ice::X8632::TargetX8632::staticInit(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 } // end of namespace X8632
...@@ -233,14 +241,30 @@ void TargetX8632::emitGetIP(CfgNode *Node) { ...@@ -233,14 +241,30 @@ void TargetX8632::emitGetIP(CfgNode *Node) {
Variable *CallDest = Variable *CallDest =
Dest->hasReg() ? Dest Dest->hasReg() ? Dest
: getPhysicalRegister(Traits::RegisterSet::Reg_eax); : getPhysicalRegister(Traits::RegisterSet::Reg_eax);
// Call the getIP_<reg> helper. auto *BeforeAddReloc = RelocOffset::create(Ctx);
IceString RegName = Traits::getRegName(CallDest->getRegNum()); BeforeAddReloc->setSubtract(true);
Constant *CallTarget = Ctx->getConstantExternSym(H_getIP_prefix + RegName); auto *BeforeAdd = InstX86Label::create(Func, this);
Context.insert<Traits::Insts::Call>(CallDest, CallTarget); 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. // Insert a new version of InstX86GetIP.
Context.insert<Traits::Insts::GetIP>(CallDest); 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. // Spill the register to its home stack location if necessary.
if (!Dest->hasReg()) { if (Dest != CallDest) {
_mov(Dest, CallDest); _mov(Dest, CallDest);
} }
} }
......
...@@ -172,6 +172,13 @@ public: ...@@ -172,6 +172,13 @@ public:
return Traits::Is64Bit ? false : Ty == IceType_i64; 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; } SizeT getMinJumpTableSize() const override { return 4; }
void emitVariable(const Variable *Var) const override; void emitVariable(const Variable *Var) const override;
......
...@@ -7097,7 +7097,7 @@ template <class Machine> ...@@ -7097,7 +7097,7 @@ template <class Machine>
void TargetX86Base<Machine>::emit(const ConstantRelocatable *C) const { void TargetX86Base<Machine>::emit(const ConstantRelocatable *C) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
assert(!Ctx->getFlags().getUseNonsfi()); assert(!Ctx->getFlags().getUseNonsfi() || C->getName() == GlobalOffsetTable);
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
Str << "$"; Str << "$";
emitWithoutPrefix(C); emitWithoutPrefix(C);
......
...@@ -729,8 +729,12 @@ protected: ...@@ -729,8 +729,12 @@ protected:
if (NeedsEpilogue) { if (NeedsEpilogue) {
addEpilogue(); addEpilogue();
} }
NeedsEpilogue = false; NeedsEpilogue = false;
for (const auto *Fixup : assembler()->fixups()) {
Fixup->emitOffset(assembler());
}
return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords); return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords);
} }
......
...@@ -222,7 +222,7 @@ TEST_F(AssemblerX8664Test, Lea) { ...@@ -222,7 +222,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseDisp(r6, 0x60000Fu, Disp, r7); TestLeaBaseDisp(r6, 0x60000Fu, Disp, r7);
TestLeaBaseDisp(r7, 0x11000Fu, Disp, r8); TestLeaBaseDisp(r7, 0x11000Fu, Disp, r8);
TestLeaBaseDisp(r8, 0x11200Fu, Disp, r10); TestLeaBaseDisp(r8, 0x11200Fu, Disp, r10);
TestLeaBaseDisp(r9, 0x000000u, Disp, r10); TestLeaBaseDisp(r9, 0x220400u, Disp, r10);
TestLeaBaseDisp(r10, 0x22000Fu, Disp, r11); TestLeaBaseDisp(r10, 0x22000Fu, Disp, r11);
TestLeaBaseDisp(r11, 0x22030Fu, Disp, r12); TestLeaBaseDisp(r11, 0x22030Fu, Disp, r12);
TestLeaBaseDisp(r12, 0x22040Fu, Disp, r13); TestLeaBaseDisp(r12, 0x22040Fu, Disp, r13);
...@@ -242,7 +242,7 @@ TEST_F(AssemblerX8664Test, Lea) { ...@@ -242,7 +242,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaIndex32bitDisp(r6, 0xA040u, Disp, r7, r5, r10, r1); TestLeaIndex32bitDisp(r6, 0xA040u, Disp, r7, r5, r10, r1);
TestLeaIndex32bitDisp(r7, 0xC050u, Disp, r5, r10, r1, r11); TestLeaIndex32bitDisp(r7, 0xC050u, Disp, r5, r10, r1, r11);
TestLeaIndex32bitDisp(r8, 0xC060u, Disp, r10, r1, r11, r12); 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(r10, 0xC008u, Disp, r11, r12, r13, r14);
TestLeaIndex32bitDisp(r11, 0xC009u, Disp, r12, r13, r14, r15); TestLeaIndex32bitDisp(r11, 0xC009u, Disp, r12, r13, r14, r15);
TestLeaIndex32bitDisp(r12, 0xC00Au, Disp, r13, r14, r15, r1); TestLeaIndex32bitDisp(r12, 0xC00Au, Disp, r13, r14, r15, r1);
...@@ -260,7 +260,7 @@ TEST_F(AssemblerX8664Test, Lea) { ...@@ -260,7 +260,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r6, 0x500000u, r7, 0x200u, Disp, r8, r5, r10, r11); TestLeaBaseIndexDisp(r6, 0x500000u, r7, 0x200u, Disp, r8, r5, r10, r11);
TestLeaBaseIndexDisp(r7, 0x600000u, r8, 0x100u, Disp, r5, r10, r11, r12); TestLeaBaseIndexDisp(r7, 0x600000u, r8, 0x100u, Disp, r5, r10, r11, r12);
TestLeaBaseIndexDisp(r8, 0x600000u, r9, 0x1A0u, Disp, r10, r11, r12, r13); 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(r10, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r11, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1); TestLeaBaseIndexDisp(r11, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1);
TestLeaBaseIndexDisp(r12, 0x604000u, r13, 0x1E0u, Disp, r14, r15, r1, r2); TestLeaBaseIndexDisp(r12, 0x604000u, r13, 0x1E0u, Disp, r14, r15, r1, r2);
...@@ -274,7 +274,7 @@ TEST_F(AssemblerX8664Test, Lea) { ...@@ -274,7 +274,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r0, 0, r6, 0x300u, Disp, r7, r8, r5, r10); TestLeaBaseIndexDisp(r0, 0, r6, 0x300u, Disp, r7, r8, r5, r10);
TestLeaBaseIndexDisp(r0, 0, r7, 0x200u, Disp, r8, r5, r10, r11); TestLeaBaseIndexDisp(r0, 0, r7, 0x200u, Disp, r8, r5, r10, r11);
TestLeaBaseIndexDisp(r0, 0, r8, 0x100u, Disp, r5, r10, r11, r12); 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, r10, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r0, 0, r11, 0x1C0u, Disp, r12, r13, r14, r15); TestLeaBaseIndexDisp(r0, 0, r11, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r0, 0, r12, 0x1D0u, Disp, r13, r14, r15, r1); TestLeaBaseIndexDisp(r0, 0, r12, 0x1D0u, Disp, r13, r14, r15, r1);
...@@ -289,7 +289,7 @@ TEST_F(AssemblerX8664Test, Lea) { ...@@ -289,7 +289,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r5, 0x400000u, r6, 0x300u, Disp, r7, r8, r1, r10); TestLeaBaseIndexDisp(r5, 0x400000u, r6, 0x300u, Disp, r7, r8, r1, r10);
TestLeaBaseIndexDisp(r5, 0x500000u, r7, 0x200u, Disp, r8, r1, r10, r11); TestLeaBaseIndexDisp(r5, 0x500000u, r7, 0x200u, Disp, r8, r1, r10, r11);
TestLeaBaseIndexDisp(r5, 0x600000u, r8, 0x100u, Disp, r1, r10, r11, r12); 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, 0x601000u, r10, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r5, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15); TestLeaBaseIndexDisp(r5, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r5, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1); TestLeaBaseIndexDisp(r5, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1);
...@@ -304,7 +304,7 @@ TEST_F(AssemblerX8664Test, Lea) { ...@@ -304,7 +304,7 @@ TEST_F(AssemblerX8664Test, Lea) {
TestLeaBaseIndexDisp(r6, 0x400000u, r5, 0x300u, Disp, r7, r8, r1, r10); TestLeaBaseIndexDisp(r6, 0x400000u, r5, 0x300u, Disp, r7, r8, r1, r10);
TestLeaBaseIndexDisp(r7, 0x500000u, r5, 0x200u, Disp, r8, r1, r10, r11); TestLeaBaseIndexDisp(r7, 0x500000u, r5, 0x200u, Disp, r8, r1, r10, r11);
TestLeaBaseIndexDisp(r8, 0x600000u, r5, 0x100u, Disp, r1, r10, r11, r12); 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(r10, 0x601000u, r5, 0x1B0u, Disp, r11, r12, r13, r14);
TestLeaBaseIndexDisp(r11, 0x602000u, r5, 0x1C0u, Disp, r12, r13, r14, r15); TestLeaBaseIndexDisp(r11, 0x602000u, r5, 0x1C0u, Disp, r12, r13, r14, r15);
TestLeaBaseIndexDisp(r12, 0x603000u, r5, 0x1D0u, Disp, r13, r14, r15, r1); TestLeaBaseIndexDisp(r12, 0x603000u, r5, 0x1D0u, Disp, r13, r14, r15, r1);
......
...@@ -913,8 +913,12 @@ protected: ...@@ -913,8 +913,12 @@ protected:
if (NeedsEpilogue) { if (NeedsEpilogue) {
addEpilogue(); addEpilogue();
} }
NeedsEpilogue = false; NeedsEpilogue = false;
for (const auto *Fixup : assembler()->fixups()) {
Fixup->emitOffset(assembler());
}
return AssembledTest(codeBytes(), codeBytesSize(), NumAllocatedDwords); 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