1 // AsmJit - Machine code generation for C++
2 //
3 // * Official AsmJit Home Page: https://asmjit.com
4 // * Official Github Repository: https://github.com/asmjit/asmjit
5 //
6 // Copyright (c) 2008-2020 The AsmJit Authors
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 // 2. Altered source versions must be plainly marked as such, and must not be
21 // misrepresented as being the original software.
22 // 3. This notice may not be removed or altered from any source distribution.
23
24 #include "../core/api-build_p.h"
25 #include "../core/assembler.h"
26 #include "../core/codewriter_p.h"
27 #include "../core/constpool.h"
28 #include "../core/emitterutils_p.h"
29 #include "../core/formatter.h"
30 #include "../core/logger.h"
31 #include "../core/support.h"
32
33 ASMJIT_BEGIN_NAMESPACE
34
35 // ============================================================================
36 // [asmjit::BaseAssembler - Construction / Destruction]
37 // ============================================================================
38
BaseAssembler()39 BaseAssembler::BaseAssembler() noexcept
40 : BaseEmitter(kTypeAssembler) {}
41
~BaseAssembler()42 BaseAssembler::~BaseAssembler() noexcept {}
43
44 // ============================================================================
45 // [asmjit::BaseAssembler - Buffer Management]
46 // ============================================================================
47
setOffset(size_t offset)48 Error BaseAssembler::setOffset(size_t offset) {
49 if (ASMJIT_UNLIKELY(!_code))
50 return reportError(DebugUtils::errored(kErrorNotInitialized));
51
52 size_t size = Support::max<size_t>(_section->bufferSize(), this->offset());
53 if (ASMJIT_UNLIKELY(offset > size))
54 return reportError(DebugUtils::errored(kErrorInvalidArgument));
55
56 _bufferPtr = _bufferData + offset;
57 return kErrorOk;
58 }
59
60 // ============================================================================
61 // [asmjit::BaseAssembler - Section Management]
62 // ============================================================================
63
BaseAssembler_initSection(BaseAssembler * self,Section * section)64 static void BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept {
65 uint8_t* p = section->_buffer._data;
66
67 self->_section = section;
68 self->_bufferData = p;
69 self->_bufferPtr = p + section->_buffer._size;
70 self->_bufferEnd = p + section->_buffer._capacity;
71 }
72
section(Section * section)73 Error BaseAssembler::section(Section* section) {
74 if (ASMJIT_UNLIKELY(!_code))
75 return reportError(DebugUtils::errored(kErrorNotInitialized));
76
77 if (!_code->isSectionValid(section->id()) || _code->_sections[section->id()] != section)
78 return reportError(DebugUtils::errored(kErrorInvalidSection));
79
80 #ifndef ASMJIT_NO_LOGGING
81 if (_logger)
82 _logger->logf(".section %s {#%u}\n", section->name(), section->id());
83 #endif
84
85 BaseAssembler_initSection(this, section);
86 return kErrorOk;
87 }
88
89 // ============================================================================
90 // [asmjit::BaseAssembler - Label Management]
91 // ============================================================================
92
newLabel()93 Label BaseAssembler::newLabel() {
94 uint32_t labelId = Globals::kInvalidId;
95 if (ASMJIT_LIKELY(_code)) {
96 LabelEntry* le;
97 Error err = _code->newLabelEntry(&le);
98 if (ASMJIT_UNLIKELY(err))
99 reportError(err);
100 else
101 labelId = le->id();
102 }
103 return Label(labelId);
104 }
105
newNamedLabel(const char * name,size_t nameSize,uint32_t type,uint32_t parentId)106 Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) {
107 uint32_t labelId = Globals::kInvalidId;
108 if (ASMJIT_LIKELY(_code)) {
109 LabelEntry* le;
110 Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId);
111 if (ASMJIT_UNLIKELY(err))
112 reportError(err);
113 else
114 labelId = le->id();
115 }
116 return Label(labelId);
117 }
118
bind(const Label & label)119 Error BaseAssembler::bind(const Label& label) {
120 if (ASMJIT_UNLIKELY(!_code))
121 return reportError(DebugUtils::errored(kErrorNotInitialized));
122
123 Error err = _code->bindLabel(label, _section->id(), offset());
124
125 #ifndef ASMJIT_NO_LOGGING
126 if (_logger)
127 EmitterUtils::logLabelBound(this, label);
128 #endif
129
130 resetInlineComment();
131 if (err)
132 return reportError(err);
133
134 return kErrorOk;
135 }
136
137 // ============================================================================
138 // [asmjit::BaseAssembler - Embed]
139 // ============================================================================
140
141 #ifndef ASMJIT_NO_LOGGING
142 struct DataSizeByPower {
143 char str[4];
144 };
145
146 static const DataSizeByPower dataSizeByPowerTable[] = {
147 { "db" },
148 { "dw" },
149 { "dd" },
150 { "dq" }
151 };
152 #endif
153
embed(const void * data,size_t dataSize)154 Error BaseAssembler::embed(const void* data, size_t dataSize) {
155 if (ASMJIT_UNLIKELY(!_code))
156 return reportError(DebugUtils::errored(kErrorNotInitialized));
157
158 if (dataSize == 0)
159 return kErrorOk;
160
161 CodeWriter writer(this);
162 ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize));
163
164 writer.emitData(data, dataSize);
165
166 #ifndef ASMJIT_NO_LOGGING
167 if (_logger)
168 _logger->logBinary(data, dataSize);
169 #endif
170
171 writer.done(this);
172 return kErrorOk;
173 }
174
embedDataArray(uint32_t typeId,const void * data,size_t itemCcount,size_t repeatCount)175 Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount) {
176 uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
177 uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
178
179 if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
180 return reportError(DebugUtils::errored(kErrorInvalidArgument));
181
182 if (itemCcount == 0 || repeatCount == 0)
183 return kErrorOk;
184
185 uint32_t typeSize = Type::sizeOf(finalTypeId);
186 Support::FastUInt8 of = 0;
187
188 size_t dataSize = Support::mulOverflow(itemCcount, size_t(typeSize), &of);
189 size_t totalSize = Support::mulOverflow(dataSize, repeatCount, &of);
190
191 if (ASMJIT_UNLIKELY(of))
192 return reportError(DebugUtils::errored(kErrorOutOfMemory));
193
194 CodeWriter writer(this);
195 ASMJIT_PROPAGATE(writer.ensureSpace(this, totalSize));
196
197 #ifndef ASMJIT_NO_LOGGING
198 const uint8_t* start = writer.cursor();
199 #endif
200
201 for (size_t i = 0; i < repeatCount; i++) {
202 writer.emitData(data, dataSize);
203 }
204
205 #ifndef ASMJIT_NO_LOGGING
206 if (_logger)
207 _logger->logBinary(start, totalSize);
208 #endif
209
210 writer.done(this);
211 return kErrorOk;
212 }
213
embedConstPool(const Label & label,const ConstPool & pool)214 Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) {
215 if (ASMJIT_UNLIKELY(!_code))
216 return reportError(DebugUtils::errored(kErrorNotInitialized));
217
218 if (ASMJIT_UNLIKELY(!isLabelValid(label)))
219 return reportError(DebugUtils::errored(kErrorInvalidLabel));
220
221 ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment())));
222 ASMJIT_PROPAGATE(bind(label));
223
224 size_t size = pool.size();
225 CodeWriter writer(this);
226 ASMJIT_PROPAGATE(writer.ensureSpace(this, size));
227
228 pool.fill(writer.cursor());
229
230 #ifndef ASMJIT_NO_LOGGING
231 if (_logger)
232 _logger->logBinary(writer.cursor(), size);
233 #endif
234
235 writer.advance(size);
236 writer.done(this);
237
238 return kErrorOk;
239 }
240
embedLabel(const Label & label,size_t dataSize)241 Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) {
242 if (ASMJIT_UNLIKELY(!_code))
243 return reportError(DebugUtils::errored(kErrorNotInitialized));
244
245 ASMJIT_ASSERT(_code != nullptr);
246 RelocEntry* re;
247 LabelEntry* le = _code->labelEntry(label);
248
249 if (ASMJIT_UNLIKELY(!le))
250 return reportError(DebugUtils::errored(kErrorInvalidLabel));
251
252 if (dataSize == 0)
253 dataSize = registerSize();
254
255 if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8))
256 return reportError(DebugUtils::errored(kErrorInvalidOperandSize));
257
258 CodeWriter writer(this);
259 ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize));
260
261 #ifndef ASMJIT_NO_LOGGING
262 if (_logger) {
263 StringTmp<256> sb;
264 sb.appendFormat("%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str);
265 Formatter::formatLabel(sb, 0, this, label.id());
266 sb.append('\n');
267 _logger->log(sb);
268 }
269 #endif
270
271 Error err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs);
272 if (ASMJIT_UNLIKELY(err))
273 return reportError(err);
274
275 re->_sourceSectionId = _section->id();
276 re->_sourceOffset = offset();
277 re->_format.resetToDataValue(uint32_t(dataSize));
278
279 if (le->isBound()) {
280 re->_targetSectionId = le->section()->id();
281 re->_payload = le->offset();
282 }
283 else {
284 OffsetFormat of;
285 of.resetToDataValue(uint32_t(dataSize));
286
287 LabelLink* link = _code->newLabelLink(le, _section->id(), offset(), 0, of);
288 if (ASMJIT_UNLIKELY(!link))
289 return reportError(DebugUtils::errored(kErrorOutOfMemory));
290
291 link->relocId = re->id();
292 }
293
294 // Emit dummy DWORD/QWORD depending on the data size.
295 writer.emitZeros(dataSize);
296 writer.done(this);
297
298 return kErrorOk;
299 }
300
embedLabelDelta(const Label & label,const Label & base,size_t dataSize)301 Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) {
302 if (ASMJIT_UNLIKELY(!_code))
303 return reportError(DebugUtils::errored(kErrorNotInitialized));
304
305 LabelEntry* labelEntry = _code->labelEntry(label);
306 LabelEntry* baseEntry = _code->labelEntry(base);
307
308 if (ASMJIT_UNLIKELY(!labelEntry || !baseEntry))
309 return reportError(DebugUtils::errored(kErrorInvalidLabel));
310
311 if (dataSize == 0)
312 dataSize = registerSize();
313
314 if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8))
315 return reportError(DebugUtils::errored(kErrorInvalidOperandSize));
316
317 CodeWriter writer(this);
318 ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize));
319
320 #ifndef ASMJIT_NO_LOGGING
321 if (_logger) {
322 StringTmp<256> sb;
323 sb.appendFormat(".%s (", dataSizeByPowerTable[Support::ctz(dataSize)].str);
324 Formatter::formatLabel(sb, 0, this, label.id());
325 sb.append(" - ");
326 Formatter::formatLabel(sb, 0, this, base.id());
327 sb.append(")\n");
328 _logger->log(sb);
329 }
330 #endif
331
332 // If both labels are bound within the same section it means the delta can be calculated now.
333 if (labelEntry->isBound() && baseEntry->isBound() && labelEntry->section() == baseEntry->section()) {
334 uint64_t delta = labelEntry->offset() - baseEntry->offset();
335 writer.emitValueLE(delta, dataSize);
336 }
337 else {
338 RelocEntry* re;
339 Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression);
340 if (ASMJIT_UNLIKELY(err))
341 return reportError(err);
342
343 Expression* exp = _code->_zone.newT<Expression>();
344 if (ASMJIT_UNLIKELY(!exp))
345 return reportError(DebugUtils::errored(kErrorOutOfMemory));
346
347 exp->reset();
348 exp->opType = Expression::kOpSub;
349 exp->setValueAsLabel(0, labelEntry);
350 exp->setValueAsLabel(1, baseEntry);
351
352 re->_format.resetToDataValue(dataSize);
353 re->_sourceSectionId = _section->id();
354 re->_sourceOffset = offset();
355 re->_payload = (uint64_t)(uintptr_t)exp;
356
357 writer.emitZeros(dataSize);
358 }
359
360 writer.done(this);
361 return kErrorOk;
362 }
363
364 // ============================================================================
365 // [asmjit::BaseAssembler - Comment]
366 // ============================================================================
367
comment(const char * data,size_t size)368 Error BaseAssembler::comment(const char* data, size_t size) {
369 if (!hasEmitterFlag(kFlagLogComments)) {
370 if (!hasEmitterFlag(kFlagAttached))
371 return reportError(DebugUtils::errored(kErrorNotInitialized));
372 return kErrorOk;
373 }
374
375 #ifndef ASMJIT_NO_LOGGING
376 // Logger cannot be NULL if `kFlagLogComments` is set.
377 ASMJIT_ASSERT(_logger != nullptr);
378
379 _logger->log(data, size);
380 _logger->log("\n", 1);
381 return kErrorOk;
382 #else
383 DebugUtils::unused(data, size);
384 return kErrorOk;
385 #endif
386 }
387
388 // ============================================================================
389 // [asmjit::BaseAssembler - Events]
390 // ============================================================================
391
onAttach(CodeHolder * code)392 Error BaseAssembler::onAttach(CodeHolder* code) noexcept {
393 ASMJIT_PROPAGATE(Base::onAttach(code));
394
395 // Attach to the end of the .text section.
396 BaseAssembler_initSection(this, code->_sections[0]);
397
398 return kErrorOk;
399 }
400
onDetach(CodeHolder * code)401 Error BaseAssembler::onDetach(CodeHolder* code) noexcept {
402 _section = nullptr;
403 _bufferData = nullptr;
404 _bufferEnd = nullptr;
405 _bufferPtr = nullptr;
406 return Base::onDetach(code);
407 }
408
409 ASMJIT_END_NAMESPACE
410