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 18namespace v8 { 19namespace 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 56namespace { 57 58#if defined(V8_OS_WIN_X64) 59 60void 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 69void 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 176void 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 271const 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 312void 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 358void 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 367void 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 376void 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 385void 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 392void 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 399void 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 409void PlatformEmbeddedFileWriterWin::EndPdataSection() { 410 if (target_arch_ != EmbeddedTargetArch::kArm64) { 411 fprintf(fp_, ".pdata ENDS\n"); 412 } 413} 414 415void 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 425void PlatformEmbeddedFileWriterWin::EndXdataSection() { 426 if (target_arch_ != EmbeddedTargetArch::kArm64) { 427 fprintf(fp_, ".xdata ENDS\n"); 428 } 429} 430 431void 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 439void 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 462void 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 470void 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 480void 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 489void PlatformEmbeddedFileWriterWin::Comment(const char* string) { 490 fprintf(fp_, "; %s\n", string); 491} 492 493void 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 503void 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 510void 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 524void 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 533int 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 542void 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 550void PlatformEmbeddedFileWriterWin::DeclareExternalFilename( 551 int fileid, const char* filename) {} 552 553void PlatformEmbeddedFileWriterWin::FileEpilogue() { 554 if (target_arch_ == EmbeddedTargetArch::kArm64) { 555 fprintf(fp_, " END\n"); 556 } else { 557 fprintf(fp_, "END\n"); 558 } 559} 560 561int 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. 583void PlatformEmbeddedFileWriterWin::SectionText() { 584 fprintf(fp_, ".section .text$hot,\"xr\"\n"); 585} 586 587void PlatformEmbeddedFileWriterWin::SectionData() { 588 fprintf(fp_, ".section .data\n"); 589} 590 591void PlatformEmbeddedFileWriterWin::SectionRoData() { 592 fprintf(fp_, ".section .rdata\n"); 593} 594 595void 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 604void 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 612void PlatformEmbeddedFileWriterWin::StartPdataSection() { 613 fprintf(fp_, ".section .pdata\n"); 614} 615 616void PlatformEmbeddedFileWriterWin::EndPdataSection() {} 617 618void PlatformEmbeddedFileWriterWin::StartXdataSection() { 619 fprintf(fp_, ".section .xdata\n"); 620} 621 622void PlatformEmbeddedFileWriterWin::EndXdataSection() {} 623 624void PlatformEmbeddedFileWriterWin::DeclareExternalFunction(const char* name) {} 625 626void 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 635void PlatformEmbeddedFileWriterWin::DeclareSymbolGlobal(const char* name) { 636 fprintf(fp_, ".global %s%s\n", SYMBOL_PREFIX, name); 637} 638 639void 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 655void 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 663void PlatformEmbeddedFileWriterWin::Comment(const char* string) { 664 fprintf(fp_, "// %s\n", string); 665} 666 667void PlatformEmbeddedFileWriterWin::DeclareLabel(const char* name) { 668 fprintf(fp_, "%s%s:\n", SYMBOL_PREFIX, name); 669} 670 671void 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 678void 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 698void PlatformEmbeddedFileWriterWin::DeclareFunctionEnd(const char* name) {} 699 700int PlatformEmbeddedFileWriterWin::HexLiteral(uint64_t value) { 701 return fprintf(fp_, "0x%" PRIx64, value); 702} 703 704void PlatformEmbeddedFileWriterWin::FilePrologue() {} 705 706void 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 712void PlatformEmbeddedFileWriterWin::FileEpilogue() {} 713 714int PlatformEmbeddedFileWriterWin::IndentedDataDirective( 715 DataDirective directive) { 716 return fprintf(fp_, " %s ", DirectiveAsString(directive)); 717} 718 719#endif 720 721DataDirective 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 735int 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