📄 assembler-ia32.cc.svn-base
字号:
// Copyright (c) 1994-2006 Sun Microsystems Inc.// All Rights Reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions// are met://// - Redistributions of source code must retain the above copyright notice,// this list of conditions and the following disclaimer.//// - Redistribution in binary form must reproduce the above copyright// notice, this list of conditions and the following disclaimer in the// documentation and/or other materials provided with the// distribution.//// - Neither the name of Sun Microsystems or the names of contributors may// be used to endorse or promote products derived from this software without// specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED// OF THE POSSIBILITY OF SUCH DAMAGE.// The original source code covered by the above license above has been modified// significantly by Google Inc.// Copyright 2006-2008 the V8 project authors. All rights reserved.#include "v8.h"#include "disassembler.h"#include "macro-assembler.h"#include "serialize.h"namespace v8 { namespace internal {// -----------------------------------------------------------------------------// Implementation of RegisterRegister eax = { 0 };Register ecx = { 1 };Register edx = { 2 };Register ebx = { 3 };Register esp = { 4 };Register ebp = { 5 };Register esi = { 6 };Register edi = { 7 };Register no_reg = { -1 };XMMRegister xmm0 = { 0 };XMMRegister xmm1 = { 1 };XMMRegister xmm2 = { 2 };XMMRegister xmm3 = { 3 };XMMRegister xmm4 = { 4 };XMMRegister xmm5 = { 5 };XMMRegister xmm6 = { 6 };XMMRegister xmm7 = { 7 };// -----------------------------------------------------------------------------// Implementation of CpuFeatures// Safe default is no features.uint32_t CpuFeatures::supported_ = 0;uint32_t CpuFeatures::enabled_ = 0;typedef int (*F0)();// The Probe method needs executable memory, so it uses Heap::CreateCode.// Allocation failure is silent and leads to safe default.void CpuFeatures::Probe() { supported_ = 0; if (Serializer::enabled()) return; // No features if we might serialize. Assembler assm(NULL, 0); Label done;#define __ assm. // Save old esp, since we are going to modify the stack. __ push(ebp); __ pushfd(); __ push(ecx); __ push(edx); __ push(ebx); __ mov(ebp, Operand(esp)); // If we can modify bit 21 of the EFLAGS register, then CPUID is supported. __ pushfd(); __ pop(eax); __ mov(edx, Operand(eax)); __ xor_(eax, 0x200000); // Flip bit 21. __ push(eax); __ popfd(); __ pushfd(); __ pop(eax); __ xor_(eax, Operand(edx)); // Different if CPUID is supported. __ j(zero, &done); // Invoke CPUID with 1 in eax to get feature information in edx. __ mov(eax, 1); // Temporarily force CPUID support, since we know it is safe here. supported_ = (1 << CPUID); { Scope fscope(CPUID); __ cpuid(); } supported_ = 0; // Return result in eax. __ mov(eax, Operand(edx)); __ bind(&done); __ mov(esp, Operand(ebp)); __ pop(ebx); __ pop(edx); __ pop(ecx); __ popfd(); __ pop(ebp); __ ret(0);#undef __ CodeDesc desc; assm.GetCode(&desc); Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB)); if (!code->IsCode()) return; F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry()); uint32_t res = f(); supported_ = (res | (1 << CPUID));}// -----------------------------------------------------------------------------// Implementation of Displacementvoid Displacement::init(Label* L, Type type) { ASSERT(!L->is_bound()); int next = 0; if (L->is_linked()) { next = L->pos(); ASSERT(next > 0); // Displacements must be at positions > 0 } // Ensure that we _never_ overflow the next field. ASSERT(NextField::is_valid(Assembler::kMaximalBufferSize)); data_ = NextField::encode(next) | TypeField::encode(type);}// -----------------------------------------------------------------------------// Implementation of RelocInfoconst int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | 1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE;void RelocInfo::patch_code(byte* instructions, int instruction_count) { // Patch the code at the current address with the supplied instructions. for (int i = 0; i < instruction_count; i++) { *(pc_ + i) = *(instructions + i); }}// Patch the code at the current PC with a call to the target address.// Additional guard int3 instructions can be added if required.void RelocInfo::patch_code_with_call(Address target, int guard_bytes) { // Call instruction takes up 5 bytes and int3 takes up one byte. int code_size = 5 + guard_bytes; // Patch the code. CodePatcher patcher(pc_, code_size); patcher.masm()->call(target, RelocInfo::NONE); // Add the requested number of int3 instructions after the call. for (int i = 0; i < guard_bytes; i++) { patcher.masm()->int3(); }}// -----------------------------------------------------------------------------// Implementation of OperandOperand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) { // [base + disp/r] if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) { // [base] set_modrm(0, base); if (base.is(esp)) set_sib(times_1, esp, base); } else if (is_int8(disp) && rmode == RelocInfo::NONE) { // [base + disp8] set_modrm(1, base); if (base.is(esp)) set_sib(times_1, esp, base); set_disp8(disp); } else { // [base + disp/r] set_modrm(2, base); if (base.is(esp)) set_sib(times_1, esp, base); set_dispr(disp, rmode); }}Operand::Operand(Register base, Register index, ScaleFactor scale, int32_t disp, RelocInfo::Mode rmode) { ASSERT(!index.is(esp)); // illegal addressing mode // [base + index*scale + disp/r] if (disp == 0 && rmode == RelocInfo::NONE && !base.is(ebp)) { // [base + index*scale] set_modrm(0, esp); set_sib(scale, index, base); } else if (is_int8(disp) && rmode == RelocInfo::NONE) { // [base + index*scale + disp8] set_modrm(1, esp); set_sib(scale, index, base); set_disp8(disp); } else { // [base + index*scale + disp/r] set_modrm(2, esp); set_sib(scale, index, base); set_dispr(disp, rmode); }}Operand::Operand(Register index, ScaleFactor scale, int32_t disp, RelocInfo::Mode rmode) { ASSERT(!index.is(esp)); // illegal addressing mode // [index*scale + disp/r] set_modrm(0, esp); set_sib(scale, index, ebp); set_dispr(disp, rmode);}void Operand::set_sib(ScaleFactor scale, Register index, Register base) { ASSERT(len_ == 1); ASSERT((scale & -4) == 0); buf_[1] = scale << 6 | index.code() << 3 | base.code(); len_ = 2;}void Operand::set_disp8(int8_t disp) { ASSERT(len_ == 1 || len_ == 2); *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp;}void Operand::set_reg(Register reg) const { ASSERT(len_ > 0); buf_[0] = (buf_[0] & ~0x38) | static_cast<byte>(reg.code() << 3);}bool Operand::is_reg(Register reg) const { return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. && ((buf_[0] & 0x07) == reg.code()); // register codes match.}// -----------------------------------------------------------------------------// Implementation of Assembler// Emit a single byte. Must always be inlined.#define EMIT(x) \ *pc_++ = (x)// spare_buffer_static byte* spare_buffer_ = NULL;Assembler::Assembler(void* buffer, int buffer_size) { if (buffer == NULL) { // do our own buffer management if (buffer_size <= kMinimalBufferSize) { buffer_size = kMinimalBufferSize; if (spare_buffer_ != NULL) { buffer = spare_buffer_; spare_buffer_ = NULL; } } if (buffer == NULL) { buffer_ = NewArray<byte>(buffer_size); } else { buffer_ = static_cast<byte*>(buffer); } buffer_size_ = buffer_size; own_buffer_ = true; } else { // use externally provided buffer instead ASSERT(buffer_size > 0); buffer_ = static_cast<byte*>(buffer); buffer_size_ = buffer_size; own_buffer_ = false; } // Clear the buffer in debug mode unless it was provided by the // caller in which case we can't be sure it's okay to overwrite // existing code in it; see CodePatcher::CodePatcher(...). if (kDebug && own_buffer_) { memset(buffer_, 0xCC, buffer_size); // int3 } // setup buffer pointers ASSERT(buffer_ != NULL); pc_ = buffer_; reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); last_pc_ = NULL; last_bound_pos_ = 0; last_position_ = RelocInfo::kNoPosition; last_statement_position_ = RelocInfo::kNoPosition;}Assembler::~Assembler() { if (own_buffer_) { if (spare_buffer_ == NULL && buffer_size_ == kMinimalBufferSize) { spare_buffer_ = buffer_; } else { DeleteArray(buffer_); } }}void Assembler::GetCode(CodeDesc* desc) { // finalize code if (unbound_label_.is_linked()) bind_to(&unbound_label_, binding_pos_); // (at this point overflow() may be true, but the gap ensures that // we are still not overlapping instructions and relocation info) ASSERT(pc_ <= reloc_info_writer.pos()); // no overlap // setup desc desc->buffer = buffer_; desc->buffer_size = buffer_size_; desc->instr_size = pc_offset(); desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); Counters::reloc_info_size.Increment(desc->reloc_size);}void Assembler::Align(int m) { ASSERT(IsPowerOf2(m)); while ((pc_offset() & (m - 1)) != 0) { nop(); }}void Assembler::cpuid() { ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID)); EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x0F); EMIT(0xA2);}void Assembler::pushad() { EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x60);}void Assembler::popad() { EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x61);}void Assembler::pushfd() { EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x9C);}void Assembler::popfd() { EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x9D);}void Assembler::push(const Immediate& x) { EnsureSpace ensure_space(this); last_pc_ = pc_; if (x.is_int8()) { EMIT(0x6a); EMIT(x.x_); } else { EMIT(0x68); emit(x); }}void Assembler::push(Register src) { EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x50 | src.code());}void Assembler::push(const Operand& src) { EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0xFF); emit_operand(esi, src);}void Assembler::pop(Register dst) { ASSERT(reloc_info_writer.last_pc() != NULL); if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) { // (last_pc_ != NULL) is rolled into the above check // If a last_pc_ is set, we need to make sure that there has not been any // relocation information generated between the last instruction and this // pop instruction. byte instr = last_pc_[0]; if (instr == (0x50 | dst.code())) { pc_ = last_pc_; last_pc_ = NULL; if (FLAG_print_push_pop_elimination) { PrintF("%d push/pop (same reg) eliminated\n", pc_offset()); } return; } else if (instr == 0xff) { // push of an operand, convert to a move byte op1 = last_pc_[1]; // Check if the operation is really a push if ((op1 & 0x38) == (6 << 3)) { op1 = (op1 & ~0x38) | static_cast<byte>(dst.code() << 3); last_pc_[0] = 0x8b; last_pc_[1] = op1; last_pc_ = NULL; if (FLAG_print_push_pop_elimination) { PrintF("%d push/pop (op->reg) eliminated\n", pc_offset()); } return; } } else if ((instr == 0x89) && (last_pc_[1] == 0x04) && (last_pc_[2] == 0x24)) { // 0x71283c 396 890424 mov [esp],eax // 0x71283f 399 58 pop eax if (dst.is(eax)) { // change to // 0x710fac 216 83c404 add esp,0x4 last_pc_[0] = 0x83; last_pc_[1] = 0xc4; last_pc_[2] = 0x04; last_pc_ = NULL; if (FLAG_print_push_pop_elimination) { PrintF("%d push/pop (mov-pop) eliminated\n", pc_offset()); } return; } } else if (instr == 0x6a && dst.is(eax)) { // push of immediate 8 bit byte imm8 = last_pc_[1]; if (imm8 == 0) { // 6a00 push 0x0 // 58 pop eax last_pc_[0] = 0x31; last_pc_[1] = 0xc0; // change to // 31c0 xor eax,eax last_pc_ = NULL; return; } else { // 6a00 push 0xXX // 58 pop eax last_pc_[0] = 0xb8; EnsureSpace ensure_space(this); if ((imm8 & 0x80) != 0) { EMIT(0xff); EMIT(0xff); EMIT(0xff); // change to // b8XXffffff mov eax,0xffffffXX } else { EMIT(0x00); EMIT(0x00); EMIT(0x00); // change to // b8XX000000 mov eax,0x000000XX } last_pc_ = NULL; return; } } else if (instr == 0x68 && dst.is(eax)) { // push of immediate 32 bit // 68XXXXXXXX push 0xXXXXXXXX // 58 pop eax last_pc_[0] = 0xb8; last_pc_ = NULL; // change to // b8XXXXXXXX mov eax,0xXXXXXXXX return; } // Other potential patterns for peephole: // 0x712716 102 890424 mov [esp], eax // 0x712719 105 8b1424 mov edx, [esp] } EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x58 | dst.code());}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -