Bug 99759 - morestack.S should support .init_array.0 besides .ctors.65535
Summary: morestack.S should support .init_array.0 besides .ctors.65535
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libgcc (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-03-25 03:16 UTC by Fangrui Song
Modified: 2021-10-08 19:09 UTC (History)
2 users (show)

See Also:
Host:
Target: i?86-linux-gnu s390-linux-gnu rs6000-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-04-05 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fangrui Song 2021-03-25 03:16:59 UTC
to drop reliance on ld's default linker script

  .init_array    :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
    PROVIDE_HIDDEN (__init_array_end = .);
  }

The input section description is quite close but does not sort .init_array.* and .ctors.* with the same priority together.
Comment 1 Andrew Pinski 2021-04-05 00:26:30 UTC
The comment in morestack.S might be just wrong.

# Make __stack_split_initialize a high priority constructor.  FIXME:
# This is ELF specific.
        .section .ctors.65535,"aw",@progbits

So I read the manual and even read the details on the linker script.  The comment is incorrect really.  The higher number the later it will be.  In this case it is 64k-1.

So looking at the linker script:
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))

this means the ctors.65535 will come last.

I don't see any issue here really in the end because GCC will produce init_array most of the time.
Comment 2 Alan Modra 2021-08-12 00:39:23 UTC
> this means the ctors.65535 will come last.
Nope, it will come first.  And since DT_INIT_ARRAY pointers are executed in the order they appear in the array, it will be one of the first to run.  .init_array and .ctors sorting is complicated.  ld.bfd will sort .init_array.0 (highest priority .init_array section) and .ctors.65535 (highest priority .ctors section) together.

I assume this comment:
> The input section description is quite close but does not sort .init_array.* and .ctors.* with the same priority together.
is referring to lld.

> I don't see any issue here really in the end because GCC will produce init_array most of the time.
So the issue really is that lld doesn't support mixing of .ctors.* and .init_array.*.

It might be nice for libgcc to use .init_array.0 here instead of .ctors.65536 whenever gcc will use .init_array in compiled code.
Comment 3 Fangrui Song 2021-08-12 01:52:58 UTC
(In reply to Alan Modra from comment #2)
> > this means the ctors.65535 will come last.
> Nope, it will come first.  And since DT_INIT_ARRAY pointers are executed in
> the order they appear in the array, it will be one of the first to run. 
> .init_array and .ctors sorting is complicated.  ld.bfd will sort
> .init_array.0 (highest priority .init_array section) and .ctors.65535
> (highest priority .ctors section) together.
> 
> I assume this comment:
> > The input section description is quite close but does not sort .init_array.* and .ctors.* with the same priority together.
> is referring to lld.

`KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))`
The syntax is ambiguous. I can read it this way: place .init_array.* before .ctors.* , but the behavior is (the ideal way):

.init_array     0x0000000000402ff9        0x7
                [!provide]                        PROVIDE (__init_array_start = .)
 *(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))
 .init_array.5  0x0000000000402ff9        0x1 a.o
 .ctors.65529   0x0000000000402ffa        0x1 a.o
 .init_array.7  0x0000000000402ffb        0x1 a.o
 .ctors.65435   0x0000000000402ffc        0x1 a.o
 .init_array.100
                0x0000000000402ffd        0x1 a.o
 *(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors)
 .init_array    0x0000000000402ffe        0x1 a.o
 .ctors         0x0000000000402fff        0x1 a.o
                [!provide]                        PROVIDE (__init_array_end = .)


It is unclear that contiguous SORT_BY_INIT_PRIORITY are sorted as a unit.

> > I don't see any issue here really in the end because GCC will produce init_array most of the time.
> So the issue really is that lld doesn't support mixing of .ctors.* and
> .init_array.*.

Yes.

> It might be nice for libgcc to use .init_array.0 here instead of
> .ctors.65536 whenever gcc will use .init_array in compiled code.

Yes. This is the only place I know where modern Linux distrubtions is still using .ctors* in .o files.
Comment 4 Fangrui Song 2021-10-08 19:09:40 UTC
Fixed by f49e3d28be44179f07b8a06159139ce77096dda7 ("libgcc: use .init_stack for constructors if available").

Thanks, Ian!