assembler.cpp 13 KB
Newer Older
1
2
3
4
5
6
7
8
9
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Export]
#define ASMJIT_EXPORTS

10
// [Dependencies]
11
#include "../base/assembler.h"
12
13
#include "../base/constpool.h"
#include "../base/utils.h"
14
15
16
#include "../base/vmem.h"

// [Api-Begin]
17
#include "../asmjit_apibegin.h"
18
19
20
21
22
23
24

namespace asmjit {

// ============================================================================
// [asmjit::Assembler - Construction / Destruction]
// ============================================================================

25
26
27
28
29
30
31
32
33
34
35
Assembler::Assembler() noexcept
  : CodeEmitter(kTypeAssembler),
    _section(nullptr),
    _bufferData(nullptr),
    _bufferEnd(nullptr),
    _bufferPtr(nullptr),
    _op4(),
    _op5() {}

Assembler::~Assembler() noexcept {
  if (_code) sync();
36
37
38
}

// ============================================================================
39
// [asmjit::Assembler - Events]
40
41
// ============================================================================

42
43
44
45
Error Assembler::onAttach(CodeHolder* code) noexcept {
  // Attach to the end of the .text section.
  _section = code->_sections[0];
  uint8_t* p = _section->_buffer._data;
46

47
48
49
  _bufferData = p;
  _bufferEnd  = p + _section->_buffer._capacity;
  _bufferPtr  = p + _section->_buffer._length;
50

51
52
53
54
55
  _op4.reset();
  _op5.reset();

  return Base::onAttach(code);
}
56

57
58
59
60
61
Error Assembler::onDetach(CodeHolder* code) noexcept {
  _section    = nullptr;
  _bufferData = nullptr;
  _bufferEnd  = nullptr;
  _bufferPtr  = nullptr;
62

63
64
  _op4.reset();
  _op5.reset();
65

66
  return Base::onDetach(code);
67
68
69
}

// ============================================================================
70
// [asmjit::Assembler - Code-Generation]
71
72
// ============================================================================

73
74
75
76
77
78
Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
  _op4 = o4;
  _op5 = o5;
  _options |= kOptionOp4Op5Used;
  return _emit(instId, o0, o1, o2, o3);
}
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
  const Operand_* op = opArray;
  switch (opCount) {
    case 0: return _emit(instId, _none, _none, _none, _none);
    case 1: return _emit(instId, op[0], _none, _none, _none);
    case 2: return _emit(instId, op[0], op[1], _none, _none);
    case 3: return _emit(instId, op[0], op[1], op[2], _none);
    case 4: return _emit(instId, op[0], op[1], op[2], op[3]);

    case 5:
      _op4 = op[4];
      _op5.reset();
      _options |= kOptionOp4Op5Used;
      return _emit(instId, op[0], op[1], op[2], op[3]);

    case 6:
      _op4 = op[4];
      _op5 = op[5];
      _options |= kOptionOp4Op5Used;
      return _emit(instId, op[0], op[1], op[2], op[3]);

    default:
      return DebugUtils::errored(kErrorInvalidArgument);
  }
}
105

106
107
108
// ============================================================================
// [asmjit::Assembler - Sync]
// ============================================================================
109

