1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * THis file is based on the template provided in the reference doc: 19 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041e/IHI0041E_cppabi.pdf 20 * 21 * ARM reference implementation is not changed, except as follows: 22 * 23 * 1 Function prototypes added to avoid compiler warning "no previous function declaration". 24 * Since all of those are internal functions presumably exclusively used by the compiler, 25 * I decided not to provide header file for those and embed function prototypes in the source. 26 * 27 * 2 Methods calling into __cxa_*() primitives; 28 * I decided to not implement such __cxa_*() primitives, and code the functionality directly in aeabi. 29 * this works because the toolchain we use is generating calls to aeabi, and not generic calls. 30 * Decision was made to simplify the solution, because generic code must take care of more corner 31 * cases than necessary in ARM case. 32 * strictly speaking, aeabi.cpp is ARM-specific and should be annotated as such. 33 * This is easy to do in Android.mk build, but not that easy with original Makefile build. 34 * For now, I'm going to ignore both the missing ARM-specific annotation, and missing 35 * certain __cxa_*() calls; I'll deal with both when it comes to that (i.e. when we actually 36 * have an offending use case). 37 * 38 * 3 __aeabi_atexit() was originally calling __cxa_atexit(); I changed that to do-nothing stub; 39 * this is because dynamic registration of destructors as per standard would require one to reserve 40 * sizeof(uintptr_t) * 32 bytes (i.e. 128 bytes on ARM Cortex M4) to comply with standard, 41 * and on top of that, be able to register variable amount of destructor methods (which may be of any size). 42 * possible solution would be to reserve extra space for BSS as boot time, and release extra space 43 * after init is done, however this does not solve entire problem, only global part of it, since 44 * local static registration may happen at any time. 45 * Another possible solution is to provide size of destructor allocation heap at build time; 46 * I reserved a field for that in application data segment for future use. 47 */ 48 49 #include <cstddef> 50 #include <cstdint> 51 #include <cxxabi.h> 52 53 using namespace __cxxabiv1; 54 55 namespace __aeabiv1 { 56 57 using ::std::size_t; 58 59 // Note: Only the __aeabi_* names are exported. 60 // array_cookie, cookie_size, cookie_of, etc. are presented for exposition only. 61 // They are not expected to be available to users, but implementers may find them useful. 62 struct array_cookie { 63 size_t element_size; // element_size != 0 64 size_t element_count; 65 }; 66 // The struct array_cookie fields and the arguments element_size and element_count 67 // are ordered for convenient use of LDRD/STRD on architecture 5TE and above. 68 const size_t cookie_size = sizeof(array_cookie); 69 70 // cookie_of() takes a pointer to the user array and returns a reference to the cookie. 71 inline array_cookie& cookie_of(void* user_array) 72 { 73 return reinterpret_cast<array_cookie*>(user_array)[-1]; 74 } 75 76 // element_size_of() takes a pointer to the user array and returns a reference to the 77 // element_size field of the cookie. 78 inline size_t& element_size_of(void* user_array) 79 { 80 return cookie_of(user_array).element_size; 81 } 82 83 // element_count_of() takes a pointer to the user array and returns a reference to the 84 // element_count field of the cookie. 85 inline size_t& element_count_of(void* user_array) 86 { 87 return cookie_of(user_array).element_count; 88 } 89 90 // user_array_of() takes a pointer to the cookie and returns a pointer to the user array. 91 inline void* user_array_of(array_cookie* cookie_address) 92 { 93 return cookie_address + 1; 94 } 95 96 extern "C" void* __aeabi_vec_ctor_nocookie_nodtor(void* user_array, 97 void* (*constructor)(void*), 98 size_t element_size, size_t element_count); 99 extern "C" void* __aeabi_vec_ctor_cookie_nodtor(array_cookie* cookie, 100 void*(*constructor)(void*), 101 size_t element_size, size_t element_count); 102 extern "C" void* __aeabi_vec_cctor_nocookie_nodtor(void* user_array_dest, 103 void* user_array_src, 104 size_t element_size, size_t element_count, 105 void* (*copy_constructor)(void*, void*)); 106 extern "C" void* __aeabi_vec_new_cookie_noctor(size_t element_size, size_t element_count); 107 extern "C" int __aeabi_atexit(void* object, void (*destroyer)(void*), void* dso_handle); 108 extern "C" void __aeabi_vec_delete3_nodtor(void* user_array, void (*dealloc)(void*, size_t)); 109 extern "C" void __aeabi_vec_delete3(void* user_array, void* (*destructor)(void*), 110 void (*dealloc)(void*, size_t)); 111 extern "C" void __aeabi_vec_delete(void* user_array, void* (*destructor)(void*)); 112 extern "C" void* __aeabi_vec_dtor_cookie(void* user_array, void* (*destructor)(void*)); 113 extern "C" void* __aeabi_vec_dtor(void* user_array, 114 void* (*destructor)(void*), 115 size_t element_size, size_t element_count); 116 extern "C" void* __aeabi_vec_new_cookie(size_t element_size, size_t element_count, 117 void* (*constructor)(void*), 118 void* (*destructor)(void*)); 119 extern "C" void* __aeabi_vec_new_cookie_nodtor(size_t element_size, 120 size_t element_count, 121 void* (*constructor)(void*)); 122 extern "C" void* __aeabi_vec_new_nocookie(size_t element_size, size_t element_count, 123 void* (*constructor)(void*)); 124 125 extern "C" void* __aeabi_vec_ctor_nocookie_nodtor(void* user_array, 126 void* (*constructor)(void*), 127 size_t element_size, size_t element_count) 128 { 129 if (constructor != nullptr) { 130 uintptr_t addr = reinterpret_cast<uintptr_t>(user_array); 131 for (size_t i = 0; i < element_count; ++i, addr += element_size) { 132 constructor(reinterpret_cast<void*>(addr)); 133 } 134 } 135 return user_array; 136 } 137 138 // __aeabi_vec_ctor_cookie_nodtor is like __aeabi_vec_ctor_nocookie_nodtor but sets 139 // cookie fields and returns user_array. The parameters are arranged to make STRD 140 // usable. Does nothing and returns NULL if cookie is NULL. 141 extern "C" void* __aeabi_vec_ctor_cookie_nodtor(array_cookie* cookie, 142 void*(*constructor)(void*), 143 size_t element_size, size_t element_count) 144 { 145 if (cookie == nullptr) { 146 return nullptr; 147 } else { 148 cookie->element_size = element_size; 149 cookie->element_count = element_count; 150 return __aeabi_vec_ctor_nocookie_nodtor(user_array_of(cookie), constructor, 151 element_size, element_count); 152 } 153 } 154 155 extern "C" void* __aeabi_vec_cctor_nocookie_nodtor(void* user_array_dest, 156 void* user_array_src, 157 size_t element_size, size_t element_count, 158 void* (*copy_constructor)(void*, void*)) 159 { 160 if (copy_constructor != nullptr) { 161 uintptr_t src_addr = reinterpret_cast<uintptr_t>(user_array_src); 162 uintptr_t dest_addr = reinterpret_cast<uintptr_t>(user_array_dest); 163 for (size_t i = 0; i < element_count; ++i, src_addr += element_size, dest_addr += element_size) { 164 copy_constructor(reinterpret_cast<void*>(dest_addr), reinterpret_cast<void*>(src_addr)); 165 } 166 } 167 return user_array_dest; 168 } 169 170 extern "C" void* __aeabi_vec_new_cookie_noctor(size_t element_size, size_t element_count) 171 { 172 array_cookie* cookie = reinterpret_cast<array_cookie*>( 173 ::operator new[](element_count * element_size + cookie_size) 174 ); 175 cookie->element_size = element_size; 176 cookie->element_count = element_count; 177 return user_array_of(cookie); 178 } 179 180 extern "C" void* __aeabi_vec_new_nocookie(size_t element_size, size_t element_count, 181 void* (*constructor)(void*)) 182 { 183 return __aeabi_vec_ctor_nocookie_nodtor(::operator new[](element_count * element_size), 184 constructor, element_size, element_count); 185 } 186 187 extern "C" void* __aeabi_vec_new_cookie_nodtor(size_t element_size, 188 size_t element_count, 189 void* (*constructor)(void*)) 190 { 191 array_cookie* cookie = reinterpret_cast<array_cookie*>( 192 ::operator new[](element_count * element_size + cookie_size) 193 ); 194 return __aeabi_vec_ctor_cookie_nodtor(cookie, constructor, element_size, element_count); 195 } 196 197 extern "C" void* __aeabi_vec_new_cookie(size_t element_size, size_t element_count, 198 void* (*constructor)(void*), 199 void* (*destructor)(void*)) 200 { 201 return __aeabi_vec_new_cookie_nodtor(element_size, element_count, constructor); 202 } 203 204 // __aeabi_vec_dtor is like __cxa_vec_dtor but has its parameters reordered and returns 205 // a pointer to the cookie (assuming user_array has one). 206 // Unlike __cxa_vec_dtor, destructor must not be NULL. 207 // user_array must not be NULL. 208 extern "C" void* __aeabi_vec_dtor(void* user_array, 209 void* (*destructor)(void*), 210 size_t element_size, size_t element_count) 211 { 212 uintptr_t addr = reinterpret_cast<uintptr_t>(user_array); 213 for (size_t i = 0; i < element_count; ++i, addr += element_size) { 214 destructor(reinterpret_cast<void*>(addr)); 215 } 216 return &cookie_of(user_array); 217 } 218 219 // __aeabi_vec_dtor_cookie is only used on arrays that have cookies. 220 // __aeabi_vec_dtor is like __cxa_vec_dtor but returns a pointer to the cookie. 221 // That is, it takes a pointer to the user array, calls the given destructor on 222 // each element (from highest index down to zero) and returns a pointer to the cookie. 223 // Does nothing and returns NULL if cookie is NULL. 224 // Unlike __cxa_vec_dtor, destructor must not be NULL. 225 // Exceptions are handled as in __cxa_vec_dtor. 226 // __aeabi_vec_dtor_cookie must not change the element count in the cookie. 227 // (But it may corrupt the element size if desired.) 228 extern "C" void* __aeabi_vec_dtor_cookie(void* user_array, void* (*destructor)(void*)) 229 { 230 return user_array == nullptr ? nullptr : 231 __aeabi_vec_dtor(user_array, destructor, 232 element_size_of(user_array), 233 element_count_of(user_array)); 234 } 235 236 extern "C" void __aeabi_vec_delete(void* user_array, void* (*destructor)(void*)) 237 { 238 ::operator delete[](__aeabi_vec_dtor_cookie(user_array, destructor)); 239 } 240 241 extern "C" void __aeabi_vec_delete3(void* user_array, void* (*destructor)(void*), void (*dealloc)(void*, size_t)) 242 { 243 if (user_array != NULL) { 244 size_t size = element_size_of(user_array) * element_count_of(user_array) + cookie_size; 245 void *array_cookie = __aeabi_vec_dtor_cookie(user_array, destructor); 246 dealloc(array_cookie, size); 247 } 248 } 249 250 extern "C" void __aeabi_vec_delete3_nodtor(void* user_array, void (*dealloc)(void*, size_t)) 251 { 252 if (user_array != NULL) { 253 size_t size = element_size_of(user_array) * element_count_of(user_array) + cookie_size; 254 (*dealloc)(&cookie_of(user_array), size); 255 } 256 } 257 258 extern "C" int __aeabi_atexit(void* object, void (*destroyer)(void*), void* dso_handle) 259 { 260 return 0; 261 } 262 263 } // namespace __aeabiv1 264