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