summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog26
-rw-r--r--bfd/coff-go32.c134
-rw-r--r--bfd/coff-stgo32.c30
-rw-r--r--bfd/coffcode.h70
-rw-r--r--bfd/cofflink.c4
-rw-r--r--bfd/coffswap.h2
-rw-r--r--bfd/libcoff-in.h6
-rw-r--r--bfd/libcoff.h6
8 files changed, 250 insertions, 28 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index b89aced0e7e..c3015012ab3 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 e43d5cee3da..448769362a7 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 d1be578c6aa..0fea119fc49 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 3bee5d2f9d5..c6569ec9cd4 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, &section, &buff) == 0
+ if (bfd_coff_swap_scnhdr_out (abfd, &section, &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 e52f543ee6e..0beff8397fa 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 c4ac067a62f..7c0be221075 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 e4155d286f4..3f0227c4acf 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 44c85d96c15..d7e0548bc50 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. */