strip: Don't treat fat IR objects as plugin object

Fat IR objects contains both regular sections and IR sections.  After

commit 717a38e9a0
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Sun May 4 05:12:46 2025 +0800

    strip: Add GCC LTO IR support

"strip --strip-debug" no longer strips debug sections in fat IR objects
since fat IR objects are recognized as plugin object and copied as unknown
objects.  Add a is_strip_input field to bfd to indicate called from strip.
Update bfd_check_format_matches not to treat archive member nor standalone
fat IR object as IR object so that strip can remove debug and IR sections
in fat IR object.  For archive member, it is copied as an unknown object
if the plugin target is in use or it is a slim IR object.  For standalone
fat IR object, it is copied as non-IR object.

bfd/

	PR binutils/33246
	* archive.c: Include "plugin-api.h" and "plugin.h" if plugin is
	enabled.
	(_bfd_compute_and_write_armap): Don't complain plugin is needed
	when the plugin target is in use.
	* bfd-in2.h: Regenerated.
	* bfd.c (bfd): Add is_strip_input.
	* format.c (bfd_set_lto_type): If there is .llvm.lto section,
	set LTO type to lto_fat_ir_object.
	(bfd_check_format_matches): Don't set LTO type when setting
	format.  When called from strip, don't treat archive member nor
	standalone fat IR object as an IR object.
	* plugin.c (bfd_plugin_get_symbols_in_object_only): Copy LTO
	type derived from input sections.

nm/

	PR binutils/33246
	* nm.c (filter_symbols): Don't complain plugin is needed when
	the plugin target is in use.
	(display_rel_file): Likewise.
	* objcopy.c (copy_archive): Set the BFD is_strip_input field of
	archive member to 1 to indicate called from strip.  Also copy
	slim IR archive member as unknown object.
	(copy_file): Set the BFD is_strip_input field of input bfd to
	1 to indicate called from strip.
	(strip_main): Keep .gnu.debuglto_* sections unless all GCC LTO
	sections will be removed.

ld/

	PR binutils/33246
	* testsuite/ld-plugin/lto-binutils.exp (run_pr33246_test): New.
	Run binutils/33246 tests with GCC and Clang.
	* testsuite/ld-plugin/pr33246.c: New file.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
H.J. Lu
2025-08-03 10:28:40 -07:00
parent d6e93eedfb
commit c2729c37f1
9 changed files with 238 additions and 7 deletions

View File

