Home | History | Annotate | Download | only in libc
      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