@@ -376,6 +376,12 @@ extern const bfd_target TARGET_SYM_BIG;
# define COFF_WITH_EXTENDED_RELOC_COUNTER
#endif
+#if defined(COFF_WITH_PE) && !defined(COFF_IMAGE_WITH_PE)
+# define COFF_DEFAULT_MAX_NSCNS (IMAGE_SYM_SECTION_MAX + 1)
+#else
+# define COFF_DEFAULT_MAX_NSCNS 32768
+#endif
+
#if defined (COFF_LONG_SECTION_NAMES)
/* Needed to expand the inputs to BLANKOR1TOODD. */
#define COFFLONGSECTIONCATHELPER(x,y) x ## y
@@ -927,6 +933,8 @@ fill_comdat_hash (bfd *abfd)
flagword sec_flags = SEC_LINK_ONCE;
bfd_coff_swap_sym_in (abfd, esym, &isym);
+ if (bfd_get_error () == bfd_error_bad_value)
+ return false;
/* According to the MSVC documentation, the first TWO entries
with the section # are both of interest to us. The first one
@@ -2315,6 +2323,11 @@ coff_set_arch_mach_hook (bfd *abfd, void * filehdr)
if (buf == NULL)
return false;
bfd_coff_swap_sym_in (abfd, buf, & sym);
+ if (bfd_get_error () == bfd_error_bad_value)
+ {
+ free (buf);
+ return false;
+ }
if (sym.n_sclass == C_FILE)
cputype = sym.n_type & 0xff;
else
@@ -5615,7 +5628,7 @@ static const bfd_coff_backend_data bfd_coff_std_swap_table ATTRIBUTE_UNUSED =
#else
2,
#endif
- 32768,
+ COFF_DEFAULT_MAX_NSCNS,
coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in,
coff_SWAP_reloc_in, coff_bad_format_hook, coff_set_arch_mach_hook,
coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook,
@@ -5656,7 +5669,7 @@ static const bfd_coff_backend_data ticoff0_swap_table =
#else
2,
#endif
- 32768,
+ COFF_DEFAULT_MAX_NSCNS,
coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in,
coff_swap_reloc_v0_in, ticoff0_bad_format_hook, coff_set_arch_mach_hook,
coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook,
@@ -5698,7 +5711,7 @@ static const bfd_coff_backend_data ticoff1_swap_table =
#else
2,
#endif
- 32768,
+ COFF_DEFAULT_MAX_NSCNS,
coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in,
coff_SWAP_reloc_in, ticoff1_bad_format_hook, coff_set_arch_mach_hook,
coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook,
@@ -1908,6 +1908,8 @@ coff_get_normalized_symtab (bfd *abfd)
bfd_coff_swap_sym_in (abfd, (void *) raw_src,
(void *) & internal_ptr->u.syment);
+ if (bfd_get_error () == bfd_error_bad_value)
+ return NULL;
internal_ptr->is_sym = true;
combined_entry_type *sym = internal_ptr;
@@ -315,6 +315,8 @@ coff_link_add_symbols (bfd *abfd,
bool copy;
bfd_coff_swap_sym_in (abfd, esym, &sym);
+ if (bfd_get_error () == bfd_error_bad_value)
+ goto error_return;
classification = bfd_coff_classify_symbol (abfd, &sym);
if (classification != COFF_SYMBOL_LOCAL)
@@ -1485,6 +1487,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd)
int add;
bfd_coff_swap_sym_in (input_bfd, esym, isymp);
+ if (bfd_get_error () == bfd_error_bad_value)
+ return false;
/* Make a copy of *isymp so that the relocate_section function
always sees the original values. This is more reliable than
@@ -1684,6 +1688,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd)
char *name_copy;
bfd_coff_swap_sym_in (input_bfd, esl, islp);
+ if (bfd_get_error () == bfd_error_bad_value)
+ return false;
amt = sizeof (struct coff_debug_merge_element);
*epp = (struct coff_debug_merge_element *)
@@ -2278,6 +2284,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd)
(flaginfo->outsyms
+ ((indx - syment_base)
* osymesz)), &is);
+ if (bfd_get_error () == bfd_error_bad_value)
+ return false;
if ((ISFCN (is.n_type)
|| is.n_sclass == C_BLOCK)
&& is.n_numaux >= 1)
@@ -109,12 +109,70 @@
#define SetHighBit(val) ((val) | 0x80000000)
#define WithoutHighBit(val) ((val) & 0x7fffffff)
+static bool
+pe_decode_sym_section_number (bfd *abfd, const char *raw_scnum, int *scnump)
+{
+ unsigned int scnum = H_GET_16 (abfd, raw_scnum);
+
+ switch (scnum)
+ {
+ case IMAGE_SYM_UNDEFINED:
+ *scnump = N_UNDEF;
+ return true;
+ case IMAGE_SYM_ABSOLUTE:
+ *scnump = N_ABS;
+ return true;
+ case IMAGE_SYM_DEBUG:
+ *scnump = N_DEBUG;
+ return true;
+ }
+
+ if (scnum > IMAGE_SYM_SECTION_MAX)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: invalid PE symbol section number %#x"), abfd, scnum);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ *scnump = scnum;
+ return true;
+}
+
+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);
+ encoded_scnum = scnum;
+ break;
+ }
+
+ H_PUT_16 (abfd, encoded_scnum, raw_scnum);
+}
+
void
_bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
{
SYMENT *ext = (SYMENT *) ext1;
struct internal_syment *in = (struct internal_syment *) in1;
+ memset (in, 0, sizeof (*in));
+
if (ext->e.e_name[0] == 0)
{
in->_n._n_n._n_zeroes = 0;
@@ -124,7 +182,8 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN);
in->n_value = H_GET_32 (abfd, ext->e_value);
- in->n_scnum = (short) H_GET_16 (abfd, ext->e_scnum);
+ if (! pe_decode_sym_section_number (abfd, ext->e_scnum, &in->n_scnum))
+ return;
if (sizeof (ext->e_type) == 2)
in->n_type = H_GET_16 (abfd, ext->e_type);
@@ -262,7 +321,7 @@ _bfd_XXi_swap_sym_out (bfd * abfd, void * inp, void * extp)
}
H_PUT_32 (abfd, in->n_value, ext->e_value);
- H_PUT_16 (abfd, in->n_scnum, ext->e_scnum);
+ pe_encode_sym_section_number (abfd, in->n_scnum, ext->e_scnum);
if (sizeof (ext->e_type) == 2)
H_PUT_16 (abfd, in->n_type, ext->e_type);
@@ -1293,6 +1293,62 @@ proc objcopy_test_elf_common_symbols {} {
}
}
+proc objcopy_test_invalid_pe_symbol_section_number {} {
+ global OBJDUMP
+ global OBJDUMPFLAGS
+ global srcdir
+ global subdir
+ global binutils_run_status
+
+ set test "objdump rejects invalid PE symbol section number"
+
+ if { ![is_pecoff_format] } {
+ return
+ }
+
+ if { [is_remote host] } {
+ untested $test
+ return
+ }
+
+ set objfile tmpdir/invalid-pe-scnum.o
+ if { ![binutils_assemble $srcdir/$subdir/bintest.s $objfile] } then {
+ unsupported $test
+ return
+ }
+
+ set file [open $objfile r+b]
+ fconfigure $file -translation binary
+ set data [read $file]
+
+ binary scan [string range $data 8 11] cu4 bytes
+ set symptr [expr {([lindex $bytes 0] << 0)
+ | ([lindex $bytes 1] << 8)
+ | ([lindex $bytes 2] << 16)
+ | ([lindex $bytes 3] << 24)}]
+ set scnum_off [expr {$symptr + 12}]
+
+ set data [string replace $data $scnum_off [expr {$scnum_off + 1}] "\xFD\xFF"]
+
+ seek $file 0 start
+ puts -nonewline $file $data
+ close $file
+
+ set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -t $objfile"]
+ if { $binutils_run_status == 0 } {
+ fail $test
+ return
+ }
+
+ if { ![regexp "invalid PE symbol section number 0xfffd" $got] } {
+ send_log "$got\n"
+ fail $test
+ return
+ }
+
+ pass $test
+}
+
# ia64 specific tests
if { ([istarget "ia64-*-elf*"]
|| [istarget "ia64-*-linux*"]) } {
@@ -1581,6 +1637,8 @@ if { ![is_xcoff_format] } {
run_dump_test "rename-section-01"
+objcopy_test_invalid_pe_symbol_section_number
+
proc objcopy_tek2bin {} {
global OBJCOPY
global OBJDUMP
new file mode 100644
@@ -0,0 +1,17 @@
+#objdump: -h -t
+#name: PE large normal object after raising the normal section limit
+
+# This only becomes meaningful once normal PE/COFF is allowed past the
+# old 32767-section cutoff. Before that, BFD errors out or auto-promotes
+# to bigobj before the normal 16-bit symbol-section encoding is exercised.
+
+.*: *file format pe-(aarch64-little|i386|x86-64)
+
+Sections:
+#...
+40002 +\.data\$a39999 .*
+ CONTENTS, ALLOC, LOAD, DATA
+
+SYMBOL TABLE:
+#...
+.*\(sec 40003\).*\(scl +2\).*\) 0x[0-9a-f]+ a39999$
new file mode 100644
@@ -0,0 +1,16 @@
+ .file "large-obj-normal.s"
+
+ .irp n,0,1,2,3
+ .irp m,0,1,2,3,4,5,6,7,8,9
+ .irp c,0,1,2,3,4,5,6,7,8,9
+ .irp d,0,1,2,3,4,5,6,7,8,9
+ .irp u,0,1,2,3,4,5,6,7,8,9
+ .globl a\n\m\c\d\u
+ .section .data$a\n\m\c\d\u,"w"
+a\n\m\c\d\u :
+ .byte 1
+ .endr
+ .endr
+ .endr
+ .endr
+ .endr
@@ -71,6 +71,7 @@ if {[istarget "aarch64-*-pe*"] || [istarget "aarch64-*-mingw*"]} {
if { [istarget "aarch64-*-*"]
|| ([istarget "i*86-*-*"] && ![istarget "*-*-interix*"])
|| [istarget "x86_64-*-*"] } then {
+ run_dump_test "large-obj-normal"
run_dump_test "big-obj"
run_dump_test "big-obj-auto"
}
@@ -388,6 +388,11 @@ struct external_SYMBOL_EX
char e_numaux[1];
} ATTRIBUTE_PACKED ;
+#define IMAGE_SYM_UNDEFINED 0
+#define IMAGE_SYM_ABSOLUTE 0xffff
+#define IMAGE_SYM_DEBUG 0xfffe
+#define IMAGE_SYM_SECTION_MAX 0xfeff
+
#define SYMENT_BIGOBJ struct external_SYMBOL_EX
#define SYMESZ_BIGOBJ 20