[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
//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
//! 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
//! // 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->_labelEntries.reset();
self->_sections.reset();
self->_sectionsByOrder.reset();
self->_unresolvedLinkCount = 0;
self->_addressTableSection = nullptr;
@@ -169,13 +170,15 @@ Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noe
ASMJIT_ASSERT(_emitters.empty());
// 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) {
Section* section = _allocator.allocZeroedT<Section>();
if (ASMJIT_LIKELY(section)) {
section->_flags = Section::kFlagExec | Section::kFlagConst;
CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
_sections.appendUnsafe(section);
_sectionsByOrder.appendUnsafe(section);
}
else {
err = DebugUtils::errored(kErrorOutOfMemory);
@@ -365,7 +368,26 @@ Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
// [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;
if (nameSize == SIZE_MAX)
@@ -385,16 +407,25 @@ Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t name
return DebugUtils::errored(kErrorTooManySections);
ASMJIT_PROPAGATE(_sections.willGrow(&_allocator));
Section* section = _allocator.allocZeroedT<Section>();
ASMJIT_PROPAGATE(_sectionsByOrder.willGrow(&_allocator));
Section* section = _allocator.allocZeroedT<Section>();
if (ASMJIT_UNLIKELY(!section))
return DebugUtils::errored(kErrorOutOfMemory);
section->_id = sectionId;
section->_flags = flags;
section->_alignment = alignment;
section->_order = order;
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);
_sectionsByOrder.insertUnsafe(n, section);
*sectionOut = section;
return kErrorOk;
@@ -420,7 +451,7 @@ Section* CodeHolder::ensureAddressTableSection() noexcept {
if (_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;
}
@@ -842,7 +873,7 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
Error CodeHolder::flatten() noexcept {
uint64_t offset = 0;
for (Section* section : _sections) {
for (Section* section : _sectionsByOrder) {
uint64_t realSize = section->realSize();
if (realSize) {
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.
Section* prev = nullptr;
offset = 0;
for (Section* section : _sections) {
for (Section* section : _sectionsByOrder) {
uint64_t realSize = section->realSize();
if (realSize)
offset = Support::alignUp(offset, section->alignment());
@@ -881,7 +912,7 @@ size_t CodeHolder::codeSize() const noexcept {
Support::FastUInt8 of = 0;
uint64_t offset = 0;
for (Section* section : _sections) {
for (Section* section : _sectionsByOrder) {
uint64_t realSize = section->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.
if (_sections.last() == addressTableSection) {
if (_sectionsByOrder.last() == addressTableSection) {
size_t addressTableSize = addressTableEntryCount * addressSize;
addressTableSection->_buffer._size = 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 {
size_t end = 0;
for (Section* section : _sections) {
for (Section* section : _sectionsByOrder) {
if (section->offset() > dstSize)
return DebugUtils::errored(kErrorInvalidArgument);
@@ -1107,4 +1138,45 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOpti
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

View File

@@ -81,8 +81,8 @@ public:
uint32_t _flags;
//! Section alignment requirements (0 if no requirements).
uint32_t _alignment;
//! Reserved for future use (padding).
uint32_t _reserved;
//! Order (lower value means higher priority).
int32_t _order;
//! Offset of this section from base-address.
uint64_t _offset;
//! Virtual size of the section (zero initialized sections).
@@ -133,6 +133,9 @@ public:
//! Sets the minimum section 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.
inline uint64_t offset() const noexcept { return _offset; }
//! Set the section offset.
@@ -519,6 +522,8 @@ public:
ZoneVector<BaseEmitter*> _emitters;
//! Section entries.
ZoneVector<Section*> _sections;
//! Section entries sorted by section order and then section id.
ZoneVector<Section*> _sectionsByOrder;
//! Label entries.
ZoneVector<LabelEntry*> _labelEntries;
//! Relocation entries.
@@ -667,6 +672,8 @@ public:
//! Returns an array of `Section*` records.
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.
inline uint32_t sectionCount() const noexcept { return _sections.size(); }
@@ -676,7 +683,7 @@ public:
//! Creates a new section and return its pointer in `sectionOut`.
//!
//! 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.
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 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 curOffset;
@@ -278,7 +278,7 @@ UNIT(const_pool) {
EXPECT(pool.alignment() == 8);
}
INFO("Retrieving %u constants from the pool.", kCount);
INFO("Retrieving %u constants from the pool", kCount);
{
uint64_t c = 0x0101010101010101u;

View File

@@ -231,7 +231,7 @@ public:
}
//! 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);
if (ASMJIT_UNLIKELY(_size == _capacity))
@@ -298,6 +298,16 @@ public:
_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.
inline void concatUnsafe(const ZoneVector<T>& other) noexcept {
uint32_t size = other._size;
@@ -326,11 +336,11 @@ public:
}
//! Removes item at index `i`.
inline void removeAt(uint32_t i) noexcept {
inline void removeAt(size_t i) noexcept {
ASMJIT_ASSERT(i < _size);
T* data = static_cast<T*>(_data) + i;
uint32_t size = --_size - i;
size_t size = --_size - i;
if (size)
::memmove(data, data + 1, size_t(size) * sizeof(T));

View File

@@ -118,7 +118,7 @@ int main() {
// how to do it explicitly.
printf("\nCalculating section offsets:\n");
uint64_t offset = 0;
for (Section* section : code.sections()) {
for (Section* section : code.sectionsByOrder()) {
offset = Support::alignUp(offset, section->alignment());
section->setOffset(offset);
offset += section->realSize();
@@ -157,7 +157,7 @@ int main() {
// 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`.
// 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());
// Execute the function and test whether it works.