mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 12:34:35 +03:00
[Bug] Added a possibility to order sections so the address table section can stay last even when user creates sections after it has been created (#293)
This commit is contained in:
@@ -870,7 +870,8 @@ namespace asmjit {
|
|||||||
//! ".data", // Section name
|
//! ".data", // Section name
|
||||||
//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
|
//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
|
||||||
//! 0, // Section flags, see Section::Flags.
|
//! 0, // Section flags, see Section::Flags.
|
||||||
//! 8); // Section alignment, must be power of 2.
|
//! 8, // Section alignment, must be power of 2.
|
||||||
|
//! 0); // Section order value (optional, default 0).
|
||||||
//!
|
//!
|
||||||
//! // When you switch sections in Assembler, Builder, or Compiler the cursor
|
//! // When you switch sections in Assembler, Builder, or Compiler the cursor
|
||||||
//! // will always move to the end of that section. When you create an Assembler
|
//! // will always move to the end of that section. When you create an Assembler
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noe
|
|||||||
self->_relocations.reset();
|
self->_relocations.reset();
|
||||||
self->_labelEntries.reset();
|
self->_labelEntries.reset();
|
||||||
self->_sections.reset();
|
self->_sections.reset();
|
||||||
|
self->_sectionsByOrder.reset();
|
||||||
|
|
||||||
self->_unresolvedLinkCount = 0;
|
self->_unresolvedLinkCount = 0;
|
||||||
self->_addressTableSection = nullptr;
|
self->_addressTableSection = nullptr;
|
||||||
@@ -169,13 +170,15 @@ Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noe
|
|||||||
ASMJIT_ASSERT(_emitters.empty());
|
ASMJIT_ASSERT(_emitters.empty());
|
||||||
|
|
||||||
// Create a default section and insert it to the `_sections` array.
|
// Create a default section and insert it to the `_sections` array.
|
||||||
Error err = _sections.willGrow(&_allocator);
|
Error err = _sections.willGrow(&_allocator) |
|
||||||
|
_sectionsByOrder.willGrow(&_allocator);
|
||||||
if (err == kErrorOk) {
|
if (err == kErrorOk) {
|
||||||
Section* section = _allocator.allocZeroedT<Section>();
|
Section* section = _allocator.allocZeroedT<Section>();
|
||||||
if (ASMJIT_LIKELY(section)) {
|
if (ASMJIT_LIKELY(section)) {
|
||||||
section->_flags = Section::kFlagExec | Section::kFlagConst;
|
section->_flags = Section::kFlagExec | Section::kFlagConst;
|
||||||
CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
|
CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
|
||||||
_sections.appendUnsafe(section);
|
_sections.appendUnsafe(section);
|
||||||
|
_sectionsByOrder.appendUnsafe(section);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err = DebugUtils::errored(kErrorOutOfMemory);
|
err = DebugUtils::errored(kErrorOutOfMemory);
|
||||||
@@ -365,7 +368,26 @@ Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
|
|||||||
// [asmjit::CodeHolder - Sections]
|
// [asmjit::CodeHolder - Sections]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t nameSize, uint32_t flags, uint32_t alignment) noexcept {
|
template<typename T, typename Compar>
|
||||||
|
static inline size_t binarySearchClosestFirst(const T* array, size_t size, const T& value, const Compar& compar) noexcept {
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const T* base = array;
|
||||||
|
while (size_t half = size / 2u) {
|
||||||
|
const T* middle = base + half;
|
||||||
|
size -= half;
|
||||||
|
if (compar(middle[0], value) < 0)
|
||||||
|
base = middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compar(base[0], value) < 0)
|
||||||
|
base++;
|
||||||
|
|
||||||
|
return size_t(base - array);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t nameSize, uint32_t flags, uint32_t alignment, int32_t order) noexcept {
|
||||||
*sectionOut = nullptr;
|
*sectionOut = nullptr;
|
||||||
|
|
||||||
if (nameSize == SIZE_MAX)
|
if (nameSize == SIZE_MAX)
|
||||||
@@ -385,16 +407,25 @@ Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t name
|
|||||||
return DebugUtils::errored(kErrorTooManySections);
|
return DebugUtils::errored(kErrorTooManySections);
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(_sections.willGrow(&_allocator));
|
ASMJIT_PROPAGATE(_sections.willGrow(&_allocator));
|
||||||
Section* section = _allocator.allocZeroedT<Section>();
|
ASMJIT_PROPAGATE(_sectionsByOrder.willGrow(&_allocator));
|
||||||
|
|
||||||
|
Section* section = _allocator.allocZeroedT<Section>();
|
||||||
if (ASMJIT_UNLIKELY(!section))
|
if (ASMJIT_UNLIKELY(!section))
|
||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
section->_id = sectionId;
|
section->_id = sectionId;
|
||||||
section->_flags = flags;
|
section->_flags = flags;
|
||||||
section->_alignment = alignment;
|
section->_alignment = alignment;
|
||||||
|
section->_order = order;
|
||||||
memcpy(section->_name.str, name, nameSize);
|
memcpy(section->_name.str, name, nameSize);
|
||||||
|
|
||||||
|
size_t n = binarySearchClosestFirst(_sectionsByOrder.data(), _sectionsByOrder.size(), section, [](const Section* a, const Section* b) -> int64_t {
|
||||||
|
return a->order() == b->order() ? int64_t(a->id()) - int64_t(b->id())
|
||||||
|
: int64_t(a->order()) - int64_t(b->order());
|
||||||
|
});
|
||||||
|
|
||||||
_sections.appendUnsafe(section);
|
_sections.appendUnsafe(section);
|
||||||
|
_sectionsByOrder.insertUnsafe(n, section);
|
||||||
|
|
||||||
*sectionOut = section;
|
*sectionOut = section;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -420,7 +451,7 @@ Section* CodeHolder::ensureAddressTableSection() noexcept {
|
|||||||
if (_addressTableSection)
|
if (_addressTableSection)
|
||||||
return _addressTableSection;
|
return _addressTableSection;
|
||||||
|
|
||||||
newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize());
|
newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize(), std::numeric_limits<int32_t>::max());
|
||||||
return _addressTableSection;
|
return _addressTableSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,7 +873,7 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
|
|||||||
|
|
||||||
Error CodeHolder::flatten() noexcept {
|
Error CodeHolder::flatten() noexcept {
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
for (Section* section : _sections) {
|
for (Section* section : _sectionsByOrder) {
|
||||||
uint64_t realSize = section->realSize();
|
uint64_t realSize = section->realSize();
|
||||||
if (realSize) {
|
if (realSize) {
|
||||||
uint64_t alignedOffset = Support::alignUp(offset, section->alignment());
|
uint64_t alignedOffset = Support::alignUp(offset, section->alignment());
|
||||||
@@ -860,7 +891,7 @@ Error CodeHolder::flatten() noexcept {
|
|||||||
// Now we know that we can assign offsets of all sections properly.
|
// Now we know that we can assign offsets of all sections properly.
|
||||||
Section* prev = nullptr;
|
Section* prev = nullptr;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
for (Section* section : _sections) {
|
for (Section* section : _sectionsByOrder) {
|
||||||
uint64_t realSize = section->realSize();
|
uint64_t realSize = section->realSize();
|
||||||
if (realSize)
|
if (realSize)
|
||||||
offset = Support::alignUp(offset, section->alignment());
|
offset = Support::alignUp(offset, section->alignment());
|
||||||
@@ -881,7 +912,7 @@ size_t CodeHolder::codeSize() const noexcept {
|
|||||||
Support::FastUInt8 of = 0;
|
Support::FastUInt8 of = 0;
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
|
|
||||||
for (Section* section : _sections) {
|
for (Section* section : _sectionsByOrder) {
|
||||||
uint64_t realSize = section->realSize();
|
uint64_t realSize = section->realSize();
|
||||||
|
|
||||||
if (realSize) {
|
if (realSize) {
|
||||||
@@ -1047,7 +1078,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fixup the virtual size of the address table if it's the last section.
|
// Fixup the virtual size of the address table if it's the last section.
|
||||||
if (_sections.last() == addressTableSection) {
|
if (_sectionsByOrder.last() == addressTableSection) {
|
||||||
size_t addressTableSize = addressTableEntryCount * addressSize;
|
size_t addressTableSize = addressTableEntryCount * addressSize;
|
||||||
addressTableSection->_buffer._size = addressTableSize;
|
addressTableSection->_buffer._size = addressTableSize;
|
||||||
addressTableSection->_virtualSize = addressTableSize;
|
addressTableSection->_virtualSize = addressTableSize;
|
||||||
@@ -1078,7 +1109,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId,
|
|||||||
|
|
||||||
Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions) noexcept {
|
Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions) noexcept {
|
||||||
size_t end = 0;
|
size_t end = 0;
|
||||||
for (Section* section : _sections) {
|
for (Section* section : _sectionsByOrder) {
|
||||||
if (section->offset() > dstSize)
|
if (section->offset() > dstSize)
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
@@ -1107,4 +1138,45 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOpti
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// [asmjit::CodeHolder - Unit]
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#if defined(ASMJIT_TEST)
|
||||||
|
UNIT(code_holder) {
|
||||||
|
CodeHolder code;
|
||||||
|
|
||||||
|
INFO("Verifying CodeHolder::init()");
|
||||||
|
Environment env;
|
||||||
|
env.init(Environment::kArchX86);
|
||||||
|
|
||||||
|
code.init(env);
|
||||||
|
EXPECT(code.arch() == Environment::kArchX86);
|
||||||
|
|
||||||
|
INFO("Verifying named labels");
|
||||||
|
LabelEntry* le;
|
||||||
|
EXPECT(code.newNamedLabelEntry(&le, "NamedLabel", SIZE_MAX, Label::kTypeGlobal) == kErrorOk);
|
||||||
|
EXPECT(strcmp(le->name(), "NamedLabel") == 0);
|
||||||
|
EXPECT(code.labelIdByName("NamedLabel") == le->id());
|
||||||
|
|
||||||
|
INFO("Verifying section ordering");
|
||||||
|
Section* section1;
|
||||||
|
EXPECT(code.newSection(§ion1, "high-priority", SIZE_MAX, 0, 1, -1) == kErrorOk);
|
||||||
|
EXPECT(code.sections()[1] == section1);
|
||||||
|
EXPECT(code.sectionsByOrder()[0] == section1);
|
||||||
|
|
||||||
|
Section* section0;
|
||||||
|
EXPECT(code.newSection(§ion0, "higher-priority", SIZE_MAX, 0, 1, -2) == kErrorOk);
|
||||||
|
EXPECT(code.sections()[2] == section0);
|
||||||
|
EXPECT(code.sectionsByOrder()[0] == section0);
|
||||||
|
EXPECT(code.sectionsByOrder()[1] == section1);
|
||||||
|
|
||||||
|
Section* section3;
|
||||||
|
EXPECT(code.newSection(§ion3, "low-priority", SIZE_MAX, 0, 1, 2) == kErrorOk);
|
||||||
|
EXPECT(code.sections()[3] == section3);
|
||||||
|
EXPECT(code.sectionsByOrder()[3] == section3);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ public:
|
|||||||
uint32_t _flags;
|
uint32_t _flags;
|
||||||
//! Section alignment requirements (0 if no requirements).
|
//! Section alignment requirements (0 if no requirements).
|
||||||
uint32_t _alignment;
|
uint32_t _alignment;
|
||||||
//! Reserved for future use (padding).
|
//! Order (lower value means higher priority).
|
||||||
uint32_t _reserved;
|
int32_t _order;
|
||||||
//! Offset of this section from base-address.
|
//! Offset of this section from base-address.
|
||||||
uint64_t _offset;
|
uint64_t _offset;
|
||||||
//! Virtual size of the section (zero initialized sections).
|
//! Virtual size of the section (zero initialized sections).
|
||||||
@@ -133,6 +133,9 @@ public:
|
|||||||
//! Sets the minimum section alignment
|
//! Sets the minimum section alignment
|
||||||
inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
|
inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
|
||||||
|
|
||||||
|
//! Returns the section order, which has a higher priority than section id.
|
||||||
|
inline int32_t order() const noexcept { return _order; }
|
||||||
|
|
||||||
//! Returns the section offset, relative to base.
|
//! Returns the section offset, relative to base.
|
||||||
inline uint64_t offset() const noexcept { return _offset; }
|
inline uint64_t offset() const noexcept { return _offset; }
|
||||||
//! Set the section offset.
|
//! Set the section offset.
|
||||||
@@ -519,6 +522,8 @@ public:
|
|||||||
ZoneVector<BaseEmitter*> _emitters;
|
ZoneVector<BaseEmitter*> _emitters;
|
||||||
//! Section entries.
|
//! Section entries.
|
||||||
ZoneVector<Section*> _sections;
|
ZoneVector<Section*> _sections;
|
||||||
|
//! Section entries sorted by section order and then section id.
|
||||||
|
ZoneVector<Section*> _sectionsByOrder;
|
||||||
//! Label entries.
|
//! Label entries.
|
||||||
ZoneVector<LabelEntry*> _labelEntries;
|
ZoneVector<LabelEntry*> _labelEntries;
|
||||||
//! Relocation entries.
|
//! Relocation entries.
|
||||||
@@ -667,6 +672,8 @@ public:
|
|||||||
|
|
||||||
//! Returns an array of `Section*` records.
|
//! Returns an array of `Section*` records.
|
||||||
inline const ZoneVector<Section*>& sections() const noexcept { return _sections; }
|
inline const ZoneVector<Section*>& sections() const noexcept { return _sections; }
|
||||||
|
//! Returns an array of `Section*` records sorted according to section order first, then section id.
|
||||||
|
inline const ZoneVector<Section*>& sectionsByOrder() const noexcept { return _sectionsByOrder; }
|
||||||
//! Returns the number of sections.
|
//! Returns the number of sections.
|
||||||
inline uint32_t sectionCount() const noexcept { return _sections.size(); }
|
inline uint32_t sectionCount() const noexcept { return _sections.size(); }
|
||||||
|
|
||||||
@@ -676,7 +683,7 @@ public:
|
|||||||
//! Creates a new section and return its pointer in `sectionOut`.
|
//! Creates a new section and return its pointer in `sectionOut`.
|
||||||
//!
|
//!
|
||||||
//! Returns `Error`, does not report a possible error to `ErrorHandler`.
|
//! Returns `Error`, does not report a possible error to `ErrorHandler`.
|
||||||
ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, uint32_t flags = 0, uint32_t alignment = 1) noexcept;
|
ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, uint32_t flags = 0, uint32_t alignment = 1, int32_t order = 0) noexcept;
|
||||||
|
|
||||||
//! Returns a section entry of the given index.
|
//! Returns a section entry of the given index.
|
||||||
inline Section* sectionById(uint32_t sectionId) const noexcept { return _sections[sectionId]; }
|
inline Section* sectionById(uint32_t sectionId) const noexcept { return _sections[sectionId]; }
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ UNIT(const_pool) {
|
|||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t kCount = BrokenAPI::hasArg("--quick") ? 1000 : 1000000;
|
uint32_t kCount = BrokenAPI::hasArg("--quick") ? 1000 : 1000000;
|
||||||
|
|
||||||
INFO("Adding %u constants to the pool.", kCount);
|
INFO("Adding %u constants to the pool", kCount);
|
||||||
{
|
{
|
||||||
size_t prevOffset;
|
size_t prevOffset;
|
||||||
size_t curOffset;
|
size_t curOffset;
|
||||||
@@ -278,7 +278,7 @@ UNIT(const_pool) {
|
|||||||
EXPECT(pool.alignment() == 8);
|
EXPECT(pool.alignment() == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO("Retrieving %u constants from the pool.", kCount);
|
INFO("Retrieving %u constants from the pool", kCount);
|
||||||
{
|
{
|
||||||
uint64_t c = 0x0101010101010101u;
|
uint64_t c = 0x0101010101010101u;
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Inserts an `item` at the specified `index`.
|
//! Inserts an `item` at the specified `index`.
|
||||||
inline Error insert(ZoneAllocator* allocator, uint32_t index, const T& item) noexcept {
|
inline Error insert(ZoneAllocator* allocator, size_t index, const T& item) noexcept {
|
||||||
ASMJIT_ASSERT(index <= _size);
|
ASMJIT_ASSERT(index <= _size);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(_size == _capacity))
|
if (ASMJIT_UNLIKELY(_size == _capacity))
|
||||||
@@ -298,6 +298,16 @@ public:
|
|||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Inserts an `item` at the specified `index` (unsafe case).
|
||||||
|
inline void insertUnsafe(size_t index, const T& item) noexcept {
|
||||||
|
ASMJIT_ASSERT(_size < _capacity);
|
||||||
|
ASMJIT_ASSERT(index <= _size);
|
||||||
|
|
||||||
|
T* dst = static_cast<T*>(_data) + index;
|
||||||
|
::memmove(dst + 1, dst, size_t(_size - index) * sizeof(T));
|
||||||
|
memcpy(dst, &item, sizeof(T));
|
||||||
|
_size++;
|
||||||
|
}
|
||||||
//! Concatenates all items of `other` at the end of the vector.
|
//! Concatenates all items of `other` at the end of the vector.
|
||||||
inline void concatUnsafe(const ZoneVector<T>& other) noexcept {
|
inline void concatUnsafe(const ZoneVector<T>& other) noexcept {
|
||||||
uint32_t size = other._size;
|
uint32_t size = other._size;
|
||||||
@@ -326,11 +336,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Removes item at index `i`.
|
//! Removes item at index `i`.
|
||||||
inline void removeAt(uint32_t i) noexcept {
|
inline void removeAt(size_t i) noexcept {
|
||||||
ASMJIT_ASSERT(i < _size);
|
ASMJIT_ASSERT(i < _size);
|
||||||
|
|
||||||
T* data = static_cast<T*>(_data) + i;
|
T* data = static_cast<T*>(_data) + i;
|
||||||
uint32_t size = --_size - i;
|
size_t size = --_size - i;
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
::memmove(data, data + 1, size_t(size) * sizeof(T));
|
::memmove(data, data + 1, size_t(size) * sizeof(T));
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ int main() {
|
|||||||
// how to do it explicitly.
|
// how to do it explicitly.
|
||||||
printf("\nCalculating section offsets:\n");
|
printf("\nCalculating section offsets:\n");
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
for (Section* section : code.sections()) {
|
for (Section* section : code.sectionsByOrder()) {
|
||||||
offset = Support::alignUp(offset, section->alignment());
|
offset = Support::alignUp(offset, section->alignment());
|
||||||
section->setOffset(offset);
|
section->setOffset(offset);
|
||||||
offset += section->realSize();
|
offset += section->realSize();
|
||||||
@@ -157,7 +157,7 @@ int main() {
|
|||||||
// Copy the flattened code into `mem.rw`. There are two ways. You can either copy
|
// Copy the flattened code into `mem.rw`. There are two ways. You can either copy
|
||||||
// everything manually by iterating over all sections or use `copyFlattenedData`.
|
// everything manually by iterating over all sections or use `copyFlattenedData`.
|
||||||
// This code is similar to what `copyFlattenedData(p, codeSize, 0)` would do:
|
// This code is similar to what `copyFlattenedData(p, codeSize, 0)` would do:
|
||||||
for (Section* section : code.sections())
|
for (Section* section : code.sectionsByOrder())
|
||||||
memcpy(static_cast<uint8_t*>(rwPtr) + size_t(section->offset()), section->data(), section->bufferSize());
|
memcpy(static_cast<uint8_t*>(rwPtr) + size_t(section->offset()), section->data(), section->bufferSize());
|
||||||
|
|
||||||
// Execute the function and test whether it works.
|
// Execute the function and test whether it works.
|
||||||
|
|||||||
Reference in New Issue
Block a user