diff options
-rw-r--r-- | bfd/ChangeLog | 26 | ||||
-rw-r--r-- | bfd/coff-go32.c | 134 | ||||
-rw-r--r-- | bfd/coff-stgo32.c | 30 | ||||
-rw-r--r-- | bfd/coffcode.h | 70 | ||||
-rw-r--r-- | bfd/cofflink.c | 4 | ||||
-rw-r--r-- | bfd/coffswap.h | 2 | ||||
-rw-r--r-- | bfd/libcoff-in.h | 6 | ||||
-rw-r--r-- | bfd/libcoff.h | 6 |
8 files changed, 250 insertions, 28 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b89aced..c301501 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,29 @@ +2020-04-14 Juan Manuel Guerrero <juan.guerrero@gmx.de> + Jan W. Jagersma <jwjagersma@gmail.com> + + * coff-go32.c (COFF_GO32, IMAGE_SCN_LNK_NRELOC_OVFL) + (coff_SWAP_scnhdr_in, coff_SWAP_scnhdr_out): Define. + (_bfd_go32_swap_scnhdr_in, _bfd_go32_swap_scnhdr_out) + (_bfd_go32_mkobject): New functions. + * coff-stgo32.c (IMAGE_SCN_LNK_NRELOC_OVFL) + (coff_SWAP_scnhdr_in, coff_SWAP_scnhdr_out): Define. + (go32exe_mkobject): Call _bfd_go32_mkobject. + * coffcode.h (COFF_WITH_EXTENDED_RELOC_COUNTER): Define. + (coff_set_alignment_hook): Define function for COFF_GO32_EXE + and COFF_GO32. + (coff_write_relocs): Enable extended reloc counter code if + COFF_WITH_EXTENDED_RELOC_COUNTER is defined. Test for obj_go32. + (coff_write_object_contents): Likewise. Pad section headers + for COFF_GO32 and COFF_GO32EXE. Use bfd_coff_swap_scnhdr_out + instead of coff_swap_scnhdr_out. + * cofflink.c (_bfd_coff_final_link): Test also for obj_go32 to + enable extended reloc counter. + * coffswap.h: (coff_swap_scnhdr_in, coff_swap_scnhdr_out): + Declare with ATTRIBUTE_UNUSED. + * libcoff-in.h: (struct coff_tdata): New field go32. + (obj_go32): Define. + * libcoff.h: Regenerate. + 2020-04-14 Fangrui Song <maskray@google.com> PR gas/25768 diff --git a/bfd/coff-go32.c b/bfd/coff-go32.c index e43d5ce..4487693 100644 --- a/bfd/coff-go32.c +++ b/bfd/coff-go32.c @@ -22,6 +22,7 @@ #define TARGET_SYM i386_coff_go32_vec #define TARGET_NAME "coff-go32" #define TARGET_UNDERSCORE '_' +#define COFF_GO32 #define COFF_LONG_SECTION_NAMES #define COFF_SUPPORT_GNU_LINKONCE #define COFF_LONG_FILENAMES @@ -42,4 +43,137 @@ { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } +/* Section contains extended relocations. */ +#define IMAGE_SCN_LNK_NRELOC_OVFL (0x01000000) + +#include "sysdep.h" +#include "bfd.h" + +/* The following functions are not static, because they are also + used for coff-go32-exe (coff-stgo32.c). */ +bfd_boolean _bfd_go32_mkobject (bfd *); +void _bfd_go32_swap_scnhdr_in (bfd *, void *, void *); +unsigned int _bfd_go32_swap_scnhdr_out (bfd *, void *, void *); + +#define coff_mkobject _bfd_go32_mkobject +#define coff_SWAP_scnhdr_in _bfd_go32_swap_scnhdr_in +#define coff_SWAP_scnhdr_out _bfd_go32_swap_scnhdr_out + #include "coff-i386.c" + +bfd_boolean +_bfd_go32_mkobject (bfd * abfd) +{ + const bfd_size_type amt = sizeof (coff_data_type); + + abfd->tdata.coff_obj_data = bfd_zalloc (abfd, amt); + if (abfd->tdata.coff_obj_data == NULL) + return FALSE; + + coff_data (abfd)->go32 = TRUE; + + return TRUE; +} + +void +_bfd_go32_swap_scnhdr_in (bfd * abfd, void * ext, void * in) +{ + SCNHDR *scnhdr_ext = (SCNHDR *) ext; + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + memcpy (scnhdr_int->s_name, scnhdr_ext->s_name, sizeof (scnhdr_int->s_name)); + + scnhdr_int->s_vaddr = GET_SCNHDR_VADDR (abfd, scnhdr_ext->s_vaddr); + scnhdr_int->s_paddr = GET_SCNHDR_PADDR (abfd, scnhdr_ext->s_paddr); + scnhdr_int->s_size = GET_SCNHDR_SIZE (abfd, scnhdr_ext->s_size); + + scnhdr_int->s_scnptr = GET_SCNHDR_SCNPTR (abfd, scnhdr_ext->s_scnptr); + scnhdr_int->s_relptr = GET_SCNHDR_RELPTR (abfd, scnhdr_ext->s_relptr); + scnhdr_int->s_lnnoptr = GET_SCNHDR_LNNOPTR (abfd, scnhdr_ext->s_lnnoptr); + scnhdr_int->s_flags = GET_SCNHDR_FLAGS (abfd, scnhdr_ext->s_flags); + scnhdr_int->s_nreloc = GET_SCNHDR_NRELOC (abfd, scnhdr_ext->s_nreloc); + scnhdr_int->s_nlnno = GET_SCNHDR_NLNNO (abfd, scnhdr_ext->s_nlnno); + + /* DJGPP follows the same strategy as PE COFF. + Iff the file is an executable then the higher 16 bits + of the line number have been stored in the relocation + counter field. */ + if (abfd->flags & EXEC_P && (strcmp (scnhdr_ext->s_name, ".text") == 0)) + { + scnhdr_int->s_nlnno + = (GET_SCNHDR_NRELOC (abfd, scnhdr_ext->s_nreloc) << 16) + + GET_SCNHDR_NLNNO (abfd, scnhdr_ext->s_nlnno); + scnhdr_int->s_nreloc = 0; + } +} + +unsigned int +_bfd_go32_swap_scnhdr_out (bfd * abfd, void * in, void * out) +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + SCNHDR *scnhdr_ext = (SCNHDR *) out; + unsigned int ret = bfd_coff_scnhsz (abfd); + + memcpy (scnhdr_ext->s_name, scnhdr_int->s_name, sizeof (scnhdr_int->s_name)); + + PUT_SCNHDR_VADDR (abfd, scnhdr_int->s_vaddr, scnhdr_ext->s_vaddr); + PUT_SCNHDR_PADDR (abfd, scnhdr_int->s_paddr, scnhdr_ext->s_paddr); + PUT_SCNHDR_SIZE (abfd, scnhdr_int->s_size, scnhdr_ext->s_size); + PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, scnhdr_ext->s_scnptr); + PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, scnhdr_ext->s_relptr); + PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, scnhdr_ext->s_lnnoptr); + PUT_SCNHDR_FLAGS (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags); + + if (abfd->flags & EXEC_P && (strcmp (scnhdr_int->s_name, ".text") == 0)) + { + /* DJGPP follows the same strategy as PE COFF. + By inference from looking at MS output, the 32 bit field + which is the combination of the number_of_relocs and + number_of_linenos is used for the line number count in + executables. A 16-bit field won't do for cc1. The MS + document says that the number of relocs is zero for + executables, but the 17-th bit has been observed to be there. + Overflow is not an issue: a 4G-line program will overflow a + bunch of other fields long before this! */ + PUT_SCNHDR_NLNNO (abfd, (scnhdr_int->s_nlnno & 0xffff), + scnhdr_ext->s_nlnno); + PUT_SCNHDR_NRELOC (abfd, (scnhdr_int->s_nlnno >> 16), + scnhdr_ext->s_nreloc); + } + else + { + /* DJGPP follows the same strategy as PE COFF. */ + if (scnhdr_int->s_nlnno <= MAX_SCNHDR_NLNNO) + PUT_SCNHDR_NLNNO (abfd, scnhdr_int->s_nlnno, scnhdr_ext->s_nlnno); + else + { + char buf[sizeof (scnhdr_int->s_name) + 1]; + + memcpy (buf, scnhdr_int->s_name, sizeof (scnhdr_int->s_name)); + buf[sizeof (scnhdr_int->s_name)] = '\0'; + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: warning: %s: line number overflow: 0x%lx > 0xffff"), + abfd, buf, scnhdr_int->s_nlnno); + bfd_set_error (bfd_error_file_truncated); + PUT_SCNHDR_NLNNO (abfd, 0xffff, scnhdr_ext->s_nlnno); + ret = 0; + } + + /* Although we could encode 0xffff relocs here, we do not, to be + consistent with other parts of bfd. Also it lets us warn, as + we should never see 0xffff here w/o having the overflow flag + set. */ + if (scnhdr_int->s_nreloc < MAX_SCNHDR_NRELOC) + PUT_SCNHDR_NRELOC (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc); + else + { + /* DJGPP can deal with large #s of relocs, but not here. */ + PUT_SCNHDR_NRELOC (abfd, 0xffff, scnhdr_ext->s_nreloc); + scnhdr_int->s_flags |= IMAGE_SCN_LNK_NRELOC_OVFL; + PUT_SCNHDR_FLAGS (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags); + } + } + + return ret; +} diff --git a/bfd/coff-stgo32.c b/bfd/coff-stgo32.c index d1be578..0fea119 100644 --- a/bfd/coff-stgo32.c +++ b/bfd/coff-stgo32.c @@ -46,6 +46,9 @@ { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } +/* Section contains extended relocations. */ +#define IMAGE_SCN_LNK_NRELOC_OVFL (0x01000000) + #include "sysdep.h" #include "bfd.h" #include "coff/msdos.h" @@ -55,10 +58,17 @@ static bfd_boolean go32exe_write_object_contents (bfd *); static bfd_boolean go32exe_mkobject (bfd *); static bfd_boolean go32exe_copy_private_bfd_data (bfd *, bfd *); +/* Defined in coff-go32.c. */ +bfd_boolean _bfd_go32_mkobject (bfd *); +void _bfd_go32_swap_scnhdr_in (bfd *, void *, void *); +unsigned int _bfd_go32_swap_scnhdr_out (bfd *, void *, void *); + #define COFF_CHECK_FORMAT go32exe_check_format #define COFF_WRITE_CONTENTS go32exe_write_object_contents #define coff_mkobject go32exe_mkobject #define coff_bfd_copy_private_bfd_data go32exe_copy_private_bfd_data +#define coff_SWAP_scnhdr_in _bfd_go32_swap_scnhdr_in +#define coff_SWAP_scnhdr_out _bfd_go32_swap_scnhdr_out #include "coff-i386.c" @@ -352,32 +362,20 @@ go32exe_write_object_contents (bfd *abfd) static bfd_boolean go32exe_mkobject (bfd *abfd) { - coff_data_type *coff = NULL; - const bfd_size_type amt = sizeof (coff_data_type); - /* Don't output to an archive. */ if (abfd->my_archive != NULL) return FALSE; - abfd->tdata.coff_obj_data = bfd_zalloc (abfd, amt); - if (abfd->tdata.coff_obj_data == NULL) + if (!_bfd_go32_mkobject (abfd)) return FALSE; - coff = coff_data (abfd); - coff->symbols = NULL; - coff->conversion_table = NULL; - coff->raw_syments = NULL; - coff->relocbase = 0; - coff->local_toc_sym_map = 0; go32exe_create_stub (abfd); - if (coff->stub == NULL) + if (coff_data (abfd)->stub == NULL) { - bfd_release (abfd, coff); + bfd_release (abfd, coff_data (abfd)); return FALSE; } - abfd->origin = coff->stub_size; - -/* make_abs_section(abfd);*/ /* ??? */ + abfd->origin = coff_data (abfd)->stub_size; return TRUE; } diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 3bee5d2..c6569ec 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -364,6 +364,10 @@ CODE_FRAGMENT #define GNU_LINKONCE_WT ".gnu.linkonce.wt." #define DOT_RELOC ".reloc" +#if defined(COFF_WITH_PE) || defined(COFF_GO32_EXE) || defined(COFF_GO32) +# define COFF_WITH_EXTENDED_RELOC_COUNTER +#endif + #if defined (COFF_LONG_SECTION_NAMES) /* Needed to expand the inputs to BLANKOR1TOODD. */ #define COFFLONGSECTIONCATHELPER(x,y) x ## y @@ -1964,6 +1968,39 @@ coff_set_alignment_hook (bfd *abfd, asection *section, void * scnhdr) } #else /* ! RS6000COFF_C */ +#if defined (COFF_GO32_EXE) || defined (COFF_GO32) + +static void +coff_set_alignment_hook (bfd * abfd, asection * section, void * scnhdr) +{ + struct internal_scnhdr *hdr = (struct internal_scnhdr *) scnhdr; + + /* Check for extended relocs. */ + if (hdr->s_flags & IMAGE_SCN_LNK_NRELOC_OVFL) + { + struct external_reloc dst; + struct internal_reloc n; + const file_ptr oldpos = bfd_tell (abfd); + const bfd_size_type relsz = bfd_coff_relsz (abfd); + + if (bfd_seek (abfd, (file_ptr) hdr->s_relptr, 0) != 0) + return; + if (bfd_bread (& dst, relsz, abfd) != relsz) + return; + + coff_swap_reloc_in (abfd, &dst, &n); + if (bfd_seek (abfd, oldpos, 0) != 0) + return; + section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1; + section->rel_filepos += relsz; + } + else if (hdr->s_nreloc == 0xffff) + _bfd_error_handler + (_("%pB: warning: claims to have 0xffff relocs, without overflow"), + abfd); +} + +#else /* ! COFF_GO32_EXE && ! COFF_GO32 */ static void coff_set_alignment_hook (bfd *abfd ATTRIBUTE_UNUSED, @@ -1972,6 +2009,7 @@ coff_set_alignment_hook (bfd *abfd ATTRIBUTE_UNUSED, { } +#endif /* ! COFF_GO32_EXE && ! COFF_GO32 */ #endif /* ! RS6000COFF_C */ #endif /* ! COFF_WITH_PE */ #endif /* ! COFF_ALIGN_IN_SECTION_HEADER */ @@ -2521,8 +2559,8 @@ coff_write_relocs (bfd * abfd, int first_undef) if (bfd_seek (abfd, s->rel_filepos, SEEK_SET) != 0) return FALSE; -#ifdef COFF_WITH_PE - if (obj_pe (abfd) && s->reloc_count >= 0xffff) +#ifdef COFF_WITH_EXTENDED_RELOC_COUNTER + if ((obj_pe (abfd) || obj_go32 (abfd)) && s->reloc_count >= 0xffff) { /* Encode real count here as first reloc. */ struct internal_reloc n; @@ -3382,9 +3420,9 @@ coff_write_object_contents (bfd * abfd) for (current = abfd->sections; current != NULL; current = current->next) { -#ifdef COFF_WITH_PE +#ifdef COFF_WITH_EXTENDED_RELOC_COUNTER /* We store the actual reloc count in the first reloc's addr. */ - if (obj_pe (abfd) && current->reloc_count >= 0xffff) + if ((obj_pe (abfd) || obj_go32 (abfd)) && current->reloc_count >= 0xffff) reloc_count ++; #endif reloc_count += current->reloc_count; @@ -3412,9 +3450,9 @@ coff_write_object_contents (bfd * abfd) { current->rel_filepos = reloc_base; reloc_base += current->reloc_count * bfd_coff_relsz (abfd); -#ifdef COFF_WITH_PE +#ifdef COFF_WITH_EXTENDED_RELOC_COUNTER /* Extra reloc to hold real count. */ - if (obj_pe (abfd) && current->reloc_count >= 0xffff) + if ((obj_pe (abfd) || obj_go32 (abfd)) && current->reloc_count >= 0xffff) reloc_base += bfd_coff_relsz (abfd); #endif } @@ -3615,7 +3653,7 @@ coff_write_object_contents (bfd * abfd) SCNHDR buff; bfd_size_type amt = bfd_coff_scnhsz (abfd); - if (coff_swap_scnhdr_out (abfd, §ion, &buff) == 0 + if (bfd_coff_swap_scnhdr_out (abfd, §ion, &buff) == 0 || bfd_bwrite (& buff, amt, abfd) != amt) return FALSE; } @@ -3741,7 +3779,7 @@ coff_write_object_contents (bfd * abfd) scnhdr.s_nlnno = current->target_index; scnhdr.s_flags = STYP_OVRFLO; amt = bfd_coff_scnhsz (abfd); - if (coff_swap_scnhdr_out (abfd, &scnhdr, &buff) == 0 + if (bfd_coff_swap_scnhdr_out (abfd, &scnhdr, &buff) == 0 || bfd_bwrite (& buff, amt, abfd) != amt) return FALSE; } @@ -3749,6 +3787,22 @@ coff_write_object_contents (bfd * abfd) #endif #endif +#if defined (COFF_GO32_EXE) || defined (COFF_GO32) + /* Pad section headers. */ + if ((abfd->flags & EXEC_P) && abfd->sections != NULL) + { + file_ptr cur_ptr = scn_base + + abfd->section_count * bfd_coff_scnhsz (abfd); + long fill_size = (abfd->sections->filepos - cur_ptr); + bfd_byte *b = bfd_zmalloc (fill_size); + if (b) + { + bfd_bwrite ((PTR)b, fill_size, abfd); + free (b); + } + } +#endif + /* OK, now set up the filehdr... */ /* Don't include the internal abs section in the section count */ diff --git a/bfd/cofflink.c b/bfd/cofflink.c index e52f543..0beff83 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -689,7 +689,7 @@ _bfd_coff_final_link (bfd *abfd, rel_filepos += o->reloc_count * relsz; /* In PE COFF, if there are at least 0xffff relocations an extra relocation will be written out to encode the count. */ - if (obj_pe (abfd) && o->reloc_count >= 0xffff) + if ((obj_pe (abfd) || obj_go32 (abfd)) && o->reloc_count >= 0xffff) rel_filepos += relsz; } @@ -1108,7 +1108,7 @@ _bfd_coff_final_link (bfd *abfd, if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0) goto error_return; - if (obj_pe (abfd) && o->reloc_count >= 0xffff) + if ((obj_pe (abfd) || obj_go32 (abfd)) && o->reloc_count >= 0xffff) { /* In PE COFF, write the count of relocs as the first reloc. The header overflow bit will be set diff --git a/bfd/coffswap.h b/bfd/coffswap.h index c4ac067..7c0be22 100644 --- a/bfd/coffswap.h +++ b/bfd/coffswap.h @@ -725,6 +725,7 @@ coff_swap_aouthdr_out (bfd * abfd, void * in, void * out) return AOUTSZ; } +ATTRIBUTE_UNUSED static void coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) { @@ -751,6 +752,7 @@ coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) #endif } +ATTRIBUTE_UNUSED static unsigned int coff_swap_scnhdr_out (bfd * abfd, void * in, void * out) { diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h index e4155d2..3f0227c 100644 --- a/bfd/libcoff-in.h +++ b/bfd/libcoff-in.h @@ -33,8 +33,9 @@ extern "C" { #define coff_data(bfd) ((bfd)->tdata.coff_obj_data) #define obj_pe(bfd) (coff_data (bfd)->pe) +#define obj_go32(bfd) (coff_data (bfd)->go32) #define obj_symbols(bfd) (coff_data (bfd)->symbols) -#define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos) +#define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos) #define obj_relocbase(bfd) (coff_data (bfd)->relocbase) #define obj_raw_syments(bfd) (coff_data (bfd)->raw_syments) #define obj_raw_syment_count(bfd) (coff_data (bfd)->raw_syment_count) @@ -114,6 +115,9 @@ typedef struct coff_tdata used by ARM code. */ flagword flags; + /* Is this a GO32 coff file? */ + bfd_boolean go32; + /* A stub (extra data prepended before the COFF image) and its size. Used by coff-go32-exe, it contains executable data that loads the COFF object into memory. */ diff --git a/bfd/libcoff.h b/bfd/libcoff.h index 44c85d9..d7e0548 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -37,8 +37,9 @@ extern "C" { #define coff_data(bfd) ((bfd)->tdata.coff_obj_data) #define obj_pe(bfd) (coff_data (bfd)->pe) +#define obj_go32(bfd) (coff_data (bfd)->go32) #define obj_symbols(bfd) (coff_data (bfd)->symbols) -#define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos) +#define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos) #define obj_relocbase(bfd) (coff_data (bfd)->relocbase) #define obj_raw_syments(bfd) (coff_data (bfd)->raw_syments) #define obj_raw_syment_count(bfd) (coff_data (bfd)->raw_syment_count) @@ -118,6 +119,9 @@ typedef struct coff_tdata used by ARM code. */ flagword flags; + /* Is this a GO32 coff file? */ + bfd_boolean go32; + /* A stub (extra data prepended before the COFF image) and its size. Used by coff-go32-exe, it contains executable data that loads the COFF object into memory. */ |