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
0007  *
0008  *  @brief
0009  */
0010 
0011 /*
0012  * Copyright (C) 2014 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 /*
0037  * Taken from NetBSD and stripped of the relocations not needed on RTEMS.
0038  */
0039 
0040 /*  $NetBSD: ppc_reloc.c,v 1.44 2010/01/13 20:17:22 christos Exp $  */
0041 
0042 #include <sys/cdefs.h>
0043 
0044 #include <errno.h>
0045 #include <inttypes.h>
0046 #include <stdio.h>
0047 #include <sys/types.h>
0048 #include <sys/stat.h>
0049 
0050 #include <rtems/rtl/rtl.h>
0051 #include "rtl-bit-alloc.h"
0052 #include "rtl-elf.h"
0053 #include "rtl-error.h"
0054 #include <rtems/rtl/rtl-trace.h>
0055 #include "rtl-unwind.h"
0056 #include "rtl-unwind-dw2.h"
0057 
0058 #define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
0059                  ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
0060 #define l(x) ((u_int32_t)(x) & 0xffff)
0061 
0062 /*
0063  * SDATA allocator.
0064  */
0065 static rtems_rtl_bit_alloc* sdata;
0066 
0067 static Elf_Addr
0068 get_sda_base (void)
0069 {
0070   uint32_t sda_base;
0071   __asm__ volatile (" mr %0, 13\n" : "=r" (sda_base));
0072   return sda_base;
0073 }
0074 
0075 /*
0076  *  Access the variables via asm statements to avoid any fix up issues
0077  *  generated by the C compiler which thinks they belong in the .sdata
0078  *  section.
0079  */
0080 
0081 #define GET_ADDR(_l, _v) \
0082   __asm__ volatile (" lis %0, " #_l "@h\n" \
0083                     " ori %0, %0, " #_l "@l\n" : "=r" (_v))
0084 
0085 static void*
0086 get_sdata_start (void)
0087 {
0088 #if _ARCH_PPC64
0089   return NULL;
0090 #else
0091   Elf_Addr addr;
0092   GET_ADDR(__SDATA_START__, addr);
0093   return (void*) addr;
0094 #endif
0095 }
0096 
0097 #if !_ARCH_PPC64
0098 static size_t
0099 get_sdata_sbss_size (void)
0100 {
0101   Elf_Addr sdata_begin;
0102   Elf_Addr sbss_end;
0103   GET_ADDR(bsp_section_sdata_begin, sdata_begin);
0104   GET_ADDR(bsp_section_sbss_end, sbss_end);
0105   return sbss_end - sdata_begin;
0106 }
0107 
0108 static size_t
0109 get_sdata_libdl_size (void)
0110 {
0111   Elf_Addr begin;
0112   Elf_Addr end;
0113   GET_ADDR(bsp_section_sdata_libdl_begin, begin);
0114   GET_ADDR(bsp_section_sdata_libdl_end, end);
0115   return end - begin;
0116 }
0117 #endif
0118 
0119 uint32_t
0120 rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
0121                              const Elf_Shdr*      shdr)
0122 {
0123   return 0;
0124 }
0125 
0126 uint32_t
0127 rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
0128                                   int                  section,
0129                                   const char*          name,
0130                                   const Elf_Shdr*      shdr,
0131                                   const uint32_t       flags)
0132 {
0133 #if !_ARCH_PPC64
0134   struct {
0135     const char* label;
0136     size_t      len;
0137   } prefix[] = {
0138     #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 }
0139     SEPARATED_PREFIX (".sdata"),
0140     SEPARATED_PREFIX (".sbss"),
0141   };
0142   const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]);
0143   size_t       p;
0144   for (p = 0; p < prefixes; ++p)
0145   {
0146     if (strncmp (name, prefix[p].label, prefix[p].len) == 0)
0147       return flags | RTEMS_RTL_OBJ_SECT_ARCH_ALLOC;
0148   }
0149 #endif
0150   return flags;
0151 }
0152 
0153 bool
0154 rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
0155                                   rtems_rtl_obj_sect*  sect)
0156 {
0157 #if _ARCH_PPC64
0158     rtems_rtl_set_error (ENOMEM, ".sdata no supported by ABI");
0159     return false;
0160 #else
0161   if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
0162     printf ("rtl: section: arch: alloc: name=%s size=%zu flags=%08" PRIx32 \
0163             " order=%i link=%d info=%d\n",
0164             sect->name, sect->size, sect->flags, sect->load_order,
0165             sect->link, sect->info);
0166 
0167   if (sdata == NULL)
0168   {
0169     sdata = rtems_rtl_bit_alloc_open (get_sdata_start (),
0170                                       get_sdata_libdl_size (),
0171                                       sizeof (uint32_t),
0172                                       get_sdata_sbss_size ());
0173     if (sdata == NULL)
0174     {
0175       rtems_rtl_set_error (ENOMEM, "no memory for sdata allocator");
0176       return false;
0177     }
0178   }
0179 
0180   sect->base = rtems_rtl_bit_alloc_balloc (sdata, sect->size);
0181   if (sect->base == NULL)
0182   {
0183     rtems_rtl_set_error (ENOMEM, "no .sdata memory: %s", sect->name);
0184     return false;
0185   }
0186 
0187   return true;
0188 #endif
0189 }
0190 
0191 bool
0192 rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
0193                                   rtems_rtl_obj_sect*  sect)
0194 {
0195 #if !_ARCH_PPC64
0196   if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
0197     printf ("rtl: section: arch: free: name=%s size=%zu\n", sect->name, sect->size);
0198   if (sdata != NULL)
0199     rtems_rtl_bit_alloc_bfree (sdata, sect->base, sect->size);
0200 #endif
0201   return true;
0202 }
0203 
0204 bool
0205 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
0206 {
0207   return true;
0208 }
0209 
0210 uint32_t rtems_rtl_obj_tramp_alignment (const rtems_rtl_obj* obj)
0211 {
0212   (void) obj;
0213   return sizeof(uint32_t);
0214 }
0215 
0216 size_t
0217 rtems_rtl_elf_relocate_tramp_max_size (void)
0218 {
0219   /*
0220    * We have 4 instructions and each instruction is 32bits.
0221    */
0222   return 4 * 4;
0223 }
0224 
0225 static void*
0226 set_veneer (void* trampoline, Elf_Addr target)
0227 {
0228   /*
0229    * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
0230    *
0231    *  lis   12,0x1234
0232    *  ori   12,12,0x5678
0233    *  mtctr 12
0234    *  bctr
0235    */
0236 #if COMPILE_ASM
0237   asm volatile (" lis   12,0x1234\n" \
0238                 " ori   12,12,0x5678\n" \
0239                 " mtctr 12\n" \
0240                 " bctr\n");
0241 #endif
0242   uint32_t* tramp = (uint32_t*) trampoline;
0243   *tramp++ = 0x3d800000 | (target >> 16);
0244   *tramp++ = 0x618c0000 | (target & 0xffff);
0245   *tramp++ = 0x7d8903a6;
0246   *tramp++ = 0x4e800420;
0247   return tramp;
0248 }
0249 
0250 static size_t
0251 get_veneer_size (int type)
0252 {
0253   (void) type;
0254   return rtems_rtl_elf_relocate_tramp_max_size ();
0255 }
0256 
0257 /**
0258  * The offsets in the reloc words.
0259  */
0260 #define REL_R_OFFSET (0)
0261 #define REL_R_INFO   (1)
0262 #define REL_R_ADDEND (2)
0263 
0264 static rtems_rtl_elf_rel_status
0265 rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
0266                           const Elf_Rela*           rela,
0267                           const rtems_rtl_obj_sect* sect,
0268                           const char*               symname,
0269                           const Elf_Byte            syminfo,
0270                           const Elf_Word            symvalue,
0271                           const bool                parsing)
0272 {
0273   Elf_Addr* where;
0274   Elf_Word tmp;
0275   uint32_t mask = 0;
0276   uint32_t bits = 0;
0277   bool     needs_tramp = false;
0278 
0279   where = (Elf_Addr *)(sect->base + rela->r_offset);
0280   switch (ELF_R_TYPE(rela->r_info)) {
0281     case R_TYPE(NONE):
0282       break;
0283 
0284     case R_TYPE(32):
0285       /*
0286        * value:1; Field: word32; Expression: S + A
0287        */
0288       if (!parsing) {
0289         *where = symvalue + rela->r_addend;
0290         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0291           printf ("rtl: ADDR32 %p @ %p in %s\n",
0292                   (void *)*(where), where, rtems_rtl_obj_oname (obj));
0293       }
0294       break;
0295 
0296     case R_TYPE(14):
0297       /*
0298        * value:7; Field: low14*; Expression: (S + A) >> 2
0299        */
0300     case R_TYPE(24):
0301       /*
0302        * value:2; Field: low24*; Expression: (S + A) >> 2
0303        */
0304       if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) {
0305         bits = 14;
0306         mask = 0xfffc;
0307       } else {
0308         bits = 24;
0309         mask = 0x3fffffc;
0310       }
0311 
0312       if (parsing && sect->base == 0) {
0313         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0314           printf ("rtl: ADDR14/ADDR24 tramp cache\n");
0315         return rtems_rtl_elf_rel_tramp_cache;
0316       }
0317 
0318       tmp = (symvalue + rela->r_addend) >> 2;
0319       if (tmp > ((1<<bits) - 1 )) {
0320         Elf_Word tramp_addr;
0321         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
0322         if (parsing) {
0323           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0324             printf ("rtl: ADDR14/ADDR24 tramp add\n");
0325           return rtems_rtl_elf_rel_tramp_add;
0326         }
0327         if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0328           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0329             printf ("rtl: ADDR14/ADDR24 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
0330           rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: ADDR14/ADDR24", sect->name);
0331           return rtems_rtl_elf_rel_failure;
0332         }
0333         needs_tramp = true;
0334         tramp_addr = (Elf_Addr) obj->tramp_brk;
0335         obj->tramp_brk = set_veneer(obj->tramp_brk,
0336                                     symvalue + rela->r_addend);
0337         tmp = *where;
0338         tmp &= ~mask;
0339         tmp |= (tramp_addr + rela->r_addend) & mask;
0340       }
0341       else {
0342         tmp = *where;
0343         tmp &= ~mask;
0344         tmp |= (symvalue + rela->r_addend) & mask;
0345       }
0346 
0347       if (!parsing) {
0348         *where = tmp;
0349         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0350           printf ("rtl: ADDR14/ADDR24%s %p @ %p in %s\n",
0351                   needs_tramp ? "(tramp)" : "",
0352                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0353       }
0354       break;
0355 
0356     case R_TYPE(16_HA):
0357     case R_TYPE(TPREL16_HA):
0358       /*
0359        * value:6; Field:half16; Expression: #ha(S+A)
0360        * value:72; Field:half16; Expression: #ha(S+A)
0361        */
0362       if (!parsing) {
0363         tmp = symvalue + rela->r_addend;
0364         *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
0365         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0366           printf ("rtl: %s16_HA %p @ %p in %s\n",
0367                   ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HA) ? "TPREL" : "",
0368                   (void *)*(where), where, rtems_rtl_obj_oname (obj));
0369       }
0370       break;
0371 
0372     case R_TYPE(16_HI):
0373     case R_TYPE(TPREL16_HI):
0374       /*
0375        * value:5; Field:half16; Expression: #hi(S+A)
0376        * value:71; Field:half16; Expression: #hi(S+A)
0377        */
0378       if (!parsing) {
0379         *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
0380         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0381           printf ("rtl: %s16_HI %p @ %p in %s\n",
0382                   ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HI) ? "TPREL" : "",
0383                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0384       }
0385       break;
0386 
0387     case R_TYPE(16_LO):
0388     case R_TYPE(TPREL16_LO):
0389       /*
0390        * value:4; Field:half16; Expression: #lo(S+A)
0391        * value:71; Field:half16; Expression: #lo(S+A)
0392        */
0393       if (!parsing) {
0394         *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
0395         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0396           printf ("rtl: %s16_LO %p @ %p in %s\n",
0397                   ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_LO) ? "TPREL" : "",
0398                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0399       }
0400       break;
0401 
0402     case R_TYPE(REL14):
0403       /*
0404        * value:11; Field:low14*; Expression:(S+A-P)>>2
0405        */
0406     case R_TYPE(REL24):
0407       /*
0408        * value:10; Field:low24*; Expression:(S+A-P)>>2
0409        */
0410       if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) {
0411         mask = 0x3fffffc;
0412         bits = 24;
0413       }
0414       else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) {
0415         mask = 0xfffc;
0416         bits = 14;
0417       }
0418 
0419       if (parsing && sect->base == 0) {
0420         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0421           printf ("rtl: REL24/REL14 tramp cache\n");
0422         return rtems_rtl_elf_rel_tramp_cache;
0423       }
0424 
0425       tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
0426       if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
0427           ((Elf_Sword)tmp < -(1<<(bits-1)))) {
0428         Elf_Word tramp_addr;
0429         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
0430         if (parsing) {
0431           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0432             printf ("rtl: REL24/REL14 tramp add\n");
0433           return rtems_rtl_elf_rel_tramp_add;
0434         }
0435         if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0436           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0437             printf ("rtl: REL24/REL14 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
0438           rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: REL24/REL14", sect->name);
0439           return rtems_rtl_elf_rel_failure;
0440         }
0441         needs_tramp = true;
0442         tramp_addr = (Elf_Addr) obj->tramp_brk;
0443         obj->tramp_brk = set_veneer(obj->tramp_brk,
0444                                     symvalue + rela->r_addend);
0445         tmp = *where;
0446         tmp &= ~mask;
0447         tmp |= (tramp_addr + rela->r_addend - (Elf_Addr)where) & mask;
0448       }
0449       else
0450       {
0451         tmp = *where;
0452         tmp &= ~mask;
0453         tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
0454       }
0455 
0456       if (!parsing) {
0457         *where = tmp;
0458         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0459           printf ("rtl: REL24/REL14%s %p @ %p in %s\n",
0460                   needs_tramp ? "(tramp)" : "",
0461                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0462       }
0463       break;
0464 
0465     case R_TYPE(REL32):
0466       /*
0467        * value:26; Field:word32*; Expression:S+A-P
0468        */
0469       if (!parsing) {
0470         *where = symvalue + rela->r_addend - (Elf_Addr)where;
0471         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0472           printf ("rtl: REL32 %p @ %p in %s\n",
0473                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0474       }
0475       break;
0476 
0477     case R_TYPE(SDAREL16):
0478       /*
0479        * A sign-extended 16 bit value relative to _SDA_BASE_, for use with
0480        * small data items.
0481        */
0482       if (!parsing) {
0483         Elf_Addr sda_base = get_sda_base ();
0484         mask = 0xffff;
0485         tmp = *((Elf32_Half*) where);
0486         tmp &= ~mask;
0487         tmp |= (symvalue + rela->r_addend - sda_base) & mask;
0488         *((Elf32_Half*) where) = tmp;
0489         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0490           printf ("rtl: SDAREL16 %p @ %p in %s\n",
0491                   (void *) (uintptr_t) *((Elf32_Half*) where),
0492                   where, rtems_rtl_obj_oname (obj));
0493       }
0494       break;
0495 
0496     default:
0497       printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, "
0498               "contents = %p\n",
0499               ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
0500               (void *)rela->r_offset, (void *)*where);
0501       rtems_rtl_set_error (EINVAL,
0502                            "%s: Unsupported relocation type %" PRId32
0503                            " in non-PLT relocations",
0504                            sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
0505       return rtems_rtl_elf_rel_failure;
0506   }
0507   return rtems_rtl_elf_rel_no_error;
0508 }
0509 
0510 rtems_rtl_elf_rel_status
0511 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
0512                                    const Elf_Rela*           rela,
0513                                    const rtems_rtl_obj_sect* sect,
0514                                    const char*               symname,
0515                                    const Elf_Byte            syminfo,
0516                                    const Elf_Word            symvalue)
0517 {
0518   return rtems_rtl_elf_reloc_rela (obj,
0519                                    rela,
0520                                    sect,
0521                                    symname,
0522                                    syminfo,
0523                                    symvalue,
0524                                    true);
0525 }
0526 
0527 rtems_rtl_elf_rel_status
0528 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
0529                              const Elf_Rela*           rela,
0530                              const rtems_rtl_obj_sect* sect,
0531                              const char*               symname,
0532                              const Elf_Byte            syminfo,
0533                              const Elf_Word            symvalue)
0534 {
0535   return rtems_rtl_elf_reloc_rela (obj,
0536                                    rela,
0537                                    sect,
0538                                    symname,
0539                                    syminfo,
0540                                    symvalue,
0541                                    false);
0542 }
0543 
0544 rtems_rtl_elf_rel_status
0545 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
0546                                   const Elf_Rel*            rel,
0547                                   const rtems_rtl_obj_sect* sect,
0548                                   const char*               symname,
0549                                   const Elf_Byte            syminfo,
0550                                   const Elf_Word            symvalue)
0551 {
0552   (void) obj;
0553   (void) rel;
0554   (void) sect;
0555   (void) symname;
0556   (void) syminfo;
0557   (void) symvalue;
0558   rtems_rtl_set_error (EINVAL, "rel type record not supported");
0559   return rtems_rtl_elf_rel_failure;
0560 }
0561 
0562 rtems_rtl_elf_rel_status
0563 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
0564                             const Elf_Rel*            rel,
0565                             const rtems_rtl_obj_sect* sect,
0566                             const char*               symname,
0567                             const Elf_Byte            syminfo,
0568                             const Elf_Word            symvalue)
0569 {
0570   (void) obj;
0571   (void) rel;
0572   (void) sect;
0573   (void) symname;
0574   (void) syminfo;
0575   (void) symvalue;
0576   rtems_rtl_set_error (EINVAL, "rel type record not supported");
0577   return rtems_rtl_elf_rel_failure;
0578 }
0579 
0580 bool
0581 rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj,
0582                             const char*          name,
0583                             uint32_t             flags)
0584 {
0585   return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
0586 }
0587 
0588 bool
0589 rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj)
0590 {
0591   return rtems_rtl_elf_unwind_dw2_register (obj);
0592 }
0593 
0594 bool
0595 rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj)
0596 {
0597   return rtems_rtl_elf_unwind_dw2_deregister (obj);
0598 }