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