]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
PE-COFF: Fix link failure of C++ code with debug info after partial linking
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 30 Mar 2026 17:10:26 +0000 (19:10 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 30 Mar 2026 17:12:46 +0000 (19:12 +0200)
If you apply the following recipe to the attached C/C++ files with a PE-COFF
toolchain, you get the specified output:

1. g++ -c clib.cpp cpplib.cpp test.c -g
2. g++ -o pl.o clib.o cpplib.o -nostdlib -Wl,-r
3. objcopy pl.o
objcopy.exe: pl.o: warning: COMDAT symbol
'.debug_frame$_ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev' does not match
section name '.debug_frame'
4. g++ -o test test.o pl.o
ld.exe: pl.o: warning: COMDAT symbol
'.debug_frame$_ZNSt12_Vector_baseIiSaIiEE12_Vector_implD1Ev' does not match
section name '.debug_frame'
pl.o:clib.cpp:(.pdata$_ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPiy+0x0):
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32NB against
`.text$_ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPiy'
pl.o:clib.cpp:(.pdata$_ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPiy+0x4):
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32NB against
`.text$_ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPiy'
pl.o:clib.cpp:(.pdata$_ZNSt12_Vector_baseIiSaIiEE19_M_get_Tp_allocatorEv+0x0):
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32NB against
`.text$_ZNSt12_Vector_baseIiSaIiEE19_M_get_Tp_allocatorEv'
pl.o:clib.cpp:(.pdata$_ZNSt12_Vector_baseIiSaIiEE19_M_get_Tp_allocatorEv+0x4):
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32NB against
`.text$_ZNSt12_Vector_baseIiSaIiEE19_M_get_Tp_allocatorEv'
pl.o:clib.cpp:(.pdata$_ZNSt15__new_allocatorIiE10deallocateEPiy+0x0):
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32NB against
`.text$_ZNSt15__new_allocatorIiE10deallocateEPiy'
pl.o:clib.cpp:(.pdata$_ZNSt15__new_allocatorIiE10deallocateEPiy+0x4):
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32NB against
`.text$_ZNSt15__new_allocatorIiE10deallocateEPiy'
collect2.exe: error: ld returned 1 exit status

The problem pertains to section symbols generated for COMDAT sections: they
are marked as local symbols as per Microsoft's PE-COFF specification, but
partial linking discards the duplicate COMDAT sections without being able
to either merge them, or remove them when they are used in a relocation.

So they end up as undefined local symbols after the partial link, which in
turn may cause the final link to fail (in practice you need e.g. a call to
objcopy in between, because it moves them to the end of the symbol list).

This change instructs the linker to "relocate" them instead, that is to say
to attach them to the one COMDAT section that is output among the multiple
COMDAT sections that are duplicate.  It also prevents partial linking from
prematurely globing the .[z]debug_frame* sections together, as already done
for the .eh_frame* sections.

bfd/
* cofflink.c (_bfd_coff_link_input_bfd): For a relocatable output,
relocate section symbols for input sections that are not going to
be emitted because they are duplicate of another one in the link.
ld/
* scripttempl/pe.sc (.debug_frame): Do not glob all .debug_frame*
sections together when not relocating.
(.zdebug_frame): Likewise for .zdebug_frame* sections.
* scripttempl/pep.sc (.debug_frame): Likewise.
(.zdebug_frame): Likewise.

bfd/cofflink.c
ld/scripttempl/pe.sc
ld/scripttempl/pep.sc

index 3504b2d4a0c52ed4a665b0b54a72d67abd11aac4..e5c8a987d699a399ee459aa4a458ff4b392cf6dc 100644 (file)
@@ -1857,12 +1857,26 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd)
              /* Compute new symbol location.  */
            if (isym.n_scnum > 0)
              {
-               isym.n_scnum = (*secpp)->output_section->target_index;
-               isym.n_value += (*secpp)->output_offset;
+               const asection *s = *secpp;
+
+               /* Relocate section symbols for sections that are not going to
+                  be emitted because they are duplicate of another one.  */
+               if (bfd_link_relocatable (flaginfo->info)
+                   && isym.n_sclass == C_STAT
+                   && isym.n_type == T_NULL
+                   && isym.n_numaux > 0
+                   && (s->output_section == bfd_abs_section_ptr
+                       || bfd_section_removed_from_list
+                          (output_bfd, s->output_section))
+                   && s->kept_section)
+                 s = s->kept_section;
+
+               isym.n_scnum = s->output_section->target_index;
+               isym.n_value += s->output_offset;
                if (! obj_pe (input_bfd))
-                 isym.n_value -= (*secpp)->vma;
+                 isym.n_value -= s->vma;
                if (! obj_pe (flaginfo->output_bfd))
-                 isym.n_value += (*secpp)->output_section->vma;
+                 isym.n_value += s->output_section->vma;
              }
            break;
 
index f8d7c8ef6e7c711e47b77d50a74872df05275d81..a669f279eda449ba25c8e6da35dcba8c9c5cbf1a 100644 (file)
@@ -364,11 +364,11 @@ SECTIONS
 
   .debug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
   {
-    *(.debug_frame*)
+    *(.debug_frame${RELOCATING+*})
   }
   .zdebug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
   {
-    *(.zdebug_frame*)
+    *(.zdebug_frame${RELOCATING+*})
   }
 
   .debug_str ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
index a5b4679544c078384cfd753d5073a3ebe41c6326..45e785492c561c6fd6e93c5660edd4d8c591035f 100644 (file)
@@ -373,11 +373,11 @@ SECTIONS
 
   .debug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
   {
-    *(.debug_frame*)
+    *(.debug_frame${RELOCATING+*})
   }
   .zdebug_frame ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :
   {
-    *(.zdebug_frame*)
+    *(.zdebug_frame${RELOCATING+*})
   }
 
   .debug_str ${RELOCATING+BLOCK(__section_alignment__)} ${RELOCATING+(NOLOAD)} :