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-generic.h"
6
7#include <algorithm>
8#include <cinttypes>
9
10#include "src/common/globals.h"
11#include "src/objects/code.h"
12
13namespace v8 {
14namespace internal {
15
16#define SYMBOL_PREFIX ""
17
18namespace {
19
20const char* DirectiveAsString(DataDirective directive) {
21  switch (directive) {
22    case kByte:
23      return ".byte";
24    case kLong:
25      return ".long";
26    case kQuad:
27      return ".quad";
28    case kOcta:
29      return ".octa";
30  }
31  UNREACHABLE();
32}
33
34}  // namespace
35
36void PlatformEmbeddedFileWriterGeneric::SectionText() {
37  if (target_os_ == EmbeddedTargetOs::kChromeOS) {
38    fprintf(fp_, ".section .text.hot.embedded\n");
39  } else {
40    fprintf(fp_, ".section .text\n");
41  }
42}
43
44void PlatformEmbeddedFileWriterGeneric::SectionData() {
45  fprintf(fp_, ".section .data\n");
46}
47
48void PlatformEmbeddedFileWriterGeneric::SectionRoData() {
49  fprintf(fp_, ".section .rodata\n");
50}
51
52void PlatformEmbeddedFileWriterGeneric::DeclareUint32(const char* name,
53                                                      uint32_t value) {
54  DeclareSymbolGlobal(name);
55  DeclareLabel(name);
56  IndentedDataDirective(kLong);
57  fprintf(fp_, "%d", value);
58  Newline();
59}
60
61void PlatformEmbeddedFileWriterGeneric::DeclarePointerToSymbol(
62    const char* name, const char* target) {
63  DeclareSymbolGlobal(name);
64  DeclareLabel(name);
65  fprintf(fp_, "  %s %s%s\n", DirectiveAsString(PointerSizeDirective()),
66          SYMBOL_PREFIX, target);
67}
68
69void PlatformEmbeddedFileWriterGeneric::DeclareSymbolGlobal(const char* name) {
70  fprintf(fp_, ".global %s%s\n", SYMBOL_PREFIX, name);
71  // These symbols are not visible outside of the final binary, this allows for
72  // reduced binary size, and less work for the dynamic linker.
73  fprintf(fp_, ".hidden %s\n", name);
74}
75
76void PlatformEmbeddedFileWriterGeneric::AlignToCodeAlignment() {
77#if V8_TARGET_ARCH_X64
78  // On x64 use 64-bytes code alignment to allow 64-bytes loop header alignment.
79  STATIC_ASSERT(64 >= kCodeAlignment);
80  fprintf(fp_, ".balign 64\n");
81#elif V8_TARGET_ARCH_PPC64
82  // 64 byte alignment is needed on ppc64 to make sure p10 prefixed instructions
83  // don't cross 64-byte boundaries.
84  STATIC_ASSERT(64 >= kCodeAlignment);
85  fprintf(fp_, ".balign 64\n");
86#else
87  STATIC_ASSERT(32 >= kCodeAlignment);
88  fprintf(fp_, ".balign 32\n");
89#endif
90}
91
92void PlatformEmbeddedFileWriterGeneric::AlignToDataAlignment() {
93  // On Windows ARM64, s390, PPC and possibly more platforms, aligned load
94  // instructions are used to retrieve v8_Default_embedded_blob_ and/or
95  // v8_Default_embedded_blob_size_. The generated instructions require the
96  // load target to be aligned at 8 bytes (2^3).
97  STATIC_ASSERT(8 >= Code::kMetadataAlignment);
98  fprintf(fp_, ".balign 8\n");
99}
100
101void PlatformEmbeddedFileWriterGeneric::Comment(const char* string) {
102  fprintf(fp_, "// %s\n", string);
103}
104
105void PlatformEmbeddedFileWriterGeneric::DeclareLabel(const char* name) {
106  fprintf(fp_, "%s%s:\n", SYMBOL_PREFIX, name);
107}
108
109void PlatformEmbeddedFileWriterGeneric::SourceInfo(int fileid,
110                                                   const char* filename,
111                                                   int line) {
112  fprintf(fp_, ".loc %d %d\n", fileid, line);
113}
114
115void PlatformEmbeddedFileWriterGeneric::DeclareFunctionBegin(const char* name,
116                                                             uint32_t size) {
117  if (ENABLE_CONTROL_FLOW_INTEGRITY_BOOL) {
118    DeclareSymbolGlobal(name);
119  }
120
121  DeclareLabel(name);
122
123  if (target_arch_ == EmbeddedTargetArch::kArm ||
124      target_arch_ == EmbeddedTargetArch::kArm64) {
125    // ELF format binaries on ARM use ".type <function name>, %function"
126    // to create a DWARF subprogram entry.
127    fprintf(fp_, ".type %s, %%function\n", name);
128  } else {
129    // Other ELF Format binaries use ".type <function name>, @function"
130    // to create a DWARF subprogram entry.
131    fprintf(fp_, ".type %s, @function\n", name);
132  }
133  fprintf(fp_, ".size %s, %u\n", name, size);
134}
135
136void PlatformEmbeddedFileWriterGeneric::DeclareFunctionEnd(const char* name) {}
137
138void PlatformEmbeddedFileWriterGeneric::FilePrologue() {}
139
140void PlatformEmbeddedFileWriterGeneric::DeclareExternalFilename(
141    int fileid, const char* filename) {
142  // Replace any Windows style paths (backslashes) with forward
143  // slashes.
144  std::string fixed_filename(filename);
145  std::replace(fixed_filename.begin(), fixed_filename.end(), '\\', '/');
146  fprintf(fp_, ".file %d \"%s\"\n", fileid, fixed_filename.c_str());
147}
148
149void PlatformEmbeddedFileWriterGeneric::FileEpilogue() {
150  // Omitting this section can imply an executable stack, which is usually
151  // a linker warning/error. C++ compilers add these automatically, but
152  // compiling assembly requires the .note.GNU-stack section to be inserted
153  // manually.
154  // Additional documentation:
155  // https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart
156  fprintf(fp_, ".section .note.GNU-stack,\"\",%%progbits\n");
157}
158
159int PlatformEmbeddedFileWriterGeneric::IndentedDataDirective(
160    DataDirective directive) {
161  return fprintf(fp_, "  %s ", DirectiveAsString(directive));
162}
163
164DataDirective PlatformEmbeddedFileWriterGeneric::ByteChunkDataDirective()
165    const {
166#if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \
167    defined(V8_TARGET_ARCH_LOONG64)
168  // MIPS and LOONG64 uses a fixed 4 byte instruction set, using .long
169  // to prevent any unnecessary padding.
170  return kLong;
171#else
172  // Other ISAs just listen to the base
173  return PlatformEmbeddedFileWriterBase::ByteChunkDataDirective();
174#endif
175}
176
177#undef SYMBOL_PREFIX
178
179}  // namespace internal
180}  // namespace v8
181