Back to index

cell-binutils  2.17cvs20070401
oasys.c
Go to the documentation of this file.
00001 /* BFD back-end for oasys objects.
00002    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001,
00003    2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
00004    Written by Steve Chamberlain of Cygnus Support, <sac@cygnus.com>.
00005 
00006    This file is part of BFD, the Binary File Descriptor library.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 #define UNDERSCORE_HACK 1
00023 #include "bfd.h"
00024 #include "sysdep.h"
00025 #include "safe-ctype.h"
00026 #include "libbfd.h"
00027 #include "oasys.h"
00028 #include "liboasys.h"
00029 
00030 /* Read in all the section data and relocation stuff too.  */
00031 
00032 static bfd_boolean
00033 oasys_read_record (bfd *abfd, oasys_record_union_type *record)
00034 {
00035   bfd_size_type amt = sizeof (record->header);
00036 
00037   if (bfd_bread ((void *) record, amt, abfd) != amt)
00038     return FALSE;
00039 
00040   amt = record->header.length - sizeof (record->header);
00041   if ((long) amt <= 0)
00042     return TRUE;
00043   if (bfd_bread ((void *) ((char *) record + sizeof (record->header)), amt, abfd)
00044       != amt)
00045     return FALSE;
00046   return TRUE;
00047 }
00048 
00049 static size_t
00050 oasys_string_length (oasys_record_union_type *record)
00051 {
00052   return record->header.length
00053     - ((char *) record->symbol.name - (char *) record);
00054 }
00055 
00056 /* Slurp the symbol table by reading in all the records at the start file
00057    till we get to the first section record.
00058 
00059    We'll sort the symbolss into  two lists, defined and undefined. The
00060    undefined symbols will be placed into the table according to their
00061    refno.
00062 
00063    We do this by placing all undefined symbols at the front of the table
00064    moving in, and the defined symbols at the end of the table moving back.  */
00065 
00066 static bfd_boolean
00067 oasys_slurp_symbol_table (bfd *const abfd)
00068 {
00069   oasys_record_union_type record;
00070   oasys_data_type *data = OASYS_DATA (abfd);
00071   bfd_boolean loop = TRUE;
00072   asymbol *dest_defined;
00073   asymbol *dest;
00074   char *string_ptr;
00075   bfd_size_type amt;
00076 
00077   if (data->symbols != NULL)
00078     return TRUE;
00079 
00080   /* Buy enough memory for all the symbols and all the names.  */
00081   amt = abfd->symcount;
00082   amt *= sizeof (asymbol);
00083   data->symbols = bfd_alloc (abfd, amt);
00084 
00085   amt = data->symbol_string_length;
00086 #ifdef UNDERSCORE_HACK
00087   /* Buy 1 more char for each symbol to keep the underscore in.  */
00088   amt += abfd->symcount;
00089 #endif
00090   data->strings = bfd_alloc (abfd, amt);
00091 
00092   if (!data->symbols || !data->strings)
00093     return FALSE;
00094 
00095   dest_defined = data->symbols + abfd->symcount - 1;
00096 
00097   string_ptr = data->strings;
00098   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
00099     return FALSE;
00100   while (loop)
00101     {
00102       if (! oasys_read_record (abfd, &record))
00103        return FALSE;
00104 
00105       switch (record.header.type)
00106        {
00107        case oasys_record_is_header_enum:
00108          break;
00109        case oasys_record_is_local_enum:
00110        case oasys_record_is_symbol_enum:
00111          {
00112            int flag = record.header.type == (int) oasys_record_is_local_enum ?
00113            (BSF_LOCAL) : (BSF_GLOBAL | BSF_EXPORT);
00114 
00115            size_t length = oasys_string_length (&record);
00116            switch (record.symbol.relb & RELOCATION_TYPE_BITS)
00117              {
00118              case RELOCATION_TYPE_ABS:
00119               dest = dest_defined--;
00120               dest->section = bfd_abs_section_ptr;
00121               dest->flags = 0;
00122 
00123               break;
00124              case RELOCATION_TYPE_REL:
00125               dest = dest_defined--;
00126               dest->section =
00127                 OASYS_DATA (abfd)->sections[record.symbol.relb &
00128                                          RELOCATION_SECT_BITS];
00129               if (record.header.type == (int) oasys_record_is_local_enum)
00130                 {
00131                   dest->flags = BSF_LOCAL;
00132                   if (dest->section == (asection *) (~0))
00133                     {
00134                      /* It seems that sometimes internal symbols are tied up, but
00135                      still get output, even though there is no
00136                      section */
00137                      dest->section = 0;
00138                     }
00139                 }
00140               else
00141                 dest->flags = flag;
00142               break;
00143              case RELOCATION_TYPE_UND:
00144               dest = data->symbols + H_GET_16 (abfd, record.symbol.refno);
00145               dest->section = bfd_und_section_ptr;
00146               break;
00147              case RELOCATION_TYPE_COM:
00148               dest = dest_defined--;
00149               dest->name = string_ptr;
00150               dest->the_bfd = abfd;
00151               dest->section = bfd_com_section_ptr;
00152               break;
00153              default:
00154               dest = dest_defined--;
00155               BFD_ASSERT (FALSE);
00156               break;
00157              }
00158            dest->name = string_ptr;
00159            dest->the_bfd = abfd;
00160            dest->udata.p = NULL;
00161            dest->value = H_GET_32 (abfd, record.symbol.value);
00162 
00163 #ifdef UNDERSCORE_HACK
00164            if (record.symbol.name[0] != '_')
00165              {
00166               string_ptr[0] = '_';
00167               string_ptr++;
00168              }
00169 #endif
00170            memcpy (string_ptr, record.symbol.name, length);
00171 
00172            string_ptr[length] = 0;
00173            string_ptr += length + 1;
00174          }
00175          break;
00176        default:
00177          loop = FALSE;
00178        }
00179     }
00180   return TRUE;
00181 }
00182 
00183 static long
00184 oasys_get_symtab_upper_bound (bfd *const abfd)
00185 {
00186   if (! oasys_slurp_symbol_table (abfd))
00187     return -1;
00188 
00189   return (abfd->symcount + 1) * (sizeof (oasys_symbol_type *));
00190 }
00191 
00192 extern const bfd_target oasys_vec;
00193 
00194 static long
00195 oasys_canonicalize_symtab (bfd *abfd, asymbol **location)
00196 {
00197   asymbol *symbase;
00198   unsigned int counter;
00199 
00200   if (! oasys_slurp_symbol_table (abfd))
00201     return -1;
00202 
00203   symbase = OASYS_DATA (abfd)->symbols;
00204   for (counter = 0; counter < abfd->symcount; counter++)
00205     *(location++) = symbase++;
00206 
00207   *location = 0;
00208   return abfd->symcount;
00209 }
00210 
00211 /* Archive stuff.  */
00212 
00213 static const bfd_target *
00214 oasys_archive_p (bfd *abfd)
00215 {
00216   oasys_archive_header_type header;
00217   oasys_extarchive_header_type header_ext;
00218   unsigned int i;
00219   file_ptr filepos;
00220   bfd_size_type amt;
00221 
00222   amt = sizeof (header_ext);
00223   if (bfd_seek (abfd, (file_ptr) 0, 0) != 0
00224       || bfd_bread ((void *) &header_ext, amt, abfd) != amt)
00225     {
00226       if (bfd_get_error () != bfd_error_system_call)
00227        bfd_set_error (bfd_error_wrong_format);
00228       return NULL;
00229     }
00230 
00231   header.version = H_GET_32 (abfd, header_ext.version);
00232   header.mod_count = H_GET_32 (abfd, header_ext.mod_count);
00233   header.mod_tbl_offset = H_GET_32 (abfd, header_ext.mod_tbl_offset);
00234   header.sym_tbl_size = H_GET_32 (abfd, header_ext.sym_tbl_size);
00235   header.sym_count = H_GET_32 (abfd, header_ext.sym_count);
00236   header.sym_tbl_offset = H_GET_32 (abfd, header_ext.sym_tbl_offset);
00237   header.xref_count = H_GET_32 (abfd, header_ext.xref_count);
00238   header.xref_lst_offset = H_GET_32 (abfd, header_ext.xref_lst_offset);
00239 
00240   /* There isn't a magic number in an Oasys archive, so the best we
00241      can do to verify reasonableness is to make sure that the values in
00242      the header are too weird.  */
00243 
00244   if (header.version > 10000
00245       || header.mod_count > 10000
00246       || header.sym_count > 100000
00247       || header.xref_count > 100000)
00248     return NULL;
00249 
00250   /* That all worked, let's buy the space for the header and read in
00251      the headers.  */
00252   {
00253     oasys_ar_data_type *ar;
00254     oasys_module_info_type *module;
00255     oasys_module_table_type record;
00256 
00257     amt = sizeof (oasys_ar_data_type);
00258     ar = bfd_alloc (abfd, amt);
00259 
00260     amt = header.mod_count;
00261     amt *= sizeof (oasys_module_info_type);
00262     module = bfd_alloc (abfd, amt);
00263 
00264     if (!ar || !module)
00265       return NULL;
00266 
00267     abfd->tdata.oasys_ar_data = ar;
00268     ar->module = module;
00269     ar->module_count = header.mod_count;
00270 
00271     filepos = header.mod_tbl_offset;
00272     for (i = 0; i < header.mod_count; i++)
00273       {
00274        if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
00275          return NULL;
00276 
00277        /* There are two ways of specifying the archive header.  */
00278          {
00279            oasys_extmodule_table_type_b_type record_ext;
00280 
00281            amt = sizeof (record_ext);
00282            if (bfd_bread ((void *) &record_ext, amt, abfd) != amt)
00283              return NULL;
00284 
00285            record.mod_size = H_GET_32 (abfd, record_ext.mod_size);
00286            record.file_offset = H_GET_32 (abfd, record_ext.file_offset);
00287 
00288            record.dep_count = H_GET_32 (abfd, record_ext.dep_count);
00289            record.depee_count = H_GET_32 (abfd, record_ext.depee_count);
00290            record.sect_count = H_GET_32 (abfd, record_ext.sect_count);
00291            record.module_name_size = H_GET_32 (abfd,
00292                                           record_ext.mod_name_length);
00293 
00294            amt = record.module_name_size;
00295            module[i].name = bfd_alloc (abfd, amt + 1);
00296            if (!module[i].name)
00297              return NULL;
00298            if (bfd_bread ((void *) module[i].name, amt, abfd) != amt)
00299              return NULL;
00300            module[i].name[record.module_name_size] = 0;
00301            filepos += (sizeof (record_ext)
00302                      + record.dep_count * 4
00303                      + record.module_name_size + 1);
00304          }
00305 
00306        module[i].size = record.mod_size;
00307        module[i].pos = record.file_offset;
00308        module[i].abfd = 0;
00309       }
00310   }
00311   return abfd->xvec;
00312 }
00313 
00314 static bfd_boolean
00315 oasys_mkobject (bfd *abfd)
00316 {
00317   bfd_size_type amt = sizeof (oasys_data_type);
00318 
00319   abfd->tdata.oasys_obj_data = bfd_alloc (abfd, amt);
00320 
00321   return abfd->tdata.oasys_obj_data != NULL;
00322 }
00323 
00324 /* The howto table is build using the top two bits of a reloc byte to
00325    index into it. The bits are PCREL,WORD/LONG.  */
00326 
00327 static reloc_howto_type howto_table[] =
00328 {
00329 
00330   HOWTO (0, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16",   TRUE, 0x0000ffff, 0x0000ffff, FALSE),
00331   HOWTO (0, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs32",   TRUE, 0xffffffff, 0xffffffff, FALSE),
00332   HOWTO (0, 0, 1, 16, TRUE,  0, complain_overflow_signed,   0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
00333   HOWTO (0, 0, 2, 32, TRUE,  0, complain_overflow_signed,   0, "pcrel32", TRUE, 0xffffffff, 0xffffffff, FALSE)
00334 };
00335 
00336 /* Read in all the section data and relocation stuff too.  */
00337 
00338 static bfd_boolean
00339 oasys_slurp_section_data (bfd *const abfd)
00340 {
00341   oasys_record_union_type record;
00342   oasys_data_type *data = OASYS_DATA (abfd);
00343   bfd_boolean loop = TRUE;
00344   oasys_per_section_type *per;
00345   asection *s;
00346   bfd_size_type amt;
00347 
00348   /* See if the data has been slurped already.  */
00349   for (s = abfd->sections; s != NULL; s = s->next)
00350     {
00351       per = oasys_per_section (s);
00352       if (per->initialized)
00353        return TRUE;
00354     }
00355 
00356   if (data->first_data_record == 0)
00357     return TRUE;
00358 
00359   if (bfd_seek (abfd, data->first_data_record, SEEK_SET) != 0)
00360     return FALSE;
00361 
00362   while (loop)
00363     {
00364       if (! oasys_read_record (abfd, &record))
00365        return FALSE;
00366 
00367       switch (record.header.type)
00368        {
00369        case oasys_record_is_header_enum:
00370          break;
00371        case oasys_record_is_data_enum:
00372          {
00373            bfd_byte *src = record.data.data;
00374            bfd_byte *end_src = ((bfd_byte *) & record) + record.header.length;
00375            bfd_byte *dst_ptr;
00376            bfd_byte *dst_base_ptr;
00377            unsigned int relbit;
00378            unsigned int count;
00379            asection *section =
00380            data->sections[record.data.relb & RELOCATION_SECT_BITS];
00381            bfd_vma dst_offset;
00382 
00383            per = oasys_per_section (section);
00384 
00385            if (! per->initialized)
00386              {
00387               arelent **relpp;
00388 
00389               per->data = bfd_zalloc (abfd, section->size);
00390               if (!per->data)
00391                 return FALSE;
00392               relpp = &section->relocation;
00393               per->reloc_tail_ptr = (oasys_reloc_type **) relpp;
00394               per->had_vma = FALSE;
00395               per->initialized = TRUE;
00396               section->reloc_count = 0;
00397               section->flags = SEC_ALLOC;
00398              }
00399 
00400            dst_offset = H_GET_32 (abfd, record.data.addr);
00401            if (! per->had_vma)
00402              {
00403               /* Take the first vma we see as the base.  */
00404               section->vma = dst_offset;
00405               per->had_vma = TRUE;
00406              }
00407 
00408            dst_offset -= section->vma;
00409 
00410            dst_base_ptr = oasys_per_section (section)->data;
00411            dst_ptr = oasys_per_section (section)->data +
00412              dst_offset;
00413 
00414            if (src < end_src)
00415              section->flags |= SEC_LOAD | SEC_HAS_CONTENTS;
00416 
00417            while (src < end_src)
00418              {
00419               unsigned char mod_byte = *src++;
00420               size_t gap = end_src - src;
00421 
00422               count = 8;
00423               if (mod_byte == 0 && gap >= 8)
00424                 {
00425                   dst_ptr[0] = src[0];
00426                   dst_ptr[1] = src[1];
00427                   dst_ptr[2] = src[2];
00428                   dst_ptr[3] = src[3];
00429                   dst_ptr[4] = src[4];
00430                   dst_ptr[5] = src[5];
00431                   dst_ptr[6] = src[6];
00432                   dst_ptr[7] = src[7];
00433                   dst_ptr += 8;
00434                   src += 8;
00435                 }
00436               else
00437                 {
00438                   for (relbit = 1; count-- != 0 && src < end_src; relbit <<= 1)
00439                     {
00440                      if (relbit & mod_byte)
00441                        {
00442                          unsigned char reloc = *src;
00443                          /* This item needs to be relocated.  */
00444                          switch (reloc & RELOCATION_TYPE_BITS)
00445                            {
00446                            case RELOCATION_TYPE_ABS:
00447                             break;
00448 
00449                            case RELOCATION_TYPE_REL:
00450                             {
00451                               /* Relocate the item relative to the section.  */
00452                               oasys_reloc_type *r;
00453 
00454                               amt = sizeof (oasys_reloc_type);
00455                               r = bfd_alloc (abfd, amt);
00456                               if (!r)
00457                                 return FALSE;
00458                               *(per->reloc_tail_ptr) = r;
00459                               per->reloc_tail_ptr = &r->next;
00460                               r->next = NULL;
00461                               /* Reference to undefined symbol.  */
00462                               src++;
00463                               /* There is no symbol.  */
00464                               r->symbol = 0;
00465                               /* Work out the howto.  */
00466                               abort ();
00467                               r->relent.address = dst_ptr - dst_base_ptr;
00468                               r->relent.howto = &howto_table[reloc >> 6];
00469                               r->relent.sym_ptr_ptr = NULL;
00470                               section->reloc_count++;
00471 
00472                               /* Fake up the data to look like
00473                                  it's got the -ve pc in it, this
00474                                  makes it much easier to convert
00475                                  into other formats.  This is done
00476                                  by hitting the addend.  */
00477                               if (r->relent.howto->pc_relative)
00478                                 r->relent.addend -= dst_ptr - dst_base_ptr;
00479                             }
00480                             break;
00481 
00482                            case RELOCATION_TYPE_UND:
00483                             {
00484                               oasys_reloc_type *r;
00485 
00486                               amt = sizeof (oasys_reloc_type);
00487                               r = bfd_alloc (abfd, amt);
00488                               if (!r)
00489                                 return FALSE;
00490                               *(per->reloc_tail_ptr) = r;
00491                               per->reloc_tail_ptr = &r->next;
00492                               r->next = NULL;
00493                               /* Reference to undefined symbol.  */
00494                               src++;
00495                               /* Get symbol number.  */
00496                               r->symbol = (src[0] << 8) | src[1];
00497                               /* Work out the howto.  */
00498                               abort ();
00499 
00500                               r->relent.addend = 0;
00501                               r->relent.address = dst_ptr - dst_base_ptr;
00502                               r->relent.howto = &howto_table[reloc >> 6];
00503                               r->relent.sym_ptr_ptr = NULL;
00504                               section->reloc_count++;
00505 
00506                               src += 2;
00507                               /* Fake up the data to look like
00508                                  it's got the -ve pc in it, this
00509                                  makes it much easier to convert
00510                                  into other formats.  This is done
00511                                  by hitting the addend.  */
00512                               if (r->relent.howto->pc_relative)
00513                                 r->relent.addend -= dst_ptr - dst_base_ptr;
00514                             }
00515                             break;
00516                            case RELOCATION_TYPE_COM:
00517                             BFD_FAIL ();
00518                            }
00519                        }
00520                      *dst_ptr++ = *src++;
00521                     }
00522                 }
00523              }
00524          }
00525          break;
00526        case oasys_record_is_local_enum:
00527        case oasys_record_is_symbol_enum:
00528        case oasys_record_is_section_enum:
00529          break;
00530        default:
00531          loop = FALSE;
00532        }
00533     }
00534 
00535   return TRUE;
00536 
00537 }
00538 
00539 #define MAX_SECS 16
00540 
00541 static const bfd_target *
00542 oasys_object_p (bfd *abfd)
00543 {
00544   oasys_data_type *oasys;
00545   oasys_data_type *save = OASYS_DATA (abfd);
00546   bfd_boolean loop = TRUE;
00547   bfd_boolean had_usefull = FALSE;
00548 
00549   abfd->tdata.oasys_obj_data = 0;
00550   oasys_mkobject (abfd);
00551   oasys = OASYS_DATA (abfd);
00552   memset ((void *) oasys->sections, 0xff, sizeof (oasys->sections));
00553 
00554   /* Point to the start of the file.  */
00555   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
00556     goto fail;
00557   oasys->symbol_string_length = 0;
00558 
00559   /* Inspect the records, but only keep the section info -
00560      remember the size of the symbols.  */
00561   oasys->first_data_record = 0;
00562   while (loop)
00563     {
00564       oasys_record_union_type record;
00565       if (! oasys_read_record (abfd, &record))
00566        goto fail;
00567       if ((size_t) record.header.length < (size_t) sizeof (record.header))
00568        goto fail;
00569 
00570       switch ((oasys_record_enum_type) (record.header.type))
00571        {
00572        case oasys_record_is_header_enum:
00573          had_usefull = TRUE;
00574          break;
00575        case oasys_record_is_symbol_enum:
00576        case oasys_record_is_local_enum:
00577          /* Count symbols and remember their size for a future malloc.  */
00578          abfd->symcount++;
00579          oasys->symbol_string_length += 1 + oasys_string_length (&record);
00580          had_usefull = TRUE;
00581          break;
00582        case oasys_record_is_section_enum:
00583          {
00584            asection *s;
00585            char *buffer;
00586            unsigned int section_number;
00587 
00588            if (record.section.header.length != sizeof (record.section))
00589              goto fail;
00590 
00591            buffer = bfd_alloc (abfd, (bfd_size_type) 3);
00592            if (!buffer)
00593              goto fail;
00594            section_number = record.section.relb & RELOCATION_SECT_BITS;
00595            sprintf (buffer, "%u", section_number);
00596            s = bfd_make_section (abfd, buffer);
00597            oasys->sections[section_number] = s;
00598            switch (record.section.relb & RELOCATION_TYPE_BITS)
00599              {
00600              case RELOCATION_TYPE_ABS:
00601              case RELOCATION_TYPE_REL:
00602               break;
00603              case RELOCATION_TYPE_UND:
00604              case RELOCATION_TYPE_COM:
00605               BFD_FAIL ();
00606              }
00607 
00608            s->size = H_GET_32 (abfd, record.section.value);
00609            s->vma = H_GET_32 (abfd, record.section.vma);
00610            s->flags = 0;
00611            had_usefull = TRUE;
00612          }
00613          break;
00614        case oasys_record_is_data_enum:
00615          oasys->first_data_record = bfd_tell (abfd) - record.header.length;
00616        case oasys_record_is_debug_enum:
00617        case oasys_record_is_module_enum:
00618        case oasys_record_is_named_section_enum:
00619        case oasys_record_is_end_enum:
00620          if (! had_usefull)
00621            goto fail;
00622          loop = FALSE;
00623          break;
00624        default:
00625          goto fail;
00626        }
00627     }
00628   oasys->symbols = NULL;
00629 
00630   /* Oasys support several architectures, but I can't see a simple way
00631      to discover which one is in a particular file - we'll guess.  */
00632   bfd_default_set_arch_mach (abfd, bfd_arch_m68k, 0);
00633   if (abfd->symcount != 0)
00634     abfd->flags |= HAS_SYMS;
00635 
00636   /* We don't know if a section has data until we've read it.  */
00637   oasys_slurp_section_data (abfd);
00638 
00639   return abfd->xvec;
00640 
00641 fail:
00642   (void) bfd_release (abfd, oasys);
00643   abfd->tdata.oasys_obj_data = save;
00644   return NULL;
00645 }
00646 
00647 
00648 static void
00649 oasys_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
00650                      asymbol *symbol,
00651                      symbol_info *ret)
00652 {
00653   bfd_symbol_info (symbol, ret);
00654 
00655   if (!symbol->section)
00656     ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A';
00657 }
00658 
00659 static void
00660 oasys_print_symbol (bfd *abfd, void * afile, asymbol *symbol, bfd_print_symbol_type how)
00661 {
00662   FILE *file = (FILE *) afile;
00663 
00664   switch (how)
00665     {
00666     case bfd_print_symbol_name:
00667     case bfd_print_symbol_more:
00668       fprintf (file, "%s", symbol->name);
00669       break;
00670     case bfd_print_symbol_all:
00671       {
00672        const char *section_name = symbol->section == NULL ?
00673        (const char *) "*abs" : symbol->section->name;
00674 
00675        bfd_print_symbol_vandf (abfd, (void *) file, symbol);
00676 
00677        fprintf (file, " %-5s %s",
00678                section_name,
00679                symbol->name);
00680       }
00681       break;
00682     }
00683 }
00684 
00685 static bfd_boolean
00686 oasys_new_section_hook (bfd *abfd, asection *newsect)
00687 {
00688   if (!newsect->used_by_bfd)
00689     {
00690       newsect->used_by_bfd
00691        = bfd_alloc (abfd, (bfd_size_type) sizeof (oasys_per_section_type));
00692       if (!newsect->used_by_bfd)
00693        return FALSE;
00694     }
00695   oasys_per_section (newsect)->data = NULL;
00696   oasys_per_section (newsect)->section = newsect;
00697   oasys_per_section (newsect)->offset = 0;
00698   oasys_per_section (newsect)->initialized = FALSE;
00699   newsect->alignment_power = 1;
00700 
00701   /* Turn the section string into an index.  */
00702   sscanf (newsect->name, "%u", &newsect->target_index);
00703 
00704   return _bfd_generic_new_section_hook (abfd, newsect);
00705 }
00706 
00707 
00708 static long
00709 oasys_get_reloc_upper_bound (bfd *abfd, sec_ptr asect)
00710 {
00711   if (! oasys_slurp_section_data (abfd))
00712     return -1;
00713   return (asect->reloc_count + 1) * sizeof (arelent *);
00714 }
00715 
00716 static bfd_boolean
00717 oasys_get_section_contents (bfd *abfd,
00718                          sec_ptr section,
00719                          void * location,
00720                          file_ptr offset,
00721                          bfd_size_type count)
00722 {
00723   oasys_per_section_type *p = oasys_per_section (section);
00724 
00725   oasys_slurp_section_data (abfd);
00726 
00727   if (! p->initialized)
00728     (void) memset (location, 0, (size_t) count);
00729   else
00730     (void) memcpy (location, (void *) (p->data + offset), (size_t) count);
00731 
00732   return TRUE;
00733 }
00734 
00735 static long
00736 oasys_canonicalize_reloc (bfd *ignore_abfd ATTRIBUTE_UNUSED,
00737                        sec_ptr section,
00738                        arelent **relptr,
00739                        asymbol **symbols ATTRIBUTE_UNUSED)
00740 {
00741   unsigned int reloc_count = 0;
00742   oasys_reloc_type *src = (oasys_reloc_type *) (section->relocation);
00743 
00744   if (src != NULL)
00745     abort ();
00746 
00747   *relptr = NULL;
00748   return section->reloc_count = reloc_count;
00749 }
00750 
00751 
00752 /* Writing.  */
00753 
00754 /* Calculate the checksum and write one record.  */
00755 
00756 static bfd_boolean
00757 oasys_write_record (bfd *abfd,
00758                   oasys_record_enum_type type,
00759                   oasys_record_union_type *record,
00760                   size_t size)
00761 {
00762   int checksum;
00763   size_t i;
00764   unsigned char *ptr;
00765 
00766   record->header.length = size;
00767   record->header.type = (int) type;
00768   record->header.check_sum = 0;
00769   record->header.fill = 0;
00770   ptr = (unsigned char *) &record->pad[0];
00771   checksum = 0;
00772   for (i = 0; i < size; i++)
00773     checksum += *ptr++;
00774   record->header.check_sum = 0xff & (-checksum);
00775   if (bfd_bwrite ((void *) record, (bfd_size_type) size, abfd) != size)
00776     return FALSE;
00777   return TRUE;
00778 }
00779 
00780 
00781 /* Write out all the symbols.  */
00782 
00783 static bfd_boolean
00784 oasys_write_syms (bfd *abfd)
00785 {
00786   unsigned int count;
00787   asymbol **generic = bfd_get_outsymbols (abfd);
00788   unsigned int index = 0;
00789 
00790   for (count = 0; count < bfd_get_symcount (abfd); count++)
00791     {
00792       oasys_symbol_record_type symbol;
00793       asymbol *const g = generic[count];
00794       const char *src = g->name;
00795       char *dst = symbol.name;
00796       unsigned int l = 0;
00797 
00798       if (bfd_is_com_section (g->section))
00799        {
00800          symbol.relb = RELOCATION_TYPE_COM;
00801          H_PUT_16 (abfd, index, symbol.refno);
00802          index++;
00803        }
00804       else if (bfd_is_abs_section (g->section))
00805        {
00806          symbol.relb = RELOCATION_TYPE_ABS;
00807          H_PUT_16 (abfd, 0, symbol.refno);
00808        }
00809       else if (bfd_is_und_section (g->section))
00810        {
00811          symbol.relb = RELOCATION_TYPE_UND;
00812          H_PUT_16 (abfd, index, symbol.refno);
00813          /* Overload the value field with the output index number */
00814          index++;
00815        }
00816       else if (g->flags & BSF_DEBUGGING)
00817        /* Throw it away.  */
00818        continue;
00819       else
00820        {
00821          if (g->section == NULL)
00822            /* Sometime, the oasys tools give out a symbol with illegal
00823               bits in it, we'll output it in the same broken way.  */
00824            symbol.relb = RELOCATION_TYPE_REL | 0;
00825          else
00826            symbol.relb = RELOCATION_TYPE_REL | g->section->output_section->target_index;
00827 
00828          H_PUT_16 (abfd, 0, symbol.refno);
00829        }
00830 
00831 #ifdef UNDERSCORE_HACK
00832       if (src[l] == '_')
00833        dst[l++] = '.';
00834 #endif
00835       while (src[l])
00836        {
00837          dst[l] = src[l];
00838          l++;
00839        }
00840 
00841       H_PUT_32 (abfd, g->value, symbol.value);
00842 
00843       if (g->flags & BSF_LOCAL)
00844        {
00845          if (! oasys_write_record (abfd,
00846                                 oasys_record_is_local_enum,
00847                                 (oasys_record_union_type *) & symbol,
00848                                 offsetof (oasys_symbol_record_type,
00849                                          name[0]) + l))
00850            return FALSE;
00851        }
00852       else
00853        {
00854          if (! oasys_write_record (abfd,
00855                                 oasys_record_is_symbol_enum,
00856                                 (oasys_record_union_type *) & symbol,
00857                                 offsetof (oasys_symbol_record_type,
00858                                          name[0]) + l))
00859            return FALSE;
00860        }
00861       g->value = index - 1;
00862     }
00863 
00864   return TRUE;
00865 }
00866 
00867 /* Write a section header for each section.  */
00868 
00869 static bfd_boolean
00870 oasys_write_sections (bfd *abfd)
00871 {
00872   asection *s;
00873   static oasys_section_record_type out;
00874 
00875   for (s = abfd->sections; s != NULL; s = s->next)
00876     {
00877       if (!ISDIGIT (s->name[0]))
00878        {
00879          (*_bfd_error_handler)
00880            (_("%s: can not represent section `%s' in oasys"),
00881             bfd_get_filename (abfd), s->name);
00882          bfd_set_error (bfd_error_nonrepresentable_section);
00883          return FALSE;
00884        }
00885       out.relb = RELOCATION_TYPE_REL | s->target_index;
00886       H_PUT_32 (abfd, s->size, out.value);
00887       H_PUT_32 (abfd, s->vma, out.vma);
00888 
00889       if (! oasys_write_record (abfd,
00890                             oasys_record_is_section_enum,
00891                             (oasys_record_union_type *) & out,
00892                             sizeof (out)))
00893        return FALSE;
00894     }
00895   return TRUE;
00896 }
00897 
00898 static bfd_boolean
00899 oasys_write_header (bfd *abfd)
00900 {
00901   /* Create and write the header.  */
00902   oasys_header_record_type r;
00903   size_t length = strlen (abfd->filename);
00904 
00905   if (length > (size_t) sizeof (r.module_name))
00906     length = sizeof (r.module_name);
00907 
00908   (void) memcpy (r.module_name, abfd->filename, length);
00909   (void) memset (r.module_name + length, ' ', sizeof (r.module_name) - length);
00910 
00911   r.version_number = OASYS_VERSION_NUMBER;
00912   r.rev_number = OASYS_REV_NUMBER;
00913 
00914   return oasys_write_record (abfd, oasys_record_is_header_enum,
00915                           (oasys_record_union_type *) & r,
00916                           offsetof (oasys_header_record_type,
00917                                    description[0]));
00918 }
00919 
00920 static bfd_boolean
00921 oasys_write_end (bfd *abfd)
00922 {
00923   oasys_end_record_type end;
00924   unsigned char null = 0;
00925 
00926   end.relb = RELOCATION_TYPE_ABS;
00927   H_PUT_32 (abfd, abfd->start_address, end.entry);
00928   H_PUT_16 (abfd, 0, end.fill);
00929   end.zero = 0;
00930   if (! oasys_write_record (abfd,
00931                          oasys_record_is_end_enum,
00932                          (oasys_record_union_type *) & end,
00933                          sizeof (end)))
00934     return FALSE;
00935 
00936   return bfd_bwrite ((void *) &null, (bfd_size_type) 1, abfd) == 1;
00937 }
00938 
00939 static int
00940 comp (const void * ap, const void * bp)
00941 {
00942   arelent *a = *((arelent **) ap);
00943   arelent *b = *((arelent **) bp);
00944 
00945   return a->address - b->address;
00946 }
00947 
00948 static bfd_boolean
00949 oasys_write_data (bfd *abfd)
00950 {
00951   asection *s;
00952 
00953   for (s = abfd->sections; s != NULL; s = s->next)
00954     {
00955       if (s->flags & SEC_LOAD)
00956        {
00957          bfd_byte *raw_data = oasys_per_section (s)->data;
00958          oasys_data_record_type processed_data;
00959          bfd_size_type current_byte_index = 0;
00960          unsigned int relocs_to_go = s->reloc_count;
00961          arelent **p = s->orelocation;
00962 
00963          if (s->reloc_count != 0)
00964            /* Sort the reloc records so it's easy to insert the relocs into the
00965               data.  */
00966            qsort (s->orelocation, s->reloc_count, sizeof (arelent **), comp);
00967 
00968          current_byte_index = 0;
00969          processed_data.relb = s->target_index | RELOCATION_TYPE_REL;
00970 
00971          while (current_byte_index < s->size)
00972            {
00973              /* Scan forwards by eight bytes or however much is left and see if
00974               there are any relocations going on.  */
00975              bfd_byte *mod = &processed_data.data[0];
00976              bfd_byte *dst = &processed_data.data[1];
00977 
00978              unsigned int i = 0;
00979              *mod = 0;
00980 
00981              H_PUT_32 (abfd, s->vma + current_byte_index,
00982                      processed_data.addr);
00983 
00984              /* Don't start a relocation unless you're sure you can finish it
00985                within the same data record.  The worst case relocation is a
00986                4-byte relocatable value which is split across two modification
00987                bytes (1 relocation byte + 2 symbol reference bytes + 2 data +
00988                1 modification byte + 2 data = 8 bytes total).  That's where
00989                the magic number 8 comes from.  */
00990              while (current_byte_index < s->size && dst <=
00991                    & processed_data.data[sizeof (processed_data.data) - 8])
00992               {
00993                 if (relocs_to_go != 0)
00994                   {
00995                     arelent *r = *p;
00996 
00997                     /* There is a relocation, is it for this byte ?  */
00998                     if (r->address == current_byte_index)
00999                      abort ();
01000                   }
01001 
01002                 /* If this is coming from an unloadable section then copy
01003                    zeros.  */
01004                 if (raw_data == NULL)
01005                   *dst++ = 0;
01006                 else
01007                   *dst++ = *raw_data++;
01008 
01009                 if (++i >= 8)
01010                   {
01011                     i = 0;
01012                     mod = dst++;
01013                     *mod = 0;
01014                   }
01015                 current_byte_index++;
01016               }
01017 
01018              /* Don't write a useless null modification byte.  */
01019              if (dst == mod + 1)
01020               --dst;
01021 
01022              if (! (oasys_write_record
01023                    (abfd, oasys_record_is_data_enum,
01024                     ((oasys_record_union_type *) &processed_data),
01025                     (size_t) (dst - (bfd_byte *) &processed_data))))
01026               return FALSE;
01027            }
01028        }
01029     }
01030 
01031   return TRUE;
01032 }
01033 
01034 static bfd_boolean
01035 oasys_write_object_contents (bfd *abfd)
01036 {
01037   if (! oasys_write_header (abfd))
01038     return FALSE;
01039   if (! oasys_write_syms (abfd))
01040     return FALSE;
01041   if (! oasys_write_sections (abfd))
01042     return FALSE;
01043   if (! oasys_write_data (abfd))
01044     return FALSE;
01045   if (! oasys_write_end (abfd))
01046     return FALSE;
01047   return TRUE;
01048 }
01049 
01050 /* Set section contents is complicated with OASYS since the format is
01051    not a byte image, but a record stream.  */
01052 
01053 static bfd_boolean
01054 oasys_set_section_contents (bfd *abfd,
01055                          sec_ptr section,
01056                          const void * location,
01057                          file_ptr offset,
01058                          bfd_size_type count)
01059 {
01060   if (count != 0)
01061     {
01062       if (oasys_per_section (section)->data == NULL)
01063        {
01064          oasys_per_section (section)->data = bfd_alloc (abfd, section->size);
01065          if (!oasys_per_section (section)->data)
01066            return FALSE;
01067        }
01068       (void) memcpy ((void *) (oasys_per_section (section)->data + offset),
01069                    location, (size_t) count);
01070     }
01071   return TRUE;
01072 }
01073 
01074 
01075 
01076 /* Native-level interface to symbols.  */
01077 
01078 /* We read the symbols into a buffer, which is discarded when this
01079    function exits.  We read the strings into a buffer large enough to
01080    hold them all plus all the cached symbol entries.  */
01081 
01082 static asymbol *
01083 oasys_make_empty_symbol (bfd *abfd)
01084 {
01085   bfd_size_type amt = sizeof (oasys_symbol_type);
01086   oasys_symbol_type *new = bfd_zalloc (abfd, amt);
01087 
01088   if (!new)
01089     return NULL;
01090   new->symbol.the_bfd = abfd;
01091   return &new->symbol;
01092 }
01093 
01094 /* User should have checked the file flags; perhaps we should return
01095    BFD_NO_MORE_SYMBOLS if there are none?  */
01096 
01097 static bfd *
01098 oasys_openr_next_archived_file (bfd *arch, bfd *prev)
01099 {
01100   oasys_ar_data_type *ar = OASYS_AR_DATA (arch);
01101   oasys_module_info_type *p;
01102 
01103   /* Take the next one from the arch state, or reset.  */
01104   if (prev == NULL)
01105     /* Reset the index - the first two entries are bogus.  */
01106     ar->module_index = 0;
01107 
01108   p = ar->module + ar->module_index;
01109   ar->module_index++;
01110 
01111   if (ar->module_index <= ar->module_count)
01112     {
01113       if (p->abfd == NULL)
01114        {
01115          p->abfd = _bfd_create_empty_archive_element_shell (arch);
01116          p->abfd->origin = p->pos;
01117          p->abfd->filename = p->name;
01118 
01119          /* Fixup a pointer to this element for the member.  */
01120          p->abfd->arelt_data = (void *) p;
01121        }
01122       return p->abfd;
01123     }
01124 
01125   bfd_set_error (bfd_error_no_more_archived_files);
01126   return NULL;
01127 }
01128 
01129 static bfd_boolean
01130 oasys_find_nearest_line (bfd *abfd ATTRIBUTE_UNUSED,
01131                       asection *section ATTRIBUTE_UNUSED,
01132                       asymbol **symbols ATTRIBUTE_UNUSED,
01133                       bfd_vma offset ATTRIBUTE_UNUSED,
01134                       const char **filename_ptr ATTRIBUTE_UNUSED,
01135                       const char **functionname_ptr ATTRIBUTE_UNUSED,
01136                       unsigned int *line_ptr ATTRIBUTE_UNUSED)
01137 {
01138   return FALSE;
01139 }
01140 
01141 static bfd_boolean
01142 oasys_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED,
01143                       const char **filename_ptr ATTRIBUTE_UNUSED,
01144                       const char **functionname_ptr ATTRIBUTE_UNUSED,
01145                       unsigned int *line_ptr ATTRIBUTE_UNUSED)
01146 {
01147   return FALSE;
01148 }
01149 
01150 static int
01151 oasys_generic_stat_arch_elt (bfd *abfd, struct stat *buf)
01152 {
01153   oasys_module_info_type *mod = (oasys_module_info_type *) abfd->arelt_data;
01154 
01155   if (mod == NULL)
01156     {
01157       bfd_set_error (bfd_error_invalid_operation);
01158       return -1;
01159     }
01160 
01161   buf->st_size = mod->size;
01162   buf->st_mode = 0666;
01163   return 0;
01164 }
01165 
01166 static int
01167 oasys_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
01168                     struct bfd_link_info *info ATTRIBUTE_UNUSED)
01169 {
01170   return 0;
01171 }
01172 
01173 #define       oasys_close_and_cleanup                    _bfd_generic_close_and_cleanup
01174 #define oasys_bfd_free_cached_info                 _bfd_generic_bfd_free_cached_info
01175 #define oasys_slurp_armap                          bfd_true
01176 #define oasys_slurp_extended_name_table            bfd_true
01177 #define oasys_construct_extended_name_table        ((bfd_boolean (*) (bfd *, char **, bfd_size_type *, const char **)) bfd_true)
01178 #define oasys_truncate_arname                      bfd_dont_truncate_arname
01179 #define oasys_write_armap                          ((bfd_boolean (*) (bfd *, unsigned int, struct orl *, unsigned int, int)) bfd_true)
01180 #define oasys_read_ar_hdr                          bfd_nullvoidptr
01181 #define oasys_get_elt_at_index                     _bfd_generic_get_elt_at_index
01182 #define oasys_update_armap_timestamp               bfd_true
01183 #define oasys_bfd_is_local_label_name              bfd_generic_is_local_label_name
01184 #define oasys_bfd_is_target_special_symbol         ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
01185 #define oasys_get_lineno                           _bfd_nosymbols_get_lineno
01186 #define oasys_bfd_make_debug_symbol                _bfd_nosymbols_bfd_make_debug_symbol
01187 #define oasys_read_minisymbols                     _bfd_generic_read_minisymbols
01188 #define oasys_minisymbol_to_symbol                 _bfd_generic_minisymbol_to_symbol
01189 #define oasys_bfd_reloc_type_lookup                _bfd_norelocs_bfd_reloc_type_lookup
01190 #define oasys_bfd_reloc_name_lookup          _bfd_norelocs_bfd_reloc_name_lookup
01191 #define oasys_set_arch_mach                        bfd_default_set_arch_mach
01192 #define oasys_get_section_contents_in_window       _bfd_generic_get_section_contents_in_window
01193 #define oasys_bfd_get_relocated_section_contents   bfd_generic_get_relocated_section_contents
01194 #define oasys_bfd_relax_section                    bfd_generic_relax_section
01195 #define oasys_bfd_gc_sections                      bfd_generic_gc_sections
01196 #define oasys_bfd_merge_sections                   bfd_generic_merge_sections
01197 #define oasys_bfd_is_group_section                 bfd_generic_is_group_section
01198 #define oasys_bfd_discard_group                    bfd_generic_discard_group
01199 #define oasys_section_already_linked               _bfd_generic_section_already_linked
01200 #define oasys_bfd_link_hash_table_create           _bfd_generic_link_hash_table_create
01201 #define oasys_bfd_link_hash_table_free             _bfd_generic_link_hash_table_free
01202 #define oasys_bfd_link_add_symbols                 _bfd_generic_link_add_symbols
01203 #define oasys_bfd_link_just_syms                   _bfd_generic_link_just_syms
01204 #define oasys_bfd_final_link                       _bfd_generic_final_link
01205 #define oasys_bfd_link_split_section               _bfd_generic_link_split_section
01206 
01207 const bfd_target oasys_vec =
01208 {
01209   "oasys",                  /* Name.  */
01210   bfd_target_oasys_flavour,
01211   BFD_ENDIAN_BIG,           /* Target byte order.  */
01212   BFD_ENDIAN_BIG,           /* Target headers byte order.  */
01213   (HAS_RELOC | EXEC_P |            /* Object flags.  */
01214    HAS_LINENO | HAS_DEBUG |
01215    HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
01216   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
01217    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),   /* Section flags.  */
01218   0,                        /* Leading underscore.  */
01219   ' ',                      /* AR_pad_char.  */
01220   16,                       /* AR_max_namelen.  */
01221   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01222   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01223   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Data.  */
01224   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01225   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01226   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Headers.  */
01227 
01228   {_bfd_dummy_target,
01229    oasys_object_p,          /* bfd_check_format.  */
01230    oasys_archive_p,
01231    _bfd_dummy_target,
01232   },
01233   {                         /* bfd_set_format.  */
01234     bfd_false,
01235     oasys_mkobject,
01236     _bfd_generic_mkarchive,
01237     bfd_false
01238   },
01239   {                         /* bfd_write_contents.  */
01240     bfd_false,
01241     oasys_write_object_contents,
01242     _bfd_write_archive_contents,
01243     bfd_false,
01244   },
01245 
01246   BFD_JUMP_TABLE_GENERIC (oasys),
01247   BFD_JUMP_TABLE_COPY (_bfd_generic),
01248   BFD_JUMP_TABLE_CORE (_bfd_nocore),
01249   BFD_JUMP_TABLE_ARCHIVE (oasys),
01250   BFD_JUMP_TABLE_SYMBOLS (oasys),
01251   BFD_JUMP_TABLE_RELOCS (oasys),
01252   BFD_JUMP_TABLE_WRITE (oasys),
01253   BFD_JUMP_TABLE_LINK (oasys),
01254   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
01255 
01256   NULL,
01257 
01258   NULL
01259 };