(root)/
binutils-2.41/
bfd/
archive64.c
       1  /* Support for 64-bit archives.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     Ian Lance Taylor, Cygnus Support
       4     Linker support added by Mark Mitchell, CodeSourcery, LLC.
       5     <mark@codesourcery.com>
       6  
       7     This file is part of BFD, the Binary File Descriptor library.
       8  
       9     This program is free software; you can redistribute it and/or modify
      10     it under the terms of the GNU General Public License as published by
      11     the Free Software Foundation; either version 3 of the License, or
      12     (at your option) any later version.
      13  
      14     This program is distributed in the hope that it will be useful,
      15     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17     GNU General Public License for more details.
      18  
      19     You should have received a copy of the GNU General Public License
      20     along with this program; if not, write to the Free Software
      21     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      22     MA 02110-1301, USA.  */
      23  
      24  /* This file supports the 64-bit archives.  We use the same format as
      25     the 64-bit (MIPS) ELF archives.  */
      26  
      27  #include "sysdep.h"
      28  #include "bfd.h"
      29  #include "libbfd.h"
      30  #include "aout/ar.h"
      31  
      32  /* Irix 6 defines a 64bit archive map format, so that they can
      33     have archives more than 4 GB in size.  */
      34  
      35  /* Read an Irix 6 armap.  */
      36  
      37  bool
      38  _bfd_archive_64_bit_slurp_armap (bfd *abfd)
      39  {
      40    struct artdata *ardata = bfd_ardata (abfd);
      41    char nextname[17];
      42    bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
      43    struct areltdata *mapdata;
      44    bfd_byte int_buf[8];
      45    char *stringbase;
      46    char *stringend;
      47    bfd_byte *raw_armap = NULL;
      48    carsym *carsyms;
      49    bfd_size_type amt;
      50    ufile_ptr filesize;
      51  
      52    ardata->symdefs = NULL;
      53  
      54    /* Get the name of the first element.  */
      55    i = bfd_bread (nextname, 16, abfd);
      56    if (i == 0)
      57      return true;
      58    if (i != 16)
      59      return false;
      60  
      61    if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
      62      return false;
      63  
      64    /* Archives with traditional armaps are still permitted.  */
      65    if (startswith (nextname, "/               "))
      66      return bfd_slurp_armap (abfd);
      67  
      68    if (! startswith (nextname, "/SYM64/         "))
      69      {
      70        abfd->has_armap = false;
      71        return true;
      72      }
      73  
      74    mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
      75    if (mapdata == NULL)
      76      return false;
      77    parsed_size = mapdata->parsed_size;
      78    free (mapdata);
      79  
      80    filesize = bfd_get_file_size (abfd);
      81    if (filesize != 0 && parsed_size > filesize)
      82      {
      83        bfd_set_error (bfd_error_malformed_archive);
      84        return false;
      85      }
      86  
      87    if (bfd_bread (int_buf, 8, abfd) != 8)
      88      {
      89        if (bfd_get_error () != bfd_error_system_call)
      90  	bfd_set_error (bfd_error_malformed_archive);
      91        return false;
      92      }
      93  
      94    nsymz = bfd_getb64 (int_buf);
      95    stringsize = parsed_size - 8 * nsymz - 8;
      96  
      97    carsym_size = nsymz * sizeof (carsym);
      98    ptrsize = 8 * nsymz;
      99  
     100    amt = carsym_size + stringsize + 1;
     101    if (/* Catch overflow in stringsize (and ptrsize) expression.  */
     102        nsymz >= (bfd_size_type) -1 / 8
     103        || stringsize > parsed_size
     104        /* Catch overflow in carsym_size expression.  */
     105        || nsymz > (bfd_size_type) -1 / sizeof (carsym)
     106        /* Catch overflow in amt expression.  */
     107        || amt <= carsym_size
     108        || amt <= stringsize)
     109      {
     110        bfd_set_error (bfd_error_malformed_archive);
     111        return false;
     112      }
     113    ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt);
     114    if (ardata->symdefs == NULL)
     115      return false;
     116    carsyms = ardata->symdefs;
     117    stringbase = ((char *) ardata->symdefs) + carsym_size;
     118  
     119    raw_armap = (bfd_byte *) _bfd_alloc_and_read (abfd, ptrsize, ptrsize);
     120    if (raw_armap == NULL
     121        || bfd_bread (stringbase, stringsize, abfd) != stringsize)
     122      {
     123        if (bfd_get_error () != bfd_error_system_call)
     124  	bfd_set_error (bfd_error_malformed_archive);
     125        goto release_symdefs;
     126      }
     127  
     128    stringend = stringbase + stringsize;
     129    *stringend = 0;
     130    for (i = 0; i < nsymz; i++)
     131      {
     132        carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
     133        carsyms->name = stringbase;
     134        stringbase += strlen (stringbase);
     135        if (stringbase != stringend)
     136  	++stringbase;
     137        ++carsyms;
     138      }
     139  
     140    ardata->symdef_count = nsymz;
     141    ardata->first_file_filepos = bfd_tell (abfd);
     142    /* Pad to an even boundary if you have to.  */
     143    ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
     144  
     145    abfd->has_armap = true;
     146    bfd_release (abfd, raw_armap);
     147  
     148    return true;
     149  
     150   release_symdefs:
     151    bfd_release (abfd, ardata->symdefs);
     152    return false;
     153  }
     154  
     155  /* Write out an Irix 6 armap.  The Irix 6 tools are supposed to be
     156     able to handle ordinary ELF armaps, but at least on Irix 6.2 the
     157     linker crashes.  */
     158  
     159  bool
     160  _bfd_archive_64_bit_write_armap (bfd *arch,
     161  				 unsigned int elength,
     162  				 struct orl *map,
     163  				 unsigned int symbol_count,
     164  				 int stridx)
     165  {
     166    unsigned int ranlibsize = (symbol_count * 8) + 8;
     167    unsigned int stringsize = stridx;
     168    unsigned int mapsize = stringsize + ranlibsize;
     169    file_ptr archive_member_file_ptr;
     170    bfd *current = arch->archive_head;
     171    unsigned int count;
     172    struct ar_hdr hdr;
     173    int padding;
     174    bfd_byte buf[8];
     175  
     176    padding = BFD_ALIGN (mapsize, 8) - mapsize;
     177    mapsize += padding;
     178  
     179    /* work out where the first object file will go in the archive */
     180    archive_member_file_ptr = (mapsize
     181  			     + elength
     182  			     + sizeof (struct ar_hdr)
     183  			     + SARMAG);
     184  
     185    memset (&hdr, ' ', sizeof (struct ar_hdr));
     186    memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/"));
     187    if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize))
     188      return false;
     189    _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld",
     190  		    time (NULL));
     191    /* This, at least, is what Intel coff sets the values to.: */
     192    _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0);
     193    _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0);
     194    _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0);
     195    memcpy (hdr.ar_fmag, ARFMAG, 2);
     196  
     197    /* Write the ar header for this item and the number of symbols */
     198  
     199    if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
     200        != sizeof (struct ar_hdr))
     201      return false;
     202  
     203    bfd_putb64 ((bfd_vma) symbol_count, buf);
     204    if (bfd_bwrite (buf, 8, arch) != 8)
     205      return false;
     206  
     207    /* Two passes, first write the file offsets for each symbol -
     208       remembering that each offset is on a two byte boundary.  */
     209  
     210    /* Write out the file offset for the file associated with each
     211       symbol, and remember to keep the offsets padded out.  */
     212    count = 0;
     213    for (current = arch->archive_head;
     214         current != NULL && count < symbol_count;
     215         current = current->archive_next)
     216      {
     217        /* For each symbol which is used defined in this object, write out
     218  	 the object file's address in the archive.  */
     219  
     220        for (;
     221  	   count < symbol_count && map[count].u.abfd == current;
     222  	   count++)
     223  	{
     224  	  bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf);
     225  	  if (bfd_bwrite (buf, 8, arch) != 8)
     226  	    return false;
     227  	}
     228  
     229        /* Add size of this archive entry */
     230        archive_member_file_ptr += sizeof (struct ar_hdr);
     231        if (! bfd_is_thin_archive (arch))
     232  	archive_member_file_ptr += arelt_size (current);
     233        /* remember about the even alignment */
     234        archive_member_file_ptr += archive_member_file_ptr % 2;
     235      }
     236  
     237    /* now write the strings themselves */
     238    for (count = 0; count < symbol_count; count++)
     239      {
     240        size_t len = strlen (*map[count].name) + 1;
     241  
     242        if (bfd_bwrite (*map[count].name, len, arch) != len)
     243  	return false;
     244      }
     245  
     246    /* The spec says that this should be padded to an 8 byte boundary.
     247       However, the Irix 6.2 tools do not appear to do this.  */
     248    while (padding != 0)
     249      {
     250        if (bfd_bwrite ("", 1, arch) != 1)
     251  	return false;
     252        --padding;
     253      }
     254  
     255    return true;
     256  }