[PATCH] ld: Avoid moving desired relro end below relro section

H.J. Lu hjl.tools@gmail.com
Mon Feb 17 07:58:40 GMT 2025


On Mon, Feb 17, 2025 at 3:20 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Feb 17, 2025 at 2:29 PM Alan Modra <amodra@gmail.com> wrote:
> >
> > On Mon, Feb 17, 2025 at 04:56:57AM +0800, H.J. Lu wrote:
> > > On Sun, Feb 16, 2025 at 12:38 PM Alan Modra <amodra@gmail.com> wrote:
> > > >
> > > > On Sun, Feb 16, 2025 at 06:19:07AM +0800, H.J. Lu wrote:
> > > > > --- a/ld/ldlang.c
> > > > > +++ b/ld/ldlang.c
> > > > > @@ -6605,10 +6605,16 @@ lang_size_relro_segment_1 (void)
> > > > >       end = start = sec->vma;
> > > > >       if (!IS_TBSS (sec))
> > > > >         end += TO_ADDR (sec->size);
> > > > > -     bump = desired_end - end;
> > > > > -     /* We'd like to increase START by BUMP, but we must heed
> > > > > -        alignment so the increase might be less than optimum.  */
> > > > > -     start += bump;
> > > > > +     if (desired_end > end)
> > > > > +       {
> > > > > +         /* Avoid moving START backwards.  */
> > > > > +         bump = desired_end - end;
> > > > > +         /* We'd like to increase START by BUMP, but we must heed
> > > > > +            alignment so the increase might be less than optimum.  */
> > > > > +         start += bump;
> > > > > +       }
> > > > > +     else
> > > > > +       start = end;
> > > > >       start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
> > > > >       /* This is now the desired end for the previous section.  */
> > > > >       desired_end = start;
> > > >
> > > > This doesn't make any sense at all.  You're putting sections on top of
> > > > each other!
> > > >
> > > > The assert failure can't be fixed by totally breaking this function.
> > > >
> > > > Look instead at why sections now don't fit.  Have they changed in size
> > > > since the time seg->relro_end and seg->base were set?
> > >
> > > When setting seg->base to 0x2f3000, there are:
> > >
> > > section       vma           size      vma + size    alignment
> > > .got   0x2c2118   0x0    0x2c2118   8
> > > .dynamic   0x2c20e8   0x0    0x2c20e8   8
> > > .data.rel.ro   0x298020   0x0    0x298020   32
> > > .fini_array   0x298008   0x0    0x298008   8
> > > .init_array   0x298000   0x0    0x298000   8
> >
> > Something doesn't add up here.  The change in vma indicates the size
> > of .init_array is 8, .fini_array between 0 and 0x18, .data.rel.ro is
> > 0x2a0c8, .dynamic is 0x30.
> >
> > >
> > > When setting seg->relro_end to 0x320fe8 after that, there are
> > >
> > > section       vma           size      vma + size    alignment
> > > .got   0x320268   0xd80    0x320fe8   8
> > > .dynamic   0x31ffe8   0x280    0x320268   8
> > > .data.rel.ro   0x2f3020   0x2cfc8    0x31ffe8   128
> > > .fini_array   0x2f3008   0x8    0x2f3010   8
> > > .init_array   0x2f3000   0x8    0x2f3008   8
> >
> > Lot's of things changed according to this, including .data.rel.ro
> > alignment.  There can be multiple iterations of layout and sizing.
> >
> > For the iteration of lang_size_relro_segment_1 that failed the
>
> lang_size_relro_segment_1 failed at the first interation.
>
> > assertion, what were the most recent assignments to relro_end and
> > base?  After those particular assignments, did any relro section size
> > or alignment change?  If they did, you've found the real problem.
>
> There were no changes in size nor alignment after he most recent
> assignments to relro_end and base before lang_size_relro_segment_1
> was called.
>
> (gdb) run
> ...
> Hardware watchpoint 2: expld.dataseg.base
>
> Old value = 0
> New value = 2719744
> fold_segment_align (lhs=0x7fffffffb350)
>     at /export/gnu/import/git/gitlab/x86-binutils/ld/ldexp.c:487
> 487       seg->commonpagesize = commonpage;
> (gdb) c
> Continuing.
>
> Hardware watchpoint 3: expld.dataseg.relro_end
>
> Old value = 0
> New value = 2892056
> fold_segment_relro_end (lhs=0x7fffffffb350)
>     at /export/gnu/import/git/gitlab/x86-binutils/ld/ldexp.c:519
> 519       if (seg->phase == exp_seg_relro_adjust
> (gdb)
> Continuing.
>
> Hardware watchpoint 2: expld.dataseg.base
>
> Old value = 2719744
> New value = 3092480
> fold_segment_align (lhs=0x7fffffffb350)
>     at /export/gnu/import/git/gitlab/x86-binutils/ld/ldexp.c:487
> 487       seg->commonpagesize = commonpage;
> (gdb)

Here I got

(gdb) call debug_vma ()
section       vma           size      vma + size    alignment
.got (0x6f91130)   0x2c2118   0x0    0x2c2118   8
.dynamic (0x6f91008)   0x2c20e8   0x0    0x2c20e8   8
.data.rel.ro (0x6f90ee0)   0x298020   0x0    0x298020   32
.fini_array (0x6f90db8)   0x298008   0x0    0x298008   8
.init_array (0x6f80a60)   0x298000   0x0    0x298000   8
(gdb)

The input dynamic .data.rel.ro (dynbss) is changed to 128:

Hardware watchpoint 6: *(unsigned int *) 0x743674

Old value = 0
New value = 7
bfd_set_section_alignment (sec=0x7435f8, val=7) at ./bfd.h:918
918   return true;
(gdb) bt
#0  bfd_set_section_alignment (sec=0x7435f8, val=7) at ./bfd.h:918
#1  0x00000000004adef3 in _bfd_elf_adjust_dynamic_copy (
    info=0x6ed380 <link_info>, h=0x1f1d820, dynbss=0x7435f8)
    at /export/gnu/import/git/gitlab/x86-binutils/bfd/elflink.c:3390
