Bug 28639

Summary: Linker should ignore input .note.gnu.build-id sections
Product: binutils Reporter: Valerii Chernous <vchernou>
Component: ldAssignee: H.J. Lu <hjl.tools>
Status: RESOLVED FIXED    
Severity: normal CC: hjl.tools
Priority: P2    
Version: 2.38   
Target Milestone: 2.38   
Host: Target:
Build: Last reconfirmed: 2021-12-01 00:00:00
Attachments: patch for fixing issue
A patch

Description Valerii Chernous 2021-11-30 17:00:45 UTC
Created attachment 13809 [details]
patch for fixing issue

building of glibc 2.32 and later with option "-Wl,--build-id" produce libc.so.6 with section ".note.gnu.build-id" that have invalid(double, 0x48) section size.
It happens because glibc use sublibraries for linking libc.so.
ld produce this sublibraries with build-id section and on last linking stage loads this sections as input for linking.
ld should create new(valid) ".note.gnu.build-id" into function ldelf_setup_build_id on last linking stage but it skip creating because build-id section already exists.
As result libc.so.6 contain ".note.gnu.build-id" with build-ids from sublibraries and without valid build-id
Howto solved:
Ignoring ".note.gnu.build-id" on linker input fix this problem.
Linker input doesn't have invalid build-id sections on ldelf_setup_build_id stage and create new(proper) one for output library/binary

Clang have it's own fix for this issue:
https://reviews.llvm.org/D42823
https://bugs.llvm.org/show_bug.cgi?id=36203

howto reproduce:
yocto:
cd GLIBC_RECIPE_WORKDIR
export CMD_PREFIX="./recipe-sysroot-native/usr/bin/x86_64-iosxe-linux/x86_64-iosxe-linux"; export GCC="$CMD_PREFIX-gcc"; export RELF="$CMD_PREFIX-readelf"
echo "void f1(){}" >f1.c
echo "void f2(){}" >f2.c
$GCC f1.c -c -o f1.o
$GCC f2.c -c -o f2.o
$GCC f1.o -Wl,--build-id -nostdlib -nostartfiles -r -o f1
$GCC f2.o -Wl,--build-id -nostdlib -nostartfiles -r -o f2
$GCC ./f1 ./f2 -shared -Wl,--build-id -nostdlib -nostartfiles -o f.so
$RELF -S f.so | grep -E -A1 "note.gnu.bu"

ubuntu:
echo "void f1(){}" >f1.c
echo "void f2(){}" >f2.c
gcc f1.c -c -o f1.o
gcc f2.c -c -o f2.o
gcc f1.o -Wl,--build-id -nostdlib -nostartfiles -r -o f1
gcc f2.o -Wl,--build-id -nostdlib -nostartfiles -r -o f2
gcc ./f1 ./f2 -shared -Wl,--build-id -nostdlib -nostartfiles -o f.so
readelf -S f.so | grep -E -A1 "note.gnu.bu"

output:
without fix
  [ 1] .note.gnu.bu[...] NOTE 0000000000000238  00000238
   0000000000000048  0000000000000000   A   0 0 4
with fix
  [ 1] .note.gnu.bu[...] NOTE 0000000000000238  00000238
   0000000000000024  0000000000000000   A   0 0 4
Comment 1 H.J. Lu 2021-12-01 01:54:41 UTC
Created attachment 13810 [details]
A patch

Please try this.
Comment 2 Valerii Chernous 2021-12-01 16:38:10 UTC
(In reply to H.J. Lu from comment #1)
> Created attachment 13810 [details]
> A patch
> 
> Please try this.

libc.so.6 for x86-64 platform have valid .note.gnu.build-id section size  
readelf -S ./image/usr/lib64/libc.so.6 | grep -E -A1 "note.gnu.bu"
  [ 1] .note.gnu.bu[...] NOTE             00000000000002e0  000002e0
       0000000000000024  0000000000000000   A       0     0     4

test case that I provided:
export CMD_PREFIX="./recipe-sysroot-native/usr/bin/x86_64-iosxe-linux/x86_64-iosxe-linux"; export GCC="$CMD_PREFIX-gcc"; export RELF="$CMD_PREFIX-readelf"
echo "void f1(){}" >f1.c
echo "void f2(){}" >f2.c
$GCC f1.c -c -o f1.o
$GCC f2.c -c -o f2.o
$GCC f1.o -Wl,--build-id -nostdlib -nostartfiles -r -o f1
$GCC f2.o -Wl,--build-id -nostdlib -nostartfiles -r -o f2
$GCC ./f1 ./f2 -shared -Wl,--build-id -nostdlib -nostartfiles -o f.so
$RELF -S f.so | grep -E -A1 "note.gnu.bu"

 [ 1] .note.gnu.bu[...] NOTE             0000000000000238  00000238
       0000000000000024  0000000000000000   A       0     0     4
Also return valid section size

I will inform you about result for all our testcases in couple of days
Thanks a lot for patch
Comment 3 Sourceware Commits 2021-12-02 00:42:28 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1f1d0f8888a6c944e612b416a2a6e11abcf5199f

commit 1f1d0f8888a6c944e612b416a2a6e11abcf5199f
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Nov 30 20:40:38 2021 -0800

    elf: Discard input .note.gnu.build-id sections
    
    1. Discard input .note.gnu.build-id sections.
    2. Clear the build ID field before writing.
    3. Use bfd_make_section_anyway_with_flags to create the output
    .note.gnu.build-id section.
    
            PR ld/28639
            * ldelf.c (ldelf_after_open): Discard input .note.gnu.build-id
            sections, excluding the first one.
            (write_build_id): Clear the build ID field before writing.
            (ldelf_setup_build_id): Use bfd_make_section_anyway_with_flags
            to create the output .note.gnu.build-id section.
            * testsuite/ld-elf/build-id.exp: New file.
            * testsuite/ld-elf/pr28639a.rd: Likewise.
            * testsuite/ld-elf/pr28639b.rd: Likewise.
            * testsuite/ld-elf/pr28639c.rd: Likewise.
            * testsuite/ld-elf/pr28639d.rd: Likewise.
Comment 4 H.J. Lu 2021-12-02 00:43:19 UTC
Fixed for 2.38.