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