110
111
112
113
void Assembler::sync() noexcept {
  ASMJIT_ASSERT(_code != nullptr);                       // Only called by CodeHolder, so we must be attached.
  ASMJIT_ASSERT(_section != nullptr);                    // One section must always be active, no matter what.
  ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`.
114

115
116
117
118
  // Update only if the current offset is greater than the section length.
  size_t offset = (size_t)(_bufferPtr - _bufferData);
  if (_section->getBuffer().getLength() < offset)
    _section->_buffer._length = offset;
119
120
}

121
122
123
// ============================================================================
// [asmjit::Assembler - Code-Buffer]
// ============================================================================
124

125
126
Error Assembler::setOffset(size_t offset) {
  if (_lastError) return _lastError;
127

128
129
130
  size_t length = std::max(_section->getBuffer().getLength(), getOffset());
  if (ASMJIT_UNLIKELY(offset > length))
    return setLastError(DebugUtils::errored(kErrorInvalidArgument));
131

132
133
134
135
136
  // If the `Assembler` generated any code the `_bufferPtr` may be higher than
  // the section length stored in `CodeHolder` as it doesn't update it each
  // time it generates machine code. This is the same as calling `sync()`.
  if (_section->_buffer._length < length)
    _section->_buffer._length = length;
137

138
  _bufferPtr = _bufferData + offset;
139
140
141
142
  return kErrorOk;
}

// ============================================================================
143
// [asmjit::Assembler - Comment]
144
145
// ============================================================================

146
147
Error Assembler::comment(const char* s, size_t len) {
  if (_lastError) return _lastError;
148

149
150
151
152
153
154
155
156
157
158
159
#if !defined(ASMJIT_DISABLE_LOGGING)
  if (_globalOptions & kOptionLoggingEnabled) {
    Logger* logger = _code->getLogger();
    logger->log(s, len);
    logger->log("\n", 1);
    return kErrorOk;
  }
#else
  ASMJIT_UNUSED(s);
  ASMJIT_UNUSED(len);
#endif
160
161
162
163

  return kErrorOk;
}

164
165
166
// ============================================================================
// [asmjit::Assembler - Building Blocks]
// ============================================================================
167

168
169
170
171
172
173
174
175
Label Assembler::newLabel() {
  uint32_t id = 0;
  if (!_lastError) {
    ASMJIT_ASSERT(_code != nullptr);
    Error err = _code->newLabelId(id);
    if (ASMJIT_UNLIKELY(err)) setLastError(err);
  }
  return Label(id);
176
177
}

178
179
180
181
182
183
Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
  uint32_t id = 0;
  if (!_lastError) {
    ASMJIT_ASSERT(_code != nullptr);
    Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
    if (ASMJIT_UNLIKELY(err)) setLastError(err);
184
  }
185
  return Label(id);
186
187
188
}

Error Assembler::bind(const Label& label) {
189
190
191
192
193
194
  if (_lastError) return _lastError;
  ASMJIT_ASSERT(_code != nullptr);

  LabelEntry* le = _code->getLabelEntry(label);
  if (ASMJIT_UNLIKELY(!le))
    return setLastError(DebugUtils::errored(kErrorInvalidLabel));
195
196

  // Label can be bound only once.
197
198
199
200
201
202
203
204
205
206
  if (ASMJIT_UNLIKELY(le->isBound()))
    return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound));

#if !defined(ASMJIT_DISABLE_LOGGING)
  if (_globalOptions & kOptionLoggingEnabled) {
    StringBuilderTmp<256> sb;
    if (le->hasName())
      sb.setFormat("%s:", le->getName());
    else
      sb.setFormat("L%u:", Operand::unpackId(label.getId()));
207

208
209
210
    size_t binSize = 0;
    if (!_code->_logger->hasOption(Logger::kOptionBinaryForm))
      binSize = Globals::kInvalidIndex;
211

212
213
214
215
216
217
    Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment());
    _code->_logger->log(sb.getData(), sb.getLength());
  }
#endif // !ASMJIT_DISABLE_LOGGING

  Error err = kErrorOk;
218
219
  size_t pos = getOffset();

220
221
  LabelLink* link = le->_links;
  LabelLink* prev = nullptr;
222
223
224

  while (link) {
    intptr_t offset = link->offset;
225
    uint32_t relocId = link->relocId;
226

227
228
229
230
    if (relocId != RelocEntry::kInvalidId) {
      // Adjust relocation data.
      RelocEntry* re = _code->_relocations[relocId];
      re->_data += static_cast<uint64_t>(pos);
231
232
233
    }
    else {
      // Not using relocId, this means that we are overwriting a real
234
      // displacement in the CodeBuffer.
235
      int32_t patchedValue = static_cast<int32_t>(
236
        static_cast<intptr_t>(pos) - offset + link->rel);
237
238

      // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
239
240
241
242
243
244
245
      uint32_t size = _bufferData[offset];
      if (size == 4)
        Utils::writeI32u(_bufferData + offset, static_cast<int32_t>(patchedValue));
      else if (size == 1 && Utils::isInt8(patchedValue))
        _bufferData[offset] = static_cast<uint8_t>(patchedValue & 0xFF);
      else
        err = DebugUtils::errored(kErrorInvalidDisplacement);
246
247
248
    }

    prev = link->prev;
249
250
    _code->_unresolvedLabelsCount--;
    _code->_baseHeap.release(link, sizeof(LabelLink));
251

252
    link = prev;
253
254
  }

255
256
257
258
259
  // Set as bound.
  le->_sectionId = _section->getId();
  le->_offset = pos;
  le->_links = nullptr;
  resetInlineComment();
260

261
262
  if (err != kErrorOk)
    return setLastError(err);
263

264
  return kErrorOk;
265
266
267
}

Error Assembler::embed(const void* data, uint32_t size) {
268
269
  if (_lastError) return _lastError;

270
  if (getRemainingSpace() < size) {
271
272
    Error err = _code->growBuffer(&_section->_buffer, size);
    if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err);
273
274
  }

275
276
  ::memcpy(_bufferPtr, data, size);
  _bufferPtr += size;
277

278
279
280
281
#if !defined(ASMJIT_DISABLE_LOGGING)
  if (_globalOptions & kOptionLoggingEnabled)
    _code->_logger->logBinary(data, size);
#endif // !ASMJIT_DISABLE_LOGGING
282
283
284
285

  return kErrorOk;
}

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
Error Assembler::embedLabel(const Label& label) {
  if (_lastError) return _lastError;
  ASMJIT_ASSERT(_code != nullptr);

  RelocEntry* re;
  LabelEntry* le = _code->getLabelEntry(label);

  if (ASMJIT_UNLIKELY(!le))
    return setLastError(DebugUtils::errored(kErrorInvalidLabel));

  Error err;
  uint32_t gpSize = getGpSize();

  if (getRemainingSpace() < gpSize) {
    err = _code->growBuffer(&_section->_buffer, gpSize);
    if (ASMJIT_UNLIKELY(err)) return setLastError(err);
  }

#if !defined(ASMJIT_DISABLE_LOGGING)
  if (_globalOptions & kOptionLoggingEnabled)
    _code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId()));
#endif // !ASMJIT_DISABLE_LOGGING

  err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize);
  if (ASMJIT_UNLIKELY(err)) return setLastError(err);
311

312
313
  re->_sourceSectionId = _section->getId();
  re->_sourceOffset = static_cast<uint64_t>(getOffset());
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  if (le->isBound()) {
    re->_targetSectionId = le->getSectionId();
    re->_data = static_cast<uint64_t>(static_cast<int64_t>(le->getOffset()));
  }
  else {
    LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0);
    if (ASMJIT_UNLIKELY(!link))
      return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
    link->relocId = re->getId();
  }

  // Emit dummy DWORD/QWORD depending on the address size.
  ::memset(_bufferPtr, 0, gpSize);
  _bufferPtr += gpSize;

  return kErrorOk;
331
332
}

333
334
335
336
337
Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) {
  if (_lastError) return _lastError;

  if (!isLabelValid(label))
    return DebugUtils::errored(kErrorInvalidLabel);
338

339
340
341
342
343
344
345
346
  ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
  ASMJIT_PROPAGATE(bind(label));

  size_t size = pool.getSize();
  if (getRemainingSpace() < size) {
    Error err = _code->growBuffer(&_section->_buffer, size);
    if (ASMJIT_UNLIKELY(err)) return setLastError(err);
  }
347

348
349
  uint8_t* p = _bufferPtr;
  pool.fill(p);
350

351
352
353
354
#if !defined(ASMJIT_DISABLE_LOGGING)
  if (_globalOptions & kOptionLoggingEnabled)
    _code->_logger->logBinary(p, size);
#endif // !ASMJIT_DISABLE_LOGGING
355

356
357
  _bufferPtr += size;
  return kErrorOk;
358
359
360
}

// ============================================================================
361
// [asmjit::Assembler - Emit-Helpers]
362
363
// ============================================================================

364
365
366
367
#if !defined(ASMJIT_DISABLE_LOGGING)
void Assembler::_emitLog(
  uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
  uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) {
368

369
370
371
  Logger* logger = _code->getLogger();
  ASMJIT_ASSERT(logger != nullptr);
  ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled);
372

373
374
  StringBuilderTmp<256> sb;
  uint32_t logOptions = logger->getOptions();
375

376
377
  uint8_t* beforeCursor = _bufferPtr;
  intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
378

379
  sb.appendString(logger->getIndentation());
380

381
382
383
384
385
  Operand_ opArray[6];
  opArray[0].copyFrom(o0);
  opArray[1].copyFrom(o1);
  opArray[2].copyFrom(o2);
  opArray[3].copyFrom(o3);
386

387
388
389
390
391
392
393
394
  if (options & kOptionOp4Op5Used) {
    opArray[4].copyFrom(_op4);
    opArray[5].copyFrom(_op5);
  }
  else {
    opArray[4].reset();
    opArray[5].reset();
  }
395

396
397
398
399
  Logging::formatInstruction(
    sb, logOptions,
    this, getArchType(),
    Inst::Detail(instId, options, _extraReg), opArray, 6);
400

401
402
403
404
  if ((logOptions & Logger::kOptionBinaryForm) != 0)
    Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
  else
    Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment());
405

406
  logger->log(sb.getData(), sb.getLength());
407
408
}

409
410
411
Error Assembler::_emitFailed(
  Error err,
  uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
412

413
414
415
  StringBuilderTmp<256> sb;
  sb.appendString(DebugUtils::errorAsString(err));
  sb.appendString(": ");
416

417
418
419
420
421
  Operand_ opArray[6];
  opArray[0].copyFrom(o0);
  opArray[1].copyFrom(o1);
  opArray[2].copyFrom(o2);
  opArray[3].copyFrom(o3);
422

423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  if (options & kOptionOp4Op5Used) {
    opArray[4].copyFrom(_op4);
    opArray[5].copyFrom(_op5);
  }
  else {
    opArray[4].reset();
    opArray[5].reset();
  }

  Logging::formatInstruction(
    sb, 0,
    this, getArchType(),
    Inst::Detail(instId, options, _extraReg), opArray, 6);

  resetOptions();
  resetExtraReg();
  resetInlineComment();
  return setLastError(err, sb.getData());
}
#endif
443
444
445
446

} // asmjit namespace

// [Api-End]
447
#include "../asmjit_apiend.h"