bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/28021] New: riscv: wrong double relaxation with LTO


From: matz at suse dot de
Subject: [Bug ld/28021] New: riscv: wrong double relaxation with LTO
Date: Mon, 28 Jun 2021 15:55:35 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=28021

            Bug ID: 28021
           Summary: riscv: wrong double relaxation with LTO
           Product: binutils
           Version: 2.37 (HEAD)
            Status: NEW
          Severity: normal
          Priority: P2
         Component: ld
          Assignee: unassigned at sourceware dot org
          Reporter: matz at suse dot de
  Target Milestone: ---

This is related to the fix for PR22756, which turns out to be incomplete.
We have seen the problem with GCC11 and it needs LTO, which makes this a bit
involved to reproduce.  See https://bugzilla.suse.com/show_bug.cgi?id=1187542
for how it came to be, but it contains unrelated things.  Eventually I came up
with a single file testcase without compiler, but that involved a hex-edited
.o file.  After much back and forth I came up with a two-file testcase that
only involves assembler, no compiler, and that I believe faithfully reflects
the error
mode.  So, the files:

% cat relax-twice-1.s
        .file   "<artificial>"
        .option pic
        .text
        # this align is here so that the .text section starts at 0x1000,
        # in order to make matching of testcase results easier
        .align 12
        .globl  foobar_new
        .weak   foobar_new
        .type   foobar_new, @function
foobar_new:
        jr ra
        .size   foobar_new, .-foobar_new
        .symver foobar_new, foobar@@New
        .section        .note.GNU-stack,"",@progbits

% cat relax-twice-2.s
        .file   "<artificial>"
        .option pic
        .text
        .section        .rodata.str1.8,"aMS",@progbits,1
        .align  3
.LC0:
        .string "%u"
        .text
        .align  1
        .globl  relaxme
        .type   relaxme, @function
relaxme:
        addi    sp,sp,-32
        addi    a2,sp,12
        lla     a1,.LC0
        li      a0,0
        sd      ra,24(sp)
        call    sscanf@plt
        ld      ra,24(sp)
        addi    sp,sp,32
        jr      ra
        .size   relaxme, .-relaxme
        .align  1
        .globl  foobar_new
        .type   foobar_new, @function
foobar_new:
        li      a0,1
        ret
        .size   foobar_new, .-foobar_new
        .symver foobar_new, foobar@@New
        .align  1
        .globl  foobar_old
        .type   foobar_old, @function
foobar_old:
        addi    sp,sp,-16
        sd      ra,8(sp)
        call    foobar@plt
        ld      ra,8(sp)
        snez    a0,a0
        addi    sp,sp,16
        jr      ra
        .size   foobar_old, .-foobar_old
        .symver foobar_old, foobar@Old
        .section        .note.GNU-stack,"",@progbits

% cat relax-twice.ver
Old {
        global:
                foobar;
                relaxme;
        local:
                *;
};
New {
        global:
                foobar;
} Old;

% ../as-new -o relax-twice-1.o relax-twice-1.s
% ../as-new -o relax-twice-2.o relax-twice-2.s
% ../ld-new -o bla.so --relax -shared --version-script relax-twice.ver
relax-twice-1.o relax-twice-2.o
% nm bla.so
...
000000000000102c t foobar_new
0000000000001028 T foobar@@New
...

Note how these two symbols are supposed to point to the same address.  (The
stunt with the weak variant of foobar_new and foobar@@New in relax-twice-1.s
is only there to prime the internal symbol table of ld in the same way as
it would have been with LTO and the linker plugin.  The prevailing variants
are the ones from relax-twice-2.s)

The reason is the one already analyzed in PR22756: multiple entries in
sym_hashes[] pointing to the same symbol entry, such that the relaxation code
adjusts the same entry multiple times.  That is the situation always created
by aliases, and the PR22756 patch fixes it for hidden aliases (created by 
non-default symbol versions, i.e. foobar@BLA).  Of course the same can happen
with non-hidden aliases, as above demonstrates.

A definitely working fix would be to always check for duplicates, but a
slowdown
for that can then only be avoided by extending the elf symbol hash structure
to contain an already-handled flag.  The more immediate, but possibly also
still incomplete fix is simply:

--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3993,7 +3993,7 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec,
bfd_vma addr, size_t count,
         foo becomes an alias for foo@BAR, and hence they need the same
         treatment.  */
       if (link_info->wrap_hash != NULL
-         || sym_hash->versioned == versioned_hidden)
+         || sym_hash->versioned != unversioned)
        {
          struct elf_link_hash_entry **cur_sym_hashes;


I will note that the problem exists for all targets that implement relaxation
that can also delete bytes from sections (it seems to all have been copied
around for decades), at least MIPS and AVR seem somewhat relevant still, but
it's also m10[23]00, cr16, h8300, ip2k, m32c, m68hc11, msp430, rl78, rx and
v850.  Only riscv goes to an effort to remidy the situation with symbol
aliases.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]