[PATCH] PE/COFF: raise normal PE section limit safely
Jan Beulich
jbeulich@suse.com
Wed Jul 1 06:55:48 GMT 2026
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 <oleg.tolmatcev@gmail.com>
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
More information about the Binutils
mailing list