Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/snapshot/embedded-file-writer.h"
6 :
7 : #include <algorithm>
8 : #include <cinttypes>
9 :
10 : #include "src/objects/code-inl.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 : // V8_CC_MSVC is true for both MSVC and clang on windows. clang can handle
16 : // __asm__-style inline assembly but MSVC cannot, and thus we need a more
17 : // precise compiler detection that can distinguish between the two. clang on
18 : // windows sets both __clang__ and _MSC_VER, MSVC sets only _MSC_VER.
19 : #if defined(_MSC_VER) && !defined(__clang__)
20 : #define V8_COMPILER_IS_MSVC
21 : #endif
22 :
23 : // MSVC uses MASM for x86 and x64, while it has a ARMASM for ARM32 and
24 : // ARMASM64 for ARM64. Since ARMASM and ARMASM64 accept a slightly tweaked
25 : // version of ARM assembly language, they are referred to together in Visual
26 : // Studio project files as MARMASM.
27 : //
28 : // ARM assembly language docs:
29 : // http://infocenter.arm.com/help/topic/com.arm.doc.dui0802b/index.html
30 : // Microsoft ARM assembler and assembly language docs:
31 : // https://docs.microsoft.com/en-us/cpp/assembler/arm/arm-assembler-reference
32 : #if defined(V8_COMPILER_IS_MSVC)
33 : #if defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_ARM)
34 : #define V8_ASSEMBLER_IS_MARMASM
35 : #elif defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64)
36 : #define V8_ASSEMBLER_IS_MASM
37 : #else
38 : #error Unknown Windows assembler target architecture.
39 : #endif
40 : #endif
41 :
42 : // Name mangling.
43 : // Symbols are prefixed with an underscore on 32-bit architectures.
44 : #if defined(V8_TARGET_OS_WIN) && !defined(V8_TARGET_ARCH_X64) && \
45 : !defined(V8_TARGET_ARCH_ARM64)
46 : #define SYMBOL_PREFIX "_"
47 : #else
48 : #define SYMBOL_PREFIX ""
49 : #endif
50 :
51 : // Platform-independent bits.
52 : // -----------------------------------------------------------------------------
53 :
54 : namespace {
55 :
56 : DataDirective PointerSizeDirective() {
57 : if (kSystemPointerSize == 8) {
58 : return kQuad;
59 : } else {
60 : CHECK_EQ(4, kSystemPointerSize);
61 : return kLong;
62 : }
63 : }
64 :
65 : } // namespace
66 :
67 38663 : const char* DirectiveAsString(DataDirective directive) {
68 : #if defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MASM)
69 : switch (directive) {
70 : case kByte:
71 : return "BYTE";
72 : case kLong:
73 : return "DWORD";
74 : case kQuad:
75 : return "QWORD";
76 : default:
77 : UNREACHABLE();
78 : }
79 : #elif defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MARMASM)
80 : switch (directive) {
81 : case kByte:
82 : return "DCB";
83 : case kLong:
84 : return "DCDU";
85 : case kQuad:
86 : return "DCQU";
87 : default:
88 : UNREACHABLE();
89 : }
90 : #elif defined(V8_OS_AIX)
91 : switch (directive) {
92 : case kByte:
93 : return ".byte";
94 : case kLong:
95 : return ".long";
96 : case kQuad:
97 : return ".llong";
98 : default:
99 : UNREACHABLE();
100 : }
101 : #else
102 38663 : switch (directive) {
103 : case kByte:
104 : return ".byte";
105 : case kLong:
106 1 : return ".long";
107 : case kQuad:
108 1 : return ".quad";
109 : case kOcta:
110 36030 : return ".octa";
111 : }
112 0 : UNREACHABLE();
113 : #endif
114 : }
115 :
116 1 : void EmbeddedFileWriter::PrepareBuiltinSourcePositionMap(Builtins* builtins) {
117 3045 : for (int i = 0; i < Builtins::builtin_count; i++) {
118 : // Retrieve the SourcePositionTable and copy it.
119 1522 : Code code = builtins->builtin(i);
120 : // Verify that the code object is still the "real code" and not a
121 : // trampoline (which wouldn't have source positions).
122 : DCHECK(!code->is_off_heap_trampoline());
123 : std::vector<unsigned char> data(
124 3044 : code->SourcePositionTable()->GetDataStartAddress(),
125 3044 : code->SourcePositionTable()->GetDataEndAddress());
126 1522 : source_positions_[i] = data;
127 : }
128 1 : }
129 :
130 : #if defined(V8_OS_WIN_X64)
131 : std::string EmbeddedFileWriter::BuiltinsUnwindInfoLabel() const {
132 : char embedded_blob_data_symbol[kTemporaryStringLength];
133 : i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
134 : "%s_Builtins_UnwindInfo", embedded_variant_);
135 : return embedded_blob_data_symbol;
136 : }
137 :
138 : void EmbeddedFileWriter::SetBuiltinUnwindData(
139 : int builtin_index, const win64_unwindinfo::BuiltinUnwindInfo& unwind_info) {
140 : DCHECK_LT(builtin_index, Builtins::builtin_count);
141 : unwind_infos_[builtin_index] = unwind_info;
142 : }
143 :
144 : void EmbeddedFileWriter::WriteUnwindInfoEntry(
145 : PlatformDependentEmbeddedFileWriter* w, uint64_t rva_start,
146 : uint64_t rva_end) const {
147 : w->DeclareRvaToSymbol(EmbeddedBlobDataSymbol().c_str(), rva_start);
148 : w->DeclareRvaToSymbol(EmbeddedBlobDataSymbol().c_str(), rva_end);
149 : w->DeclareRvaToSymbol(BuiltinsUnwindInfoLabel().c_str());
150 : }
151 :
152 : void EmbeddedFileWriter::WriteUnwindInfo(PlatformDependentEmbeddedFileWriter* w,
153 : const i::EmbeddedData* blob) const {
154 : // Emit an UNWIND_INFO (XDATA) struct, which contains the unwinding
155 : // information that is used for all builtin functions.
156 : DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
157 : w->Comment("xdata for all the code in the embedded blob.");
158 : w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
159 :
160 : w->StartXdataSection();
161 : {
162 : w->DeclareLabel(BuiltinsUnwindInfoLabel().c_str());
163 : std::vector<uint8_t> xdata =
164 : win64_unwindinfo::GetUnwindInfoForBuiltinFunctions();
165 : WriteBinaryContentsAsInlineAssembly(w, xdata.data(),
166 : static_cast<uint32_t>(xdata.size()));
167 : w->Comment(" ExceptionHandler");
168 : w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
169 : }
170 : w->EndXdataSection();
171 : w->Newline();
172 :
173 : // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as
174 : // documented here:
175 : // https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
176 : w->Comment(
177 : "pdata for all the code in the embedded blob (structs of type "
178 : "RUNTIME_FUNCTION).");
179 : w->Comment(" BeginAddress");
180 : w->Comment(" EndAddress");
181 : w->Comment(" UnwindInfoAddress");
182 : w->StartPdataSection();
183 : {
184 : Address prev_builtin_end_offset = 0;
185 : for (int i = 0; i < Builtins::builtin_count; i++) {
186 : // Some builtins are leaf functions from the point of view of Win64 stack
187 : // walking: they do not move the stack pointer and do not require a PDATA
188 : // entry because the return address can be retrieved from [rsp].
189 : if (!blob->ContainsBuiltin(i)) continue;
190 : if (unwind_infos_[i].is_leaf_function()) continue;
191 :
192 : uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) -
193 : reinterpret_cast<Address>(blob->data());
194 : uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i);
195 :
196 : const std::vector<int>& xdata_desc = unwind_infos_[i].fp_offsets();
197 : if (xdata_desc.empty()) {
198 : // Some builtins do not have any "push rbp - mov rbp, rsp" instructions
199 : // to start a stack frame. We still emit a PDATA entry as if they had,
200 : // relying on the fact that we can find the previous frame address from
201 : // rbp in most cases. Note that since the function does not really start
202 : // with a 'push rbp' we need to specify the start RVA in the PDATA entry
203 : // a few bytes before the beginning of the function, if it does not
204 : // overlap the end of the previous builtin.
205 : WriteUnwindInfoEntry(
206 : w,
207 : std::max(prev_builtin_end_offset,
208 : builtin_start_offset - win64_unwindinfo::kRbpPrefixLength),
209 : builtin_start_offset + builtin_size);
210 : } else {
211 : // Some builtins have one or more "push rbp - mov rbp, rsp" sequences,
212 : // but not necessarily at the beginning of the function. In this case
213 : // we want to yield a PDATA entry for each block of instructions that
214 : // emit an rbp frame. If the function does not start with 'push rbp'
215 : // we also emit a PDATA entry for the initial block of code up to the
216 : // first 'push rbp', like in the case above.
217 : if (xdata_desc[0] > 0) {
218 : WriteUnwindInfoEntry(w,
219 : std::max(prev_builtin_end_offset,
220 : builtin_start_offset -
221 : win64_unwindinfo::kRbpPrefixLength),
222 : builtin_start_offset + xdata_desc[0]);
223 : }
224 :
225 : for (size_t j = 0; j < xdata_desc.size(); j++) {
226 : int chunk_start = xdata_desc[j];
227 : int chunk_end =
228 : (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size;
229 : WriteUnwindInfoEntry(w, builtin_start_offset + chunk_start,
230 : builtin_start_offset + chunk_end);
231 : }
232 : }
233 :
234 : prev_builtin_end_offset = builtin_start_offset + builtin_size;
235 : w->Newline();
236 : }
237 : }
238 : w->EndPdataSection();
239 : w->Newline();
240 : }
241 : #endif
242 :
243 : // V8_OS_MACOSX
244 : // Fuchsia target is explicitly excluded here for Mac hosts. This is to avoid
245 : // generating uncompilable assembly files for the Fuchsia target.
246 : // -----------------------------------------------------------------------------
247 :
248 : #if defined(V8_OS_MACOSX) && !defined(V8_TARGET_OS_FUCHSIA)
249 :
250 : void PlatformDependentEmbeddedFileWriter::SectionText() {
251 : fprintf(fp_, ".text\n");
252 : }
253 :
254 : void PlatformDependentEmbeddedFileWriter::SectionData() {
255 : fprintf(fp_, ".data\n");
256 : }
257 :
258 : void PlatformDependentEmbeddedFileWriter::SectionRoData() {
259 : fprintf(fp_, ".const_data\n");
260 : }
261 :
262 : void PlatformDependentEmbeddedFileWriter::DeclareUint32(const char* name,
263 : uint32_t value) {
264 : DeclareSymbolGlobal(name);
265 : DeclareLabel(name);
266 : IndentedDataDirective(kLong);
267 : fprintf(fp_, "%d", value);
268 : Newline();
269 : }
270 :
271 : void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol(
272 : const char* name, const char* target) {
273 : DeclareSymbolGlobal(name);
274 : DeclareLabel(name);
275 : fprintf(fp_, " %s _%s\n", DirectiveAsString(PointerSizeDirective()), target);
276 : }
277 :
278 : void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal(
279 : const char* name) {
280 : // TODO(jgruber): Investigate switching to .globl. Using .private_extern
281 : // prevents something along the compilation chain from messing with the
282 : // embedded blob. Using .global here causes embedded blob hash verification
283 : // failures at runtime.
284 : fprintf(fp_, ".private_extern _%s\n", name);
285 : }
286 :
287 : void PlatformDependentEmbeddedFileWriter::AlignToCodeAlignment() {
288 : fprintf(fp_, ".balign 32\n");
289 : }
290 :
291 : void PlatformDependentEmbeddedFileWriter::AlignToDataAlignment() {
292 : fprintf(fp_, ".balign 8\n");
293 : }
294 :
295 : void PlatformDependentEmbeddedFileWriter::Comment(const char* string) {
296 : fprintf(fp_, "// %s\n", string);
297 : }
298 :
299 : void PlatformDependentEmbeddedFileWriter::DeclareLabel(const char* name) {
300 : fprintf(fp_, "_%s:\n", name);
301 : }
302 :
303 : void PlatformDependentEmbeddedFileWriter::SourceInfo(int fileid,
304 : const char* filename,
305 : int line) {
306 : fprintf(fp_, ".loc %d %d\n", fileid, line);
307 : }
308 :
309 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionBegin(
310 : const char* name) {
311 : DeclareLabel(name);
312 :
313 : // TODO(mvstanton): Investigate the proper incantations to mark the label as
314 : // a function on OSX.
315 : }
316 :
317 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionEnd(const char* name) {
318 : }
319 :
320 : int PlatformDependentEmbeddedFileWriter::HexLiteral(uint64_t value) {
321 : return fprintf(fp_, "0x%" PRIx64, value);
322 : }
323 :
324 : void PlatformDependentEmbeddedFileWriter::FilePrologue() {}
325 :
326 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFilename(
327 : int fileid, const char* filename) {
328 : fprintf(fp_, ".file %d \"%s\"\n", fileid, filename);
329 : }
330 :
331 : void PlatformDependentEmbeddedFileWriter::FileEpilogue() {}
332 :
333 : int PlatformDependentEmbeddedFileWriter::IndentedDataDirective(
334 : DataDirective directive) {
335 : return fprintf(fp_, " %s ", DirectiveAsString(directive));
336 : }
337 :
338 : // V8_OS_AIX
339 : // -----------------------------------------------------------------------------
340 :
341 : #elif defined(V8_OS_AIX)
342 :
343 : void PlatformDependentEmbeddedFileWriter::SectionText() {
344 : fprintf(fp_, ".csect .text[PR]\n");
345 : }
346 :
347 : void PlatformDependentEmbeddedFileWriter::SectionData() {
348 : fprintf(fp_, ".csect .data[RW]\n");
349 : }
350 :
351 : void PlatformDependentEmbeddedFileWriter::SectionRoData() {
352 : fprintf(fp_, ".csect[RO]\n");
353 : }
354 :
355 : void PlatformDependentEmbeddedFileWriter::DeclareUint32(const char* name,
356 : uint32_t value) {
357 : DeclareSymbolGlobal(name);
358 : fprintf(fp_, ".align 2\n");
359 : fprintf(fp_, "%s:\n", name);
360 : IndentedDataDirective(kLong);
361 : fprintf(fp_, "%d\n", value);
362 : Newline();
363 : }
364 :
365 : void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol(
366 : const char* name, const char* target) {
367 : AlignToCodeAlignment();
368 : DeclareLabel(name);
369 : fprintf(fp_, " %s %s\n", DirectiveAsString(PointerSizeDirective()), target);
370 : Newline();
371 : }
372 :
373 : void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal(
374 : const char* name) {
375 : fprintf(fp_, ".globl %s\n", name);
376 : }
377 :
378 : void PlatformDependentEmbeddedFileWriter::AlignToCodeAlignment() {
379 : fprintf(fp_, ".align 5\n");
380 : }
381 :
382 : void PlatformDependentEmbeddedFileWriter::AlignToDataAlignment() {
383 : fprintf(fp_, ".align 3\n");
384 : }
385 :
386 : void PlatformDependentEmbeddedFileWriter::Comment(const char* string) {
387 : fprintf(fp_, "// %s\n", string);
388 : }
389 :
390 : void PlatformDependentEmbeddedFileWriter::DeclareLabel(const char* name) {
391 : DeclareSymbolGlobal(name);
392 : fprintf(fp_, "%s:\n", name);
393 : }
394 :
395 : void PlatformDependentEmbeddedFileWriter::SourceInfo(int fileid,
396 : const char* filename,
397 : int line) {
398 : fprintf(fp_, ".xline %d, \"%s\"\n", line, filename);
399 : }
400 :
401 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionBegin(
402 : const char* name) {
403 : Newline();
404 : DeclareSymbolGlobal(name);
405 : fprintf(fp_, ".csect %s[DS]\n", name); // function descriptor
406 : fprintf(fp_, "%s:\n", name);
407 : fprintf(fp_, ".llong .%s, 0, 0\n", name);
408 : SectionText();
409 : fprintf(fp_, ".%s:\n", name);
410 : }
411 :
412 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionEnd(const char* name) {
413 : }
414 :
415 : int PlatformDependentEmbeddedFileWriter::HexLiteral(uint64_t value) {
416 : return fprintf(fp_, "0x%" PRIx64, value);
417 : }
418 :
419 : void PlatformDependentEmbeddedFileWriter::FilePrologue() {}
420 :
421 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFilename(
422 : int fileid, const char* filename) {
423 : // File name cannot be declared with an identifier on AIX.
424 : // We use the SourceInfo method to emit debug info in
425 : //.xline <line-number> <file-name> format.
426 : }
427 :
428 : void PlatformDependentEmbeddedFileWriter::FileEpilogue() {}
429 :
430 : int PlatformDependentEmbeddedFileWriter::IndentedDataDirective(
431 : DataDirective directive) {
432 : return fprintf(fp_, " %s ", DirectiveAsString(directive));
433 : }
434 :
435 : // V8_TARGET_OS_WIN (MSVC)
436 : // -----------------------------------------------------------------------------
437 :
438 : #elif defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MASM)
439 :
440 : // For MSVC builds we emit assembly in MASM syntax.
441 : // See https://docs.microsoft.com/en-us/cpp/assembler/masm/directives-reference.
442 :
443 : void PlatformDependentEmbeddedFileWriter::SectionText() {
444 : fprintf(fp_, ".CODE\n");
445 : }
446 :
447 : void PlatformDependentEmbeddedFileWriter::SectionData() {
448 : fprintf(fp_, ".DATA\n");
449 : }
450 :
451 : void PlatformDependentEmbeddedFileWriter::SectionRoData() {
452 : fprintf(fp_, ".CONST\n");
453 : }
454 :
455 : void PlatformDependentEmbeddedFileWriter::DeclareUint32(const char* name,
456 : uint32_t value) {
457 : DeclareSymbolGlobal(name);
458 : fprintf(fp_, "%s%s %s %d\n", SYMBOL_PREFIX, name, DirectiveAsString(kLong),
459 : value);
460 : }
461 :
462 : void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol(
463 : const char* name, const char* target) {
464 : DeclareSymbolGlobal(name);
465 : fprintf(fp_, "%s%s %s %s%s\n", SYMBOL_PREFIX, name,
466 : DirectiveAsString(PointerSizeDirective()), SYMBOL_PREFIX, target);
467 : }
468 :
469 : #if defined(V8_OS_WIN_X64)
470 :
471 : void PlatformDependentEmbeddedFileWriter::StartPdataSection() {
472 : fprintf(fp_, "OPTION DOTNAME\n");
473 : fprintf(fp_, ".pdata SEGMENT DWORD READ ''\n");
474 : }
475 :
476 : void PlatformDependentEmbeddedFileWriter::EndPdataSection() {
477 : fprintf(fp_, ".pdata ENDS\n");
478 : }
479 :
480 : void PlatformDependentEmbeddedFileWriter::StartXdataSection() {
481 : fprintf(fp_, "OPTION DOTNAME\n");
482 : fprintf(fp_, ".xdata SEGMENT DWORD READ ''\n");
483 : }
484 :
485 : void PlatformDependentEmbeddedFileWriter::EndXdataSection() {
486 : fprintf(fp_, ".xdata ENDS\n");
487 : }
488 :
489 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFunction(
490 : const char* name) {
491 : fprintf(fp_, "EXTERN %s : PROC\n", name);
492 : }
493 :
494 : void PlatformDependentEmbeddedFileWriter::DeclareRvaToSymbol(const char* name,
495 : uint64_t offset) {
496 : if (offset > 0) {
497 : fprintf(fp_, "DD IMAGEREL %s+%llu\n", name, offset);
498 : } else {
499 : fprintf(fp_, "DD IMAGEREL %s\n", name);
500 : }
501 : }
502 :
503 : #endif // defined(V8_OS_WIN_X64)
504 :
505 : void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal(
506 : const char* name) {
507 : fprintf(fp_, "PUBLIC %s%s\n", SYMBOL_PREFIX, name);
508 : }
509 :
510 : void PlatformDependentEmbeddedFileWriter::AlignToCodeAlignment() {
511 : // Diverges from other platforms due to compile error
512 : // 'invalid combination with segment alignment'.
513 : fprintf(fp_, "ALIGN 4\n");
514 : }
515 :
516 : void PlatformDependentEmbeddedFileWriter::AlignToDataAlignment() {
517 : fprintf(fp_, "ALIGN 4\n");
518 : }
519 :
520 : void PlatformDependentEmbeddedFileWriter::Comment(const char* string) {
521 : fprintf(fp_, "; %s\n", string);
522 : }
523 :
524 : void PlatformDependentEmbeddedFileWriter::DeclareLabel(const char* name) {
525 : fprintf(fp_, "%s%s LABEL %s\n", SYMBOL_PREFIX, name,
526 : DirectiveAsString(kByte));
527 : }
528 :
529 : void PlatformDependentEmbeddedFileWriter::SourceInfo(int fileid,
530 : const char* filename,
531 : int line) {
532 : // TODO(mvstanton): output source information for MSVC.
533 : // Its syntax is #line <line> "<filename>"
534 : }
535 :
536 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionBegin(
537 : const char* name) {
538 : fprintf(fp_, "%s%s PROC\n", SYMBOL_PREFIX, name);
539 : }
540 :
541 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionEnd(const char* name) {
542 : fprintf(fp_, "%s%s ENDP\n", SYMBOL_PREFIX, name);
543 : }
544 :
545 : int PlatformDependentEmbeddedFileWriter::HexLiteral(uint64_t value) {
546 : return fprintf(fp_, "0%" PRIx64 "h", value);
547 : }
548 :
549 : void PlatformDependentEmbeddedFileWriter::FilePrologue() {
550 : #if !defined(V8_TARGET_ARCH_X64)
551 : fprintf(fp_, ".MODEL FLAT\n");
552 : #endif
553 : }
554 :
555 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFilename(
556 : int fileid, const char* filename) {}
557 :
558 : void PlatformDependentEmbeddedFileWriter::FileEpilogue() {
559 : fprintf(fp_, "END\n");
560 : }
561 :
562 : int PlatformDependentEmbeddedFileWriter::IndentedDataDirective(
563 : DataDirective directive) {
564 : return fprintf(fp_, " %s ", DirectiveAsString(directive));
565 : }
566 :
567 : #undef V8_ASSEMBLER_IS_MASM
568 :
569 : #elif defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MARMASM)
570 :
571 : // The the AARCH64 ABI requires instructions be 4-byte-aligned and Windows does
572 : // not have a stricter alignment requirement (see the TEXTAREA macro of
573 : // kxarm64.h in the Windows SDK), so code is 4-byte-aligned.
574 : // The data fields in the emitted assembly tend to be accessed with 8-byte
575 : // LDR instructions, so data is 8-byte-aligned.
576 : //
577 : // armasm64's warning A4228 states
578 : // Alignment value exceeds AREA alignment; alignment not guaranteed
579 : // To ensure that ALIGN directives are honored, their values are defined as
580 : // equal to their corresponding AREA's ALIGN attributes.
581 :
582 : #define ARM64_DATA_ALIGNMENT_POWER (3)
583 : #define ARM64_DATA_ALIGNMENT (1 << ARM64_DATA_ALIGNMENT_POWER)
584 : #define ARM64_CODE_ALIGNMENT_POWER (2)
585 : #define ARM64_CODE_ALIGNMENT (1 << ARM64_CODE_ALIGNMENT_POWER)
586 :
587 : void PlatformDependentEmbeddedFileWriter::SectionText() {
588 : fprintf(fp_, " AREA |.text|, CODE, ALIGN=%d, READONLY\n",
589 : ARM64_CODE_ALIGNMENT_POWER);
590 : }
591 :
592 : void PlatformDependentEmbeddedFileWriter::SectionData() {
593 : fprintf(fp_, " AREA |.data|, DATA, ALIGN=%d, READWRITE\n",
594 : ARM64_DATA_ALIGNMENT_POWER);
595 : }
596 :
597 : void PlatformDependentEmbeddedFileWriter::SectionRoData() {
598 : fprintf(fp_, " AREA |.rodata|, DATA, ALIGN=%d, READONLY\n",
599 : ARM64_DATA_ALIGNMENT_POWER);
600 : }
601 :
602 : void PlatformDependentEmbeddedFileWriter::DeclareUint32(const char* name,
603 : uint32_t value) {
604 : DeclareSymbolGlobal(name);
605 : fprintf(fp_, "%s%s %s %d\n", SYMBOL_PREFIX, name, DirectiveAsString(kLong),
606 : value);
607 : }
608 :
609 : void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol(
610 : const char* name, const char* target) {
611 : DeclareSymbolGlobal(name);
612 : fprintf(fp_, "%s%s %s %s%s\n", SYMBOL_PREFIX, name,
613 : DirectiveAsString(PointerSizeDirective()), SYMBOL_PREFIX, target);
614 : }
615 :
616 : void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal(
617 : const char* name) {
618 : fprintf(fp_, " EXPORT %s%s\n", SYMBOL_PREFIX, name);
619 : }
620 :
621 : void PlatformDependentEmbeddedFileWriter::AlignToCodeAlignment() {
622 : fprintf(fp_, " ALIGN %d\n", ARM64_CODE_ALIGNMENT);
623 : }
624 :
625 : void PlatformDependentEmbeddedFileWriter::AlignToDataAlignment() {
626 : fprintf(fp_, " ALIGN %d\n", ARM64_DATA_ALIGNMENT);
627 : }
628 :
629 : void PlatformDependentEmbeddedFileWriter::Comment(const char* string) {
630 : fprintf(fp_, "; %s\n", string);
631 : }
632 :
633 : void PlatformDependentEmbeddedFileWriter::DeclareLabel(const char* name) {
634 : fprintf(fp_, "%s%s\n", SYMBOL_PREFIX, name);
635 : }
636 :
637 : void PlatformDependentEmbeddedFileWriter::SourceInfo(int fileid,
638 : const char* filename,
639 : int line) {
640 : // TODO(mvstanton): output source information for MSVC.
641 : // Its syntax is #line <line> "<filename>"
642 : }
643 :
644 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionBegin(
645 : const char* name) {
646 : fprintf(fp_, "%s%s FUNCTION\n", SYMBOL_PREFIX, name);
647 : }
648 :
649 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionEnd(const char* name) {
650 : fprintf(fp_, " ENDFUNC\n");
651 : }
652 :
653 : int PlatformDependentEmbeddedFileWriter::HexLiteral(uint64_t value) {
654 : return fprintf(fp_, "0x%" PRIx64, value);
655 : }
656 :
657 : void PlatformDependentEmbeddedFileWriter::FilePrologue() {}
658 :
659 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFilename(
660 : int fileid, const char* filename) {}
661 :
662 : void PlatformDependentEmbeddedFileWriter::FileEpilogue() {
663 : fprintf(fp_, " END\n");
664 : }
665 :
666 : int PlatformDependentEmbeddedFileWriter::IndentedDataDirective(
667 : DataDirective directive) {
668 : return fprintf(fp_, " %s ", DirectiveAsString(directive));
669 : }
670 :
671 : #undef V8_ASSEMBLER_IS_MARMASM
672 : #undef ARM64_DATA_ALIGNMENT_POWER
673 : #undef ARM64_DATA_ALIGNMENT
674 : #undef ARM64_CODE_ALIGNMENT_POWER
675 : #undef ARM64_CODE_ALIGNMENT
676 :
677 : // Everything but AIX, Windows with MSVC, or OSX.
678 : // -----------------------------------------------------------------------------
679 :
680 : #else
681 :
682 1 : void PlatformDependentEmbeddedFileWriter::SectionText() {
683 : #if defined(V8_TARGET_OS_CHROMEOS)
684 : fprintf(fp_, ".section .text.hot.embedded\n");
685 : #else
686 1 : fprintf(fp_, ".section .text\n");
687 : #endif
688 1 : }
689 :
690 1 : void PlatformDependentEmbeddedFileWriter::SectionData() {
691 1 : fprintf(fp_, ".section .data\n");
692 1 : }
693 :
694 1 : void PlatformDependentEmbeddedFileWriter::SectionRoData() {
695 2 : if (i::FLAG_target_os == std::string("win"))
696 0 : fprintf(fp_, ".section .rdata\n");
697 : else
698 1 : fprintf(fp_, ".section .rodata\n");
699 1 : }
700 :
701 1 : void PlatformDependentEmbeddedFileWriter::DeclareUint32(const char* name,
702 : uint32_t value) {
703 : DeclareSymbolGlobal(name);
704 : DeclareLabel(name);
705 1 : IndentedDataDirective(kLong);
706 1 : fprintf(fp_, "%d", value);
707 : Newline();
708 1 : }
709 :
710 1 : void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol(
711 : const char* name, const char* target) {
712 : DeclareSymbolGlobal(name);
713 : DeclareLabel(name);
714 1 : fprintf(fp_, " %s %s%s\n", DirectiveAsString(PointerSizeDirective()),
715 : SYMBOL_PREFIX, target);
716 1 : }
717 :
718 : #if defined(V8_OS_WIN_X64)
719 :
720 : void PlatformDependentEmbeddedFileWriter::StartPdataSection() {
721 : fprintf(fp_, ".section .pdata\n");
722 : }
723 :
724 : void PlatformDependentEmbeddedFileWriter::EndPdataSection() {}
725 :
726 : void PlatformDependentEmbeddedFileWriter::StartXdataSection() {
727 : fprintf(fp_, ".section .xdata\n");
728 : }
729 :
730 : void PlatformDependentEmbeddedFileWriter::EndXdataSection() {}
731 :
732 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFunction(
733 : const char* name) {}
734 :
735 : void PlatformDependentEmbeddedFileWriter::DeclareRvaToSymbol(const char* name,
736 : uint64_t offset) {
737 : if (offset > 0) {
738 : fprintf(fp_, ".rva %s + %llu\n", name, offset);
739 : } else {
740 : fprintf(fp_, ".rva %s\n", name);
741 : }
742 : }
743 :
744 : #endif // defined(V8_OS_WIN_X64)
745 :
746 0 : void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal(
747 : const char* name) {
748 2 : fprintf(fp_, ".global %s%s\n", SYMBOL_PREFIX, name);
749 0 : }
750 :
751 1 : void PlatformDependentEmbeddedFileWriter::AlignToCodeAlignment() {
752 1 : fprintf(fp_, ".balign 32\n");
753 1 : }
754 :
755 2 : void PlatformDependentEmbeddedFileWriter::AlignToDataAlignment() {
756 : // On Windows ARM64, s390, PPC and possibly more platforms, aligned load
757 : // instructions are used to retrieve v8_Default_embedded_blob_ and/or
758 : // v8_Default_embedded_blob_size_. The generated instructions require the
759 : // load target to be aligned at 8 bytes (2^3).
760 2 : fprintf(fp_, ".balign 8\n");
761 2 : }
762 :
763 7 : void PlatformDependentEmbeddedFileWriter::Comment(const char* string) {
764 7 : fprintf(fp_, "// %s\n", string);
765 7 : }
766 :
767 1 : void PlatformDependentEmbeddedFileWriter::DeclareLabel(const char* name) {
768 1525 : fprintf(fp_, "%s%s:\n", SYMBOL_PREFIX, name);
769 1 : }
770 :
771 1108 : void PlatformDependentEmbeddedFileWriter::SourceInfo(int fileid,
772 : const char* filename,
773 : int line) {
774 1108 : fprintf(fp_, ".loc %d %d\n", fileid, line);
775 1108 : }
776 :
777 1522 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionBegin(
778 : const char* name) {
779 : DeclareLabel(name);
780 :
781 3044 : if (i::FLAG_target_os == std::string("win")) {
782 : #if defined(V8_TARGET_ARCH_ARM64)
783 : // Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive
784 : // in PE/COFF for Windows.
785 : #else
786 : // The directives for inserting debugging information on Windows come
787 : // from the PE (Portable Executable) and COFF (Common Object File Format)
788 : // standards. Documented here:
789 : // https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
790 : //
791 : // .scl 2 means StorageClass external.
792 : // .type 32 means Type Representation Function.
793 0 : fprintf(fp_, ".def %s%s; .scl 2; .type 32; .endef;\n", SYMBOL_PREFIX, name);
794 : #endif
795 : } else {
796 : #if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64)
797 : // ELF format binaries on ARM use ".type <function name>, %function"
798 : // to create a DWARF subprogram entry.
799 : fprintf(fp_, ".type %s, %%function\n", name);
800 : #else
801 : // Other ELF Format binaries use ".type <function name>, @function"
802 : // to create a DWARF subprogram entry.
803 1522 : fprintf(fp_, ".type %s, @function\n", name);
804 : #endif
805 : }
806 1522 : }
807 :
808 1522 : void PlatformDependentEmbeddedFileWriter::DeclareFunctionEnd(const char* name) {
809 1522 : }
810 :
811 32112 : int PlatformDependentEmbeddedFileWriter::HexLiteral(uint64_t value) {
812 64224 : return fprintf(fp_, "0x%" PRIx64, value);
813 : }
814 :
815 1 : void PlatformDependentEmbeddedFileWriter::FilePrologue() {}
816 :
817 50 : void PlatformDependentEmbeddedFileWriter::DeclareExternalFilename(
818 : int fileid, const char* filename) {
819 : // Replace any Windows style paths (backslashes) with forward
820 : // slashes.
821 50 : std::string fixed_filename(filename);
822 : std::replace(fixed_filename.begin(), fixed_filename.end(), '\\', '/');
823 50 : fprintf(fp_, ".file %d \"%s\"\n", fileid, fixed_filename.c_str());
824 50 : }
825 :
826 1 : void PlatformDependentEmbeddedFileWriter::FileEpilogue() {}
827 :
828 38662 : int PlatformDependentEmbeddedFileWriter::IndentedDataDirective(
829 : DataDirective directive) {
830 77324 : return fprintf(fp_, " %s ", DirectiveAsString(directive));
831 : }
832 :
833 : #endif
834 :
835 : #undef SYMBOL_PREFIX
836 : #undef V8_COMPILER_IS_MSVC
837 :
838 : } // namespace internal
839 2 : } // namespace v8
|