aboutsummaryrefslogtreecommitdiff
path: root/bfd/coff-go32.c
blob: ac2ae7116dc32d2fae8f445bfcf718bcbc628549 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* BFD back-end for Intel 386 COFF files (DJGPP variant).
   Copyright (C) 1990-2022 Free Software Foundation, Inc.
   Written by DJ Delorie.

   This file is part of BFD, the Binary File Descriptor library.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#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

#define COFF_SECTION_ALIGNMENT_ENTRIES \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".data"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".text"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".const"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".rodata"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".bss"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.d"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.t"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.r"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.b"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
{ 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).  */
bool _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"

bool
_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;
}