OSDN Git Service

Locale changes from Bruno Haible <haible@clisp.cons.org>.
[pf3gnuchains/pf3gnuchains3x.git] / bfd / ppcboot.c
1 /* BFD back-end for PPCbug boot records.
2    Copyright 1996, 1997, 1998, 1999, 2000, 2001
3    Free Software Foundation, Inc.
4    Written by Michael Meissner, Cygnus Support, <meissner@cygnus.com>
5
6 This file is part of BFD, the Binary File Descriptor library.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 /* This is a BFD backend which may be used to write PowerPCBug boot objects.
23    It may only be used for output, not input.  The intention is that this may
24    be used as an output format for objcopy in order to generate raw binary
25    data.
26
27    This is very simple.  The only complication is that the real data
28    will start at some address X, and in some cases we will not want to
29    include X zeroes just to get to that point.  Since the start
30    address is not meaningful for this object file format, we use it
31    instead to indicate the number of zeroes to skip at the start of
32    the file.  objcopy cooperates by specially setting the start
33    address to zero by default.  */
34
35 #include "safe-ctype.h"
36 #include "bfd.h"
37 #include "sysdep.h"
38 #include "libbfd.h"
39
40 /* PPCbug location structure */
41 typedef struct ppcboot_location {
42   bfd_byte      ind;
43   bfd_byte      head;
44   bfd_byte      sector;
45   bfd_byte      cylinder;
46 } ppcboot_location_t;
47
48 /* PPCbug partition table layout */
49 typedef struct ppcboot_partition {
50   ppcboot_location_t    partition_begin;        /* partition begin */
51   ppcboot_location_t    partition_end;          /* partition end */
52   bfd_byte              sector_begin[4];        /* 32-bit start RBA (zero-based), little endian */
53   bfd_byte              sector_length[4];       /* 32-bit RBA count (one-based), little endian */
54 } ppcboot_partition_t;
55
56 /* PPCbug boot layout.  */
57 typedef struct ppcboot_hdr {
58   bfd_byte              pc_compatibility[446];  /* x86 instruction field */
59   ppcboot_partition_t   partition[4];           /* partition information */
60   bfd_byte              signature[2];           /* 0x55 and 0xaa */
61   bfd_byte              entry_offset[4];        /* entry point offset, little endian */
62   bfd_byte              length[4];              /* load image length, little endian */
63   bfd_byte              flags;                  /* flag field */
64   bfd_byte              os_id;                  /* OS_ID */
65   char                  partition_name[32];     /* partition name */
66   bfd_byte              reserved1[470];         /* reserved */
67 }
68 #ifdef __GNUC__
69   __attribute__ ((packed))
70 #endif
71 ppcboot_hdr_t;
72
73 /* Signature bytes for last 2 bytes of the 512 byte record */
74 #define SIGNATURE0 0x55
75 #define SIGNATURE1 0xaa
76
77 /* PowerPC boot type */
78 #define PPC_IND 0x41
79
80 /* Information needed for ppcboot header */
81 typedef struct ppcboot_data {
82   ppcboot_hdr_t header;                         /* raw header */
83   asection *sec;                                /* single section */
84 } ppcboot_data_t;
85
86 /* Any bfd we create by reading a ppcboot file has three symbols:
87    a start symbol, an end symbol, and an absolute length symbol.  */
88 #define PPCBOOT_SYMS 3
89
90 static boolean ppcboot_mkobject PARAMS ((bfd *));
91 static const bfd_target *ppcboot_object_p PARAMS ((bfd *));
92 static boolean ppcboot_set_arch_mach
93   PARAMS ((bfd *, enum bfd_architecture, unsigned long));
94 static boolean ppcboot_get_section_contents
95   PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
96 static long ppcboot_get_symtab_upper_bound PARAMS ((bfd *));
97 static char *mangle_name PARAMS ((bfd *, char *));
98 static long ppcboot_get_symtab PARAMS ((bfd *, asymbol **));
99 static asymbol *ppcboot_make_empty_symbol PARAMS ((bfd *));
100 static void ppcboot_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
101 static boolean ppcboot_set_section_contents
102   PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
103 static int ppcboot_sizeof_headers PARAMS ((bfd *, boolean));
104 static boolean ppcboot_bfd_print_private_bfd_data PARAMS ((bfd *, PTR));
105
106 #define ppcboot_set_tdata(abfd, ptr) ((abfd)->tdata.any = (PTR) (ptr))
107 #define ppcboot_get_tdata(abfd) ((ppcboot_data_t *) ((abfd)->tdata.any))
108 \f
109 /* Create a ppcboot object.  Invoked via bfd_set_format.  */
110
111 static boolean
112 ppcboot_mkobject (abfd)
113      bfd *abfd;
114 {
115   if (!ppcboot_get_tdata (abfd))
116     {
117       bfd_size_type amt = sizeof (ppcboot_data_t);
118       ppcboot_set_tdata (abfd, bfd_zalloc (abfd, amt));
119     }
120
121   return true;
122 }
123
124 \f
125 /* Set the architecture to PowerPC */
126 static boolean
127 ppcboot_set_arch_mach (abfd, arch, machine)
128      bfd *abfd;
129      enum bfd_architecture arch;
130      unsigned long machine;
131 {
132   if (arch == bfd_arch_unknown)
133     arch = bfd_arch_powerpc;
134
135   else if (arch != bfd_arch_powerpc)
136     return false;
137
138   return bfd_default_set_arch_mach (abfd, arch, machine);
139 }
140
141 \f
142 /* Any file may be considered to be a ppcboot file, provided the target
143    was not defaulted.  That is, it must be explicitly specified as
144    being ppcboot.  */
145
146 static const bfd_target *
147 ppcboot_object_p (abfd)
148      bfd *abfd;
149 {
150   struct stat statbuf;
151   asection *sec;
152   ppcboot_hdr_t hdr;
153   size_t i;
154   ppcboot_data_t *tdata;
155
156   BFD_ASSERT (sizeof (ppcboot_hdr_t) == 1024);
157
158   if (abfd->target_defaulted)
159     {
160       bfd_set_error (bfd_error_wrong_format);
161       return NULL;
162     }
163
164   /* Find the file size.  */
165   if (bfd_stat (abfd, &statbuf) < 0)
166     {
167       bfd_set_error (bfd_error_system_call);
168       return NULL;
169     }
170
171   if ((size_t) statbuf.st_size < sizeof (ppcboot_hdr_t))
172     {
173       bfd_set_error (bfd_error_wrong_format);
174       return NULL;
175     }
176
177   if (bfd_bread ((PTR) &hdr, (bfd_size_type) sizeof (hdr), abfd)
178       != sizeof (hdr))
179     {
180       if (bfd_get_error () != bfd_error_system_call)
181         bfd_set_error (bfd_error_wrong_format);
182
183       return NULL;
184     }
185
186   /* Now do some basic checks.  */
187   for (i = 0; i < sizeof (hdr.pc_compatibility); i++)
188     if (hdr.pc_compatibility[i])
189       {
190         bfd_set_error (bfd_error_wrong_format);
191         return NULL;
192       }
193
194   if (hdr.signature[0] != SIGNATURE0 || hdr.signature[1] != SIGNATURE1)
195     {
196       bfd_set_error (bfd_error_wrong_format);
197       return NULL;
198     }
199
200   if (hdr.partition[0].partition_end.ind != PPC_IND)
201     {
202       bfd_set_error (bfd_error_wrong_format);
203       return NULL;
204     }
205
206   abfd->symcount = PPCBOOT_SYMS;
207
208   /* One data section.  */
209   sec = bfd_make_section (abfd, ".data");
210   if (sec == NULL)
211     return NULL;
212   sec->flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_CODE | SEC_HAS_CONTENTS;
213   sec->vma = 0;
214   sec->_raw_size = statbuf.st_size - sizeof (ppcboot_hdr_t);
215   sec->filepos = sizeof (ppcboot_hdr_t);
216
217   ppcboot_mkobject (abfd);
218   tdata = ppcboot_get_tdata (abfd);
219   tdata->sec = sec;
220   memcpy ((PTR) &tdata->header, (PTR) &hdr, sizeof (ppcboot_hdr_t));
221
222   ppcboot_set_arch_mach (abfd, bfd_arch_powerpc, 0L);
223   return abfd->xvec;
224 }
225
226 #define ppcboot_close_and_cleanup _bfd_generic_close_and_cleanup
227 #define ppcboot_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
228 #define ppcboot_new_section_hook _bfd_generic_new_section_hook
229
230 \f
231 /* Get contents of the only section.  */
232
233 static boolean
234 ppcboot_get_section_contents (abfd, section, location, offset, count)
235      bfd *abfd;
236      asection *section ATTRIBUTE_UNUSED;
237      PTR location;
238      file_ptr offset;
239      bfd_size_type count;
240 {
241   if (bfd_seek (abfd, offset + (file_ptr) sizeof (ppcboot_hdr_t), SEEK_SET) != 0
242       || bfd_bread (location, count, abfd) != count)
243     return false;
244   return true;
245 }
246
247 \f
248 /* Return the amount of memory needed to read the symbol table.  */
249
250 static long
251 ppcboot_get_symtab_upper_bound (abfd)
252      bfd *abfd ATTRIBUTE_UNUSED;
253 {
254   return (PPCBOOT_SYMS + 1) * sizeof (asymbol *);
255 }
256
257 \f
258 /* Create a symbol name based on the bfd's filename.  */
259
260 static char *
261 mangle_name (abfd, suffix)
262      bfd *abfd;
263      char *suffix;
264 {
265   bfd_size_type size;
266   char *buf;
267   char *p;
268
269   size = (strlen (bfd_get_filename (abfd))
270           + strlen (suffix)
271           + sizeof "_ppcboot__");
272
273   buf = (char *) bfd_alloc (abfd, size);
274   if (buf == NULL)
275     return "";
276
277   sprintf (buf, "_ppcboot_%s_%s", bfd_get_filename (abfd), suffix);
278
279   /* Change any non-alphanumeric characters to underscores.  */
280   for (p = buf; *p; p++)
281     if (! ISALNUM (*p))
282       *p = '_';
283
284   return buf;
285 }
286
287 \f
288 /* Return the symbol table.  */
289
290 static long
291 ppcboot_get_symtab (abfd, alocation)
292      bfd *abfd;
293      asymbol **alocation;
294 {
295   asection *sec = ppcboot_get_tdata (abfd)->sec;
296   asymbol *syms;
297   unsigned int i;
298   bfd_size_type amt = PPCBOOT_SYMS * sizeof (asymbol);
299
300   syms = (asymbol *) bfd_alloc (abfd, amt);
301   if (syms == NULL)
302     return false;
303
304   /* Start symbol.  */
305   syms[0].the_bfd = abfd;
306   syms[0].name = mangle_name (abfd, "start");
307   syms[0].value = 0;
308   syms[0].flags = BSF_GLOBAL;
309   syms[0].section = sec;
310   syms[0].udata.p = NULL;
311
312   /* End symbol.  */
313   syms[1].the_bfd = abfd;
314   syms[1].name = mangle_name (abfd, "end");
315   syms[1].value = sec->_raw_size;
316   syms[1].flags = BSF_GLOBAL;
317   syms[1].section = sec;
318   syms[1].udata.p = NULL;
319
320   /* Size symbol.  */
321   syms[2].the_bfd = abfd;
322   syms[2].name = mangle_name (abfd, "size");
323   syms[2].value = sec->_raw_size;
324   syms[2].flags = BSF_GLOBAL;
325   syms[2].section = bfd_abs_section_ptr;
326   syms[2].udata.p = NULL;
327
328   for (i = 0; i < PPCBOOT_SYMS; i++)
329     *alocation++ = syms++;
330   *alocation = NULL;
331
332   return PPCBOOT_SYMS;
333 }
334
335 \f
336 /* Make an empty symbol.  */
337
338 static asymbol *
339 ppcboot_make_empty_symbol (abfd)
340      bfd *abfd;
341 {
342   return (asymbol *) bfd_alloc (abfd, (bfd_size_type) sizeof (asymbol));
343 }
344
345 \f
346 #define ppcboot_print_symbol _bfd_nosymbols_print_symbol
347
348 /* Get information about a symbol.  */
349
350 static void
351 ppcboot_get_symbol_info (ignore_abfd, symbol, ret)
352      bfd *ignore_abfd ATTRIBUTE_UNUSED;
353      asymbol *symbol;
354      symbol_info *ret;
355 {
356   bfd_symbol_info (symbol, ret);
357 }
358
359 #define ppcboot_bfd_is_local_label_name bfd_generic_is_local_label_name
360 #define ppcboot_get_lineno _bfd_nosymbols_get_lineno
361 #define ppcboot_find_nearest_line _bfd_nosymbols_find_nearest_line
362 #define ppcboot_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
363 #define ppcboot_read_minisymbols _bfd_generic_read_minisymbols
364 #define ppcboot_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
365
366 #define ppcboot_get_reloc_upper_bound \
367   ((long (*) PARAMS ((bfd *, asection *))) bfd_0l)
368 #define ppcboot_canonicalize_reloc \
369   ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l)
370 #define ppcboot_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
371 \f
372 /* Write section contents of a ppcboot file.  */
373
374 static boolean
375 ppcboot_set_section_contents (abfd, sec, data, offset, size)
376      bfd *abfd;
377      asection *sec;
378      PTR data;
379      file_ptr offset;
380      bfd_size_type size;
381 {
382   if (! abfd->output_has_begun)
383     {
384       bfd_vma low;
385       asection *s;
386
387       /* The lowest section VMA sets the virtual address of the start
388          of the file.  We use the set the file position of all the
389          sections.  */
390       low = abfd->sections->vma;
391       for (s = abfd->sections->next; s != NULL; s = s->next)
392         if (s->vma < low)
393           low = s->vma;
394
395       for (s = abfd->sections; s != NULL; s = s->next)
396         s->filepos = s->vma - low;
397
398       abfd->output_has_begun = true;
399     }
400
401   return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
402 }
403
404 \f
405 static int
406 ppcboot_sizeof_headers (abfd, exec)
407      bfd *abfd ATTRIBUTE_UNUSED;
408      boolean exec ATTRIBUTE_UNUSED;
409 {
410   return sizeof (ppcboot_hdr_t);
411 }
412
413 \f
414 /* Print out the program headers.  */
415
416 static boolean
417 ppcboot_bfd_print_private_bfd_data (abfd, farg)
418      bfd *abfd;
419      PTR farg;
420 {
421   FILE *f = (FILE *)farg;
422   ppcboot_data_t *tdata = ppcboot_get_tdata (abfd);
423   long entry_offset = bfd_getl_signed_32 ((PTR) tdata->header.entry_offset);
424   long length = bfd_getl_signed_32 ((PTR) tdata->header.length);
425   int i;
426
427   fprintf (f, _("\nppcboot header:\n"));
428   fprintf (f, _("Entry offset        = 0x%.8lx (%ld)\n"), entry_offset, entry_offset);
429   fprintf (f, _("Length              = 0x%.8lx (%ld)\n"), length, length);
430
431   if (tdata->header.flags)
432     fprintf (f, _("Flag field          = 0x%.2x\n"), tdata->header.flags);
433
434   if (tdata->header.os_id)
435     fprintf (f, "OS_ID               = 0x%.2x\n", tdata->header.os_id);
436
437   if (tdata->header.partition_name)
438     fprintf (f, _("Partition name      = \"%s\"\n"), tdata->header.partition_name);
439
440   for (i = 0; i < 4; i++)
441     {
442       long sector_begin  = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_begin);
443       long sector_length = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_length);
444
445       /* Skip all 0 entries */
446       if (!tdata->header.partition[i].partition_begin.ind
447           && !tdata->header.partition[i].partition_begin.head
448           && !tdata->header.partition[i].partition_begin.sector
449           && !tdata->header.partition[i].partition_begin.cylinder
450           && !tdata->header.partition[i].partition_end.ind
451           && !tdata->header.partition[i].partition_end.head
452           && !tdata->header.partition[i].partition_end.sector
453           && !tdata->header.partition[i].partition_end.cylinder
454           && !sector_begin && !sector_length)
455         continue;
456
457       fprintf (f, _("\nPartition[%d] start  = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
458                tdata->header.partition[i].partition_begin.ind,
459                tdata->header.partition[i].partition_begin.head,
460                tdata->header.partition[i].partition_begin.sector,
461                tdata->header.partition[i].partition_begin.cylinder);
462
463       fprintf (f, _("Partition[%d] end    = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
464                tdata->header.partition[i].partition_end.ind,
465                tdata->header.partition[i].partition_end.head,
466                tdata->header.partition[i].partition_end.sector,
467                tdata->header.partition[i].partition_end.cylinder);
468
469       fprintf (f, _("Partition[%d] sector = 0x%.8lx (%ld)\n"), i, sector_begin, sector_begin);
470       fprintf (f, _("Partition[%d] length = 0x%.8lx (%ld)\n"), i, sector_length, sector_length);
471     }
472
473   fprintf (f, "\n");
474   return true;
475 }
476
477 \f
478 #define ppcboot_bfd_get_relocated_section_contents \
479   bfd_generic_get_relocated_section_contents
480 #define ppcboot_bfd_relax_section bfd_generic_relax_section
481 #define ppcboot_bfd_gc_sections bfd_generic_gc_sections
482 #define ppcboot_bfd_merge_sections bfd_generic_merge_sections
483 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
484 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
485 #define ppcboot_bfd_final_link _bfd_generic_final_link
486 #define ppcboot_bfd_link_split_section _bfd_generic_link_split_section
487 #define ppcboot_get_section_contents_in_window \
488   _bfd_generic_get_section_contents_in_window
489
490 #define ppcboot_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
491 #define ppcboot_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
492 #define ppcboot_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
493 #define ppcboot_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
494 #define ppcboot_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
495 #define ppcboot_bfd_print_private_bfd_dat ppcboot_bfd_print_private_bfd_data
496
497 const bfd_target ppcboot_vec =
498 {
499   "ppcboot",                    /* name */
500   bfd_target_unknown_flavour,   /* flavour */
501   BFD_ENDIAN_BIG,               /* byteorder is big endian for code */
502   BFD_ENDIAN_LITTLE,            /* header_byteorder */
503   EXEC_P,                       /* object_flags */
504   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
505    | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */
506   0,                            /* symbol_leading_char */
507   ' ',                          /* ar_pad_char */
508   16,                           /* ar_max_namelen */
509   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
510   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
511   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* data */
512   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
513   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
514   bfd_getl16, bfd_getl_signed_16, bfd_putl16,   /* hdrs */
515   {                             /* bfd_check_format */
516     _bfd_dummy_target,
517     ppcboot_object_p,           /* bfd_check_format */
518     _bfd_dummy_target,
519     _bfd_dummy_target,
520   },
521   {                             /* bfd_set_format */
522     bfd_false,
523     ppcboot_mkobject,
524     bfd_false,
525     bfd_false,
526   },
527   {                             /* bfd_write_contents */
528     bfd_false,
529     bfd_true,
530     bfd_false,
531     bfd_false,
532   },
533
534   BFD_JUMP_TABLE_GENERIC (ppcboot),
535   BFD_JUMP_TABLE_COPY (ppcboot),
536   BFD_JUMP_TABLE_CORE (_bfd_nocore),
537   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
538   BFD_JUMP_TABLE_SYMBOLS (ppcboot),
539   BFD_JUMP_TABLE_RELOCS (ppcboot),
540   BFD_JUMP_TABLE_WRITE (ppcboot),
541   BFD_JUMP_TABLE_LINK (ppcboot),
542   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
543
544   NULL,
545
546   NULL
547 };