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   STATIC_ASSERT(32 >= kCodeAlignment);
78   fprintf(fp_, ".balign 32\n");
79 }
80 
AlignToDataAlignment()81 void PlatformEmbeddedFileWriterGeneric::AlignToDataAlignment() {
82   // On Windows ARM64, s390, PPC and possibly more platforms, aligned load
83   // instructions are used to retrieve v8_Default_embedded_blob_ and/or
84   // v8_Default_embedded_blob_size_. The generated instructions require the
85   // load target to be aligned at 8 bytes (2^3).
86   STATIC_ASSERT(8 >= Code::kMetadataAlignment);
87   fprintf(fp_, ".balign 8\n");
88 }
89 
Comment(const char * string)90 void PlatformEmbeddedFileWriterGeneric::Comment(const char* string) {
91   fprintf(fp_, "// %s\n", string);
92 }
93 
DeclareLabel(const char * name)94 void PlatformEmbeddedFileWriterGeneric::DeclareLabel(const char* name) {
95   fprintf(fp_, "%s%s:\n", SYMBOL_PREFIX, name);
96 }
97 
SourceInfo(int fileid,const char * filename,int line)98 void PlatformEmbeddedFileWriterGeneric::SourceInfo(int fileid,
99                                                    const char* filename,
100                                                    int line) {
101   fprintf(fp_, ".loc %d %d\n", fileid, line);
102 }
103 
DeclareFunctionBegin(const char * name,uint32_t size)104 void PlatformEmbeddedFileWriterGeneric::DeclareFunctionBegin(const char* name,
105                                                              uint32_t size) {
106   if (ENABLE_CONTROL_FLOW_INTEGRITY_BOOL) {
107     DeclareSymbolGlobal(name);
108   }
109 
110   DeclareLabel(name);
111 
112   if (target_arch_ == EmbeddedTargetArch::kArm ||
113       target_arch_ == EmbeddedTargetArch::kArm64) {
114     // ELF format binaries on ARM use ".type <function name>, %function"
115     // to create a DWARF subprogram entry.
116     fprintf(fp_, ".type %s, %%function\n", name);
117   } else {
118     // Other ELF Format binaries use ".type <function name>, @function"
119     // to create a DWARF subprogram entry.
120     fprintf(fp_, ".type %s, @function\n", name);
121   }
122   fprintf(fp_, ".size %s, %u\n", name, size);
123 }
124 
DeclareFunctionEnd(const char * name)125 void PlatformEmbeddedFileWriterGeneric::DeclareFunctionEnd(const char* name) {}
126 
FilePrologue()127 void PlatformEmbeddedFileWriterGeneric::FilePrologue() {
128   // TODO(v8:10026): Add ELF note required for BTI.
129 }
130 
DeclareExternalFilename(int fileid,const char * filename)131 void PlatformEmbeddedFileWriterGeneric::DeclareExternalFilename(
132     int fileid, const char* filename) {
133   // Replace any Windows style paths (backslashes) with forward
134   // slashes.
135   std::string fixed_filename(filename);
136   std::replace(fixed_filename.begin(), fixed_filename.end(), '\\', '/');
137   fprintf(fp_, ".file %d \"%s\"\n", fileid, fixed_filename.c_str());
138 }
139 
FileEpilogue()140 void PlatformEmbeddedFileWriterGeneric::FileEpilogue() {
141   // Omitting this section can imply an executable stack, which is usually
142   // a linker warning/error. C++ compilers add these automatically, but
143   // compiling assembly requires the .note.GNU-stack section to be inserted
144   // manually.
145   // Additional documentation:
146   // https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart
147   fprintf(fp_, ".section .note.GNU-stack,\"\",%%progbits\n");
148 }
149 
IndentedDataDirective(DataDirective directive)150 int PlatformEmbeddedFileWriterGeneric::IndentedDataDirective(
151     DataDirective directive) {
152   return fprintf(fp_, "  %s ", DirectiveAsString(directive));
153 }
154 
ByteChunkDataDirective() const155 DataDirective PlatformEmbeddedFileWriterGeneric::ByteChunkDataDirective()
156     const {
157 #if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)
158   // MIPS uses a fixed 4 byte instruction set, using .long
159   // to prevent any unnecessary padding.
160   return kLong;
161 #else
162   // Other ISAs just listen to the base
163   return PlatformEmbeddedFileWriterBase::ByteChunkDataDirective();
164 #endif
165 }
166 
167 #undef SYMBOL_PREFIX
168 
169 }  // namespace internal
170 }  // namespace v8
171