#2  0x000000000047d11b in _bfd_x86_elf_adjust_dynamic_symbol (
    info=0x6ed380 <link_info>, h=0x1f1d820)
    at /export/gnu/import/git/gitlab/x86-binutils/bfd/elfxx-x86.c:3611
#3  0x00000000004ade47 in _bfd_elf_adjust_dynamic_symbol (h=0x1f1d820,
    data=0x7fffffffb270)
    at /export/gnu/import/git/gitlab/x86-binutils/bfd/elflink.c:3353
#4  0x00000000004552a0 in bfd_link_hash_traverse (htab=0x71bbe0,
    func=0x4adb54 <_bfd_elf_adjust_dynamic_symbol>, info=0x7fffffffb270)
    at /export/gnu/import/git/gitlab/x86-binutils/bfd/linker.c:692
#5  0x00000000004a7d68 in elf_link_hash_traverse (table=0x71bbe0,
    f=0x4adb54 <_bfd_elf_adjust_dynamic_symbol>, info=0x7fffffffb270)
    at /export/gnu/import/git/gitlab/x86-binutils/bfd/elf-bfd.h:800
#6  0x00000000004b72b0 in bfd_elf_size_dynamic_sections (output_bfd=0x704230,
    soname=0x0, rpath=0x701c40 "/tmp/foo", filter_shlib=0x0, audit=0x0,
    depaudit=0x0, auxiliary_filters=0x0, info=0x6ed380 <link_info>,
    sinterpptr=0x7fffffffb4f8)
    at /export/gnu/import/git/gitlab/x86-binutils/bfd/elflink.c:7586
#7  0x0000000000440fb5 in ldelf_before_allocation (audit=0x6ed8c0 <audit>,
    depaudit=0x6ed8c8 <depaudit>, default_interpreter_name=0x0)
    at /export/gnu/import/git/gitlab/x86-binutils/ld/ldelf.c:1840
