xref: /dflybsd-src/contrib/gdb-7/bfd/archive64.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
1*ef5ccd6cSJohn Marino /* Support for 64-bit ELF archives.
2*ef5ccd6cSJohn Marino    Copyright 1996-2013 Free Software Foundation, Inc.
35796c8dcSSimon Schubert    Ian Lance Taylor, Cygnus Support
45796c8dcSSimon Schubert    Linker support added by Mark Mitchell, CodeSourcery, LLC.
55796c8dcSSimon Schubert    <mark@codesourcery.com>
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This file is part of BFD, the Binary File Descriptor library.
85796c8dcSSimon Schubert 
95796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
105796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
115796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
125796c8dcSSimon Schubert    (at your option) any later version.
135796c8dcSSimon Schubert 
145796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
155796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
165796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
175796c8dcSSimon Schubert    GNU General Public License for more details.
185796c8dcSSimon Schubert 
195796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
205796c8dcSSimon Schubert    along with this program; if not, write to the Free Software
215796c8dcSSimon Schubert    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
225796c8dcSSimon Schubert    MA 02110-1301, USA.  */
235796c8dcSSimon Schubert 
245796c8dcSSimon Schubert /* This file supports the 64-bit (MIPS) ELF archives.  */
255796c8dcSSimon Schubert 
265796c8dcSSimon Schubert #include "sysdep.h"
275796c8dcSSimon Schubert #include "bfd.h"
285796c8dcSSimon Schubert #include "libbfd.h"
295796c8dcSSimon Schubert #include "aout/ar.h"
305796c8dcSSimon Schubert 
315796c8dcSSimon Schubert /* Irix 6 defines a 64bit archive map format, so that they can
325796c8dcSSimon Schubert    have archives more than 4 GB in size.  */
335796c8dcSSimon Schubert 
345796c8dcSSimon Schubert bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
355796c8dcSSimon Schubert bfd_boolean bfd_elf64_archive_write_armap
365796c8dcSSimon Schubert   (bfd *, unsigned int, struct orl *, unsigned int, int);
375796c8dcSSimon Schubert 
385796c8dcSSimon Schubert /* Read an Irix 6 armap.  */
395796c8dcSSimon Schubert 
405796c8dcSSimon Schubert bfd_boolean
bfd_elf64_archive_slurp_armap(bfd * abfd)415796c8dcSSimon Schubert bfd_elf64_archive_slurp_armap (bfd *abfd)
425796c8dcSSimon Schubert {
435796c8dcSSimon Schubert   struct artdata *ardata = bfd_ardata (abfd);
445796c8dcSSimon Schubert   char nextname[17];
455796c8dcSSimon Schubert   bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
465796c8dcSSimon Schubert   struct areltdata *mapdata;
475796c8dcSSimon Schubert   bfd_byte int_buf[8];
485796c8dcSSimon Schubert   char *stringbase;
495796c8dcSSimon Schubert   bfd_byte *raw_armap = NULL;
505796c8dcSSimon Schubert   carsym *carsyms;
515796c8dcSSimon Schubert   bfd_size_type amt;
525796c8dcSSimon Schubert 
535796c8dcSSimon Schubert   ardata->symdefs = NULL;
545796c8dcSSimon Schubert 
555796c8dcSSimon Schubert   /* Get the name of the first element.  */
565796c8dcSSimon Schubert   i = bfd_bread (nextname, 16, abfd);
575796c8dcSSimon Schubert   if (i == 0)
585796c8dcSSimon Schubert     return TRUE;
595796c8dcSSimon Schubert   if (i != 16)
605796c8dcSSimon Schubert     return FALSE;
615796c8dcSSimon Schubert 
625796c8dcSSimon Schubert   if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
635796c8dcSSimon Schubert     return FALSE;
645796c8dcSSimon Schubert 
655796c8dcSSimon Schubert   /* Archives with traditional armaps are still permitted.  */
665796c8dcSSimon Schubert   if (CONST_STRNEQ (nextname, "/               "))
675796c8dcSSimon Schubert     return bfd_slurp_armap (abfd);
685796c8dcSSimon Schubert 
695796c8dcSSimon Schubert   if (! CONST_STRNEQ (nextname, "/SYM64/         "))
705796c8dcSSimon Schubert     {
715796c8dcSSimon Schubert       bfd_has_map (abfd) = FALSE;
725796c8dcSSimon Schubert       return TRUE;
735796c8dcSSimon Schubert     }
745796c8dcSSimon Schubert 
755796c8dcSSimon Schubert   mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
765796c8dcSSimon Schubert   if (mapdata == NULL)
775796c8dcSSimon Schubert     return FALSE;
785796c8dcSSimon Schubert   parsed_size = mapdata->parsed_size;
79*ef5ccd6cSJohn Marino   free (mapdata);
805796c8dcSSimon Schubert 
815796c8dcSSimon Schubert   if (bfd_bread (int_buf, 8, abfd) != 8)
825796c8dcSSimon Schubert     {
835796c8dcSSimon Schubert       if (bfd_get_error () != bfd_error_system_call)
845796c8dcSSimon Schubert 	bfd_set_error (bfd_error_malformed_archive);
855796c8dcSSimon Schubert       return FALSE;
865796c8dcSSimon Schubert     }
875796c8dcSSimon Schubert 
885796c8dcSSimon Schubert   nsymz = bfd_getb64 (int_buf);
895796c8dcSSimon Schubert   stringsize = parsed_size - 8 * nsymz - 8;
905796c8dcSSimon Schubert 
915796c8dcSSimon Schubert   carsym_size = nsymz * sizeof (carsym);
925796c8dcSSimon Schubert   ptrsize = 8 * nsymz;
935796c8dcSSimon Schubert 
945796c8dcSSimon Schubert   amt = carsym_size + stringsize + 1;
955796c8dcSSimon Schubert   ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, amt);
965796c8dcSSimon Schubert   if (ardata->symdefs == NULL)
975796c8dcSSimon Schubert     return FALSE;
985796c8dcSSimon Schubert   carsyms = ardata->symdefs;
995796c8dcSSimon Schubert   stringbase = ((char *) ardata->symdefs) + carsym_size;
1005796c8dcSSimon Schubert 
1015796c8dcSSimon Schubert   raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize);
1025796c8dcSSimon Schubert   if (raw_armap == NULL)
1035796c8dcSSimon Schubert     goto release_symdefs;
1045796c8dcSSimon Schubert 
1055796c8dcSSimon Schubert   if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
1065796c8dcSSimon Schubert       || bfd_bread (stringbase, stringsize, abfd) != stringsize)
1075796c8dcSSimon Schubert     {
1085796c8dcSSimon Schubert       if (bfd_get_error () != bfd_error_system_call)
1095796c8dcSSimon Schubert 	bfd_set_error (bfd_error_malformed_archive);
1105796c8dcSSimon Schubert       goto release_raw_armap;
1115796c8dcSSimon Schubert     }
1125796c8dcSSimon Schubert 
1135796c8dcSSimon Schubert   for (i = 0; i < nsymz; i++)
1145796c8dcSSimon Schubert     {
1155796c8dcSSimon Schubert       carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
1165796c8dcSSimon Schubert       carsyms->name = stringbase;
1175796c8dcSSimon Schubert       stringbase += strlen (stringbase) + 1;
1185796c8dcSSimon Schubert       ++carsyms;
1195796c8dcSSimon Schubert     }
1205796c8dcSSimon Schubert   *stringbase = '\0';
1215796c8dcSSimon Schubert 
1225796c8dcSSimon Schubert   ardata->symdef_count = nsymz;
1235796c8dcSSimon Schubert   ardata->first_file_filepos = bfd_tell (abfd);
1245796c8dcSSimon Schubert   /* Pad to an even boundary if you have to.  */
1255796c8dcSSimon Schubert   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
1265796c8dcSSimon Schubert 
1275796c8dcSSimon Schubert   bfd_has_map (abfd) = TRUE;
1285796c8dcSSimon Schubert   bfd_release (abfd, raw_armap);
1295796c8dcSSimon Schubert 
1305796c8dcSSimon Schubert   return TRUE;
1315796c8dcSSimon Schubert 
1325796c8dcSSimon Schubert release_raw_armap:
1335796c8dcSSimon Schubert   bfd_release (abfd, raw_armap);
1345796c8dcSSimon Schubert release_symdefs:
1355796c8dcSSimon Schubert   bfd_release (abfd, ardata->symdefs);
1365796c8dcSSimon Schubert   return FALSE;
1375796c8dcSSimon Schubert }
1385796c8dcSSimon Schubert 
1395796c8dcSSimon Schubert /* Write out an Irix 6 armap.  The Irix 6 tools are supposed to be
1405796c8dcSSimon Schubert    able to handle ordinary ELF armaps, but at least on Irix 6.2 the
1415796c8dcSSimon Schubert    linker crashes.  */
1425796c8dcSSimon Schubert 
1435796c8dcSSimon Schubert bfd_boolean
bfd_elf64_archive_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int symbol_count,int stridx)1445796c8dcSSimon Schubert bfd_elf64_archive_write_armap (bfd *arch,
1455796c8dcSSimon Schubert 			       unsigned int elength,
1465796c8dcSSimon Schubert 			       struct orl *map,
1475796c8dcSSimon Schubert 			       unsigned int symbol_count,
1485796c8dcSSimon Schubert 			       int stridx)
1495796c8dcSSimon Schubert {
1505796c8dcSSimon Schubert   unsigned int ranlibsize = (symbol_count * 8) + 8;
1515796c8dcSSimon Schubert   unsigned int stringsize = stridx;
1525796c8dcSSimon Schubert   unsigned int mapsize = stringsize + ranlibsize;
1535796c8dcSSimon Schubert   file_ptr archive_member_file_ptr;
1545796c8dcSSimon Schubert   bfd *current = arch->archive_head;
1555796c8dcSSimon Schubert   unsigned int count;
1565796c8dcSSimon Schubert   struct ar_hdr hdr;
1575796c8dcSSimon Schubert   int padding;
1585796c8dcSSimon Schubert   bfd_byte buf[8];
1595796c8dcSSimon Schubert 
1605796c8dcSSimon Schubert   padding = BFD_ALIGN (mapsize, 8) - mapsize;
1615796c8dcSSimon Schubert   mapsize += padding;
1625796c8dcSSimon Schubert 
1635796c8dcSSimon Schubert   /* work out where the first object file will go in the archive */
1645796c8dcSSimon Schubert   archive_member_file_ptr = (mapsize
1655796c8dcSSimon Schubert 			     + elength
1665796c8dcSSimon Schubert 			     + sizeof (struct ar_hdr)
1675796c8dcSSimon Schubert 			     + SARMAG);
1685796c8dcSSimon Schubert 
1695796c8dcSSimon Schubert   memset (&hdr, ' ', sizeof (struct ar_hdr));
1705796c8dcSSimon Schubert   memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/"));
171*ef5ccd6cSJohn Marino   if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize))
172*ef5ccd6cSJohn Marino     return FALSE;
1735796c8dcSSimon Schubert   _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld",
1745796c8dcSSimon Schubert                     time (NULL));
1755796c8dcSSimon Schubert   /* This, at least, is what Intel coff sets the values to.: */
1765796c8dcSSimon Schubert   _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0);
1775796c8dcSSimon Schubert   _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0);
1785796c8dcSSimon Schubert   _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0);
1795796c8dcSSimon Schubert   memcpy (hdr.ar_fmag, ARFMAG, 2);
1805796c8dcSSimon Schubert 
1815796c8dcSSimon Schubert   /* Write the ar header for this item and the number of symbols */
1825796c8dcSSimon Schubert 
1835796c8dcSSimon Schubert   if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
1845796c8dcSSimon Schubert       != sizeof (struct ar_hdr))
1855796c8dcSSimon Schubert     return FALSE;
1865796c8dcSSimon Schubert 
1875796c8dcSSimon Schubert   bfd_putb64 ((bfd_vma) symbol_count, buf);
1885796c8dcSSimon Schubert   if (bfd_bwrite (buf, 8, arch) != 8)
1895796c8dcSSimon Schubert     return FALSE;
1905796c8dcSSimon Schubert 
1915796c8dcSSimon Schubert   /* Two passes, first write the file offsets for each symbol -
1925796c8dcSSimon Schubert      remembering that each offset is on a two byte boundary.  */
1935796c8dcSSimon Schubert 
1945796c8dcSSimon Schubert   /* Write out the file offset for the file associated with each
1955796c8dcSSimon Schubert      symbol, and remember to keep the offsets padded out.  */
1965796c8dcSSimon Schubert   count = 0;
197cf7f2e2dSJohn Marino   for (current = arch->archive_head;
198cf7f2e2dSJohn Marino        current != NULL && count < symbol_count;
199cf7f2e2dSJohn Marino        current = current->archive_next)
2005796c8dcSSimon Schubert     {
2015796c8dcSSimon Schubert       /* For each symbol which is used defined in this object, write out
202*ef5ccd6cSJohn Marino 	 the object file's address in the archive.  */
2035796c8dcSSimon Schubert 
204cf7f2e2dSJohn Marino       for (;
205cf7f2e2dSJohn Marino 	   count < symbol_count && map[count].u.abfd == current;
206cf7f2e2dSJohn Marino 	   count++)
2075796c8dcSSimon Schubert 	{
2085796c8dcSSimon Schubert 	  bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf);
2095796c8dcSSimon Schubert 	  if (bfd_bwrite (buf, 8, arch) != 8)
2105796c8dcSSimon Schubert 	    return FALSE;
2115796c8dcSSimon Schubert 	}
212*ef5ccd6cSJohn Marino 
2135796c8dcSSimon Schubert       /* Add size of this archive entry */
214*ef5ccd6cSJohn Marino       archive_member_file_ptr += sizeof (struct ar_hdr);
215*ef5ccd6cSJohn Marino       if (! bfd_is_thin_archive (arch))
216*ef5ccd6cSJohn Marino 	archive_member_file_ptr += arelt_size (current);
2175796c8dcSSimon Schubert       /* remember about the even alignment */
2185796c8dcSSimon Schubert       archive_member_file_ptr += archive_member_file_ptr % 2;
2195796c8dcSSimon Schubert     }
2205796c8dcSSimon Schubert 
2215796c8dcSSimon Schubert   /* now write the strings themselves */
2225796c8dcSSimon Schubert   for (count = 0; count < symbol_count; count++)
2235796c8dcSSimon Schubert     {
2245796c8dcSSimon Schubert       size_t len = strlen (*map[count].name) + 1;
2255796c8dcSSimon Schubert 
2265796c8dcSSimon Schubert       if (bfd_bwrite (*map[count].name, len, arch) != len)
2275796c8dcSSimon Schubert 	return FALSE;
2285796c8dcSSimon Schubert     }
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert   /* The spec says that this should be padded to an 8 byte boundary.
2315796c8dcSSimon Schubert      However, the Irix 6.2 tools do not appear to do this.  */
2325796c8dcSSimon Schubert   while (padding != 0)
2335796c8dcSSimon Schubert     {
2345796c8dcSSimon Schubert       if (bfd_bwrite ("", 1, arch) != 1)
2355796c8dcSSimon Schubert 	return FALSE;
2365796c8dcSSimon Schubert       --padding;
2375796c8dcSSimon Schubert     }
2385796c8dcSSimon Schubert 
2395796c8dcSSimon Schubert   return TRUE;
2405796c8dcSSimon Schubert }
241