Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Dependencies]
33 : #include "./assembler.h"
34 : #include "./utils.h"
35 : #include "./vmem.h"
36 :
37 : // [Api-Begin]
38 : #include "./asmjit_apibegin.h"
39 :
40 : namespace PLMD {
41 : namespace asmjit {
42 :
43 : // ============================================================================
44 : // [asmjit::ErrorHandler]
45 : // ============================================================================
46 :
47 0 : ErrorHandler::ErrorHandler() noexcept {}
48 0 : ErrorHandler::~ErrorHandler() noexcept {}
49 :
50 : // ============================================================================
51 : // [asmjit::CodeHolder - Utilities]
52 : // ============================================================================
53 :
54 0 : static void CodeHolder_setGlobalOption(CodeHolder* self, uint32_t clear, uint32_t add) noexcept {
55 : // Modify global options of `CodeHolder` itself.
56 0 : self->_globalOptions = (self->_globalOptions & ~clear) | add;
57 :
58 : // Modify all global options of all `CodeEmitter`s attached.
59 0 : CodeEmitter* emitter = self->_emitters;
60 0 : while (emitter) {
61 0 : emitter->_globalOptions = (emitter->_globalOptions & ~clear) | add;
62 0 : emitter = emitter->_nextEmitter;
63 : }
64 0 : }
65 :
66 1944 : static void CodeHolder_resetInternal(CodeHolder* self, bool releaseMemory) noexcept {
67 : // Detach all `CodeEmitter`s.
68 1944 : while (self->_emitters)
69 0 : self->detach(self->_emitters);
70 :
71 : // Reset everything into its construction state.
72 : self->_codeInfo.reset();
73 1944 : self->_globalHints = 0;
74 1944 : self->_globalOptions = 0;
75 1944 : self->_logger = nullptr;
76 1944 : self->_errorHandler = nullptr;
77 :
78 1944 : self->_unresolvedLabelsCount = 0;
79 1944 : self->_trampolinesSize = 0;
80 :
81 : // Reset all sections.
82 : size_t numSections = self->_sections.getLength();
83 3888 : for (size_t i = 0; i < numSections; i++) {
84 1944 : SectionEntry* section = self->_sections[i];
85 1944 : if (section->_buffer.hasData() && !section->_buffer.isExternal())
86 : Internal::releaseMemory(section->_buffer._data);
87 1944 : section->_buffer._data = nullptr;
88 1944 : section->_buffer._capacity = 0;
89 : }
90 :
91 : // Reset zone allocator and all containers using it.
92 1944 : ZoneHeap* heap = &self->_baseHeap;
93 :
94 1944 : self->_namedLabels.reset(heap);
95 : self->_relocations.reset();
96 : self->_labels.reset();
97 : self->_sections.reset();
98 :
99 1944 : heap->reset(&self->_baseZone);
100 1944 : self->_baseZone.reset(releaseMemory);
101 1944 : }
102 :
103 : // ============================================================================
104 : // [asmjit::CodeHolder - Construction / Destruction]
105 : // ============================================================================
106 :
107 1944 : CodeHolder::CodeHolder() noexcept
108 : : _codeInfo(),
109 1944 : _globalHints(0),
110 1944 : _globalOptions(0),
111 1944 : _emitters(nullptr),
112 1944 : _cgAsm(nullptr),
113 1944 : _logger(nullptr),
114 1944 : _errorHandler(nullptr),
115 1944 : _unresolvedLabelsCount(0),
116 1944 : _trampolinesSize(0),
117 1944 : _baseZone(16384 - Zone::kZoneOverhead),
118 1944 : _dataZone(16384 - Zone::kZoneOverhead),
119 1944 : _baseHeap(&_baseZone),
120 1944 : _namedLabels(&_baseHeap) {}
121 :
122 1944 : CodeHolder::~CodeHolder() noexcept {
123 1944 : CodeHolder_resetInternal(this, true);
124 1944 : }
125 :
126 : // ============================================================================
127 : // [asmjit::CodeHolder - Init / Reset]
128 : // ============================================================================
129 :
130 1944 : Error CodeHolder::init(const CodeInfo& info) noexcept {
131 : // Cannot reinitialize if it's locked or there is one or more CodeEmitter
132 : // attached.
133 1944 : if (isInitialized())
134 : return DebugUtils::errored(kErrorAlreadyInitialized);
135 :
136 : // If we are just initializing there should be no emitters attached).
137 : ASMJIT_ASSERT(_emitters == nullptr);
138 :
139 : // Create the default section and insert it to the `_sections` array.
140 1944 : Error err = _sections.willGrow(&_baseHeap);
141 1944 : if (err == kErrorOk) {
142 1944 : SectionEntry* se = _baseZone.allocZeroedT<SectionEntry>();
143 1944 : if (ASMJIT_LIKELY(se)) {
144 1944 : se->_flags = SectionEntry::kFlagExec | SectionEntry::kFlagConst;
145 : se->_setDefaultName('.', 't', 'e', 'x', 't');
146 : _sections.appendUnsafe(se);
147 : }
148 : else {
149 : err = DebugUtils::errored(kErrorNoHeapMemory);
150 : }
151 : }
152 :
153 1944 : if (ASMJIT_UNLIKELY(err)) {
154 0 : _baseZone.reset(false);
155 0 : return err;
156 : }
157 : else {
158 : _codeInfo = info;
159 1944 : return kErrorOk;
160 : }
161 : }
162 :
163 0 : void CodeHolder::reset(bool releaseMemory) noexcept {
164 0 : CodeHolder_resetInternal(this, releaseMemory);
165 0 : }
166 :
167 : // ============================================================================
168 : // [asmjit::CodeHolder - Attach / Detach]
169 : // ============================================================================
170 :
171 3888 : Error CodeHolder::attach(CodeEmitter* emitter) noexcept {
172 : // Catch a possible misuse of the API.
173 3888 : if (!emitter)
174 : return DebugUtils::errored(kErrorInvalidArgument);
175 :
176 : uint32_t type = emitter->getType();
177 3888 : if (type == CodeEmitter::kTypeNone || type >= CodeEmitter::kTypeCount)
178 : return DebugUtils::errored(kErrorInvalidState);
179 :
180 : // This is suspicious, but don't fail if `emitter` matches.
181 3888 : if (emitter->_code != nullptr) {
182 0 : if (emitter->_code == this) return kErrorOk;
183 : return DebugUtils::errored(kErrorInvalidState);
184 : }
185 :
186 : // Special case - attach `Assembler`.
187 : CodeEmitter** pSlot = nullptr;
188 3888 : if (type == CodeEmitter::kTypeAssembler) {
189 1944 : if (_cgAsm)
190 : return DebugUtils::errored(kErrorSlotOccupied);
191 1944 : pSlot = reinterpret_cast<CodeEmitter**>(&_cgAsm);
192 : }
193 :
194 3888 : Error err = emitter->onAttach(this);
195 3888 : if (err != kErrorOk) return err;
196 :
197 : // Add to a single-linked list of `CodeEmitter`s.
198 3888 : emitter->_nextEmitter = _emitters;
199 3888 : _emitters = emitter;
200 3888 : if (pSlot) *pSlot = emitter;
201 :
202 : // Establish the connection.
203 3888 : emitter->_code = this;
204 3888 : return kErrorOk;
205 : }
206 :
207 3888 : Error CodeHolder::detach(CodeEmitter* emitter) noexcept {
208 3888 : if (!emitter)
209 : return DebugUtils::errored(kErrorInvalidArgument);
210 :
211 3888 : if (emitter->_code != this)
212 : return DebugUtils::errored(kErrorInvalidState);
213 :
214 : uint32_t type = emitter->getType();
215 : Error err = kErrorOk;
216 :
217 : // NOTE: We always detach if we were asked to, if error happens during
218 : // `emitter->onDetach()` we just propagate it, but the CodeEmitter will
219 : // be detached.
220 3888 : if (!emitter->_destroyed) {
221 0 : if (type == CodeEmitter::kTypeAssembler)
222 0 : static_cast<Assembler*>(emitter)->sync();
223 0 : err = emitter->onDetach(this);
224 : }
225 :
226 : // Special case - detach `Assembler`.
227 3888 : if (type == CodeEmitter::kTypeAssembler)
228 1944 : _cgAsm = nullptr;
229 :
230 : // Remove from a single-linked list of `CodeEmitter`s.
231 3888 : CodeEmitter** pPrev = &_emitters;
232 : for (;;) {
233 : ASMJIT_ASSERT(*pPrev != nullptr);
234 3888 : CodeEmitter* cur = *pPrev;
235 :
236 3888 : if (cur == emitter) {
237 3888 : *pPrev = emitter->_nextEmitter;
238 : break;
239 : }
240 :
241 0 : pPrev = &cur->_nextEmitter;
242 0 : }
243 :
244 3888 : emitter->_code = nullptr;
245 3888 : emitter->_nextEmitter = nullptr;
246 :
247 3888 : return err;
248 : }
249 :
250 : // ============================================================================
251 : // [asmjit::CodeHolder - Sync]
252 : // ============================================================================
253 :
254 3888 : void CodeHolder::sync() noexcept {
255 3888 : if (_cgAsm) _cgAsm->sync();
256 3888 : }
257 :
258 : // ============================================================================
259 : // [asmjit::CodeHolder - Result Information]
260 : // ============================================================================
261 :
262 3888 : size_t CodeHolder::getCodeSize() const noexcept {
263 : // Reflect all changes first.
264 3888 : const_cast<CodeHolder*>(this)->sync();
265 :
266 : // TODO: Support sections.
267 3888 : return _sections[0]->_buffer._length + getTrampolinesSize();
268 : }
269 :
270 : // ============================================================================
271 : // [asmjit::CodeHolder - Logging & Error Handling]
272 : // ============================================================================
273 :
274 : #if !defined(ASMJIT_DISABLE_LOGGING)
275 0 : void CodeHolder::setLogger(Logger* logger) noexcept {
276 : uint32_t opt = 0;
277 0 : if (logger) opt = CodeEmitter::kOptionLoggingEnabled;
278 :
279 0 : _logger = logger;
280 0 : CodeHolder_setGlobalOption(this, CodeEmitter::kOptionLoggingEnabled, opt);
281 0 : }
282 : #endif // !ASMJIT_DISABLE_LOGGING
283 :
284 0 : Error CodeHolder::setErrorHandler(ErrorHandler* handler) noexcept {
285 0 : _errorHandler = handler;
286 0 : return kErrorOk;
287 : }
288 :
289 : // ============================================================================
290 : // [asmjit::CodeHolder - Sections]
291 : // ============================================================================
292 :
293 1944 : static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
294 1944 : uint8_t* oldData = cb->_data;
295 : uint8_t* newData;
296 :
297 1944 : if (oldData && !cb->isExternal())
298 : newData = static_cast<uint8_t*>(Internal::reallocMemory(oldData, n));
299 : else
300 : newData = static_cast<uint8_t*>(Internal::allocMemory(n));
301 :
302 1944 : if (ASMJIT_UNLIKELY(!newData))
303 : return DebugUtils::errored(kErrorNoHeapMemory);
304 :
305 1944 : cb->_data = newData;
306 1944 : cb->_capacity = n;
307 :
308 : // Update the `Assembler` pointers if attached. Maybe we should introduce an
309 : // event for this, but since only one Assembler can be attached at a time it
310 : // should not matter how these pointers are updated.
311 1944 : Assembler* a = self->_cgAsm;
312 1944 : if (a && &a->_section->_buffer == cb) {
313 : size_t offset = a->getOffset();
314 :
315 1944 : a->_bufferData = newData;
316 1944 : a->_bufferEnd = newData + n;
317 1944 : a->_bufferPtr = newData + offset;
318 : }
319 :
320 : return kErrorOk;
321 : }
322 :
323 1944 : Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept {
324 : // This is most likely called by `Assembler` so `sync()` shouldn't be needed,
325 : // however, if this is called by the user and the currently attached Assembler
326 : // did generate some code we could lose that, so sync now and make sure the
327 : // section length is updated.
328 1944 : if (_cgAsm) _cgAsm->sync();
329 :
330 : // Now the length of the section must be valid.
331 : size_t length = cb->getLength();
332 1944 : if (ASMJIT_UNLIKELY(n > IntTraits<uintptr_t>::maxValue() - length))
333 : return DebugUtils::errored(kErrorNoHeapMemory);
334 :
335 : // We can now check if growing the buffer is really necessary. It's unlikely
336 : // that this function is called while there is still room for `n` bytes.
337 : size_t capacity = cb->getCapacity();
338 1944 : size_t required = cb->getLength() + n;
339 1944 : if (ASMJIT_UNLIKELY(required <= capacity)) return kErrorOk;
340 :
341 1944 : if (cb->isFixedSize())
342 : return DebugUtils::errored(kErrorCodeTooLarge);
343 :
344 1944 : if (capacity < 8096)
345 : capacity = 8096;
346 : else
347 0 : capacity += Globals::kAllocOverhead;
348 :
349 : do {
350 : size_t old = capacity;
351 1944 : if (capacity < Globals::kAllocThreshold)
352 1944 : capacity *= 2;
353 : else
354 0 : capacity += Globals::kAllocThreshold;
355 :
356 1944 : if (capacity < Globals::kAllocThreshold)
357 1944 : capacity *= 2;
358 : else
359 0 : capacity += Globals::kAllocThreshold;
360 :
361 : // Overflow.
362 1944 : if (ASMJIT_UNLIKELY(old > capacity))
363 : return DebugUtils::errored(kErrorNoHeapMemory);
364 1944 : } while (capacity - Globals::kAllocOverhead < required);
365 :
366 1944 : return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead);
367 : }
368 :
369 0 : Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
370 : size_t capacity = cb->getCapacity();
371 0 : if (n <= capacity) return kErrorOk;
372 :
373 0 : if (cb->isFixedSize())
374 : return DebugUtils::errored(kErrorCodeTooLarge);
375 :
376 : // We must sync, as mentioned in `growBuffer()` as well.
377 0 : if (_cgAsm) _cgAsm->sync();
378 :
379 0 : return CodeHolder_reserveInternal(this, cb, n);
380 : }
381 :
382 : // ============================================================================
383 : // [asmjit::CodeHolder - Labels & Symbols]
384 : // ============================================================================
385 :
386 : namespace {
387 :
388 : //! \internal
389 : //!
390 : //! Only used to lookup a label from `_namedLabels`.
391 : class LabelByName {
392 : public:
393 : ASMJIT_INLINE LabelByName(const char* name, size_t nameLength, uint32_t hVal) noexcept
394 : : name(name),
395 0 : nameLength(static_cast<uint32_t>(nameLength)),
396 : hVal(hVal) {}
397 :
398 : ASMJIT_INLINE bool matches(const LabelEntry* entry) const noexcept {
399 0 : return static_cast<uint32_t>(entry->getNameLength()) == nameLength &&
400 0 : ::memcmp(entry->getName(), name, nameLength) == 0;
401 : }
402 :
403 : const char* name;
404 : uint32_t nameLength;
405 : uint32_t hVal;
406 : };
407 :
408 : // Returns a hash of `name` and fixes `nameLength` if it's `Globals::kInvalidIndex`.
409 0 : static uint32_t CodeHolder_hashNameAndFixLen(const char* name, size_t& nameLength) noexcept {
410 : uint32_t hVal = 0;
411 0 : if (nameLength == Globals::kInvalidIndex) {
412 : size_t i = 0;
413 : for (;;) {
414 0 : uint8_t c = static_cast<uint8_t>(name[i]);
415 0 : if (!c) break;
416 0 : hVal = Utils::hashRound(hVal, c);
417 0 : i++;
418 0 : }
419 0 : nameLength = i;
420 : }
421 : else {
422 0 : for (size_t i = 0; i < nameLength; i++) {
423 0 : uint8_t c = static_cast<uint8_t>(name[i]);
424 0 : if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName);
425 0 : hVal = Utils::hashRound(hVal, c);
426 : }
427 : }
428 : return hVal;
429 : }
430 :
431 : } // anonymous namespace
432 :
433 0 : LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept {
434 0 : LabelLink* link = _baseHeap.allocT<LabelLink>();
435 0 : if (ASMJIT_UNLIKELY(!link)) return nullptr;
436 :
437 0 : link->prev = le->_links;
438 0 : le->_links = link;
439 :
440 0 : link->sectionId = sectionId;
441 0 : link->relocId = RelocEntry::kInvalidId;
442 0 : link->offset = offset;
443 0 : link->rel = rel;
444 :
445 0 : _unresolvedLabelsCount++;
446 0 : return link;
447 : }
448 :
449 3888 : Error CodeHolder::newLabelId(uint32_t& idOut) noexcept {
450 3888 : idOut = 0;
451 :
452 : size_t index = _labels.getLength();
453 3888 : if (ASMJIT_LIKELY(index >= Operand::kPackedIdCount))
454 : return DebugUtils::errored(kErrorLabelIndexOverflow);
455 :
456 5832 : ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
457 3888 : LabelEntry* le = _baseHeap.allocZeroedT<LabelEntry>();
458 :
459 3888 : if (ASMJIT_UNLIKELY(!le))
460 : return DebugUtils::errored(kErrorNoHeapMemory);;
461 :
462 3888 : uint32_t id = Operand::packId(static_cast<uint32_t>(index));
463 : le->_setId(id);
464 3888 : le->_parentId = 0;
465 3888 : le->_sectionId = SectionEntry::kInvalidId;
466 3888 : le->_offset = 0;
467 :
468 : _labels.appendUnsafe(le);
469 3888 : idOut = id;
470 3888 : return kErrorOk;
471 : }
472 :
473 0 : Error CodeHolder::newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept {
474 0 : idOut = 0;
475 0 : uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
476 :
477 0 : if (ASMJIT_UNLIKELY(nameLength == 0))
478 : return DebugUtils::errored(kErrorInvalidLabelName);
479 :
480 0 : if (ASMJIT_UNLIKELY(nameLength > Globals::kMaxLabelLength))
481 : return DebugUtils::errored(kErrorLabelNameTooLong);
482 :
483 0 : switch (type) {
484 : case Label::kTypeLocal:
485 0 : if (ASMJIT_UNLIKELY(Operand::unpackId(parentId) >= _labels.getLength()))
486 : return DebugUtils::errored(kErrorInvalidParentLabel);
487 :
488 0 : hVal ^= parentId;
489 0 : break;
490 :
491 0 : case Label::kTypeGlobal:
492 0 : if (ASMJIT_UNLIKELY(parentId != 0))
493 : return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent);
494 :
495 : break;
496 :
497 : default:
498 : return DebugUtils::errored(kErrorInvalidArgument);
499 : }
500 :
501 : // Don't allow to insert duplicates. Local labels allow duplicates that have
502 : // different id, this is already accomplished by having a different hashes
503 : // between the same label names having different parent labels.
504 0 : LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
505 0 : if (ASMJIT_UNLIKELY(le))
506 : return DebugUtils::errored(kErrorLabelAlreadyDefined);
507 :
508 : Error err = kErrorOk;
509 : size_t index = _labels.getLength();
510 :
511 0 : if (ASMJIT_UNLIKELY(index >= Operand::kPackedIdCount))
512 : return DebugUtils::errored(kErrorLabelIndexOverflow);
513 :
514 0 : ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
515 0 : le = _baseHeap.allocZeroedT<LabelEntry>();
516 :
517 0 : if (ASMJIT_UNLIKELY(!le))
518 : return DebugUtils::errored(kErrorNoHeapMemory);
519 :
520 0 : uint32_t id = Operand::packId(static_cast<uint32_t>(index));
521 0 : le->_hVal = hVal;
522 : le->_setId(id);
523 0 : le->_type = static_cast<uint8_t>(type);
524 0 : le->_parentId = 0;
525 0 : le->_sectionId = SectionEntry::kInvalidId;
526 0 : le->_offset = 0;
527 :
528 0 : if (le->_name.mustEmbed(nameLength)) {
529 : le->_name.setEmbedded(name, nameLength);
530 : }
531 : else {
532 0 : char* nameExternal = static_cast<char*>(_dataZone.dup(name, nameLength, true));
533 0 : if (ASMJIT_UNLIKELY(!nameExternal))
534 : return DebugUtils::errored(kErrorNoHeapMemory);
535 0 : le->_name.setExternal(nameExternal, nameLength);
536 : }
537 :
538 : _labels.appendUnsafe(le);
539 : _namedLabels.put(le);
540 :
541 0 : idOut = id;
542 0 : return err;
543 : }
544 :
545 0 : uint32_t CodeHolder::getLabelIdByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
546 0 : uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
547 0 : if (ASMJIT_UNLIKELY(!nameLength)) return 0;
548 :
549 : LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
550 0 : return le ? le->getId() : static_cast<uint32_t>(0);
551 : }
552 :
553 : // ============================================================================
554 : // [asmjit::CodeEmitter - Relocations]
555 : // ============================================================================
556 :
557 : //! Encode MOD byte.
558 : static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
559 : return (m << 6) | (o << 3) | rm;
560 : }
561 :
562 0 : Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept {
563 0 : ASMJIT_PROPAGATE(_relocations.willGrow(&_baseHeap));
564 :
565 : size_t index = _relocations.getLength();
566 0 : if (ASMJIT_UNLIKELY(index > size_t(0xFFFFFFFFU)))
567 : return DebugUtils::errored(kErrorRelocIndexOverflow);
568 :
569 0 : RelocEntry* re = _baseHeap.allocZeroedT<RelocEntry>();
570 0 : if (ASMJIT_UNLIKELY(!re))
571 : return DebugUtils::errored(kErrorNoHeapMemory);
572 :
573 0 : re->_id = static_cast<uint32_t>(index);
574 0 : re->_type = static_cast<uint8_t>(type);
575 0 : re->_size = static_cast<uint8_t>(size);
576 0 : re->_sourceSectionId = SectionEntry::kInvalidId;
577 0 : re->_targetSectionId = SectionEntry::kInvalidId;
578 : _relocations.appendUnsafe(re);
579 :
580 0 : *dst = re;
581 0 : return kErrorOk;
582 : }
583 :
584 : // TODO: Support multiple sections, this only relocates the first.
585 : // TODO: This should go to Runtime as it's responsible for relocating the
586 : // code, CodeHolder should just hold it.
587 1944 : size_t CodeHolder::relocate(void* _dst, uint64_t baseAddress) const noexcept {
588 1944 : SectionEntry* section = _sections[0];
589 : ASMJIT_ASSERT(section != nullptr);
590 :
591 : uint8_t* dst = static_cast<uint8_t*>(_dst);
592 1944 : if (baseAddress == Globals::kNoBaseAddress)
593 1944 : baseAddress = static_cast<uint64_t>((uintptr_t)dst);
594 :
595 : #if !defined(ASMJIT_DISABLE_LOGGING)
596 : Logger* logger = getLogger();
597 : #endif // ASMJIT_DISABLE_LOGGING
598 :
599 : size_t minCodeSize = section->getBuffer().getLength(); // Minimum code size.
600 1944 : size_t maxCodeSize = getCodeSize(); // Includes all possible trampolines.
601 :
602 : // We will copy the exact size of the generated code. Extra code for trampolines
603 : // is generated on-the-fly by the relocator (this code doesn't exist at the moment).
604 1944 : ::memcpy(dst, section->_buffer._data, minCodeSize);
605 :
606 : // Trampoline offset from the beginning of dst/baseAddress.
607 : size_t trampOffset = minCodeSize;
608 :
609 : // Relocate all recorded locations.
610 : size_t numRelocs = _relocations.getLength();
611 : const RelocEntry* const* reArray = _relocations.getData();
612 :
613 1944 : for (size_t i = 0; i < numRelocs; i++) {
614 0 : const RelocEntry* re = reArray[i];
615 :
616 : // Possibly deleted or optimized out relocation entry.
617 0 : if (re->getType() == RelocEntry::kTypeNone)
618 0 : continue;
619 :
620 : uint64_t ptr = re->getData();
621 : size_t codeOffset = static_cast<size_t>(re->getSourceOffset());
622 :
623 : // Make sure that the `RelocEntry` is correct, we don't want to write
624 : // out of bounds in `dst`.
625 0 : if (ASMJIT_UNLIKELY(codeOffset + re->getSize() > maxCodeSize))
626 : return DebugUtils::errored(kErrorInvalidRelocEntry);
627 :
628 : // Whether to use trampoline, can be only used if relocation type is `kRelocTrampoline`.
629 : bool useTrampoline = false;
630 :
631 0 : switch (re->getType()) {
632 : case RelocEntry::kTypeAbsToAbs: {
633 : break;
634 : }
635 :
636 0 : case RelocEntry::kTypeRelToAbs: {
637 0 : ptr += baseAddress;
638 0 : break;
639 : }
640 :
641 : case RelocEntry::kTypeAbsToRel: {
642 0 : ptr -= baseAddress + re->getSourceOffset() + re->getSize();
643 0 : break;
644 : }
645 :
646 : case RelocEntry::kTypeTrampoline: {
647 0 : if (re->getSize() != 4)
648 : return DebugUtils::errored(kErrorInvalidRelocEntry);
649 :
650 0 : ptr -= baseAddress + re->getSourceOffset() + re->getSize();
651 0 : if (!Utils::isInt32(static_cast<int64_t>(ptr))) {
652 0 : ptr = (uint64_t)trampOffset - re->getSourceOffset() - re->getSize();
653 : useTrampoline = true;
654 : }
655 : break;
656 : }
657 :
658 : default:
659 : return DebugUtils::errored(kErrorInvalidRelocEntry);
660 : }
661 :
662 0 : switch (re->getSize()) {
663 0 : case 1:
664 0 : Utils::writeU8(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFU));
665 : break;
666 :
667 0 : case 4:
668 0 : Utils::writeU32u(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFFFFFFFU));
669 : break;
670 :
671 0 : case 8:
672 0 : Utils::writeU64u(dst + codeOffset, ptr);
673 : break;
674 :
675 : default:
676 : return DebugUtils::errored(kErrorInvalidRelocEntry);
677 : }
678 :
679 : // Handle the trampoline case.
680 0 : if (useTrampoline) {
681 : // Bytes that replace [REX, OPCODE] bytes.
682 : uint32_t byte0 = 0xFF;
683 0 : uint32_t byte1 = dst[codeOffset - 1];
684 :
685 0 : if (byte1 == 0xE8) {
686 : // Patch CALL/MOD byte to FF/2 (-> 0x15).
687 : byte1 = x86EncodeMod(0, 2, 5);
688 : }
689 0 : else if (byte1 == 0xE9) {
690 : // Patch JMP/MOD byte to FF/4 (-> 0x25).
691 : byte1 = x86EncodeMod(0, 4, 5);
692 : }
693 : else {
694 : return DebugUtils::errored(kErrorInvalidRelocEntry);
695 : }
696 :
697 : // Patch `jmp/call` instruction.
698 : ASMJIT_ASSERT(codeOffset >= 2);
699 0 : dst[codeOffset - 2] = static_cast<uint8_t>(byte0);
700 0 : dst[codeOffset - 1] = static_cast<uint8_t>(byte1);
701 :
702 : // Store absolute address and advance the trampoline pointer.
703 0 : Utils::writeU64u(dst + trampOffset, re->getData());
704 0 : trampOffset += 8;
705 :
706 : #if !defined(ASMJIT_DISABLE_LOGGING)
707 0 : if (logger)
708 0 : logger->logf("[reloc] dq 0x%016llX ; Trampoline\n", re->getData());
709 : #endif // !ASMJIT_DISABLE_LOGGING
710 : }
711 : }
712 :
713 : // If there are no trampolines this is the same as `minCodeSize`.
714 : return trampOffset;
715 : }
716 :
717 : } // asmjit namespace
718 : } // namespace PLMD
719 :
720 : // [Api-End]
721 : #include "./asmjit_apiend.h"
722 : #pragma GCC diagnostic pop
723 : #endif // __PLUMED_HAS_ASMJIT
|