diff --git a/test/jmp.cpp b/test/jmp.cpp index 148fa7a..9ff4a03 100644 --- a/test/jmp.cpp +++ b/test/jmp.cpp @@ -464,9 +464,8 @@ bool checkAddr(const uint8 *p, size_t offset, size_t expect) { size_t v = getValue(p + offset); printf("v=%p\n", (void*)v); - v -= size_t(p); - if (v == expect) return true; - printf("err p=%p, offset=%lld, v=%d, expect=%d\n", p, (long long)offset, (int)v, (int)expect); + if (v == size_t(p) + expect) return true; + printf("err p=%p, offset=%lld, v=%llx(%llx), expect=%d\n", p, (long long)offset, (long long)v, (long long)(expect + size_t(p)), (int)expect); return false; } diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h index 0a0e54f..15ebdd6 100644 --- a/xbyak/xbyak.h +++ b/xbyak/xbyak.h @@ -197,7 +197,7 @@ namespace inner { enum { debug = 1 }; static const size_t ALIGN_PAGE_SIZE = 4096; -inline bool IsInDisp8(uint64 x) { return 0xFFFFFF80 <= x || x <= 0x7F; } +inline bool IsInDisp8(uint32 x) { return 0xFFFFFF80 <= x || x <= 0x7F; } inline bool IsInInt32(uint64 x) { return ~uint64(0x7fffffffu) <= x || x <= 0x7FFFFFFFU; } inline uint32 VerifyInInt32(uint64 x) @@ -208,6 +208,12 @@ inline uint32 VerifyInInt32(uint64 x) return static_cast(x); } +enum LabelMode { + Labs, // absolute + Lrelative, // relative(input addr is relative) + LaddTop // relative(addr + top) +}; + } // inner /* @@ -221,7 +227,6 @@ struct Allocator { virtual bool useProtect() const { return true; } }; - class Operand { private: const uint8 idx_; @@ -480,10 +485,13 @@ class CodeArray { struct AddrInfo { size_t offset_; size_t val_; - int size_; - bool isRelative_; - AddrInfo(size_t offset, size_t val, int size, bool isRelative) - : offset_(offset), val_(val), size_(size), isRelative_(isRelative) {} + int jmpSize; + inner::LabelMode mode; + AddrInfo(size_t offset, size_t val, int size, inner::LabelMode _mode) + : offset_(offset), val_(val), jmpSize(size), mode(_mode) {} + bool isAbs() const { return mode == inner::Labs; } + bool isRelative() const { return mode == inner::Lrelative; } + bool isAddTop() const { return mode == inner::LaddTop; } }; typedef std::list AddrInfoList; AddrInfoList addrInfoList_; @@ -515,9 +523,9 @@ protected: void calcJmpAddress() { for (AddrInfoList::const_iterator i = addrInfoList_.begin(), ie = addrInfoList_.end(); i != ie; ++i) { -// uint32 disp = inner::GetOffsetDist(i->val_, i->isRelative_ ? 0 : size_t(top_)); - uint32 disp = inner::VerifyInInt32(i->isRelative_ ? i->val_ : i->val_ - size_t(top_)); - rewrite(i->offset_, disp, i->size_); + uint64 disp = i->isAddTop() ? i->val_ + size_t(top_) : i->isRelative() ? i->val_ : i->val_ - size_t(top_); + if (i->jmpSize == 4) disp = inner::VerifyInInt32(disp); + rewrite(i->offset_, disp, i->jmpSize); } if (alloc_->useProtect() && !protect(top_, size_, true)) throw ERR_CANT_PROTECT; } @@ -627,9 +635,9 @@ public: data[i] = static_cast(disp >> (i * 8)); } } - void save(size_t offset, size_t val, int size, bool isRelative) + void save(size_t offset, size_t val, int size, inner::LabelMode mode) { - addrInfoList_.push_back(AddrInfo(offset, val, size, isRelative)); + addrInfoList_.push_back(AddrInfo(offset, val, size, mode)); } bool isAutoGrow() const { return type_ == AUTO_GROW; } void updateRegField(uint8 regIdx) const @@ -767,13 +775,16 @@ public: struct JmpLabel { size_t endOfJmp; /* offset from top to the end address of jmp */ int jmpSize; - bool isAbs; - JmpLabel() - : endOfJmp(0) - , jmpSize(0) - , isAbs(false) + inner::LabelMode mode; + JmpLabel(size_t _endOfJmp = 0, int _jmpSize = 0, inner::LabelMode _mode = inner::Lrelative) + : endOfJmp(_endOfJmp) + , jmpSize(_jmpSize) + , mode(_mode) { } + bool isAbs() const { return mode == inner::Labs; } + bool isRelative() const { return mode == inner::Lrelative; } + bool isAddTop() const { return mode == inner::LaddTop; } }; class Label { @@ -786,14 +797,21 @@ class Label { int stackPos_; int usedCount_; int localCount_; // for .*** +public: + struct Addr { + Addr(size_t _offset = 0, const uint8 *_addr = 0) : offset(_offset), addr(_addr) {} + size_t offset; + const uint8 *addr; + }; +private: #ifdef XBYAK_USE_UNORDERED_MAP - typedef std::unordered_map DefinedList; + typedef std::unordered_map DefinedList; typedef std::unordered_multimap UndefinedList; #elif defined(XBYAK_USE_TR1_UNORDERED_MAP) - typedef std::tr1::unordered_map DefinedList; + typedef std::tr1::unordered_map DefinedList; typedef std::tr1::unordered_multimap UndefinedList; #else - typedef std::map DefinedList; + typedef std::map DefinedList; typedef std::multimap UndefinedList; #endif DefinedList definedList_; @@ -857,7 +875,7 @@ public: } label = newLabel.c_str(); // add label - DefinedList::value_type item(label, addrOffset); + DefinedList::value_type item(label, Label::Addr(addrOffset, addr)); std::pair ret = definedList_.insert(item); if (!ret.second) throw ERR_LABEL_IS_REDEFINED; // search undefined label @@ -867,12 +885,12 @@ public: const JmpLabel *jmp = &itr->second; size_t disp = addrOffset - jmp->endOfJmp; if (jmp->jmpSize <= 4) disp = inner::VerifyInInt32(disp); - if (jmp->jmpSize == 1 && !inner::IsInDisp8(disp)) throw ERR_LABEL_IS_TOO_FAR; + if (jmp->jmpSize == 1 && !inner::IsInDisp8((uint32)disp)) throw ERR_LABEL_IS_TOO_FAR; size_t offset = jmp->endOfJmp - jmp->jmpSize; if (base_->isAutoGrow()) { - base_->save(offset, disp, jmp->jmpSize, true); + base_->save(offset, jmp->isAddTop() ? addrOffset : jmp->isAbs() ? size_t(addr) : disp, jmp->jmpSize, jmp->mode); } else { - base_->rewrite(offset, jmp->isAbs ? size_t(addr) : disp, jmp->jmpSize); + base_->rewrite(offset, jmp->isAbs() ? size_t(addr) : disp, jmp->jmpSize); } undefinedList_.erase(itr); } @@ -882,12 +900,18 @@ public: std::string newLabel = convertLabel(label); DefinedList::const_iterator itr = definedList_.find(newLabel); if (itr != definedList_.end()) { - *offset = itr->second; + *offset = itr->second.offset; return true; } else { return false; } } + const Label::Addr *getAddr(const char *label) const + { + std::string newLabel = convertLabel(label); + DefinedList::const_iterator itr = definedList_.find(newLabel); + return (itr == definedList_.end()) ? 0 : &(itr->second); + } void addUndefinedLabel(const char *label, const JmpLabel& jmp) { std::string newLabel = convertLabel(label); @@ -1031,9 +1055,9 @@ private: void opJmp(const char *label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) { if (isAutoGrow() && size_ + 16 >= maxSize_) growMemory(); /* avoid splitting code of jmp */ - size_t offset = 0; - if (label_.getOffset(&offset, label)) { /* label exists */ - makeJmp(inner::VerifyInInt32(offset - getSize()), type, shortCode, longCode, longPref); + const Label::Addr *addr = label_.getAddr(label); + if (addr) { /* label exists */ + makeJmp(inner::VerifyInInt32(addr->offset - getSize()), type, shortCode, longCode, longPref); } else { JmpLabel jmp; if (type == T_NEAR) { @@ -1054,8 +1078,8 @@ private: if (type != T_NEAR) throw ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW; if (size_ + 16 >= maxSize_) growMemory(); db(longCode); - save(size_, size_t(addr) - (getSize() + 4), 4, false); dd(0); + save(size_ - 4, size_t(addr) - size_, 4, inner::Labs); } else { makeJmp(inner::VerifyInInt32(reinterpret_cast(addr) - getCurr()), type, shortCode, longCode, 0); } @@ -1425,26 +1449,29 @@ public: #endif const char *label) { + if (label == 0) { + mov(reg, 0, true); + return; + } const int jmpSize = (int)sizeof(size_t); #ifdef XBYAK64 const size_t dummyAddr = size_t(0x1122334455667788ull); #else const size_t dummyAddr = 0x12345678; #endif - if (isAutoGrow()) { - if (size_ + 16 >= maxSize_) growMemory(); - return; - } - size_t offset = 0; - if (label_.getOffset(&offset, label)) { - mov(reg, size_t(top_) + offset, false); + if (isAutoGrow() && size_ + 16 >= maxSize_) growMemory(); + const Label::Addr *addr = label_.getAddr(label); + if (addr) { + if (isAutoGrow()) { + mov(reg, dummyAddr); + save(size_ - jmpSize, addr->offset, jmpSize, inner::LaddTop); + } else { + mov(reg, size_t(top_) + addr->offset, false); + } return; } mov(reg, dummyAddr); - JmpLabel jmp; - jmp.jmpSize = jmpSize; - jmp.endOfJmp = getSize(); - jmp.isAbs = true; + JmpLabel jmp(getSize(), jmpSize, isAutoGrow() ? inner::LaddTop : inner::Labs); label_.addUndefinedLabel(label, jmp); } void cmpxchg8b(const Address& addr) { opModM(addr, Reg32(1), 0x0F, B11000111); }