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 "./constpool.h"
35 : #include "./utils.h"
36 : #include "./vmem.h"
37 :
38 : // [Api-Begin]
39 : #include "./asmjit_apibegin.h"
40 :
41 : namespace PLMD {
42 : namespace asmjit {
43 :
44 : // ============================================================================
45 : // [asmjit::Assembler - Construction / Destruction]
46 : // ============================================================================
47 :
48 1944 : Assembler::Assembler() noexcept
49 : : CodeEmitter(kTypeAssembler),
50 1944 : _section(nullptr),
51 1944 : _bufferData(nullptr),
52 1944 : _bufferEnd(nullptr),
53 1944 : _bufferPtr(nullptr),
54 1944 : _op4(),
55 1944 : _op5() {}
56 :
57 1944 : Assembler::~Assembler() noexcept {
58 1944 : if (_code) sync();
59 1944 : }
60 :
61 : // ============================================================================
62 : // [asmjit::Assembler - Events]
63 : // ============================================================================
64 :
65 1944 : Error Assembler::onAttach(CodeHolder* code) noexcept {
66 : // Attach to the end of the .text section.
67 1944 : _section = code->_sections[0];
68 1944 : uint8_t* p = _section->_buffer._data;
69 :
70 1944 : _bufferData = p;
71 1944 : _bufferEnd = p + _section->_buffer._capacity;
72 1944 : _bufferPtr = p + _section->_buffer._length;
73 :
74 : _op4.reset();
75 : _op5.reset();
76 :
77 1944 : return Base::onAttach(code);
78 : }
79 :
80 0 : Error Assembler::onDetach(CodeHolder* code) noexcept {
81 0 : _section = nullptr;
82 0 : _bufferData = nullptr;
83 0 : _bufferEnd = nullptr;
84 0 : _bufferPtr = nullptr;
85 :
86 : _op4.reset();
87 : _op5.reset();
88 :
89 0 : return Base::onDetach(code);
90 : }
91 :
92 : // ============================================================================
93 : // [asmjit::Assembler - Code-Generation]
94 : // ============================================================================
95 :
96 0 : Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
97 0 : _op4 = o4;
98 0 : _op5 = o5;
99 0 : _options |= kOptionOp4Op5Used;
100 0 : return _emit(instId, o0, o1, o2, o3);
101 : }
102 :
103 48254 : Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
104 : const Operand_* op = opArray;
105 48254 : switch (opCount) {
106 1944 : case 0: return _emit(instId, _none, _none, _none, _none);
107 3852 : case 1: return _emit(instId, op[0], _none, _none, _none);
108 42338 : case 2: return _emit(instId, op[0], op[1], _none, _none);
109 120 : case 3: return _emit(instId, op[0], op[1], op[2], _none);
110 0 : case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
111 :
112 0 : case 5:
113 0 : _op4 = op[4];
114 : _op5.reset();
115 0 : _options |= kOptionOp4Op5Used;
116 0 : return _emit(instId, op[0], op[1], op[2], op[3]);
117 :
118 0 : case 6:
119 0 : _op4 = op[4];
120 0 : _op5 = op[5];
121 0 : _options |= kOptionOp4Op5Used;
122 0 : return _emit(instId, op[0], op[1], op[2], op[3]);
123 :
124 : default:
125 : return DebugUtils::errored(kErrorInvalidArgument);
126 : }
127 : }
128 :
129 : // ============================================================================
130 : // [asmjit::Assembler - Sync]
131 : // ============================================================================
132 :
133 3888 : void Assembler::sync() noexcept {
134 : ASMJIT_ASSERT(_code != nullptr); // Only called by CodeHolder, so we must be attached.
135 : ASMJIT_ASSERT(_section != nullptr); // One section must always be active, no matter what.
136 : ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`.
137 :
138 : // Update only if the current offset is greater than the section length.
139 3888 : size_t offset = (size_t)(_bufferPtr - _bufferData);
140 3888 : if (_section->getBuffer().getLength() < offset)
141 1944 : _section->_buffer._length = offset;
142 3888 : }
143 :
144 : // ============================================================================
145 : // [asmjit::Assembler - Code-Buffer]
146 : // ============================================================================
147 :
148 0 : Error Assembler::setOffset(size_t offset) {
149 0 : if (_lastError) return _lastError;
150 :
151 0 : size_t length = std::max(_section->getBuffer().getLength(), getOffset());
152 0 : if (ASMJIT_UNLIKELY(offset > length))
153 0 : return setLastError(DebugUtils::errored(kErrorInvalidArgument));
154 :
155 : // If the `Assembler` generated any code the `_bufferPtr` may be higher than
156 : // the section length stored in `CodeHolder` as it doesn't update it each
157 : // time it generates machine code. This is the same as calling `sync()`.
158 0 : if (_section->_buffer._length < length)
159 0 : _section->_buffer._length = length;
160 :
161 0 : _bufferPtr = _bufferData + offset;
162 0 : return kErrorOk;
163 : }
164 :
165 : // ============================================================================
166 : // [asmjit::Assembler - Comment]
167 : // ============================================================================
168 :
169 0 : Error Assembler::comment(const char* s, size_t len) {
170 0 : if (_lastError) return _lastError;
171 :
172 : #if !defined(ASMJIT_DISABLE_LOGGING)
173 0 : if (_globalOptions & kOptionLoggingEnabled) {
174 0 : Logger* logger = _code->getLogger();
175 : logger->log(s, len);
176 : logger->log("\n", 1);
177 0 : return kErrorOk;
178 : }
179 : #else
180 : ASMJIT_UNUSED(s);
181 : ASMJIT_UNUSED(len);
182 : #endif
183 :
184 : return kErrorOk;
185 : }
186 :
187 : // ============================================================================
188 : // [asmjit::Assembler - Building Blocks]
189 : // ============================================================================
190 :
191 0 : Label Assembler::newLabel() {
192 0 : uint32_t id = 0;
193 0 : if (!_lastError) {
194 : ASMJIT_ASSERT(_code != nullptr);
195 0 : Error err = _code->newLabelId(id);
196 0 : if (ASMJIT_UNLIKELY(err)) setLastError(err);
197 : }
198 0 : return Label(id);
199 : }
200 :
201 0 : Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
202 0 : uint32_t id = 0;
203 0 : if (!_lastError) {
204 : ASMJIT_ASSERT(_code != nullptr);
205 0 : Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
206 0 : if (ASMJIT_UNLIKELY(err)) setLastError(err);
207 : }
208 0 : return Label(id);
209 : }
210 :
211 3888 : Error Assembler::bind(const Label& label) {
212 3888 : if (_lastError) return _lastError;
213 : ASMJIT_ASSERT(_code != nullptr);
214 :
215 3888 : LabelEntry* le = _code->getLabelEntry(label);
216 3888 : if (ASMJIT_UNLIKELY(!le))
217 0 : return setLastError(DebugUtils::errored(kErrorInvalidLabel));
218 :
219 : // Label can be bound only once.
220 3888 : if (ASMJIT_UNLIKELY(le->isBound()))
221 0 : return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound));
222 :
223 : #if !defined(ASMJIT_DISABLE_LOGGING)
224 3888 : if (_globalOptions & kOptionLoggingEnabled) {
225 : StringBuilderTmp<256> sb;
226 0 : if (le->hasName())
227 0 : sb.setFormat("%s:", le->getName());
228 : else
229 0 : sb.setFormat("L%u:", Operand::unpackId(label.getId()));
230 :
231 : size_t binSize = 0;
232 0 : if (!_code->_logger->hasOption(Logger::kOptionBinaryForm))
233 : binSize = Globals::kInvalidIndex;
234 :
235 0 : Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment());
236 0 : _code->_logger->log(sb.getData(), sb.getLength());
237 : }
238 : #endif // !ASMJIT_DISABLE_LOGGING
239 :
240 : Error err = kErrorOk;
241 : size_t pos = getOffset();
242 :
243 3888 : LabelLink* link = le->_links;
244 : LabelLink* prev = nullptr;
245 :
246 3888 : while (link) {
247 0 : intptr_t offset = link->offset;
248 0 : uint32_t relocId = link->relocId;
249 :
250 0 : if (relocId != RelocEntry::kInvalidId) {
251 : // Adjust relocation data.
252 0 : RelocEntry* re = _code->_relocations[relocId];
253 0 : re->_data += static_cast<uint64_t>(pos);
254 : }
255 : else {
256 : // Not using relocId, this means that we are overwriting a real
257 : // displacement in the CodeBuffer.
258 0 : int32_t patchedValue = static_cast<int32_t>(
259 0 : static_cast<intptr_t>(pos) - offset + link->rel);
260 :
261 : // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
262 0 : uint32_t size = _bufferData[offset];
263 0 : if (size == 4)
264 : Utils::writeI32u(_bufferData + offset, static_cast<int32_t>(patchedValue));
265 0 : else if (size == 1 && Utils::isInt8(patchedValue))
266 0 : _bufferData[offset] = static_cast<uint8_t>(patchedValue & 0xFF);
267 : else
268 : err = DebugUtils::errored(kErrorInvalidDisplacement);
269 : }
270 :
271 0 : prev = link->prev;
272 0 : _code->_unresolvedLabelsCount--;
273 0 : _code->_baseHeap.release(link, sizeof(LabelLink));
274 :
275 : link = prev;
276 : }
277 :
278 : // Set as bound.
279 3888 : le->_sectionId = _section->getId();
280 3888 : le->_offset = pos;
281 3888 : le->_links = nullptr;
282 : resetInlineComment();
283 :
284 3888 : if (err != kErrorOk)
285 0 : return setLastError(err);
286 :
287 : return kErrorOk;
288 : }
289 :
290 0 : Error Assembler::embed(const void* data, uint32_t size) {
291 0 : if (_lastError) return _lastError;
292 :
293 0 : if (getRemainingSpace() < size) {
294 0 : Error err = _code->growBuffer(&_section->_buffer, size);
295 0 : if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err);
296 : }
297 :
298 0 : ::memcpy(_bufferPtr, data, size);
299 0 : _bufferPtr += size;
300 :
301 : #if !defined(ASMJIT_DISABLE_LOGGING)
302 0 : if (_globalOptions & kOptionLoggingEnabled)
303 0 : _code->_logger->logBinary(data, size);
304 : #endif // !ASMJIT_DISABLE_LOGGING
305 :
306 : return kErrorOk;
307 : }
308 :
309 0 : Error Assembler::embedLabel(const Label& label) {
310 0 : if (_lastError) return _lastError;
311 : ASMJIT_ASSERT(_code != nullptr);
312 :
313 : RelocEntry* re;
314 0 : LabelEntry* le = _code->getLabelEntry(label);
315 :
316 0 : if (ASMJIT_UNLIKELY(!le))
317 0 : return setLastError(DebugUtils::errored(kErrorInvalidLabel));
318 :
319 : Error err;
320 : uint32_t gpSize = getGpSize();
321 :
322 0 : if (getRemainingSpace() < gpSize) {
323 0 : err = _code->growBuffer(&_section->_buffer, gpSize);
324 0 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
325 : }
326 :
327 : #if !defined(ASMJIT_DISABLE_LOGGING)
328 0 : if (_globalOptions & kOptionLoggingEnabled)
329 0 : _code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId()));
330 : #endif // !ASMJIT_DISABLE_LOGGING
331 :
332 0 : err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize);
333 0 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
334 :
335 0 : re->_sourceSectionId = _section->getId();
336 0 : re->_sourceOffset = static_cast<uint64_t>(getOffset());
337 :
338 0 : if (le->isBound()) {
339 0 : re->_targetSectionId = le->getSectionId();
340 0 : re->_data = static_cast<uint64_t>(static_cast<int64_t>(le->getOffset()));
341 : }
342 : else {
343 0 : LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0);
344 0 : if (ASMJIT_UNLIKELY(!link))
345 0 : return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
346 0 : link->relocId = re->getId();
347 : }
348 :
349 : // Emit dummy DWORD/QWORD depending on the address size.
350 0 : ::memset(_bufferPtr, 0, gpSize);
351 0 : _bufferPtr += gpSize;
352 :
353 0 : return kErrorOk;
354 : }
355 :
356 0 : Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) {
357 0 : if (_lastError) return _lastError;
358 :
359 0 : if (!isLabelValid(label))
360 : return DebugUtils::errored(kErrorInvalidLabel);
361 :
362 0 : ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
363 0 : ASMJIT_PROPAGATE(bind(label));
364 :
365 : size_t size = pool.getSize();
366 0 : if (getRemainingSpace() < size) {
367 0 : Error err = _code->growBuffer(&_section->_buffer, size);
368 0 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
369 : }
370 :
371 0 : uint8_t* p = _bufferPtr;
372 0 : pool.fill(p);
373 :
374 : #if !defined(ASMJIT_DISABLE_LOGGING)
375 0 : if (_globalOptions & kOptionLoggingEnabled)
376 0 : _code->_logger->logBinary(p, size);
377 : #endif // !ASMJIT_DISABLE_LOGGING
378 :
379 0 : _bufferPtr += size;
380 0 : return kErrorOk;
381 : }
382 :
383 : // ============================================================================
384 : // [asmjit::Assembler - Emit-Helpers]
385 : // ============================================================================
386 :
387 : #if !defined(ASMJIT_DISABLE_LOGGING)
388 0 : void Assembler::_emitLog(
389 : uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
390 : uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) {
391 :
392 0 : Logger* logger = _code->getLogger();
393 : ASMJIT_ASSERT(logger != nullptr);
394 : ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled);
395 :
396 : StringBuilderTmp<256> sb;
397 : uint32_t logOptions = logger->getOptions();
398 :
399 0 : uint8_t* beforeCursor = _bufferPtr;
400 0 : intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
401 :
402 : sb.appendString(logger->getIndentation());
403 :
404 : Operand_ opArray[6];
405 : opArray[0].copyFrom(o0);
406 : opArray[1].copyFrom(o1);
407 : opArray[2].copyFrom(o2);
408 : opArray[3].copyFrom(o3);
409 :
410 0 : if (options & kOptionOp4Op5Used) {
411 : opArray[4].copyFrom(_op4);
412 : opArray[5].copyFrom(_op5);
413 : }
414 : else {
415 : opArray[4].reset();
416 : opArray[5].reset();
417 : }
418 :
419 0 : Logging::formatInstruction(
420 : sb, logOptions,
421 : this, getArchType(),
422 0 : Inst::Detail(instId, options, _extraReg), opArray, 6);
423 :
424 0 : if ((logOptions & Logger::kOptionBinaryForm) != 0)
425 0 : Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
426 : else
427 0 : Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment());
428 :
429 : logger->log(sb.getData(), sb.getLength());
430 0 : }
431 :
432 0 : Error Assembler::_emitFailed(
433 : Error err,
434 : uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
435 :
436 : StringBuilderTmp<256> sb;
437 0 : sb.appendString(DebugUtils::errorAsString(err));
438 : sb.appendString(": ");
439 :
440 : Operand_ opArray[6];
441 : opArray[0].copyFrom(o0);
442 : opArray[1].copyFrom(o1);
443 : opArray[2].copyFrom(o2);
444 : opArray[3].copyFrom(o3);
445 :
446 0 : if (options & kOptionOp4Op5Used) {
447 : opArray[4].copyFrom(_op4);
448 : opArray[5].copyFrom(_op5);
449 : }
450 : else {
451 : opArray[4].reset();
452 : opArray[5].reset();
453 : }
454 :
455 0 : Logging::formatInstruction(
456 : sb, 0,
457 : this, getArchType(),
458 0 : Inst::Detail(instId, options, _extraReg), opArray, 6);
459 :
460 : resetOptions();
461 : resetExtraReg();
462 : resetInlineComment();
463 0 : return setLastError(err, sb.getData());
464 : }
465 : #endif
466 :
467 : } // asmjit namespace
468 : } // namespace PLMD
469 :
470 : // [Api-End]
471 : #include "./asmjit_apiend.h"
472 : #pragma GCC diagnostic pop
473 : #endif // __PLUMED_HAS_ASMJIT
|