#8  0x0000000000436057 in gldelf_x86_64_before_allocation ()
    at eelf_x86_64.c:172
#9  0x0000000000435efb in elf_x86_64_before_allocation () at eelf_x86_64.c:115
#10 0x0000000000429535 in ldemul_before_allocation ()
    at /export/gnu/import/git/gitlab/x86-binutils/ld/ldemul.c:96
#11 0x000000000041c3bf in lang_process ()
    at /export/gnu/import/git/gitlab/x86-binutils/ld/ldlang.c:8628
#12 0x00000000004227ea in main (argc=382, argv=0x7fffffffb858)
    at /export/gnu/import/git/gitlab/x86-binutils/ld/ldmain.c:533
(gdb)

.data.rel.ro in libbfd.so is aligned to 128 bytes.  We guess
the symbol, tic6x_elf32_c6000_be_vec, alignment

bool
_bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info,
                              struct elf_link_hash_entry *h,
                              asection *dynbss)
{
  unsigned int power_of_two;
  bfd_vma mask;
  asection *sec = h->root.u.def.section;

  /* The section alignment of the definition is the maximum alignment
     requirement of symbols defined in the section.  Since we don't
     know the symbol alignment requirement, we start with the
     maximum alignment and check low bits of the symbol address
     for the minimum alignment.  */
  power_of_two = bfd_section_alignment (sec);
  mask = ((bfd_vma) 1 << power_of_two) - 1;
  while ((h->root.u.def.value & mask) != 0)

We got a non-zero value since sec->vma != 0 after my patch.

    {
       mask >>= 1;
       --power_of_two;
    }

  if (power_of_two > bfd_section_alignment (dynbss))
    {
      /* Adjust the section alignment if needed.  */
      if (!bfd_set_section_alignment (dynbss, power_of_two))
        return false;
    }

> Continuing.
>
> Hardware watchpoint 3: expld.dataseg.relro_end
>
> Old value = 2892056
> New value = 0
> fold_segment_align (lhs=0x7fffffffb350)
>     at /export/gnu/import/git/gitlab/x86-binutils/ld/ldexp.c:496
> 496 }
> (gdb)
> Continuing.
>
> Hardware watchpoint 3: expld.dataseg.relro_end
>
> Old value = 0
> New value = 3280872
> fold_segment_relro_end (lhs=0x7fffffffb350)
>     at /export/gnu/import/git/gitlab/x86-binutils/ld/ldexp.c:519
> 519       if (seg->phase == exp_seg_relro_adjust
> (gdb) call debug_vma ()
> section       vma           size      vma + size    alignment
> .got (0x6f91130)   0x320268   0xd80    0x320fe8   8
> .dynamic (0x6f91008)   0x31ffe8   0x280    0x320268   8
> .data.rel.ro (0x6f90ee0)   0x2f3020   0x2cfc8    0x31ffe8   128
> .fini_array (0x6f90db8)   0x2f3008   0x8    0x2f3010   8
> .init_array (0x6f80a60)   0x2f3000   0x8    0x2f3008   8
> (gdb) c
> Continuing.
>
> Breakpoint 1, lang_size_relro_segment_1 ()
>     at /export/gnu/import/git/gitlab/x86-binutils/ld/ldlang.c:6616
> 6616   seg_align_type *seg = &expld.dataseg;
> (gdb) call debug_vma ()
> section       vma           size      vma + size    alignment
> .got (0x6f91130)   0x320268   0xd80    0x320fe8   8
> .dynamic (0x6f91008)   0x31ffe8   0x280    0x320268   8
> .data.rel.ro (0x6f90ee0)   0x2f3020   0x2cfc8    0x31ffe8   128
> .fini_array (0x6f90db8)   0x2f3008   0x8    0x2f3010   8
> .init_array (0x6f80a60)   0x2f3000   0x8    0x2f3008   8
> (gdb)
>
>
> H.J.



-- 
H.J.


More information about the Binutils mailing list