[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:
kobalicek
2020-08-07 23:44:44 +02:00
parent 10be0c8f1d
commit 0646d0a48f
6 changed files with 110 additions and 20 deletions

View File

@@ -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

View File

@@ -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(&section1, "high-priority", SIZE_MAX, 0, 1, -1) == kErrorOk);
EXPECT(code.sections()[1] == section1);
EXPECT(code.sectionsByOrder()[0] == section1);
Section* section0;
EXPECT(code.newSection(&section0, "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(&section3, "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

View File

@@ -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]; }

View File

@@ -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;

View File

@@ -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));

View File

@@ -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.