xref: /openbsd-src/gnu/usr.bin/binutils-2.17/bfd/archive64.c (revision 68ffdd0c752cc561186b6e2d655a856032d142c9)
13d8817e4Smiod /* MIPS-specific support for 64-bit ELF
23d8817e4Smiod    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
33d8817e4Smiod    Free Software Foundation, Inc.
43d8817e4Smiod    Ian Lance Taylor, Cygnus Support
53d8817e4Smiod    Linker support added by Mark Mitchell, CodeSourcery, LLC.
63d8817e4Smiod    <mark@codesourcery.com>
73d8817e4Smiod 
83d8817e4Smiod This file is part of BFD, the Binary File Descriptor library.
93d8817e4Smiod 
103d8817e4Smiod This program is free software; you can redistribute it and/or modify
113d8817e4Smiod it under the terms of the GNU General Public License as published by
123d8817e4Smiod the Free Software Foundation; either version 2 of the License, or
133d8817e4Smiod (at your option) any later version.
143d8817e4Smiod 
153d8817e4Smiod This program is distributed in the hope that it will be useful,
163d8817e4Smiod but WITHOUT ANY WARRANTY; without even the implied warranty of
173d8817e4Smiod MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
183d8817e4Smiod GNU General Public License for more details.
193d8817e4Smiod 
203d8817e4Smiod You should have received a copy of the GNU General Public License
213d8817e4Smiod along with this program; if not, write to the Free Software
223d8817e4Smiod Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
233d8817e4Smiod 
243d8817e4Smiod /* This file supports the 64-bit (MIPS) ELF archives.  */
253d8817e4Smiod 
263d8817e4Smiod #include "bfd.h"
273d8817e4Smiod #include "sysdep.h"
283d8817e4Smiod #include "libbfd.h"
293d8817e4Smiod #include "aout/ar.h"
303d8817e4Smiod 
313d8817e4Smiod /* Irix 6 defines a 64bit archive map format, so that they can
323d8817e4Smiod    have archives more than 4 GB in size.  */
333d8817e4Smiod 
343d8817e4Smiod bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
353d8817e4Smiod bfd_boolean bfd_elf64_archive_write_armap
363d8817e4Smiod   (bfd *, unsigned int, struct orl *, unsigned int, int);
373d8817e4Smiod 
383d8817e4Smiod /* Read an Irix 6 armap.  */
393d8817e4Smiod 
403d8817e4Smiod bfd_boolean
bfd_elf64_archive_slurp_armap(bfd * abfd)413d8817e4Smiod bfd_elf64_archive_slurp_armap (bfd *abfd)
423d8817e4Smiod {
433d8817e4Smiod   struct artdata *ardata = bfd_ardata (abfd);
443d8817e4Smiod   char nextname[17];
453d8817e4Smiod   file_ptr arhdrpos;
463d8817e4Smiod   bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
473d8817e4Smiod   struct areltdata *mapdata;
483d8817e4Smiod   bfd_byte int_buf[8];
493d8817e4Smiod   char *stringbase;
503d8817e4Smiod   bfd_byte *raw_armap = NULL;
513d8817e4Smiod   carsym *carsyms;
523d8817e4Smiod   bfd_size_type amt;
533d8817e4Smiod 
543d8817e4Smiod   ardata->symdefs = NULL;
553d8817e4Smiod 
563d8817e4Smiod   /* Get the name of the first element.  */
573d8817e4Smiod   arhdrpos = bfd_tell (abfd);
583d8817e4Smiod   i = bfd_bread (nextname, 16, abfd);
593d8817e4Smiod   if (i == 0)
603d8817e4Smiod     return TRUE;
613d8817e4Smiod   if (i != 16)
623d8817e4Smiod     return FALSE;
633d8817e4Smiod 
643d8817e4Smiod   if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
653d8817e4Smiod     return FALSE;
663d8817e4Smiod 
673d8817e4Smiod   /* Archives with traditional armaps are still permitted.  */
683d8817e4Smiod   if (strncmp (nextname, "/               ", 16) == 0)
693d8817e4Smiod     return bfd_slurp_armap (abfd);
703d8817e4Smiod 
713d8817e4Smiod   if (strncmp (nextname, "/SYM64/         ", 16) != 0)
723d8817e4Smiod     {
733d8817e4Smiod       bfd_has_map (abfd) = FALSE;
743d8817e4Smiod       return TRUE;
753d8817e4Smiod     }
763d8817e4Smiod 
773d8817e4Smiod   mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
783d8817e4Smiod   if (mapdata == NULL)
793d8817e4Smiod     return FALSE;
803d8817e4Smiod   parsed_size = mapdata->parsed_size;
813d8817e4Smiod   bfd_release (abfd, mapdata);
823d8817e4Smiod 
833d8817e4Smiod   if (bfd_bread (int_buf, 8, abfd) != 8)
843d8817e4Smiod     {
853d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
863d8817e4Smiod 	bfd_set_error (bfd_error_malformed_archive);
873d8817e4Smiod       return FALSE;
883d8817e4Smiod     }
893d8817e4Smiod 
903d8817e4Smiod   nsymz = bfd_getb64 (int_buf);
913d8817e4Smiod   stringsize = parsed_size - 8 * nsymz - 8;
923d8817e4Smiod 
933d8817e4Smiod   carsym_size = nsymz * sizeof (carsym);
943d8817e4Smiod   ptrsize = 8 * nsymz;
953d8817e4Smiod 
963d8817e4Smiod   amt = carsym_size + stringsize + 1;
973d8817e4Smiod   ardata->symdefs = bfd_zalloc (abfd, amt);
983d8817e4Smiod   if (ardata->symdefs == NULL)
993d8817e4Smiod     return FALSE;
1003d8817e4Smiod   carsyms = ardata->symdefs;
1013d8817e4Smiod   stringbase = ((char *) ardata->symdefs) + carsym_size;
1023d8817e4Smiod 
1033d8817e4Smiod   raw_armap = bfd_alloc (abfd, ptrsize);
1043d8817e4Smiod   if (raw_armap == NULL)
1053d8817e4Smiod     goto release_symdefs;
1063d8817e4Smiod 
1073d8817e4Smiod   if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
1083d8817e4Smiod       || bfd_bread (stringbase, stringsize, abfd) != stringsize)
1093d8817e4Smiod     {
1103d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
1113d8817e4Smiod 	bfd_set_error (bfd_error_malformed_archive);
1123d8817e4Smiod       goto release_raw_armap;
1133d8817e4Smiod     }
1143d8817e4Smiod 
1153d8817e4Smiod   for (i = 0; i < nsymz; i++)
1163d8817e4Smiod     {
1173d8817e4Smiod       carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
1183d8817e4Smiod       carsyms->name = stringbase;
1193d8817e4Smiod       stringbase += strlen (stringbase) + 1;
1203d8817e4Smiod       ++carsyms;
1213d8817e4Smiod     }
1223d8817e4Smiod   *stringbase = '\0';
1233d8817e4Smiod 
1243d8817e4Smiod   ardata->symdef_count = nsymz;
1253d8817e4Smiod   ardata->first_file_filepos = bfd_tell (abfd);
1263d8817e4Smiod   /* Pad to an even boundary if you have to.  */
1273d8817e4Smiod   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
1283d8817e4Smiod 
1293d8817e4Smiod   bfd_has_map (abfd) = TRUE;
1303d8817e4Smiod   bfd_release (abfd, raw_armap);
1313d8817e4Smiod 
1323d8817e4Smiod   return TRUE;
1333d8817e4Smiod 
1343d8817e4Smiod release_raw_armap:
1353d8817e4Smiod   bfd_release (abfd, raw_armap);
1363d8817e4Smiod release_symdefs:
1373d8817e4Smiod   bfd_release (abfd, ardata->symdefs);
1383d8817e4Smiod   return FALSE;
1393d8817e4Smiod }
1403d8817e4Smiod 
1413d8817e4Smiod /* Write out an Irix 6 armap.  The Irix 6 tools are supposed to be
1423d8817e4Smiod    able to handle ordinary ELF armaps, but at least on Irix 6.2 the
1433d8817e4Smiod    linker crashes.  */
1443d8817e4Smiod 
1453d8817e4Smiod bfd_boolean
bfd_elf64_archive_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int symbol_count,int stridx)1463d8817e4Smiod bfd_elf64_archive_write_armap (bfd *arch,
1473d8817e4Smiod 			       unsigned int elength,
1483d8817e4Smiod 			       struct orl *map,
1493d8817e4Smiod 			       unsigned int symbol_count,
1503d8817e4Smiod 			       int stridx)
1513d8817e4Smiod {
1523d8817e4Smiod   unsigned int ranlibsize = (symbol_count * 8) + 8;
1533d8817e4Smiod   unsigned int stringsize = stridx;
1543d8817e4Smiod   unsigned int mapsize = stringsize + ranlibsize;
1553d8817e4Smiod   file_ptr archive_member_file_ptr;
1563d8817e4Smiod   bfd *current = arch->archive_head;
1573d8817e4Smiod   unsigned int count;
1583d8817e4Smiod   struct ar_hdr hdr;
1593d8817e4Smiod   int padding;
1603d8817e4Smiod   bfd_byte buf[8];
1613d8817e4Smiod 
1623d8817e4Smiod   padding = BFD_ALIGN (mapsize, 8) - mapsize;
1633d8817e4Smiod   mapsize += padding;
1643d8817e4Smiod 
1653d8817e4Smiod   /* work out where the first object file will go in the archive */
1663d8817e4Smiod   archive_member_file_ptr = (mapsize
1673d8817e4Smiod 			     + elength
1683d8817e4Smiod 			     + sizeof (struct ar_hdr)
1693d8817e4Smiod 			     + SARMAG);
1703d8817e4Smiod 
1713d8817e4Smiod   memset (&hdr, ' ', sizeof (struct ar_hdr));
1723d8817e4Smiod   memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/"));
1733d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
1743d8817e4Smiod                     mapsize);
17504a47612Sguenther   _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
1763d8817e4Smiod                     time (NULL));
1773d8817e4Smiod   /* This, at least, is what Intel coff sets the values to.: */
1783d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0);
1793d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0);
1803d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0);
1813d8817e4Smiod   memcpy (hdr.ar_fmag, ARFMAG, 2);
1823d8817e4Smiod 
1833d8817e4Smiod   /* Write the ar header for this item and the number of symbols */
1843d8817e4Smiod 
1853d8817e4Smiod   if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
1863d8817e4Smiod       != sizeof (struct ar_hdr))
1873d8817e4Smiod     return FALSE;
1883d8817e4Smiod 
1893d8817e4Smiod   bfd_putb64 ((bfd_vma) symbol_count, buf);
1903d8817e4Smiod   if (bfd_bwrite (buf, 8, arch) != 8)
1913d8817e4Smiod     return FALSE;
1923d8817e4Smiod 
1933d8817e4Smiod   /* Two passes, first write the file offsets for each symbol -
1943d8817e4Smiod      remembering that each offset is on a two byte boundary.  */
1953d8817e4Smiod 
1963d8817e4Smiod   /* Write out the file offset for the file associated with each
1973d8817e4Smiod      symbol, and remember to keep the offsets padded out.  */
1983d8817e4Smiod 
1993d8817e4Smiod   current = arch->archive_head;
2003d8817e4Smiod   count = 0;
2013d8817e4Smiod   while (current != NULL && count < symbol_count)
2023d8817e4Smiod     {
2033d8817e4Smiod       /* For each symbol which is used defined in this object, write out
2043d8817e4Smiod 	 the object file's address in the archive */
2053d8817e4Smiod 
206*68ffdd0cSvisa       while (count < symbol_count && map[count].u.abfd == current)
2073d8817e4Smiod 	{
2083d8817e4Smiod 	  bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf);
2093d8817e4Smiod 	  if (bfd_bwrite (buf, 8, arch) != 8)
2103d8817e4Smiod 	    return FALSE;
2113d8817e4Smiod 	  count++;
2123d8817e4Smiod 	}
2133d8817e4Smiod       /* Add size of this archive entry */
2143d8817e4Smiod       archive_member_file_ptr += (arelt_size (current)
2153d8817e4Smiod 				  + sizeof (struct ar_hdr));
2163d8817e4Smiod       /* remember about the even alignment */
2173d8817e4Smiod       archive_member_file_ptr += archive_member_file_ptr % 2;
2183d8817e4Smiod       current = current->next;
2193d8817e4Smiod     }
2203d8817e4Smiod 
2213d8817e4Smiod   /* now write the strings themselves */
2223d8817e4Smiod   for (count = 0; count < symbol_count; count++)
2233d8817e4Smiod     {
2243d8817e4Smiod       size_t len = strlen (*map[count].name) + 1;
2253d8817e4Smiod 
2263d8817e4Smiod       if (bfd_bwrite (*map[count].name, len, arch) != len)
2273d8817e4Smiod 	return FALSE;
2283d8817e4Smiod     }
2293d8817e4Smiod 
2303d8817e4Smiod   /* The spec says that this should be padded to an 8 byte boundary.
2313d8817e4Smiod      However, the Irix 6.2 tools do not appear to do this.  */
2323d8817e4Smiod   while (padding != 0)
2333d8817e4Smiod     {
2343d8817e4Smiod       if (bfd_bwrite ("", 1, arch) != 1)
2353d8817e4Smiod 	return FALSE;
2363d8817e4Smiod       --padding;
2373d8817e4Smiod     }
2383d8817e4Smiod 
2393d8817e4Smiod   return TRUE;
2403d8817e4Smiod }
241