Re: [PATCH] PE/COFF: raise normal PE section limit safely

Jan Beulich <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
On 30.06.2026 22:59, Oleg Tolmatcev wrote:
> PE/COFF stores symbol section numbers in a 16-bit field.  Binutils used
> signed 16-bit handling there, which limited normal PE objects to 32767
> sections even though MSVC and Clang already accept a larger unsigned
> range.
> 
> Raise the normal PE section limit to 65279, while keeping the PE/COFF
> special section-number values for undefined, absolute and debug symbols
> working correctly.  Do this by decoding and encoding normal PE symbol
> section numbers as unsigned values in the ordinary range, but preserving
> the reserved PE constants explicitly.
> 
> Also add a gas test that exercises a normal PE object above the old
> 32767-section limit and checks that objdump reports the high section
> number correctly.
> 
> bfd/ChangeLog:
> 
> 	* coffcode.h (COFF_DEFAULT_MAX_NSCNS): Define.
> 	(bfd_coff_std_swap_table): Use it for the default maximum section
> 	count.
> 	(ticoff0_swap_table): Likewise.
> 	(ticoff1_swap_table): Likewise.
> 	* peXXigen.c (pe_decode_sym_section_number): New function.
> 	(pe_encode_sym_section_number): New function.
> 	(_bfd_XXi_swap_sym_in): Use pe_decode_sym_section_number.
> 	(_bfd_XXi_swap_sym_out): Use pe_encode_sym_section_number.
> 
> include/ChangeLog:
> 
> 	* coff/pe.h (IMAGE_SYM_UNDEFINED): Define.
> 	(IMAGE_SYM_ABSOLUTE): Define.
> 	(IMAGE_SYM_DEBUG): Define.
> 	(IMAGE_SYM_SECTION_MAX): Define.
> 
> gas/ChangeLog:
> 
> 	* testsuite/gas/pe/pe.exp: Run large-obj-normal.
> 	* testsuite/gas/pe/large-obj-normal.s: New test.
> 	* testsuite/gas/pe/large-obj-normal.d: New test.
> 
> Signed-off-by: Oleg Tolmatcev <[email protected]>

Looks largely okay to me, there's just one concern I have:

> --- a/bfd/peXXigen.c
> +++ b/bfd/peXXigen.c
> @@ -109,6 +109,49 @@
>  #define SetHighBit(val)      ((val) | 0x80000000)
>  #define WithoutHighBit(val)  ((val) & 0x7fffffff)
>  
> +static int
> +pe_decode_sym_section_number (bfd *abfd, const char *raw_scnum)
> +{
> +  unsigned int scnum = H_GET_16 (abfd, raw_scnum);
> +
> +  switch (scnum)
> +    {
> +    case IMAGE_SYM_UNDEFINED:
> +      return N_UNDEF;
> +    case IMAGE_SYM_ABSOLUTE:
> +      return N_ABS;
> +    case IMAGE_SYM_DEBUG:
> +      return N_DEBUG;
> +    default:
> +      return scnum;
> +    }
> +}

When coming here for objcopy, upon reading the input we blindly accept any
other values in the reserved range. Then ...

> +static void
> +pe_encode_sym_section_number (bfd *abfd, int scnum, char *raw_scnum)
> +{
> +  unsigned int encoded_scnum;
> +
> +  switch (scnum)
> +    {
> +    case N_UNDEF:
> +      encoded_scnum = IMAGE_SYM_UNDEFINED;
> +      break;
> +    case N_ABS:
> +      encoded_scnum = IMAGE_SYM_ABSOLUTE;
> +      break;
> +    case N_DEBUG:
> +      encoded_scnum = IMAGE_SYM_DEBUG;
> +      break;
> +    default:
> +      BFD_ASSERT (scnum > 0 && (unsigned int) scnum <= IMAGE_SYM_SECTION_MAX);

... upon writing we'd stumble over this assertion. Assertions really should
be about internal state only, not about input we consumed.

Jan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.