@@ -141,6 +141,10 @@ SUBSECTION
#include "hashtab.h" #include "hashtab.h"
#include "filenames.h" #include "filenames.h"
#include "bfdlink.h" #include "bfdlink.h"
#if BFD_SUPPORTS_PLUGINS
#include "plugin-api.h"
#include "plugin.h"
#endif
#ifndef errno #ifndef errno
extern int errno; extern int errno;
@@ -2343,6 +2347,9 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
long src_count; long src_count;
if (bfd_get_lto_type (current) == lto_slim_ir_object if (bfd_get_lto_type (current) == lto_slim_ir_object
#if BFD_SUPPORTS_PLUGINS
&& !bfd_plugin_target_p (current->xvec)
#endif
&& report_plugin_err) && report_plugin_err)
{ {
report_plugin_err = false; report_plugin_err = false;
@@ -2400,6 +2407,9 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
if (bfd_lto_slim_symbol_p (current, if (bfd_lto_slim_symbol_p (current,
syms[src_count]->name) syms[src_count]->name)
#if BFD_SUPPORTS_PLUGINS
&& !bfd_plugin_target_p (current->xvec)
#endif
&& report_plugin_err) && report_plugin_err)
{ {
report_plugin_err = false; report_plugin_err = false;

View File

@@ -2131,6 +2131,9 @@ struct bfd
/* Set if this is the linker input BFD. */ /* Set if this is the linker input BFD. */
unsigned int is_linker_input : 1; unsigned int is_linker_input : 1;
/* Set if this is the strip input BFD. */
unsigned int is_strip_input : 1;
/* If this is an input for a compiler plug-in library. */ /* If this is an input for a compiler plug-in library. */
ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2; ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;

View File

@@ -296,6 +296,9 @@ CODE_FRAGMENT
. {* Set if this is the linker input BFD. *} . {* Set if this is the linker input BFD. *}
. unsigned int is_linker_input : 1; . unsigned int is_linker_input : 1;
. .
. {* Set if this is the strip input BFD. *}
. unsigned int is_strip_input : 1;
.
. {* If this is an input for a compiler plug-in library. *} . {* If this is an input for a compiler plug-in library. *}
. ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2; . ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
. .

View File

@@ -389,6 +389,11 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
abfd->object_only_section = sec; abfd->object_only_section = sec;
break; break;
} }
else if (strcmp (sec->name, ".llvm.lto") == 0)
{
type = lto_fat_ir_object;
break;
}
else if (lsection.major_version == 0 else if (lsection.major_version == 0
&& startswith (sec->name, ".gnu.lto_.lto.") && startswith (sec->name, ".gnu.lto_.lto.")
&& bfd_get_section_contents (abfd, sec, &lsection, 0, && bfd_get_section_contents (abfd, sec, &lsection, 0,
@@ -453,10 +458,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
} }
if (abfd->format != bfd_unknown) if (abfd->format != bfd_unknown)
{
bfd_set_lto_type (abfd);
return abfd->format == format; return abfd->format == format;
}
if (matching != NULL || *bfd_associated_vector != NULL) if (matching != NULL || *bfd_associated_vector != NULL)
{ {
@@ -510,7 +512,20 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
if (cleanup) /* When called from strip, don't treat archive member nor
standalone fat IR object as an IR object. For archive
member, it will be copied as an unknown object if the
plugin target is in use or it is a slim IR object. For
standalone fat IR object, it will be copied as non-IR
object. */
if (cleanup
#if BFD_SUPPORTS_PLUGINS
&& (!abfd->is_strip_input
|| !bfd_plugin_target_p (abfd->xvec)
|| (abfd->lto_type != lto_fat_ir_object
&& abfd->my_archive == NULL))
#endif
)
goto ok_ret; goto ok_ret;
/* For a long time the code has dropped through to check all /* For a long time the code has dropped through to check all

View File

@@ -206,6 +206,9 @@ bfd_plugin_get_symbols_in_object_only (bfd *abfd)
bfd_close (nbfd); bfd_close (nbfd);
return; return;
} }
/* Copy LTO type derived from input sections. */
abfd->lto_type = nbfd->lto_type;
} }
else else
{ {

View File

@@ -802,6 +802,9 @@ filter_symbols (bfd *abfd, bool is_dynamic, void *minisyms,
continue; continue;
if (bfd_lto_slim_symbol_p (abfd, sym->name) if (bfd_lto_slim_symbol_p (abfd, sym->name)
#if BFD_SUPPORTS_PLUGINS
&& !bfd_plugin_target_p (abfd->xvec)
#endif
&& report_plugin_err) && report_plugin_err)
{ {
report_plugin_err = false; report_plugin_err = false;
@@ -1484,7 +1487,11 @@ display_rel_file (bfd *abfd, bfd *archive_bfd)
/* lto_type is set to lto_non_ir_object when a bfd is loaded with a /* lto_type is set to lto_non_ir_object when a bfd is loaded with a
compiler LTO plugin. */ compiler LTO plugin. */
if (bfd_get_lto_type (abfd) == lto_slim_ir_object) if (bfd_get_lto_type (abfd) == lto_slim_ir_object
#if BFD_SUPPORTS_PLUGINS
&& !bfd_plugin_target_p (abfd->xvec)
#endif
)
{ {
report_plugin_err = false; report_plugin_err = false;
non_fatal (_("%s: plugin needed to handle lto object"), non_fatal (_("%s: plugin needed to handle lto object"),

View File

@@ -3689,6 +3689,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
bool ok_object; bool ok_object;
const char *element_name; const char *element_name;
this_element->is_strip_input = 1;
element_name = bfd_get_filename (this_element); element_name = bfd_get_filename (this_element);
/* PR binutils/17533: Do not allow directory traversal /* PR binutils/17533: Do not allow directory traversal
outside of the current directory tree by archive members. */ outside of the current directory tree by archive members. */
@@ -3769,7 +3771,9 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
#if BFD_SUPPORTS_PLUGINS #if BFD_SUPPORTS_PLUGINS
/* Copy LTO IR file as unknown object. */ /* Copy LTO IR file as unknown object. */
if (bfd_plugin_target_p (this_element->xvec)) if ((!lto_sections_removed
&& this_element->lto_type == lto_slim_ir_object)
|| bfd_plugin_target_p (this_element->xvec))
ok_object = false; ok_object = false;
else else
#endif #endif
@@ -3966,6 +3970,8 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
break; break;
} }
ibfd->is_strip_input = 1;
if (bfd_check_format (ibfd, bfd_archive)) if (bfd_check_format (ibfd, bfd_archive))
{ {
bool force_output_target; bool force_output_target;
@@ -5072,6 +5078,11 @@ strip_main (int argc, char *argv[])
SECTION_CONTEXT_REMOVE) SECTION_CONTEXT_REMOVE)
|| !!find_section_list (".llvm.lto", false, || !!find_section_list (".llvm.lto", false,
SECTION_CONTEXT_REMOVE)); SECTION_CONTEXT_REMOVE));
/* NB: Must keep .gnu.debuglto_* sections unless all GCC LTO sections
will be removed to avoid undefined references to symbols in GCC LTO
debug sections. */
if (!lto_sections_removed)
find_section_list (".gnu.debuglto_*", true, SECTION_CONTEXT_KEEP);
#endif #endif
i = optind; i = optind;

View File

@@ -355,3 +355,178 @@ run_cc_link_tests [list \
"tmpdir/libstrip-1b-fat-s.a" \ "tmpdir/libstrip-1b-fat-s.a" \
] \ ] \
] ]
proc run_pr33246_test { llvm fat } {
global srcdir
global subdir
global plug_opt
global llvm_plug_opt
global ar
global CLANG_FOR_TARGET
global CC_FOR_TARGET
global NM
global READELF
global strip
set strip_flags "--strip-debug --enable-deterministic-archives"
set test pr33246
set testname "${test}${llvm}${fat} with $strip_flags"
if { "$llvm" == "-llvm" } {
# Skip native x32 and i?86 targets since system LLVMgold.so may
# not be compatible with native x32 and i?86 targets binutils.
if { [istarget "x86_64-*-linux*-gnux32"]
|| [istarget "i?86-*-*"]
|| ![info exists CLANG_FOR_TARGET]
|| [string match "" $llvm_plug_opt] } then {
untested $testname
return
}
set CC $CLANG_FOR_TARGET
set binutils_plug_opt "$llvm_plug_opt"
} else {
if { ![info exists CC_FOR_TARGET]
|| [string match "" $plug_opt] } then {
untested $testname
return
}
set CC $CC_FOR_TARGET
set binutils_plug_opt "$plug_opt"
}
append strip_flags " $binutils_plug_opt"
set src $srcdir/$subdir/${test}.c
set obj tmpdir/${test}${llvm}${fat}.o
set archive tmpdir/${test}${llvm}${fat}.a
set CFLAGS "-c -g -O2 -flto"
if { "$fat" == "-fat" } {
append CFLAGS " -ffat-lto-objects"
} else {
append CFLAGS " -fno-fat-lto-objects"
}
set cmd "$CC $CFLAGS -o $obj $src"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![string match "" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname ($obj)"
return
}
set cmd "$strip $strip_flags $obj -o ${obj}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![string match "" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $obj)"
return
}
set cmd "$NM $binutils_plug_opt ${obj}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![regexp "0+ T foo" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $obj)"
return
}
if { "$fat" == "-fat" } {
set cmd "$READELF -SW ${obj}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if [regexp " \.debug_" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $obj)"
return
}
} else {
set cmd "cmp $obj ${obj}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![string match "" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $obj)"
return
}
}
pass "$testname (strip $obj)"
set cmd "$ar $binutils_plug_opt -D -s -r -c $archive $obj"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![string match "" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname ($archive)"
return
}
set cmd "$strip $strip_flags $archive -o ${archive}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![string match "" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $archive)"
return
}
set cmd "$NM $binutils_plug_opt ${archive}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![regexp "0+ T foo" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $archive)"
return
}
if { "$fat" == "-fat" } {
set cmd "$READELF -SW ${archive}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if [regexp " \.debug_" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $archive)"
return
}
} else {
set cmd "cmp $archive ${archive}.strip"
send_log "$cmd\n"
verbose "$cmd" 1
catch "exec $cmd" got
if ![string match "" $got] then {
send_log "$got\n"
verbose "$got" 1
fail "$testname (strip $archive)"
return
}
}
pass "$testname (strip $archive)"
}
run_pr33246_test "" ""
run_pr33246_test "" "-fat"
run_pr33246_test "-llvm" ""
run_pr33246_test "-llvm" "-fat"

View File

@@ -0,0 +1,4 @@
void
foo (void)
{
}