1 // Copyright 2017, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include "code-buffer-vixl.h"
28 #include "utils-vixl.h"
29
30 namespace vixl {
31
CodeBuffer(size_t capacity)32 CodeBuffer::CodeBuffer(size_t capacity)
33 : buffer_(NULL),
34 managed_(true),
35 cursor_(NULL),
36 dirty_(false),
37 capacity_(capacity) {
38 if (capacity_ == 0) {
39 return;
40 }
41 #ifdef VIXL_CODE_BUFFER_MALLOC
42 buffer_ = reinterpret_cast<byte*>(malloc(capacity_));
43 #elif defined(VIXL_CODE_BUFFER_MMAP)
44 buffer_ = reinterpret_cast<byte*>(mmap(NULL,
45 capacity,
46 PROT_READ | PROT_WRITE,
47 MAP_PRIVATE | MAP_ANONYMOUS,
48 -1,
49 0));
50 #else
51 #error Unknown code buffer allocator.
52 #endif
53 VIXL_CHECK(buffer_ != NULL);
54 // Aarch64 instructions must be word aligned, we assert the default allocator
55 // always returns word align memory.
56 if (buffer_ != MAP_FAILED) {
57 VIXL_ASSERT(IsWordAligned(buffer_));
58 cursor_ = buffer_;
59 }
60 }
61
62
CodeBuffer(byte* buffer, size_t capacity)63 CodeBuffer::CodeBuffer(byte* buffer, size_t capacity)
64 : buffer_(reinterpret_cast<byte*>(buffer)),
65 managed_(false),
66 cursor_(reinterpret_cast<byte*>(buffer)),
67 dirty_(false),
68 capacity_(capacity) {
69 VIXL_ASSERT(buffer_ != NULL);
70 }
71
72
73 CodeBuffer::~CodeBuffer() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION {
74 // VIXL_ASSERT(!IsDirty()); // Use own allocator - not applied
75 if (managed_) {
76 #ifdef VIXL_CODE_BUFFER_MALLOC
77 free(buffer_);
78 #elif defined(VIXL_CODE_BUFFER_MMAP)
79 if (buffer_ != MAP_FAILED) {
80 [[maybe_unused]] int res = munmap(buffer_, capacity_);
81 // Success unmap position
82 VIXL_ASSERT(res == 0);
83 if ((mmap_max_ != 0) && (capacity_ > mmap_max_)) {
84 // Force crash - allocated too much
85 printf(" Allocated too much memory.\n");
86 VIXL_UNREACHABLE();
87 }
88 }
89 #else
90 #error Unknown code buffer allocator.
91 #endif
92 }
93 }
94
95
SetExecutable()96 void CodeBuffer::SetExecutable() {
97 #ifdef VIXL_CODE_BUFFER_MMAP
98 int ret = mprotect(buffer_, capacity_, PROT_READ | PROT_EXEC);
99 VIXL_CHECK(ret == 0);
100 #else
101 // This requires page-aligned memory blocks, which we can only guarantee with
102 // mmap.
103 VIXL_UNIMPLEMENTED();
104 #endif
105 }
106
107
SetWritable()108 void CodeBuffer::SetWritable() {
109 #ifdef VIXL_CODE_BUFFER_MMAP
110 int ret = mprotect(buffer_, capacity_, PROT_READ | PROT_WRITE);
111 VIXL_CHECK(ret == 0);
112 #else
113 // This requires page-aligned memory blocks, which we can only guarantee with
114 // mmap.
115 VIXL_UNIMPLEMENTED();
116 #endif
117 }
118
119 // For some reason OHOS toolchain doesn't have this function
120 #ifdef PANDA_TARGET_MOBILE
stpcpy(char *dst, const char *src)121 char* stpcpy (char *dst, const char *src) {
122 const size_t len = strlen (src);
123 return (char *) memcpy (dst, src, len + 1) + len;
124 }
125 #endif
126
EmitString(const char* string)127 void CodeBuffer::EmitString(const char* string) {
128 const auto len = strlen(string) + 1;
129 VIXL_ASSERT(HasSpaceFor(len));
130 char* dst = reinterpret_cast<char*>(cursor_);
131 dirty_ = true;
132 memcpy(dst, string, len);
133 cursor_ = reinterpret_cast<byte*>(dst + len);
134 }
135
136
EmitData(const void* data, size_t size)137 void CodeBuffer::EmitData(const void* data, size_t size) {
138 VIXL_ASSERT(HasSpaceFor(size));
139 dirty_ = true;
140 memcpy(cursor_, data, size);
141 cursor_ = cursor_ + size;
142 }
143
144
UpdateData(size_t offset, const void* data, size_t size)145 void CodeBuffer::UpdateData(size_t offset, const void* data, size_t size) {
146 dirty_ = true;
147 byte* dst = buffer_ + offset;
148 VIXL_ASSERT(dst + size <= cursor_);
149 memcpy(dst, data, size);
150 }
151
152
Align()153 void CodeBuffer::Align() {
154 byte* end = AlignUp(cursor_, 4);
155 const size_t padding_size = end - cursor_;
156 VIXL_ASSERT(padding_size <= 4);
157 EmitZeroedBytes(static_cast<int>(padding_size));
158 }
159
EmitZeroedBytes(int n)160 void CodeBuffer::EmitZeroedBytes(int n) {
161 EnsureSpaceFor(n);
162 dirty_ = true;
163 memset(cursor_, 0, n);
164 cursor_ += n;
165 }
166
Reset()167 void CodeBuffer::Reset() {
168 #ifdef VIXL_DEBUG
169 if (managed_) {
170 // Fill with zeros (there is no useful value common to A32 and T32).
171 memset(buffer_, 0, capacity_);
172 }
173 #endif
174 cursor_ = buffer_;
175 SetClean();
176 }
177
178
Grow(size_t new_capacity)179 void CodeBuffer::Grow(size_t new_capacity) {
180 VIXL_ASSERT(managed_);
181 VIXL_ASSERT(new_capacity > capacity_);
182 ptrdiff_t cursor_offset = GetCursorOffset();
183 VIXL_ASSERT(false);
184 // Do not support grow with our allocators
185 #ifdef VIXL_CODE_BUFFER_MALLOC
186 buffer_ = static_cast<byte*>(realloc(buffer_, new_capacity));
187 VIXL_CHECK(buffer_ != NULL);
188 #elif defined(VIXL_CODE_BUFFER_MMAP)
189 buffer_ = static_cast<byte*>(
190 mremap(buffer_, capacity_, new_capacity, MREMAP_MAYMOVE));
191 VIXL_CHECK(buffer_ != MAP_FAILED);
192 if ((mmap_max_ != 0) && (new_capacity > mmap_max_)) {
193 // Force crash - allocated too much
194 printf(" Allocated too much memory.\n");
195 VIXL_UNREACHABLE();
196 }
197 #else
198 #error Unknown code buffer allocator.
199 #endif
200 cursor_ = buffer_ + cursor_offset;
201 capacity_ = new_capacity;
202 }
203
204
205 } // namespace vixl
206