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