• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/platform-embedded-file-writer-win.h"
6 
7 #include <algorithm>
8 
9 #include "src/common/globals.h"  // For V8_OS_WIN64
10 
11 #if defined(V8_OS_WIN64)
12 #include "src/builtins/builtins.h"
13 #include "src/diagnostics/unwinding-info-win64.h"
14 #include "src/snapshot/embedded/embedded-data-inl.h"
15 #include "src/snapshot/embedded/embedded-file-writer.h"
16 #endif  // V8_OS_WIN64
17 
18 namespace v8 {
19 namespace internal {
20 
21 // V8_CC_MSVC is true for both MSVC and clang on windows. clang can handle
22 // __asm__-style inline assembly but MSVC cannot, and thus we need a more
23 // precise compiler detection that can distinguish between the two. clang on
24 // windows sets both __clang__ and _MSC_VER, MSVC sets only _MSC_VER.
25 #if defined(_MSC_VER) && !defined(__clang__)
26 #define V8_COMPILER_IS_MSVC
27 #endif
28 
29 // MSVC uses MASM for x86 and x64, while it has a ARMASM for ARM32 and
30 // ARMASM64 for ARM64. Since ARMASM and ARMASM64 accept a slightly tweaked
31 // version of ARM assembly language, they are referred to together in Visual
32 // Studio project files as MARMASM.
33 //
34 // ARM assembly language docs:
35 // http://infocenter.arm.com/help/topic/com.arm.doc.dui0802b/index.html
36 // Microsoft ARM assembler and assembly language docs:
37 // https://docs.microsoft.com/en-us/cpp/assembler/arm/arm-assembler-reference
38 
39 // Name mangling.
40 // Symbols are prefixed with an underscore on 32-bit architectures.
41 #if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64)
42 #define SYMBOL_PREFIX "_"
43 #else
44 #define SYMBOL_PREFIX ""
45 #endif
46 
47 // Notes:
48 //
49 // Cross-bitness builds are unsupported. It's thus safe to detect bitness
50 // through compile-time defines.
51 //
52 // Cross-compiler builds (e.g. with mixed use of clang / MSVC) are likewise
53 // unsupported and hence the compiler can also be detected through compile-time
54 // defines.
55 
56 namespace {
57 
58 #if defined(V8_OS_WIN_X64)
59 
WriteUnwindInfoEntry(PlatformEmbeddedFileWriterWin * w,const char * unwind_info_symbol,const char * embedded_blob_data_symbol,uint64_t rva_start,uint64_t rva_end)60 void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterWin* w,
61                           const char* unwind_info_symbol,
62                           const char* embedded_blob_data_symbol,
63                           uint64_t rva_start, uint64_t rva_end) {
64   w->DeclareRvaToSymbol(embedded_blob_data_symbol, rva_start);
65   w->DeclareRvaToSymbol(embedded_blob_data_symbol, rva_end);
66   w->DeclareRvaToSymbol(unwind_info_symbol);
67 }
68 
EmitUnwindData(PlatformEmbeddedFileWriterWin * w,const char * unwind_info_symbol,const char * embedded_blob_data_symbol,const EmbeddedData * blob,const win64_unwindinfo::BuiltinUnwindInfo * unwind_infos)69 void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
70                     const char* unwind_info_symbol,
71                     const char* embedded_blob_data_symbol,
72                     const EmbeddedData* blob,
73                     const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) {
74   // Emit an UNWIND_INFO (XDATA) struct, which contains the unwinding
75   // information that is used for all builtin functions.
76   DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
77   w->Comment("xdata for all the code in the embedded blob.");
78   w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
79 
80   w->StartXdataSection();
81   {
82     w->DeclareLabel(unwind_info_symbol);
83 
84     std::vector<uint8_t> xdata =
85         win64_unwindinfo::GetUnwindInfoForBuiltinFunctions();
86     DCHECK(!xdata.empty());
87 
88     w->IndentedDataDirective(kByte);
89     for (size_t i = 0; i < xdata.size(); i++) {
90       if (i > 0) fprintf(w->fp(), ",");
91       w->HexLiteral(xdata[i]);
92     }
93     w->Newline();
94 
95     w->Comment("    ExceptionHandler");
96     w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
97   }
98   w->EndXdataSection();
99   w->Newline();
100 
101   // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as
102   // documented here:
103   // https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
104   w->Comment(
105       "pdata for all the code in the embedded blob (structs of type "
106       "RUNTIME_FUNCTION).");
107   w->Comment("    BeginAddress");
108   w->Comment("    EndAddress");
109   w->Comment("    UnwindInfoAddress");
110   w->StartPdataSection();
111   {
112     STATIC_ASSERT(Builtins::kAllBuiltinsAreIsolateIndependent);
113     Address prev_builtin_end_offset = 0;
114     for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
115          ++builtin) {
116       const int builtin_index = static_cast<int>(builtin);
117       // Some builtins are leaf functions from the point of view of Win64 stack
118       // walking: they do not move the stack pointer and do not require a PDATA
119       // entry because the return address can be retrieved from [rsp].
120       if (unwind_infos[builtin_index].is_leaf_function()) continue;
121 
122       uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(builtin) -
123                                       reinterpret_cast<Address>(blob->code());
124       uint32_t builtin_size = blob->InstructionSizeOfBuiltin(builtin);
125 
126       const std::vector<int>& xdata_desc =
127           unwind_infos[builtin_index].fp_offsets();
128       if (xdata_desc.empty()) {
129         // Some builtins do not have any "push rbp - mov rbp, rsp" instructions
130         // to start a stack frame. We still emit a PDATA entry as if they had,
131         // relying on the fact that we can find the previous frame address from
132         // rbp in most cases. Note that since the function does not really start
133         // with a 'push rbp' we need to specify the start RVA in the PDATA entry
134         // a few bytes before the beginning of the function, if it does not
135         // overlap the end of the previous builtin.
136         WriteUnwindInfoEntry(
137             w, unwind_info_symbol, embedded_blob_data_symbol,
138             std::max(prev_builtin_end_offset,
139                      builtin_start_offset - win64_unwindinfo::kRbpPrefixLength),
140             builtin_start_offset + builtin_size);
141       } else {
142         // Some builtins have one or more "push rbp - mov rbp, rsp" sequences,
143         // but not necessarily at the beginning of the function. In this case
144         // we want to yield a PDATA entry for each block of instructions that
145         // emit an rbp frame. If the function does not start with 'push rbp'
146         // we also emit a PDATA entry for the initial block of code up to the
147         // first 'push rbp', like in the case above.
148         if (xdata_desc[0] > 0) {
149           WriteUnwindInfoEntry(w, unwind_info_symbol, embedded_blob_data_symbol,
150                                std::max(prev_builtin_end_offset,
151                                         builtin_start_offset -
152                                             win64_unwindinfo::kRbpPrefixLength),
153                                builtin_start_offset + xdata_desc[0]);
154         }
155 
156         for (size_t j = 0; j < xdata_desc.size(); j++) {
157           int chunk_start = xdata_desc[j];
158           int chunk_end =
159               (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size;
160           WriteUnwindInfoEntry(w, unwind_info_symbol, embedded_blob_data_symbol,
161                                builtin_start_offset + chunk_start,
162                                builtin_start_offset + chunk_end);
163         }
164       }
165 
166       prev_builtin_end_offset = builtin_start_offset + builtin_size;
167       w->Newline();
168     }
169   }
170   w->EndPdataSection();
171   w->Newline();
172 }
173 
174 #elif defined(V8_OS_WIN_ARM64)
175 
176 void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
177                     const char* unwind_info_symbol,
178                     const char* embedded_blob_data_symbol,
179                     const EmbeddedData* blob,
180                     const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) {
181   DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
182 
183   // Fairly arbitrary but should fit all symbol names.
184   static constexpr int kTemporaryStringLength = 256;
185   base::EmbeddedVector<char, kTemporaryStringLength> unwind_info_full_symbol;
186 
187   // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as
188   // documented here:
189   // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling.
190   w->Comment(
191       "pdata for all the code in the embedded blob (structs of type "
192       "RUNTIME_FUNCTION).");
193   w->Comment("    BeginAddress");
194   w->Comment("    UnwindInfoAddress");
195   w->StartPdataSection();
196   std::vector<int> code_chunks;
197   std::vector<win64_unwindinfo::FrameOffsets> fp_adjustments;
198 
199   STATIC_ASSERT(Builtins::kAllBuiltinsAreIsolateIndependent);
200   for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
201        ++builtin) {
202     const int builtin_index = static_cast<int>(builtin);
203     if (unwind_infos[builtin_index].is_leaf_function()) continue;
204 
205     uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(builtin) -
206                                     reinterpret_cast<Address>(blob->code());
207     uint32_t builtin_size = blob->InstructionSizeOfBuiltin(builtin);
208 
209     const std::vector<int>& xdata_desc =
210         unwind_infos[builtin_index].fp_offsets();
211     const std::vector<win64_unwindinfo::FrameOffsets>& xdata_fp_adjustments =
212         unwind_infos[builtin_index].fp_adjustments();
213     DCHECK_EQ(xdata_desc.size(), xdata_fp_adjustments.size());
214 
215     for (size_t j = 0; j < xdata_desc.size(); j++) {
216       int chunk_start = xdata_desc[j];
217       int chunk_end =
218           (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size;
219       int chunk_len = ::RoundUp(chunk_end - chunk_start, kInstrSize);
220 
221       while (chunk_len > 0) {
222         int allowed_chunk_len =
223             std::min(chunk_len, win64_unwindinfo::kMaxFunctionLength);
224         chunk_len -= win64_unwindinfo::kMaxFunctionLength;
225 
226         // Record the chunk length and fp_adjustment for emitting UNWIND_INFO
227         // later.
228         code_chunks.push_back(allowed_chunk_len);
229         fp_adjustments.push_back(xdata_fp_adjustments[j]);
230         base::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol,
231                        code_chunks.size());
232         w->DeclareRvaToSymbol(embedded_blob_data_symbol,
233                               builtin_start_offset + chunk_start);
234         w->DeclareRvaToSymbol(unwind_info_full_symbol.begin());
235       }
236     }
237   }
238   w->EndPdataSection();
239   w->Newline();
240 
241   // Emit an UNWIND_INFO (XDATA) structs, which contains the unwinding
242   // information.
243   w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
244   w->StartXdataSection();
245   {
246     for (size_t i = 0; i < code_chunks.size(); i++) {
247       base::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol,
248                      i + 1);
249       w->DeclareLabel(unwind_info_full_symbol.begin());
250       std::vector<uint8_t> xdata =
251           win64_unwindinfo::GetUnwindInfoForBuiltinFunction(code_chunks[i],
252                                                             fp_adjustments[i]);
253 
254       w->IndentedDataDirective(kByte);
255       for (size_t j = 0; j < xdata.size(); j++) {
256         if (j > 0) fprintf(w->fp(), ",");
257         w->HexLiteral(xdata[j]);
258       }
259       w->Newline();
260       w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
261     }
262   }
263   w->EndXdataSection();
264   w->Newline();
265 }
266 
267 #endif  // V8_OS_WIN_X64
268 
269 }  // namespace
270 
DirectiveAsString(DataDirective directive)271 const char* PlatformEmbeddedFileWriterWin::DirectiveAsString(
272     DataDirective directive) {
273 #if defined(V8_COMPILER_IS_MSVC)
274   if (target_arch_ != EmbeddedTargetArch::kArm64) {
275     switch (directive) {
276       case kByte:
277         return "BYTE";
278       case kLong:
279         return "DWORD";
280       case kQuad:
281         return "QWORD";
282       default:
283         UNREACHABLE();
284     }
285   } else {
286     switch (directive) {
287       case kByte:
288         return "DCB";
289       case kLong:
290         return "DCDU";
291       case kQuad:
292         return "DCQU";
293       default:
294         UNREACHABLE();
295     }
296   }
297 #else
298   switch (directive) {
299     case kByte:
300       return ".byte";
301     case kLong:
302       return ".long";
303     case kQuad:
304       return ".quad";
305     case kOcta:
306       return ".octa";
307   }
308   UNREACHABLE();
309 #endif
310 }
311 
MaybeEmitUnwindData(const char * unwind_info_symbol,const char * embedded_blob_data_symbol,const EmbeddedData * blob,const void * unwind_infos)312 void PlatformEmbeddedFileWriterWin::MaybeEmitUnwindData(
313     const char* unwind_info_symbol, const char* embedded_blob_data_symbol,
314     const EmbeddedData* blob, const void* unwind_infos) {
315 // Windows ARM64 supports cross build which could require unwind info for
316 // host_os. Ignore this case because it is only used in build time.
317 #if defined(V8_OS_WIN_ARM64)
318   if (target_arch_ != EmbeddedTargetArch::kArm64) {
319     return;
320   }
321 #endif  // V8_OS_WIN_ARM64
322 
323 #if defined(V8_OS_WIN64)
324   if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) {
325     EmitUnwindData(this, unwind_info_symbol, embedded_blob_data_symbol, blob,
326                    reinterpret_cast<const win64_unwindinfo::BuiltinUnwindInfo*>(
327                        unwind_infos));
328   }
329 #endif  // V8_OS_WIN64
330 }
331 
332 // Windows, MSVC
333 // -----------------------------------------------------------------------------
334 
335 #if defined(V8_COMPILER_IS_MSVC)
336 
337 // For x64 MSVC builds we emit assembly in MASM syntax.
338 // See https://docs.microsoft.com/en-us/cpp/assembler/masm/directives-reference.
339 // For Arm build, we emit assembly in MARMASM syntax.
340 // Note that the same mksnapshot has to be used to compile the host and target.
341 
342 // The AARCH64 ABI requires instructions be 4-byte-aligned and Windows does
343 // not have a stricter alignment requirement (see the TEXTAREA macro of
344 // kxarm64.h in the Windows SDK), so code is 4-byte-aligned.
345 // The data fields in the emitted assembly tend to be accessed with 8-byte
346 // LDR instructions, so data is 8-byte-aligned.
347 //
348 // armasm64's warning A4228 states
349 //     Alignment value exceeds AREA alignment; alignment not guaranteed
350 // To ensure that ALIGN directives are honored, their values are defined as
351 // equal to their corresponding AREA's ALIGN attributes.
352 
353 #define ARM64_DATA_ALIGNMENT_POWER (3)
354 #define ARM64_DATA_ALIGNMENT (1 << ARM64_DATA_ALIGNMENT_POWER)
355 #define ARM64_CODE_ALIGNMENT_POWER (2)
356 #define ARM64_CODE_ALIGNMENT (1 << ARM64_CODE_ALIGNMENT_POWER)
357 
SectionText()358 void PlatformEmbeddedFileWriterWin::SectionText() {
359   if (target_arch_ == EmbeddedTargetArch::kArm64) {
360     fprintf(fp_, "  AREA |.text|, CODE, ALIGN=%d, READONLY\n",
361             ARM64_CODE_ALIGNMENT_POWER);
362   } else {
363     fprintf(fp_, ".CODE\n");
364   }
365 }
366 
SectionData()367 void PlatformEmbeddedFileWriterWin::SectionData() {
368   if (target_arch_ == EmbeddedTargetArch::kArm64) {
369     fprintf(fp_, "  AREA |.data|, DATA, ALIGN=%d, READWRITE\n",
370             ARM64_DATA_ALIGNMENT_POWER);
371   } else {
372     fprintf(fp_, ".DATA\n");
373   }
374 }
375 
SectionRoData()376 void PlatformEmbeddedFileWriterWin::SectionRoData() {
377   if (target_arch_ == EmbeddedTargetArch::kArm64) {
378     fprintf(fp_, "  AREA |.rodata|, DATA, ALIGN=%d, READONLY\n",
379             ARM64_DATA_ALIGNMENT_POWER);
380   } else {
381     fprintf(fp_, ".CONST\n");
382   }
383 }
384 
DeclareUint32(const char * name,uint32_t value)385 void PlatformEmbeddedFileWriterWin::DeclareUint32(const char* name,
386                                                   uint32_t value) {
387   DeclareSymbolGlobal(name);
388   fprintf(fp_, "%s%s %s %d\n", SYMBOL_PREFIX, name, DirectiveAsString(kLong),
389           value);
390 }
391 
DeclarePointerToSymbol(const char * name,const char * target)392 void PlatformEmbeddedFileWriterWin::DeclarePointerToSymbol(const char* name,
393                                                            const char* target) {
394   DeclareSymbolGlobal(name);
395   fprintf(fp_, "%s%s %s %s%s\n", SYMBOL_PREFIX, name,
396           DirectiveAsString(PointerSizeDirective()), SYMBOL_PREFIX, target);
397 }
398 
StartPdataSection()399 void PlatformEmbeddedFileWriterWin::StartPdataSection() {
400   if (target_arch_ == EmbeddedTargetArch::kArm64) {
401     fprintf(fp_, "  AREA |.pdata|, DATA, ALIGN=%d, READONLY\n",
402             ARM64_DATA_ALIGNMENT_POWER);
403   } else {
404     fprintf(fp_, "OPTION DOTNAME\n");
405     fprintf(fp_, ".pdata SEGMENT DWORD READ ''\n");
406   }
407 }
408 
EndPdataSection()409 void PlatformEmbeddedFileWriterWin::EndPdataSection() {
410   if (target_arch_ != EmbeddedTargetArch::kArm64) {
411     fprintf(fp_, ".pdata ENDS\n");
412   }
413 }
414 
StartXdataSection()415 void PlatformEmbeddedFileWriterWin::StartXdataSection() {
416   if (target_arch_ == EmbeddedTargetArch::kArm64) {
417     fprintf(fp_, "  AREA |.xdata|, DATA, ALIGN=%d, READONLY\n",
418             ARM64_DATA_ALIGNMENT_POWER);
419   } else {
420     fprintf(fp_, "OPTION DOTNAME\n");
421     fprintf(fp_, ".xdata SEGMENT DWORD READ ''\n");
422   }
423 }
424 
EndXdataSection()425 void PlatformEmbeddedFileWriterWin::EndXdataSection() {
426   if (target_arch_ != EmbeddedTargetArch::kArm64) {
427     fprintf(fp_, ".xdata ENDS\n");
428   }
429 }
430 
DeclareExternalFunction(const char * name)431 void PlatformEmbeddedFileWriterWin::DeclareExternalFunction(const char* name) {
432   if (target_arch_ == EmbeddedTargetArch::kArm64) {
433     fprintf(fp_, "  EXTERN %s \n", name);
434   } else {
435     fprintf(fp_, "EXTERN %s : PROC\n", name);
436   }
437 }
438 
DeclareRvaToSymbol(const char * name,uint64_t offset)439 void PlatformEmbeddedFileWriterWin::DeclareRvaToSymbol(const char* name,
440                                                        uint64_t offset) {
441   if (target_arch_ == EmbeddedTargetArch::kArm64) {
442     if (offset > 0) {
443       fprintf(fp_, "  DCD  %s + %llu\n", name, offset);
444     } else {
445       fprintf(fp_, "  DCD  %s\n", name);
446     }
447     // The default relocation entry generated by MSVC armasm64.exe for DCD
448     // directive is IMAGE_REL_ARM64_ADDR64 which represents relocation for
449     // 64-bit pointer instead of 32-bit RVA. Append RELOC with
450     // IMAGE_REL_ARM64_ADDR32NB(2) to generate correct relocation entry for
451     // 32-bit RVA.
452     fprintf(fp_, "  RELOC 2\n");
453   } else {
454     if (offset > 0) {
455       fprintf(fp_, "DD IMAGEREL %s+%llu\n", name, offset);
456     } else {
457       fprintf(fp_, "DD IMAGEREL %s\n", name);
458     }
459   }
460 }
461 
DeclareSymbolGlobal(const char * name)462 void PlatformEmbeddedFileWriterWin::DeclareSymbolGlobal(const char* name) {
463   if (target_arch_ == EmbeddedTargetArch::kArm64) {
464     fprintf(fp_, "  EXPORT %s%s\n", SYMBOL_PREFIX, name);
465   } else {
466     fprintf(fp_, "PUBLIC %s%s\n", SYMBOL_PREFIX, name);
467   }
468 }
469 
AlignToCodeAlignment()470 void PlatformEmbeddedFileWriterWin::AlignToCodeAlignment() {
471   if (target_arch_ == EmbeddedTargetArch::kArm64) {
472     fprintf(fp_, "  ALIGN %d\n", ARM64_CODE_ALIGNMENT);
473   } else {
474     // Diverges from other platforms due to compile error
475     // 'invalid combination with segment alignment'.
476     fprintf(fp_, "ALIGN 4\n");
477   }
478 }
479 
AlignToDataAlignment()480 void PlatformEmbeddedFileWriterWin::AlignToDataAlignment() {
481   if (target_arch_ == EmbeddedTargetArch::kArm64) {
482     fprintf(fp_, "  ALIGN %d\n", ARM64_DATA_ALIGNMENT);
483 
484   } else {
485     fprintf(fp_, "ALIGN 4\n");
486   }
487 }
488 
Comment(const char * string)489 void PlatformEmbeddedFileWriterWin::Comment(const char* string) {
490   fprintf(fp_, "; %s\n", string);
491 }
492 
DeclareLabel(const char * name)493 void PlatformEmbeddedFileWriterWin::DeclareLabel(const char* name) {
494   if (target_arch_ == EmbeddedTargetArch::kArm64) {
495     fprintf(fp_, "%s%s\n", SYMBOL_PREFIX, name);
496 
497   } else {
498     fprintf(fp_, "%s%s LABEL %s\n", SYMBOL_PREFIX, name,
499             DirectiveAsString(kByte));
500   }
501 }
502 
SourceInfo(int fileid,const char * filename,int line)503 void PlatformEmbeddedFileWriterWin::SourceInfo(int fileid, const char* filename,
504                                                int line) {
505   // TODO(mvstanton): output source information for MSVC.
506   // Its syntax is #line <line> "<filename>"
507 }
508 
509 // TODO(mmarchini): investigate emitting size annotations for Windows
DeclareFunctionBegin(const char * name,uint32_t size)510 void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name,
511                                                          uint32_t size) {
512   if (ENABLE_CONTROL_FLOW_INTEGRITY_BOOL) {
513     DeclareSymbolGlobal(name);
514   }
515 
516   if (target_arch_ == EmbeddedTargetArch::kArm64) {
517     fprintf(fp_, "%s%s FUNCTION\n", SYMBOL_PREFIX, name);
518 
519   } else {
520     fprintf(fp_, "%s%s PROC\n", SYMBOL_PREFIX, name);
521   }
522 }
523 
DeclareFunctionEnd(const char * name)524 void PlatformEmbeddedFileWriterWin::DeclareFunctionEnd(const char* name) {
525   if (target_arch_ == EmbeddedTargetArch::kArm64) {
526     fprintf(fp_, "  ENDFUNC\n");
527 
528   } else {
529     fprintf(fp_, "%s%s ENDP\n", SYMBOL_PREFIX, name);
530   }
531 }
532 
HexLiteral(uint64_t value)533 int PlatformEmbeddedFileWriterWin::HexLiteral(uint64_t value) {
534   if (target_arch_ == EmbeddedTargetArch::kArm64) {
535     return fprintf(fp_, "0x%" PRIx64, value);
536 
537   } else {
538     return fprintf(fp_, "0%" PRIx64 "h", value);
539   }
540 }
541 
FilePrologue()542 void PlatformEmbeddedFileWriterWin::FilePrologue() {
543   if (target_arch_ != EmbeddedTargetArch::kArm64 &&
544       target_arch_ != EmbeddedTargetArch::kX64) {
545     // x86 falls into this case
546     fprintf(fp_, ".MODEL FLAT\n");
547   }
548 }
549 
DeclareExternalFilename(int fileid,const char * filename)550 void PlatformEmbeddedFileWriterWin::DeclareExternalFilename(
551     int fileid, const char* filename) {}
552 
FileEpilogue()553 void PlatformEmbeddedFileWriterWin::FileEpilogue() {
554   if (target_arch_ == EmbeddedTargetArch::kArm64) {
555     fprintf(fp_, "  END\n");
556   } else {
557     fprintf(fp_, "END\n");
558   }
559 }
560 
IndentedDataDirective(DataDirective directive)561 int PlatformEmbeddedFileWriterWin::IndentedDataDirective(
562     DataDirective directive) {
563   return fprintf(fp_, "  %s ", DirectiveAsString(directive));
564 }
565 
566 #undef ARM64_DATA_ALIGNMENT_POWER
567 #undef ARM64_DATA_ALIGNMENT
568 #undef ARM64_CODE_ALIGNMENT_POWER
569 #undef ARM64_CODE_ALIGNMENT
570 
571 // All Windows builds without MSVC.
572 // -----------------------------------------------------------------------------
573 
574 #else
575 
576 // The directives for text section prefix come from the COFF
577 // (Common Object File Format) standards:
578 // https://llvm.org/docs/Extensions.html
579 //
580 // .text$hot means this section contains hot code.
581 // x means executable section.
582 // r means read-only section.
SectionText()583 void PlatformEmbeddedFileWriterWin::SectionText() {
584   fprintf(fp_, ".section .text$hot,\"xr\"\n");
585 }
586 
SectionData()587 void PlatformEmbeddedFileWriterWin::SectionData() {
588   fprintf(fp_, ".section .data\n");
589 }
590 
SectionRoData()591 void PlatformEmbeddedFileWriterWin::SectionRoData() {
592   fprintf(fp_, ".section .rdata\n");
593 }
594 
DeclareUint32(const char * name,uint32_t value)595 void PlatformEmbeddedFileWriterWin::DeclareUint32(const char* name,
596                                                   uint32_t value) {
597   DeclareSymbolGlobal(name);
598   DeclareLabel(name);
599   IndentedDataDirective(kLong);
600   fprintf(fp_, "%d", value);
601   Newline();
602 }
603 
DeclarePointerToSymbol(const char * name,const char * target)604 void PlatformEmbeddedFileWriterWin::DeclarePointerToSymbol(const char* name,
605                                                            const char* target) {
606   DeclareSymbolGlobal(name);
607   DeclareLabel(name);
608   fprintf(fp_, "  %s %s%s\n", DirectiveAsString(PointerSizeDirective()),
609           SYMBOL_PREFIX, target);
610 }
611 
StartPdataSection()612 void PlatformEmbeddedFileWriterWin::StartPdataSection() {
613   fprintf(fp_, ".section .pdata\n");
614 }
615 
EndPdataSection()616 void PlatformEmbeddedFileWriterWin::EndPdataSection() {}
617 
StartXdataSection()618 void PlatformEmbeddedFileWriterWin::StartXdataSection() {
619   fprintf(fp_, ".section .xdata\n");
620 }
621 
EndXdataSection()622 void PlatformEmbeddedFileWriterWin::EndXdataSection() {}
623 
DeclareExternalFunction(const char * name)624 void PlatformEmbeddedFileWriterWin::DeclareExternalFunction(const char* name) {}
625 
DeclareRvaToSymbol(const char * name,uint64_t offset)626 void PlatformEmbeddedFileWriterWin::DeclareRvaToSymbol(const char* name,
627                                                        uint64_t offset) {
628   if (offset > 0) {
629     fprintf(fp_, ".rva %s + %" PRIu64 "\n", name, offset);
630   } else {
631     fprintf(fp_, ".rva %s\n", name);
632   }
633 }
634 
DeclareSymbolGlobal(const char * name)635 void PlatformEmbeddedFileWriterWin::DeclareSymbolGlobal(const char* name) {
636   fprintf(fp_, ".global %s%s\n", SYMBOL_PREFIX, name);
637 }
638 
AlignToCodeAlignment()639 void PlatformEmbeddedFileWriterWin::AlignToCodeAlignment() {
640 #if V8_TARGET_ARCH_X64
641   // On x64 use 64-bytes code alignment to allow 64-bytes loop header alignment.
642   STATIC_ASSERT(64 >= kCodeAlignment);
643   fprintf(fp_, ".balign 64\n");
644 #elif V8_TARGET_ARCH_PPC64
645   // 64 byte alignment is needed on ppc64 to make sure p10 prefixed instructions
646   // don't cross 64-byte boundaries.
647   STATIC_ASSERT(64 >= kCodeAlignment);
648   fprintf(fp_, ".balign 64\n");
649 #else
650   STATIC_ASSERT(32 >= kCodeAlignment);
651   fprintf(fp_, ".balign 32\n");
652 #endif
653 }
654 
AlignToDataAlignment()655 void PlatformEmbeddedFileWriterWin::AlignToDataAlignment() {
656   // On Windows ARM64, s390, PPC and possibly more platforms, aligned load
657   // instructions are used to retrieve v8_Default_embedded_blob_ and/or
658   // v8_Default_embedded_blob_size_. The generated instructions require the
659   // load target to be aligned at 8 bytes (2^3).
660   fprintf(fp_, ".balign 8\n");
661 }
662 
Comment(const char * string)663 void PlatformEmbeddedFileWriterWin::Comment(const char* string) {
664   fprintf(fp_, "// %s\n", string);
665 }
666 
DeclareLabel(const char * name)667 void PlatformEmbeddedFileWriterWin::DeclareLabel(const char* name) {
668   fprintf(fp_, "%s%s:\n", SYMBOL_PREFIX, name);
669 }
670 
SourceInfo(int fileid,const char * filename,int line)671 void PlatformEmbeddedFileWriterWin::SourceInfo(int fileid, const char* filename,
672                                                int line) {
673   // BUG(9944): Use .cv_loc to ensure CodeView information is used on
674   // Windows.
675 }
676 
677 // TODO(mmarchini): investigate emitting size annotations for Windows
DeclareFunctionBegin(const char * name,uint32_t size)678 void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name,
679                                                          uint32_t size) {
680   DeclareLabel(name);
681 
682   if (target_arch_ == EmbeddedTargetArch::kArm64) {
683     // Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive
684     // in PE/COFF for Windows.
685     DeclareSymbolGlobal(name);
686   } else {
687     // The directives for inserting debugging information on Windows come
688     // from the PE (Portable Executable) and COFF (Common Object File Format)
689     // standards. Documented here:
690     // https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
691     //
692     // .scl 2 means StorageClass external.
693     // .type 32 means Type Representation Function.
694     fprintf(fp_, ".def %s%s; .scl 2; .type 32; .endef;\n", SYMBOL_PREFIX, name);
695   }
696 }
697 
DeclareFunctionEnd(const char * name)698 void PlatformEmbeddedFileWriterWin::DeclareFunctionEnd(const char* name) {}
699 
HexLiteral(uint64_t value)700 int PlatformEmbeddedFileWriterWin::HexLiteral(uint64_t value) {
701   return fprintf(fp_, "0x%" PRIx64, value);
702 }
703 
FilePrologue()704 void PlatformEmbeddedFileWriterWin::FilePrologue() {}
705 
DeclareExternalFilename(int fileid,const char * filename)706 void PlatformEmbeddedFileWriterWin::DeclareExternalFilename(
707     int fileid, const char* filename) {
708   // BUG(9944): Use .cv_filename to ensure CodeView information is used on
709   // Windows.
710 }
711 
FileEpilogue()712 void PlatformEmbeddedFileWriterWin::FileEpilogue() {}
713 
IndentedDataDirective(DataDirective directive)714 int PlatformEmbeddedFileWriterWin::IndentedDataDirective(
715     DataDirective directive) {
716   return fprintf(fp_, "  %s ", DirectiveAsString(directive));
717 }
718 
719 #endif
720 
ByteChunkDataDirective() const721 DataDirective PlatformEmbeddedFileWriterWin::ByteChunkDataDirective() const {
722 #if defined(V8_COMPILER_IS_MSVC)
723   // Windows MASM doesn't have an .octa directive, use QWORDs instead.
724   // Note: MASM *really* does not like large data streams. It takes over 5
725   // minutes to assemble the ~350K lines of embedded.S produced when using
726   // BYTE directives in a debug build. QWORD produces roughly 120KLOC and
727   // reduces assembly time to ~40 seconds. Still terrible, but much better
728   // than before. See also: https://crbug.com/v8/8475.
729   return kQuad;
730 #else
731   return PlatformEmbeddedFileWriterBase::ByteChunkDataDirective();
732 #endif
733 }
734 
WriteByteChunk(const uint8_t * data)735 int PlatformEmbeddedFileWriterWin::WriteByteChunk(const uint8_t* data) {
736 #if defined(V8_COMPILER_IS_MSVC)
737   DCHECK_EQ(ByteChunkDataDirective(), kQuad);
738   const uint64_t* quad_ptr = reinterpret_cast<const uint64_t*>(data);
739   return HexLiteral(*quad_ptr);
740 #else
741   return PlatformEmbeddedFileWriterBase::WriteByteChunk(data);
742 #endif
743 }
744 
745 #undef SYMBOL_PREFIX
746 #undef V8_ASSEMBLER_IS_MASM
747 #undef V8_ASSEMBLER_IS_MARMASM
748 #undef V8_COMPILER_IS_MSVC
749 
750 }  // namespace internal
751 }  // namespace v8
752