#include "src/snapshot/embedded/platform-embedded-file-writer-win.h"
#include <algorithm>
#include "src/common/globals.h"
#if defined(V8_OS_WIN64)
#include "src/builtins/builtins.h"
#include "src/diagnostics/unwinding-info-win64.h"
#include "src/snapshot/embedded/embedded-data-inl.h"
#include "src/snapshot/embedded/embedded-file-writer.h"
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#define V8_COMPILER_IS_MSVC
#endif
#if defined(V8_COMPILER_IS_MSVC)
#include "src/flags/flags.h"
#endif
namespace v8 {
namespace internal {
#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64)
#define SYMBOL_PREFIX …
#else
#define SYMBOL_PREFIX …
#endif
namespace {
#if defined(V8_OS_WIN_X64)
void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterWin* w,
const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
uint64_t rva_start, uint64_t rva_end) {
w->DeclareRvaToSymbol(embedded_blob_data_symbol, rva_start);
w->DeclareRvaToSymbol(embedded_blob_data_symbol, rva_end);
w->DeclareRvaToSymbol(unwind_info_symbol);
}
void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
const EmbeddedData* blob,
const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) {
DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
w->Comment("xdata for all the code in the embedded blob.");
w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
w->StartXdataSection();
{
w->DeclareLabel(unwind_info_symbol);
std::vector<uint8_t> xdata =
win64_unwindinfo::GetUnwindInfoForBuiltinFunctions();
DCHECK(!xdata.empty());
w->IndentedDataDirective(kByte);
for (size_t i = 0; i < xdata.size(); i++) {
if (i > 0) fprintf(w->fp(), ",");
w->HexLiteral(xdata[i]);
}
w->Newline();
w->Comment(" ExceptionHandler");
w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
}
w->EndXdataSection();
w->Newline();
w->Comment(
"pdata for all the code in the embedded blob (structs of type "
"RUNTIME_FUNCTION).");
w->Comment(" BeginAddress");
w->Comment(" EndAddress");
w->Comment(" UnwindInfoAddress");
w->StartPdataSection();
{
static_assert(Builtins::kAllBuiltinsAreIsolateIndependent);
Address prev_builtin_end_offset = 0;
for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
++builtin) {
const int builtin_index = static_cast<int>(builtin);
if (unwind_infos[builtin_index].is_leaf_function()) continue;
uint64_t builtin_start_offset = blob->InstructionStartOf(builtin) -
reinterpret_cast<Address>(blob->code());
uint32_t builtin_size = blob->InstructionSizeOf(builtin);
const std::vector<int>& xdata_desc =
unwind_infos[builtin_index].fp_offsets();
if (xdata_desc.empty()) {
WriteUnwindInfoEntry(
w, unwind_info_symbol, embedded_blob_data_symbol,
std::max(prev_builtin_end_offset,
builtin_start_offset - win64_unwindinfo::kRbpPrefixLength),
builtin_start_offset + builtin_size);
} else {
if (xdata_desc[0] > 0) {
WriteUnwindInfoEntry(w, unwind_info_symbol, embedded_blob_data_symbol,
std::max(prev_builtin_end_offset,
builtin_start_offset -
win64_unwindinfo::kRbpPrefixLength),
builtin_start_offset + xdata_desc[0]);
}
for (size_t j = 0; j < xdata_desc.size(); j++) {
int chunk_start = xdata_desc[j];
int chunk_end =
(j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size;
WriteUnwindInfoEntry(w, unwind_info_symbol, embedded_blob_data_symbol,
builtin_start_offset + chunk_start,
builtin_start_offset + chunk_end);
}
}
prev_builtin_end_offset = builtin_start_offset + builtin_size;
w->Newline();
}
}
w->EndPdataSection();
w->Newline();
}
#elif defined(V8_OS_WIN_ARM64)
void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
const EmbeddedData* blob,
const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) {
DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
static constexpr int kTemporaryStringLength = 256;
base::EmbeddedVector<char, kTemporaryStringLength> unwind_info_full_symbol;
w->Comment(
"pdata for all the code in the embedded blob (structs of type "
"RUNTIME_FUNCTION).");
w->Comment(" BeginAddress");
w->Comment(" UnwindInfoAddress");
w->StartPdataSection();
std::vector<int> code_chunks;
std::vector<win64_unwindinfo::FrameOffsets> fp_adjustments;
static_assert(Builtins::kAllBuiltinsAreIsolateIndependent);
for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
++builtin) {
const int builtin_index = static_cast<int>(builtin);
if (unwind_infos[builtin_index].is_leaf_function()) continue;
uint64_t builtin_start_offset = blob->InstructionStartOf(builtin) -
reinterpret_cast<Address>(blob->code());
uint32_t builtin_size = blob->InstructionSizeOf(builtin);
const std::vector<int>& xdata_desc =
unwind_infos[builtin_index].fp_offsets();
const std::vector<win64_unwindinfo::FrameOffsets>& xdata_fp_adjustments =
unwind_infos[builtin_index].fp_adjustments();
DCHECK_EQ(xdata_desc.size(), xdata_fp_adjustments.size());
for (size_t j = 0; j < xdata_desc.size(); j++) {
int chunk_start = xdata_desc[j];
int chunk_end =
(j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size;
int chunk_len = ::RoundUp(chunk_end - chunk_start, kInstrSize);
while (chunk_len > 0) {
int allowed_chunk_len =
std::min(chunk_len, win64_unwindinfo::kMaxFunctionLength);
chunk_len -= win64_unwindinfo::kMaxFunctionLength;
code_chunks.push_back(allowed_chunk_len);
fp_adjustments.push_back(xdata_fp_adjustments[j]);
base::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol,
code_chunks.size());
w->DeclareRvaToSymbol(embedded_blob_data_symbol,
builtin_start_offset + chunk_start);
w->DeclareRvaToSymbol(unwind_info_full_symbol.begin());
}
}
}
w->EndPdataSection();
w->Newline();
w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
w->StartXdataSection();
{
for (size_t i = 0; i < code_chunks.size(); i++) {
base::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol,
i + 1);
w->DeclareLabel(unwind_info_full_symbol.begin());
std::vector<uint8_t> xdata =
win64_unwindinfo::GetUnwindInfoForBuiltinFunction(code_chunks[i],
fp_adjustments[i]);
w->IndentedDataDirective(kByte);
for (size_t j = 0; j < xdata.size(); j++) {
if (j > 0) fprintf(w->fp(), ",");
w->HexLiteral(xdata[j]);
}
w->Newline();
w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
}
}
w->EndXdataSection();
w->Newline();
}
#endif
}
const char* PlatformEmbeddedFileWriterWin::DirectiveAsString(
DataDirective directive) { … }
void PlatformEmbeddedFileWriterWin::MaybeEmitUnwindData(
const char* unwind_info_symbol, const char* embedded_blob_data_symbol,
const EmbeddedData* blob, const void* unwind_infos) { … }
#if defined(V8_COMPILER_IS_MSVC)
#define ARM64_DATA_ALIGNMENT_POWER …
#define ARM64_DATA_ALIGNMENT …
#define ARM64_CODE_ALIGNMENT_POWER …
#define ARM64_CODE_ALIGNMENT …
void PlatformEmbeddedFileWriterWin::SectionText() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " AREA |.text|, CODE, ALIGN=%d, READONLY\n",
ARM64_CODE_ALIGNMENT_POWER);
} else {
fprintf(fp_, ".CODE\n");
}
}
void PlatformEmbeddedFileWriterWin::SectionRoData() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " AREA |.rodata|, DATA, ALIGN=%d, READONLY\n",
ARM64_DATA_ALIGNMENT_POWER);
} else {
fprintf(fp_, ".CONST\n");
}
}
void PlatformEmbeddedFileWriterWin::DeclareUint32(const char* name,
uint32_t value) {
DeclareSymbolGlobal(name);
fprintf(fp_, "%s%s %s %d\n", SYMBOL_PREFIX, name, DirectiveAsString(kLong),
value);
}
void PlatformEmbeddedFileWriterWin::StartPdataSection() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " AREA |.pdata|, DATA, ALIGN=%d, READONLY\n",
ARM64_DATA_ALIGNMENT_POWER);
} else {
fprintf(fp_, "OPTION DOTNAME\n");
fprintf(fp_, ".pdata SEGMENT DWORD READ ''\n");
}
}
void PlatformEmbeddedFileWriterWin::EndPdataSection() {
if (target_arch_ != EmbeddedTargetArch::kArm64) {
fprintf(fp_, ".pdata ENDS\n");
}
}
void PlatformEmbeddedFileWriterWin::StartXdataSection() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " AREA |.xdata|, DATA, ALIGN=%d, READONLY\n",
ARM64_DATA_ALIGNMENT_POWER);
} else {
fprintf(fp_, "OPTION DOTNAME\n");
fprintf(fp_, ".xdata SEGMENT DWORD READ ''\n");
}
}
void PlatformEmbeddedFileWriterWin::EndXdataSection() {
if (target_arch_ != EmbeddedTargetArch::kArm64) {
fprintf(fp_, ".xdata ENDS\n");
}
}
void PlatformEmbeddedFileWriterWin::DeclareExternalFunction(const char* name) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " EXTERN %s \n", name);
} else {
fprintf(fp_, "EXTERN %s : PROC\n", name);
}
}
void PlatformEmbeddedFileWriterWin::DeclareRvaToSymbol(const char* name,
uint64_t offset) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
if (offset > 0) {
fprintf(fp_, " DCD %s + %llu\n", name, offset);
} else {
fprintf(fp_, " DCD %s\n", name);
}
fprintf(fp_, " RELOC 2\n");
} else {
if (offset > 0) {
fprintf(fp_, "DD IMAGEREL %s+%llu\n", name, offset);
} else {
fprintf(fp_, "DD IMAGEREL %s\n", name);
}
}
}
void PlatformEmbeddedFileWriterWin::DeclareSymbolGlobal(const char* name) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " EXPORT %s%s\n", SYMBOL_PREFIX, name);
} else {
fprintf(fp_, "PUBLIC %s%s\n", SYMBOL_PREFIX, name);
}
}
void PlatformEmbeddedFileWriterWin::AlignToCodeAlignment() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " ALIGN %d\n", ARM64_CODE_ALIGNMENT);
} else {
fprintf(fp_, "ALIGN 4\n");
}
}
void PlatformEmbeddedFileWriterWin::AlignToDataAlignment() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " ALIGN %d\n", ARM64_DATA_ALIGNMENT);
} else {
fprintf(fp_, "ALIGN 4\n");
}
}
void PlatformEmbeddedFileWriterWin::Comment(const char* string) {
fprintf(fp_, "; %s\n", string);
}
void PlatformEmbeddedFileWriterWin::DeclareLabel(const char* name) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, "%s%s\n", SYMBOL_PREFIX, name);
} else {
fprintf(fp_, "%s%s LABEL %s\n", SYMBOL_PREFIX, name,
DirectiveAsString(kByte));
}
}
void PlatformEmbeddedFileWriterWin::SourceInfo(int fileid, const char* filename,
int line) {
}
void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name,
uint32_t size) {
if (ENABLE_CONTROL_FLOW_INTEGRITY_BOOL) {
DeclareSymbolGlobal(name);
}
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, "%s%s FUNCTION\n", SYMBOL_PREFIX, name);
} else {
fprintf(fp_, "%s%s PROC\n", SYMBOL_PREFIX, name);
}
}
void PlatformEmbeddedFileWriterWin::DeclareFunctionEnd(const char* name) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " ENDFUNC\n");
} else {
fprintf(fp_, "%s%s ENDP\n", SYMBOL_PREFIX, name);
}
}
int PlatformEmbeddedFileWriterWin::HexLiteral(uint64_t value) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
return fprintf(fp_, "0x%" PRIx64, value);
} else {
return fprintf(fp_, "0%" PRIx64 "h", value);
}
}
void PlatformEmbeddedFileWriterWin::FilePrologue() {
if (target_arch_ != EmbeddedTargetArch::kArm64 &&
target_arch_ != EmbeddedTargetArch::kX64) {
fprintf(fp_, ".MODEL FLAT\n");
}
}
void PlatformEmbeddedFileWriterWin::DeclareExternalFilename(
int fileid, const char* filename) {}
void PlatformEmbeddedFileWriterWin::FileEpilogue() {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
fprintf(fp_, " END\n");
} else {
fprintf(fp_, "END\n");
}
}
int PlatformEmbeddedFileWriterWin::IndentedDataDirective(
DataDirective directive) {
return fprintf(fp_, " %s ", DirectiveAsString(directive));
}
#undef ARM64_DATA_ALIGNMENT_POWER
#undef ARM64_DATA_ALIGNMENT
#undef ARM64_CODE_ALIGNMENT_POWER
#undef ARM64_CODE_ALIGNMENT
#else
void PlatformEmbeddedFileWriterWin::SectionText() { … }
void PlatformEmbeddedFileWriterWin::SectionRoData() { … }
void PlatformEmbeddedFileWriterWin::DeclareUint32(const char* name,
uint32_t value) { … }
void PlatformEmbeddedFileWriterWin::StartPdataSection() { … }
void PlatformEmbeddedFileWriterWin::EndPdataSection() { … }
void PlatformEmbeddedFileWriterWin::StartXdataSection() { … }
void PlatformEmbeddedFileWriterWin::EndXdataSection() { … }
void PlatformEmbeddedFileWriterWin::DeclareExternalFunction(const char* name) { … }
void PlatformEmbeddedFileWriterWin::DeclareRvaToSymbol(const char* name,
uint64_t offset) { … }
void PlatformEmbeddedFileWriterWin::DeclareSymbolGlobal(const char* name) { … }
void PlatformEmbeddedFileWriterWin::AlignToCodeAlignment() { … }
void PlatformEmbeddedFileWriterWin::AlignToDataAlignment() { … }
void PlatformEmbeddedFileWriterWin::Comment(const char* string) { … }
void PlatformEmbeddedFileWriterWin::DeclareLabel(const char* name) { … }
void PlatformEmbeddedFileWriterWin::SourceInfo(int fileid, const char* filename,
int line) { … }
void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name,
uint32_t size) { … }
void PlatformEmbeddedFileWriterWin::DeclareFunctionEnd(const char* name) { … }
int PlatformEmbeddedFileWriterWin::HexLiteral(uint64_t value) { … }
void PlatformEmbeddedFileWriterWin::FilePrologue() { … }
void PlatformEmbeddedFileWriterWin::DeclareExternalFilename(
int fileid, const char* filename) { … }
void PlatformEmbeddedFileWriterWin::FileEpilogue() { … }
int PlatformEmbeddedFileWriterWin::IndentedDataDirective(
DataDirective directive) { … }
#endif
DataDirective PlatformEmbeddedFileWriterWin::ByteChunkDataDirective() const { … }
int PlatformEmbeddedFileWriterWin::WriteByteChunk(const uint8_t* data) { … }
#undef SYMBOL_PREFIX
#undef V8_ASSEMBLER_IS_MASM
#undef V8_ASSEMBLER_IS_MARMASM
#undef V8_COMPILER_IS_MSVC
}
}