Problem of execution order of entries in .fini_array

Jing Yu jingyu@google.com
Fri Apr 17 14:32:00 GMT 2009


I find under newlib/libc/sys/linux/dl directory, the dl-*.* files are
copied from glibc/libc/elf/ directory. These dl-* files have been
updated in glibc, but not in newlib.

I only search for "FINI", and find the following two places that may
need to change.

newlib/libc/sys/linux/dl/dl-close.c:
void internal_function _dl_close (void *_map)
{
...
          if (imap->l_info[DT_FINI_ARRAY] != NULL)
            {
              ElfW(Addr) *array =
                (ElfW(Addr) *) (imap->l_addr
                                + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
              unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
                                 / sizeof (ElfW(Addr)));
              unsigned int cnt;

              for (cnt = 0; cnt < sz; ++cnt)
<----------- changed in new glibc
                ((fini_t) (imap->l_addr + array[cnt])) ();
<------------changed
            }
...

In glibc/libc/elf/dl-close.c, the arrowed two lines have been changed into:
                  while (sz-- > 0)
                    ((fini_t) array[sz]) ();


newlib/libc/sys/linux/dl/dl-fini.c:
void internal_function _dl_fini (void)
{
...
          if (l->l_info[DT_FINI_ARRAY] != NULL)
            {
              ElfW(Addr) *array =
                (ElfW(Addr) *) (l->l_addr
                                + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
              unsigned int sz =
(l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val <---Changed
                                 / sizeof (ElfW(Addr)));
              unsigned int cnt;                  <----- changed

              for (cnt = 0; cnt < sz; ++cnt)        <-----------
Changed in new glibc
                ((fini_t) (l->l_addr + array[cnt])) ();  <----------- Changed
            }

          /* Next try the old-style destructor.  */
          if (l->l_info[DT_FINI] != NULL)
            ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr +
l->l_info[DT_FINI]->d_un.d_ptr)) ();
        }
    }

The arrowed four lines have been updated in glibc/libc/elf/dl-fini.c:

                      unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
                                        / sizeof (ElfW(Addr)));
                      while (i-- > 0)
                        ((fini_t) array[i]) ();


Thanks,
Jing


On Thu, Apr 16, 2009 at 12:20 PM, Jeff Johnston <jjohnstn@redhat.com> wrote:
> Hans-Peter Nilsson wrote:
>>>
>>> Received-SPF: none (bart: domain of
>>> newlib-return-7494-hp=axis.com@sourceware.org does not designate permitted
>>> sender hosts) client ip=209.132.176.174;
>>> envelope-from=newlib-return-7494-hp=axis.com@sourceware.org;
>>> helo=sourceware.org;
>>> X-SWARE-Spam-Status: No, hits=-0.4 required=5.0
>>> tests=AWL,BAYES_00,SARE_MSGID_LONG40,SPF_PASS
>>> X-Spam-Check-By: sourceware.org
>>> MIME-Version: 1.0
>>> Date: Wed, 15 Apr 2009 16:08:17 -0700
>>> From: Jing Yu <jingyu@google.com>
>>>
>>
>> (Long analysis cut short)
>>
>>>
>>> Should we change the access order or fini_array?
>>>
>>
>> I'd suggest correcting the access order, as opposed to hacking
>> the linker.  See for example glibc.
>>
>> (Note that there are *three* files in newlib doing the access in
>> the wrong order.  And I'm not counting the misguided
>> newlib/libc/sys/arm/crt0.S in which fini_array is treated like a
>> synonym for _fini!)
>>
>> brgds, H-P
>>
>
> Agreed.  I have checked in a patch for misc/init.c.  Where are the other 2
> accesses?
>
> -- Jeff J.
>



More information about the Newlib mailing list