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
13 namespace v8 {
14 namespace internal {
15
16 #define SYMBOL_PREFIX ""
17
18 namespace {
19
DirectiveAsString(DataDirective directive)20 const 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
SectionText()36 void 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
SectionData()44 void PlatformEmbeddedFileWriterGeneric::SectionData() {
45 fprintf(fp_, ".section .data\n");
46 }
47
SectionRoData()48 void PlatformEmbeddedFileWriterGeneric::SectionRoData() {
49 fprintf(fp_, ".section .rodata\n");
50 }
51
DeclareUint32(const char* name, uint32_t value)52 void 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
DeclarePointerToSymbol( const char* name, const char* target)61 void 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
DeclareSymbolGlobal(const char* name)69 void 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
AlignToCodeAlignment()76 void 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
AlignToDataAlignment()92 void 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
Comment(const char* string)101 void PlatformEmbeddedFileWriterGeneric::Comment(const char* string) {
102 fprintf(fp_, "// %s\n", string);
103 }
104
DeclareLabel(const char* name)105 void PlatformEmbeddedFileWriterGeneric::DeclareLabel(const char* name) {
106 fprintf(fp_, "%s%s:\n", SYMBOL_PREFIX, name);
107 }
108
SourceInfo(int fileid, const char* filename, int line)109 void PlatformEmbeddedFileWriterGeneric::SourceInfo(int fileid,
110 const char* filename,
111 int line) {
112 fprintf(fp_, ".loc %d %d\n", fileid, line);
113 }
114
DeclareFunctionBegin(const char* name, uint32_t size)115 void 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
DeclareFunctionEnd(const char* name)136 void PlatformEmbeddedFileWriterGeneric::DeclareFunctionEnd(const char* name) {}
137
FilePrologue()138 void PlatformEmbeddedFileWriterGeneric::FilePrologue() {}
139
DeclareExternalFilename( int fileid, const char* filename)140 void 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
FileEpilogue()149 void 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
IndentedDataDirective( DataDirective directive)159 int PlatformEmbeddedFileWriterGeneric::IndentedDataDirective(
160 DataDirective directive) {
161 return fprintf(fp_, " %s ", DirectiveAsString(directive));
162 }
163
ByteChunkDataDirective() const164 DataDirective 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