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