Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtl
0007  *
0008  * @brief RTEMS Run-Time Linker Allocator
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 2012, 2018, 2023 Chris Johns <chrisj@rtems.org>
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <stdio.h>
0037 #include <string.h>
0038 
0039 #include <rtems/rtl/rtl.h>
0040 #include "rtl-alloc-heap.h"
0041 #include <rtems/rtl/rtl-trace.h>
0042 
0043 /**
0044  * Tags as symbols for tracing.
0045  */
0046 #if RTEMS_RTL_TRACE
0047 static const char* tag_labels[6] =
0048 {
0049   "OBJECT",
0050   "SYMBOL",
0051   "EXTERNAL",
0052   "READ",
0053   "READ_WRITE",
0054   "READ_EXEC",
0055 };
0056 #define rtems_rtl_trace_tag_label(_l) tag_labels[_l]
0057 #else
0058 #define rtems_rtl_trace_tag_label(_l) ""
0059 #endif
0060 
0061 void
0062 rtems_rtl_alloc_initialise (rtems_rtl_alloc_data* data)
0063 {
0064   int c;
0065   data->allocator = rtems_rtl_alloc_heap;
0066   for (c = 0; c < RTEMS_RTL_ALLOC_TAGS; ++c)
0067     rtems_chain_initialize_empty (&data->indirects[c]);
0068 }
0069 
0070 void*
0071 rtems_rtl_alloc_new (rtems_rtl_alloc_tag tag, size_t size, bool zero)
0072 {
0073   rtems_rtl_data* rtl = rtems_rtl_lock ();
0074   void*           address = NULL;
0075 
0076   /*
0077    * Obtain memory from the allocator. The address field is set by the
0078    * allocator.
0079    */
0080   if (rtl != NULL)
0081     rtl->allocator.allocator (RTEMS_RTL_ALLOC_NEW, tag, &address, size);
0082 
0083   rtems_rtl_unlock ();
0084 
0085   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0086     printf ("rtl: alloc: new: %s addr=%p size=%zu\n",
0087             rtems_rtl_trace_tag_label (tag), address, size);
0088 
0089   /*
0090    * Only zero the memory if asked to and the allocation was successful.
0091    */
0092   if (address != NULL && zero)
0093     memset (address, 0, size);
0094 
0095   return address;
0096 }
0097 
0098 void
0099 rtems_rtl_alloc_del (rtems_rtl_alloc_tag tag, void* address)
0100 {
0101   rtems_rtl_data* rtl = rtems_rtl_lock ();
0102 
0103   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0104     printf ("rtl: alloc: del: %s addr=%p\n",
0105             rtems_rtl_trace_tag_label (tag), address);
0106 
0107   if (rtl != NULL && address != NULL)
0108     rtl->allocator.allocator (RTEMS_RTL_ALLOC_DEL, tag, &address, 0);
0109 
0110   rtems_rtl_unlock ();
0111 }
0112 
0113 void* rtems_rtl_alloc_resize (rtems_rtl_alloc_tag tag,
0114                               void*               address,
0115                               size_t              size,
0116                               bool                zero)
0117 {
0118   rtems_rtl_data* rtl = rtems_rtl_lock ();
0119   const void* prev_address = address;
0120 
0121   /*
0122    * Resize memory of an existing allocation. The address field is set
0123    * by the allocator and may change.
0124    */
0125   if (rtl != NULL)
0126     rtl->allocator.allocator (RTEMS_RTL_ALLOC_RESIZE, tag, &address, size);
0127 
0128   rtems_rtl_unlock ();
0129 
0130   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0131     printf ("rtl: alloc: resize: %s%s prev-addr=%p addr=%p size=%zu\n",
0132             rtems_rtl_trace_tag_label (tag), prev_address == address ? "" : " MOVED",
0133             prev_address, address, size);
0134 
0135   /*
0136    * Only zero the memory if asked to and the resize was successful. We
0137    * cannot clear the resized area if bigger than the previouis allocation
0138    * because we do not have the original size.
0139    */
0140   if (address != NULL && zero)
0141     memset (address, 0, size);
0142 
0143   return address;
0144 }
0145 
0146 void
0147 rtems_rtl_alloc_wr_enable (rtems_rtl_alloc_tag tag, void* address)
0148 {
0149   rtems_rtl_data* rtl = rtems_rtl_lock ();
0150 
0151   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0152     printf ("rtl: alloc: wr-enable: addr=%p\n", address);
0153 
0154   if (rtl != NULL && address != NULL)
0155     rtl->allocator.allocator (RTEMS_RTL_ALLOC_WR_ENABLE,
0156                               tag,
0157                               address,
0158                               0);
0159 
0160   rtems_rtl_unlock ();
0161 }
0162 
0163 void
0164 rtems_rtl_alloc_lock (void)
0165 {
0166   rtems_rtl_data* rtl = rtems_rtl_lock ();
0167 
0168   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0169     printf ("rtl: alloc: lock\n");
0170 
0171   if (rtl != NULL)
0172     rtl->allocator.allocator (RTEMS_RTL_ALLOC_LOCK,
0173                               RTEMS_RTL_ALLOC_OBJECT, /* should be ignored */
0174                               NULL,
0175                               0);
0176 
0177   rtems_rtl_unlock ();
0178 }
0179 
0180 
0181 void
0182 rtems_rtl_alloc_unlock (void)
0183 {
0184   rtems_rtl_data* rtl = rtems_rtl_lock ();
0185 
0186   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0187     printf ("rtl: alloc: unlock\n");
0188 
0189   if (rtl != NULL)
0190     rtl->allocator.allocator (RTEMS_RTL_ALLOC_UNLOCK,
0191                               RTEMS_RTL_ALLOC_OBJECT, /* should be ignored */
0192                               NULL,
0193                               0);
0194 
0195   rtems_rtl_unlock ();
0196 }
0197 void
0198 rtems_rtl_alloc_wr_disable (rtems_rtl_alloc_tag tag, void* address)
0199 {
0200   rtems_rtl_data* rtl = rtems_rtl_lock ();
0201 
0202   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0203     printf ("rtl: alloc: wr-disable: addr=%p\n", address);
0204 
0205   if (rtl != NULL && address != NULL)
0206     rtl->allocator.allocator (RTEMS_RTL_ALLOC_WR_DISABLE,
0207                               tag,
0208                               address,
0209                               0);
0210 
0211   rtems_rtl_unlock ();
0212 }
0213 
0214 rtems_rtl_allocator
0215 rtems_rtl_alloc_hook (rtems_rtl_allocator handler)
0216 {
0217   rtems_rtl_data*     rtl = rtems_rtl_lock ();
0218   rtems_rtl_allocator previous = rtl->allocator.allocator;
0219   rtl->allocator.allocator = handler;
0220   rtems_rtl_unlock ();
0221   return previous;
0222 }
0223 
0224 void
0225 rtems_rtl_alloc_indirect_new (rtems_rtl_alloc_tag tag,
0226                               rtems_rtl_ptr*      handle,
0227                               size_t              size)
0228 {
0229   rtems_rtl_data* rtl = rtems_rtl_lock ();
0230 
0231   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0232   {
0233     if (!rtems_rtl_ptr_null (handle))
0234       printf ("rtl: alloc: inew: %s handle=%p: not null\n",
0235               rtems_rtl_trace_tag_label (tag), handle);
0236     printf ("rtl: alloc: inew: %s handle=%p size=%zd\n",
0237             rtems_rtl_trace_tag_label (tag), handle, size);
0238   }
0239 
0240   if (rtl)
0241   {
0242     rtems_rtl_alloc_data* allocator = &rtl->allocator;
0243     handle->pointer = rtems_rtl_alloc_new (tag, size, false);
0244     if (!rtems_rtl_ptr_null (handle))
0245       rtems_chain_append_unprotected (&allocator->indirects[tag],
0246                                       &handle->node);
0247   }
0248 
0249   rtems_rtl_unlock ();
0250 }
0251 
0252 void
0253 rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag tag,
0254                               rtems_rtl_ptr*      handle)
0255 {
0256   rtems_rtl_data* rtl = rtems_rtl_lock ();
0257 
0258   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
0259   {
0260     if (rtems_rtl_ptr_null (handle))
0261       printf ("rtl: alloc: idel: %s handle=%p: is null\n",
0262               rtems_rtl_trace_tag_label (tag), handle);
0263     printf ("rtl: alloc: idel: %s handle=%p\n",
0264             rtems_rtl_trace_tag_label (tag), handle);
0265   }
0266 
0267   if (rtl && !rtems_rtl_ptr_null (handle))
0268   {
0269     rtems_chain_extract_unprotected (&handle->node);
0270     rtems_rtl_alloc_del (tag, &handle->pointer);
0271   }
0272 }
0273 
0274 rtems_rtl_alloc_tag
0275 rtems_rtl_alloc_text_tag (void)
0276 {
0277   return RTEMS_RTL_ALLOC_READ_EXEC;
0278 }
0279 
0280 rtems_rtl_alloc_tag
0281 rtems_rtl_alloc_const_tag (void)
0282 {
0283   return RTEMS_RTL_ALLOC_READ;
0284 }
0285 
0286 rtems_rtl_alloc_tag
0287 rtems_rtl_alloc_eh_tag (void)
0288 {
0289   return RTEMS_RTL_ALLOC_READ;
0290 }
0291 
0292 rtems_rtl_alloc_tag
0293 rtems_rtl_alloc_data_tag (void)
0294 {
0295   return RTEMS_RTL_ALLOC_READ_WRITE;
0296 }
0297 
0298 rtems_rtl_alloc_tag
0299 rtems_rtl_alloc_bss_tag (void)
0300 {
0301   return RTEMS_RTL_ALLOC_READ_WRITE;
0302 }
0303 
0304 bool
0305 rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
0306                             void** const_base, size_t const_size,
0307                             void** eh_base, size_t eh_size,
0308                             void** data_base, size_t data_size,
0309                             void** bss_base, size_t bss_size)
0310 {
0311   *text_base = *const_base = *data_base = *bss_base = NULL;
0312 
0313   if (data_size != 0)
0314   {
0315     *data_base = rtems_rtl_alloc_new (rtems_rtl_alloc_data_tag (),
0316                                       data_size, false);
0317     if (*data_base == NULL)
0318     {
0319       rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
0320                                   data_base, bss_base);
0321       return false;
0322     }
0323   }
0324 
0325   if (bss_size != 0)
0326   {
0327     *bss_base = rtems_rtl_alloc_new (rtems_rtl_alloc_bss_tag (),
0328                                      bss_size, false);
0329     if (*bss_base == NULL)
0330     {
0331       rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
0332                                   data_base, bss_base);
0333       return false;
0334     }
0335   }
0336 
0337   if (eh_size != 0)
0338   {
0339     *eh_base = rtems_rtl_alloc_new (rtems_rtl_alloc_eh_tag (),
0340                                     eh_size, false);
0341     if (*eh_base == NULL)
0342     {
0343       rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
0344                                   data_base, bss_base);
0345       return false;
0346     }
0347   }
0348 
0349   if (const_size != 0)
0350   {
0351     *const_base = rtems_rtl_alloc_new (rtems_rtl_alloc_const_tag (),
0352                                        const_size, false);
0353     if (*const_base == NULL)
0354     {
0355       rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
0356                                   data_base, bss_base);
0357       return false;
0358     }
0359   }
0360 
0361   if (text_size != 0)
0362   {
0363     *text_base = rtems_rtl_alloc_new (rtems_rtl_alloc_text_tag (),
0364                                       text_size, false);
0365     if (*text_base == NULL)
0366     {
0367       return false;
0368     }
0369   }
0370 
0371   return true;
0372 }
0373 
0374 bool
0375 rtems_rtl_alloc_module_resize (void** text_base, size_t text_size,
0376                                void** const_base, size_t const_size,
0377                                void** eh_base, size_t eh_size,
0378                                void** data_base, size_t data_size,
0379                                void** bss_base, size_t bss_size)
0380 {
0381   if (data_size != 0)
0382   {
0383     *data_base = rtems_rtl_alloc_resize (rtems_rtl_alloc_data_tag (),
0384                                          *data_base, data_size, false);
0385     if (*data_base == NULL)
0386     {
0387       return false;
0388     }
0389   }
0390 
0391   if (bss_size != 0)
0392   {
0393     *bss_base = rtems_rtl_alloc_resize (rtems_rtl_alloc_bss_tag (),
0394                                         *bss_base, bss_size, false);
0395     if (*bss_base == NULL)
0396     {
0397       return false;
0398     }
0399   }
0400 
0401   if (eh_size != 0)
0402   {
0403     *eh_base = rtems_rtl_alloc_resize (rtems_rtl_alloc_eh_tag (),
0404                                        *eh_base, eh_size, false);
0405     if (*eh_base == NULL)
0406     {
0407       return false;
0408     }
0409   }
0410 
0411   if (const_size != 0)
0412   {
0413     *const_base = rtems_rtl_alloc_resize (rtems_rtl_alloc_const_tag (),
0414                                           *const_base, const_size, false);
0415     if (*const_base == NULL)
0416     {
0417       return false;
0418     }
0419   }
0420 
0421   if (text_size != 0)
0422   {
0423     *text_base = rtems_rtl_alloc_resize (rtems_rtl_alloc_text_tag (),
0424                                          *text_base, text_size, false);
0425     if (*text_base == NULL)
0426     {
0427       return false;
0428     }
0429   }
0430 
0431   return true;
0432 }
0433 
0434 void
0435 rtems_rtl_alloc_module_del (void** text_base,
0436                             void** const_base,
0437                             void** eh_base,
0438                             void** data_base,
0439                             void** bss_base)
0440 {
0441   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *bss_base);
0442   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *data_base);
0443   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *eh_base);
0444   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_base);
0445   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_EXEC, *text_base);
0446   *text_base = *const_base = *eh_base = *data_base = *bss_base = NULL;
0447 }