Index: src/x64/assembler-x64.cc |
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc |
index 355996458cf70a163fc919f9cd7575e48e56ace1..597aa31f54d86c59d0cb5fe3dccae6334c716aa3 100644 |
--- a/src/x64/assembler-x64.cc |
+++ b/src/x64/assembler-x64.cc |
@@ -219,6 +219,13 @@ Operand::Operand(Register index, |
} |
+Operand::Operand(Label* label) : rex_(0), len_(1) { |
+ DCHECK_NOT_NULL(label); |
+ set_modrm(0, rbp); |
+ set_disp64(reinterpret_cast<intptr_t>(label)); |
+} |
+ |
+ |
Operand::Operand(const Operand& operand, int32_t offset) { |
DCHECK(operand.len_ >= 1); |
// Operand encodes REX ModR/M [SIB] [Disp]. |
@@ -365,15 +372,30 @@ void Assembler::bind_to(Label* L, int pos) { |
int current = L->pos(); |
int next = long_at(current); |
while (next != current) { |
- // Relative address, relative to point after address. |
- int imm32 = pos - (current + sizeof(int32_t)); |
- long_at_put(current, imm32); |
+ if (current >= 4 && long_at(current - 4) == 0) { |
+ // Absolute address. |
+ intptr_t imm64 = reinterpret_cast<intptr_t>(buffer_ + pos); |
+ *reinterpret_cast<intptr_t*>(addr_at(current - 4)) = imm64; |
+ internal_reference_positions_.push_back(current - 4); |
+ } else { |
+ // Relative address, relative to point after address. |
+ int imm32 = pos - (current + sizeof(int32_t)); |
+ long_at_put(current, imm32); |
+ } |
current = next; |
next = long_at(next); |
} |
// Fix up last fixup on linked list. |
- int last_imm32 = pos - (current + sizeof(int32_t)); |
- long_at_put(current, last_imm32); |
+ if (current >= 4 && long_at(current - 4) == 0) { |
+ // Absolute address. |
+ intptr_t imm64 = reinterpret_cast<intptr_t>(buffer_ + pos); |
+ *reinterpret_cast<intptr_t*>(addr_at(current - 4)) = imm64; |
+ internal_reference_positions_.push_back(current - 4); |
+ } else { |
+ // Relative address, relative to point after address. |
+ int imm32 = pos - (current + sizeof(int32_t)); |
+ long_at_put(current, imm32); |
+ } |
} |
while (L->is_near_linked()) { |
int fixup_pos = L->near_link_pos(); |
@@ -441,15 +463,10 @@ void Assembler::GrowBuffer() { |
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, |
reloc_info_writer.last_pc() + pc_delta); |
- // Relocate runtime entries. |
- for (RelocIterator it(desc); !it.done(); it.next()) { |
- RelocInfo::Mode rmode = it.rinfo()->rmode(); |
- if (rmode == RelocInfo::INTERNAL_REFERENCE) { |
- intptr_t* p = reinterpret_cast<intptr_t*>(it.rinfo()->pc()); |
- if (*p != 0) { // 0 means uninitialized. |
- *p += pc_delta; |
- } |
- } |
+ // Relocate internal references. |
+ for (auto pos : internal_reference_positions_) { |
+ intptr_t* p = reinterpret_cast<intptr_t*>(buffer_ + pos); |
+ *p += pc_delta; |
} |
DCHECK(!buffer_overflow()); |
@@ -463,11 +480,29 @@ void Assembler::emit_operand(int code, const Operand& adr) { |
// Emit updated ModR/M byte containing the given register. |
DCHECK((adr.buf_[0] & 0x38) == 0); |
- pc_[0] = adr.buf_[0] | code << 3; |
- |
- // Emit the rest of the encoded operand. |
- for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i]; |
- pc_ += length; |
+ *pc_++ = adr.buf_[0] | code << 3; |
+ |
+ // Recognize RIP relative addressing. |
+ if (adr.buf_[0] == 5) { |
+ DCHECK_EQ(9u, length); |
+ Label* label = *reinterpret_cast<Label* const*>(&adr.buf_[1]); |
+ if (label->is_bound()) { |
+ int offset = label->pos() - pc_offset() - sizeof(int32_t); |
+ DCHECK_GE(0, offset); |
+ emitl(offset); |
+ } else if (label->is_linked()) { |
+ emitl(label->pos()); |
+ label->link_to(pc_offset() - sizeof(int32_t)); |
+ } else { |
+ DCHECK(label->is_unused()); |
+ int32_t current = pc_offset(); |
+ emitl(current); |
+ label->link_to(current); |
+ } |
+ } else { |
+ // Emit the rest of the encoded operand. |
+ for (unsigned i = 1; i < length; i++) *pc_++ = adr.buf_[i]; |
+ } |
} |
@@ -1815,6 +1850,13 @@ void Assembler::ret(int imm16) { |
} |
+void Assembler::ud2() { |
+ EnsureSpace ensure_space(this); |
+ emit(0x0F); |
+ emit(0x0B); |
+} |
+ |
+ |
void Assembler::setcc(Condition cc, Register reg) { |
if (cc > last_condition) { |
movb(reg, Immediate(cc == always ? 1 : 0)); |
@@ -3347,6 +3389,27 @@ void Assembler::dd(uint32_t data) { |
} |
+void Assembler::dq(Label* label) { |
+ EnsureSpace ensure_space(this); |
+ if (label->is_bound()) { |
+ internal_reference_positions_.push_back(pc_offset()); |
+ emitp(buffer_ + label->pos(), RelocInfo::INTERNAL_REFERENCE); |
+ } else { |
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); |
+ emitl(0); // Zero for the first 32bit marks it as 64bit absolute address. |
+ if (label->is_linked()) { |
+ emitl(label->pos()); |
+ label->link_to(pc_offset() - sizeof(int32_t)); |
+ } else { |
+ DCHECK(label->is_unused()); |
+ int32_t current = pc_offset(); |
+ emitl(current); |
+ label->link_to(current); |
+ } |
+ } |
+} |
+ |
+ |
// Relocation information implementations. |
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |