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