A major rewrite to move the bulk of the linker into BFD so that
[external/binutils.git] / ld / ldwrite.c
1 /* ldwrite.c -- write out the linked file
2    Copyright (C) 1993 Free Software Foundation, Inc.
3    Written by Steve Chamberlain sac@cygnus.com
4
5 This file is part of GLD, the Gnu Linker.
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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #include "bfd.h"
22 #include "sysdep.h"
23 #include "bfdlink.h"
24
25 #include "ld.h"
26 #include "ldexp.h"
27 #include "ldlang.h"
28 #include "ldwrite.h"
29 #include "ldmisc.h"
30 #include "ldgram.h"
31 #include "ldmain.h"
32
33 static void build_link_order PARAMS ((lang_statement_union_type *));
34 static void print_symbol_table PARAMS ((void));
35 static void print_file_stuff PARAMS ((lang_input_statement_type *));
36 static boolean print_symbol PARAMS ((struct bfd_link_hash_entry *, PTR));
37
38 /* Build link_order structures for the BFD linker.  */
39
40 static void
41 build_link_order (statement)
42      lang_statement_union_type *statement;
43 {
44   switch (statement->header.type)
45     {
46     case lang_data_statement_enum:
47       /* FIXME: This should probably build a link_order, but instead
48          it just does the output directly.  */
49       {
50         bfd_vma value = statement->data_statement.value;
51         bfd_byte play_area[LONG_SIZE];
52         unsigned int size = 0;
53         asection *output_section = statement->data_statement.output_section;
54
55         ASSERT (output_section->owner == output_bfd);
56         switch (statement->data_statement.type)
57           {
58           case LONG:
59             bfd_put_32 (output_bfd, value, play_area);
60             size = LONG_SIZE;
61             break;
62           case SHORT:
63             bfd_put_16 (output_bfd, value, play_area);
64             size = SHORT_SIZE;
65             break;
66           case BYTE:
67             bfd_put_8 (output_bfd, value, play_area);
68             size = BYTE_SIZE;
69             break;
70           default:
71             abort ();
72           }
73
74         if (! bfd_set_section_contents (output_bfd, output_section,
75                                         play_area,
76                                         statement->data_statement.output_vma,
77                                         size))
78           einfo ("%P%X: writing data failed: %E\n");
79       }
80       break;
81
82     case lang_input_section_enum:
83       /* Create a new link_order in the output section with this
84          attached */
85       if (statement->input_section.ifile->just_syms_flag == false)
86         {
87           asection *i = statement->input_section.section;
88           asection *output_section = i->output_section;
89
90           ASSERT (output_section->owner == output_bfd);
91
92           if ((output_section->flags & SEC_HAS_CONTENTS) != 0)
93             {
94               struct bfd_link_order *link_order;
95
96               link_order = bfd_new_link_order (output_bfd, output_section);
97
98               if (i->flags & SEC_NEVER_LOAD)
99                 {
100                   /* We've got a never load section inside one which
101                      is going to be output, we'll change it into a
102                      fill link_order */
103                   link_order->type = bfd_fill_link_order;
104                   link_order->u.fill.value = 0;
105                 }
106               else
107                 {
108                   link_order->type = bfd_indirect_link_order;
109                   link_order->u.indirect.section = i;
110                   ASSERT (i->output_section == output_section);
111                 }
112               link_order->size = bfd_section_size (i->owner, i);
113               link_order->offset = i->output_offset;
114             }
115         }
116       break;
117
118     case lang_padding_statement_enum:
119       /* Make a new link_order with the right filler */
120       {
121         asection *output_section;
122         struct bfd_link_order *link_order;
123
124         output_section = statement->padding_statement.output_section;
125         ASSERT (statement->padding_statement.output_section->owner
126                 == output_bfd);
127         if ((output_section->flags & SEC_HAS_CONTENTS) != 0)
128           {
129             link_order = bfd_new_link_order (output_bfd, output_section);
130             link_order->type = bfd_fill_link_order;
131             link_order->size = statement->padding_statement.size;
132             link_order->offset = statement->padding_statement.output_offset;
133             link_order->u.fill.value = statement->padding_statement.fill;
134           }
135       }
136       break;
137
138     default:
139       /* All the other ones fall through */
140       break;
141     }
142 }
143
144 /* Call BFD to write out the linked file.  */
145
146 void
147 ldwrite ()
148 {
149   lang_for_each_statement (build_link_order);
150
151   if (! bfd_final_link (output_bfd, &link_info))
152     einfo ("%F%P: %B: %E\n", output_bfd);
153
154   if (config.map_file)
155     {
156       print_symbol_table ();
157       lang_map ();
158     }
159 }
160
161 /* Print the symbol table.  */
162
163 static void
164 print_symbol_table ()
165 {
166   fprintf (config.map_file, "**FILES**\n\n");
167   lang_for_each_file (print_file_stuff);
168
169   fprintf (config.map_file, "**GLOBAL SYMBOLS**\n\n");
170   fprintf (config.map_file, "offset    section    offset   symbol\n");
171   bfd_link_hash_traverse (link_info.hash, print_symbol, (PTR) NULL);
172 }
173
174 /* Print information about a file.  */
175
176 static void
177 print_file_stuff (f)
178      lang_input_statement_type * f;
179 {
180   fprintf (config.map_file, "  %s\n", f->filename);
181   if (f->just_syms_flag)
182     {
183       fprintf (config.map_file, " symbols only\n");
184     }
185   else
186     {
187       asection *s;
188       if (true)
189         {
190           for (s = f->the_bfd->sections;
191                s != (asection *) NULL;
192                s = s->next)
193             {
194               print_address (s->output_offset);
195               if (s->reloc_done)
196                 {
197                   fprintf (config.map_file, " %08x 2**%2ud %s\n",
198                            (unsigned) bfd_get_section_size_after_reloc (s),
199                            s->alignment_power, s->name);
200                 }
201
202               else
203                 {
204                   fprintf (config.map_file, " %08x 2**%2ud %s\n",
205                            (unsigned) bfd_get_section_size_before_reloc (s),
206                            s->alignment_power, s->name);
207                 }
208             }
209         }
210       else
211         {
212           for (s = f->the_bfd->sections;
213                s != (asection *) NULL;
214                s = s->next)
215             {
216               fprintf (config.map_file, "%s ", s->name);
217               print_address (s->output_offset);
218               fprintf (config.map_file, "(%x)",
219                        (unsigned) bfd_get_section_size_after_reloc (s));
220             }
221           fprintf (config.map_file, "hex \n");
222         }
223     }
224   print_nl ();
225 }
226
227 /* Print a symbol.  */
228
229 static boolean
230 print_symbol (p, ignore)
231      struct bfd_link_hash_entry *p;
232      PTR ignore;
233 {
234   while (p->type == bfd_link_hash_indirect
235          || p->type == bfd_link_hash_warning)
236     p = p->u.i.link;
237
238   switch (p->type) 
239     {
240     case bfd_link_hash_new:
241       abort ();
242
243     case bfd_link_hash_undefined:
244       fprintf (config.map_file, "undefined                     ");
245       fprintf (config.map_file, "%s ", p->root.string);
246       print_nl ();    
247       break;
248
249     case bfd_link_hash_weak:
250       fprintf (config.map_file, "weak                          ");
251       fprintf (config.map_file, "%s ", p->root.string);
252       print_nl ();    
253       break;
254
255     case bfd_link_hash_defined:     
256       {
257         asection *defsec = p->u.def.section;
258
259         print_address (p->u.def.value);
260         if (defsec)
261           {
262             fprintf (config.map_file, "  %-10s",
263                      bfd_section_name (output_bfd, defsec));
264             print_space ();
265             print_address (p->u.def.value + defsec->vma);
266           }
267         else
268           {
269             fprintf (config.map_file, "         .......");
270           }
271         fprintf (config.map_file, " %s ", p->root.string);
272       }
273       print_nl ();    
274       break;
275
276     case bfd_link_hash_common:
277       fprintf (config.map_file, "common               ");
278       print_address (p->u.c.size);
279       fprintf (config.map_file, " %s ", p->root.string);
280       print_nl ();
281       break;
282
283     default:
284       abort ();
285     }
286
287   return true;
288 }