1 /* BFD back-end for Intel 386 COFF files (DJGPP variant).
2    Copyright (C) 1990-2024 Free Software Foundation, Inc.
3    Written by DJ Delorie.
4 
5    This file is part of BFD, the Binary File Descriptor library.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21 
22 #define TARGET_SYM            i386_coff_go32_vec
23 #define TARGET_NAME           "coff-go32"
24 #define TARGET_UNDERSCORE     '_'
25 #define COFF_GO32
26 #define COFF_LONG_SECTION_NAMES
27 #define COFF_SUPPORT_GNU_LINKONCE
28 #define COFF_LONG_FILENAMES
29 
30 #define COFF_SECTION_ALIGNMENT_ENTRIES \
31 { COFF_SECTION_NAME_PARTIAL_MATCH (".data"), \
32   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
33 { COFF_SECTION_NAME_PARTIAL_MATCH (".text"), \
34   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
35 { COFF_SECTION_NAME_PARTIAL_MATCH (".const"), \
36   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
37 { COFF_SECTION_NAME_PARTIAL_MATCH (".rodata"), \
38   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
39 { COFF_SECTION_NAME_PARTIAL_MATCH (".bss"), \
40   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
41 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.d"), \
42   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
43 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.t"), \
44   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
45 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.r"), \
46   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
47 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.b"), \
48   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
49 { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
50   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
51 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \
52   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
53 
54 /* Section contains extended relocations. */
55 #define IMAGE_SCN_LNK_NRELOC_OVFL (0x01000000)
56 
57 #include "sysdep.h"
58 #include "bfd.h"
59 
60 /* The following functions are not static, because they are also
61    used for coff-go32-exe (coff-stgo32.c).  */
62 bool _bfd_go32_mkobject (bfd *);
63 void _bfd_go32_swap_scnhdr_in (bfd *, void *, void *);
64 unsigned int _bfd_go32_swap_scnhdr_out (bfd *, void *, void *);
65 
66 #define coff_mkobject _bfd_go32_mkobject
67 #define coff_SWAP_scnhdr_in _bfd_go32_swap_scnhdr_in
68 #define coff_SWAP_scnhdr_out _bfd_go32_swap_scnhdr_out
69 
70 #include "coff-i386.c"
71 
72 bool
_bfd_go32_mkobject(bfd * abfd)73 _bfd_go32_mkobject (bfd * abfd)
74 {
75   const bfd_size_type amt = sizeof (coff_data_type);
76 
77   abfd->tdata.coff_obj_data = bfd_zalloc (abfd, amt);
78   if (abfd->tdata.coff_obj_data == NULL)
79     return false;
80 
81   coff_data (abfd)->go32 = true;
82 
83   bfd_coff_long_section_names (abfd)
84     = coff_backend_info (abfd)->_bfd_coff_long_section_names;
85 
86   return true;
87 }
88 
89 void
_bfd_go32_swap_scnhdr_in(bfd * abfd,void * ext,void * in)90 _bfd_go32_swap_scnhdr_in (bfd * abfd, void * ext, void * in)
91 {
92   SCNHDR *scnhdr_ext = (SCNHDR *) ext;
93   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
94 
95   memcpy (scnhdr_int->s_name, scnhdr_ext->s_name, sizeof (scnhdr_int->s_name));
96 
97   scnhdr_int->s_vaddr = GET_SCNHDR_VADDR (abfd, scnhdr_ext->s_vaddr);
98   scnhdr_int->s_paddr = GET_SCNHDR_PADDR (abfd, scnhdr_ext->s_paddr);
99   scnhdr_int->s_size = GET_SCNHDR_SIZE (abfd, scnhdr_ext->s_size);
100 
101   scnhdr_int->s_scnptr = GET_SCNHDR_SCNPTR (abfd, scnhdr_ext->s_scnptr);
102   scnhdr_int->s_relptr = GET_SCNHDR_RELPTR (abfd, scnhdr_ext->s_relptr);
103   scnhdr_int->s_lnnoptr = GET_SCNHDR_LNNOPTR (abfd, scnhdr_ext->s_lnnoptr);
104   scnhdr_int->s_flags = GET_SCNHDR_FLAGS (abfd, scnhdr_ext->s_flags);
105   scnhdr_int->s_nreloc = GET_SCNHDR_NRELOC (abfd, scnhdr_ext->s_nreloc);
106   scnhdr_int->s_nlnno = GET_SCNHDR_NLNNO (abfd, scnhdr_ext->s_nlnno);
107 
108   /* DJGPP follows the same strategy as PE COFF.
109      Iff the file is an executable then the higher 16 bits
110      of the line number have been stored in the relocation
111      counter field.  */
112   if (abfd->flags & EXEC_P && (strcmp (scnhdr_ext->s_name, ".text") == 0))
113     {
114       scnhdr_int->s_nlnno
115           = (GET_SCNHDR_NRELOC (abfd, scnhdr_ext->s_nreloc) << 16)
116             + GET_SCNHDR_NLNNO (abfd, scnhdr_ext->s_nlnno);
117       scnhdr_int->s_nreloc = 0;
118     }
119 }
120 
121 unsigned int
_bfd_go32_swap_scnhdr_out(bfd * abfd,void * in,void * out)122 _bfd_go32_swap_scnhdr_out (bfd * abfd, void * in, void * out)
123 {
124   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
125   SCNHDR *scnhdr_ext = (SCNHDR *) out;
126   unsigned int ret = bfd_coff_scnhsz (abfd);
127 
128   memcpy (scnhdr_ext->s_name, scnhdr_int->s_name, sizeof (scnhdr_int->s_name));
129 
130   PUT_SCNHDR_VADDR (abfd, scnhdr_int->s_vaddr, scnhdr_ext->s_vaddr);
131   PUT_SCNHDR_PADDR (abfd, scnhdr_int->s_paddr, scnhdr_ext->s_paddr);
132   PUT_SCNHDR_SIZE (abfd, scnhdr_int->s_size, scnhdr_ext->s_size);
133   PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, scnhdr_ext->s_scnptr);
134   PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, scnhdr_ext->s_relptr);
135   PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, scnhdr_ext->s_lnnoptr);
136   PUT_SCNHDR_FLAGS (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags);
137 
138   if (abfd->flags & EXEC_P && (strcmp (scnhdr_int->s_name, ".text") == 0))
139     {
140       /* DJGPP follows the same strategy as PE COFF.
141            By inference from looking at MS output, the 32 bit field
142            which is the combination of the number_of_relocs and
143            number_of_linenos is used for the line number count in
144            executables.  A 16-bit field won't do for cc1.  The MS
145            document says that the number of relocs is zero for
146            executables, but the 17-th bit has been observed to be there.
147            Overflow is not an issue: a 4G-line program will overflow a
148            bunch of other fields long before this!  */
149       PUT_SCNHDR_NLNNO (abfd, (scnhdr_int->s_nlnno & 0xffff),
150                               scnhdr_ext->s_nlnno);
151       PUT_SCNHDR_NRELOC (abfd, (scnhdr_int->s_nlnno >> 16),
152                                scnhdr_ext->s_nreloc);
153     }
154   else
155     {
156       /* DJGPP follows the same strategy as PE COFF.  */
157       if (scnhdr_int->s_nlnno <= MAX_SCNHDR_NLNNO)
158           PUT_SCNHDR_NLNNO (abfd, scnhdr_int->s_nlnno, scnhdr_ext->s_nlnno);
159       else
160           {
161             char buf[sizeof (scnhdr_int->s_name) + 1];
162 
163             memcpy (buf, scnhdr_int->s_name, sizeof (scnhdr_int->s_name));
164             buf[sizeof (scnhdr_int->s_name)] = '\0';
165             _bfd_error_handler
166               /* xgettext:c-format */
167               (_("%pB: warning: %s: line number overflow: 0x%lx > 0xffff"),
168                abfd, buf, scnhdr_int->s_nlnno);
169             bfd_set_error (bfd_error_file_truncated);
170             PUT_SCNHDR_NLNNO (abfd, 0xffff, scnhdr_ext->s_nlnno);
171             ret = 0;
172           }
173 
174       /* Although we could encode 0xffff relocs here, we do not, to be
175            consistent with other parts of bfd.  Also it lets us warn, as
176            we should never see 0xffff here w/o having the overflow flag
177            set.  */
178       if (scnhdr_int->s_nreloc < MAX_SCNHDR_NRELOC)
179           PUT_SCNHDR_NRELOC (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc);
180       else
181           {
182             /* DJGPP can deal with large #s of relocs, but not here.  */
183             PUT_SCNHDR_NRELOC (abfd, 0xffff, scnhdr_ext->s_nreloc);
184             scnhdr_int->s_flags |= IMAGE_SCN_LNK_NRELOC_OVFL;
185             PUT_SCNHDR_FLAGS (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags);
186           }
187     }
188 
189   return ret;
190 }
191