189857Sobrien/* MIPS-specific support for 64-bit ELF 2218822Sdim Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2006, 2007 389857Sobrien Free Software Foundation, Inc. 489857Sobrien Ian Lance Taylor, Cygnus Support 589857Sobrien Linker support added by Mark Mitchell, CodeSourcery, LLC. 689857Sobrien <mark@codesourcery.com> 789857Sobrien 8218822Sdim This file is part of BFD, the Binary File Descriptor library. 989857Sobrien 10218822Sdim This program is free software; you can redistribute it and/or modify 11218822Sdim it under the terms of the GNU General Public License as published by 12218822Sdim the Free Software Foundation; either version 2 of the License, or 13218822Sdim (at your option) any later version. 1489857Sobrien 15218822Sdim This program is distributed in the hope that it will be useful, 16218822Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 17218822Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18218822Sdim GNU General Public License for more details. 1989857Sobrien 20218822Sdim You should have received a copy of the GNU General Public License 21218822Sdim along with this program; if not, write to the Free Software 22218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2389857Sobrien 2489857Sobrien/* This file supports the 64-bit (MIPS) ELF archives. */ 2589857Sobrien 26218822Sdim#include "sysdep.h" 2789857Sobrien#include "bfd.h" 2889857Sobrien#include "libbfd.h" 2989857Sobrien#include "aout/ar.h" 3089857Sobrien 3189857Sobrien/* Irix 6 defines a 64bit archive map format, so that they can 3289857Sobrien have archives more than 4 GB in size. */ 3389857Sobrien 34130561Sobrienbfd_boolean bfd_elf64_archive_slurp_armap (bfd *); 35130561Sobrienbfd_boolean bfd_elf64_archive_write_armap 36130561Sobrien (bfd *, unsigned int, struct orl *, unsigned int, int); 3789857Sobrien 3889857Sobrien/* Read an Irix 6 armap. */ 3989857Sobrien 40130561Sobrienbfd_boolean 41130561Sobrienbfd_elf64_archive_slurp_armap (bfd *abfd) 4289857Sobrien{ 4389857Sobrien struct artdata *ardata = bfd_ardata (abfd); 4489857Sobrien char nextname[17]; 4589857Sobrien file_ptr arhdrpos; 4689857Sobrien bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize; 4789857Sobrien struct areltdata *mapdata; 4889857Sobrien bfd_byte int_buf[8]; 4989857Sobrien char *stringbase; 5089857Sobrien bfd_byte *raw_armap = NULL; 5189857Sobrien carsym *carsyms; 5289857Sobrien bfd_size_type amt; 5389857Sobrien 5489857Sobrien ardata->symdefs = NULL; 5589857Sobrien 5689857Sobrien /* Get the name of the first element. */ 5789857Sobrien arhdrpos = bfd_tell (abfd); 58130561Sobrien i = bfd_bread (nextname, 16, abfd); 5989857Sobrien if (i == 0) 60130561Sobrien return TRUE; 6189857Sobrien if (i != 16) 62130561Sobrien return FALSE; 6389857Sobrien 6489857Sobrien if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0) 65130561Sobrien return FALSE; 6689857Sobrien 6789857Sobrien /* Archives with traditional armaps are still permitted. */ 68218822Sdim if (CONST_STRNEQ (nextname, "/ ")) 6989857Sobrien return bfd_slurp_armap (abfd); 7089857Sobrien 71218822Sdim if (! CONST_STRNEQ (nextname, "/SYM64/ ")) 7289857Sobrien { 73130561Sobrien bfd_has_map (abfd) = FALSE; 74130561Sobrien return TRUE; 7589857Sobrien } 7689857Sobrien 7789857Sobrien mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); 7889857Sobrien if (mapdata == NULL) 79130561Sobrien return FALSE; 8089857Sobrien parsed_size = mapdata->parsed_size; 81130561Sobrien bfd_release (abfd, mapdata); 8289857Sobrien 83130561Sobrien if (bfd_bread (int_buf, 8, abfd) != 8) 8489857Sobrien { 8589857Sobrien if (bfd_get_error () != bfd_error_system_call) 8689857Sobrien bfd_set_error (bfd_error_malformed_archive); 87130561Sobrien return FALSE; 8889857Sobrien } 8989857Sobrien 9089857Sobrien nsymz = bfd_getb64 (int_buf); 9189857Sobrien stringsize = parsed_size - 8 * nsymz - 8; 9289857Sobrien 9389857Sobrien carsym_size = nsymz * sizeof (carsym); 9489857Sobrien ptrsize = 8 * nsymz; 9589857Sobrien 9689857Sobrien amt = carsym_size + stringsize + 1; 97130561Sobrien ardata->symdefs = bfd_zalloc (abfd, amt); 9889857Sobrien if (ardata->symdefs == NULL) 99130561Sobrien return FALSE; 10089857Sobrien carsyms = ardata->symdefs; 10189857Sobrien stringbase = ((char *) ardata->symdefs) + carsym_size; 10289857Sobrien 103130561Sobrien raw_armap = bfd_alloc (abfd, ptrsize); 10489857Sobrien if (raw_armap == NULL) 10589857Sobrien goto release_symdefs; 10689857Sobrien 10789857Sobrien if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize 10889857Sobrien || bfd_bread (stringbase, stringsize, abfd) != stringsize) 10989857Sobrien { 11089857Sobrien if (bfd_get_error () != bfd_error_system_call) 11189857Sobrien bfd_set_error (bfd_error_malformed_archive); 11289857Sobrien goto release_raw_armap; 11389857Sobrien } 11489857Sobrien 11589857Sobrien for (i = 0; i < nsymz; i++) 11689857Sobrien { 11789857Sobrien carsyms->file_offset = bfd_getb64 (raw_armap + i * 8); 11889857Sobrien carsyms->name = stringbase; 11989857Sobrien stringbase += strlen (stringbase) + 1; 12089857Sobrien ++carsyms; 12189857Sobrien } 12289857Sobrien *stringbase = '\0'; 12389857Sobrien 12489857Sobrien ardata->symdef_count = nsymz; 12589857Sobrien ardata->first_file_filepos = bfd_tell (abfd); 12689857Sobrien /* Pad to an even boundary if you have to. */ 12789857Sobrien ardata->first_file_filepos += (ardata->first_file_filepos) % 2; 12889857Sobrien 129130561Sobrien bfd_has_map (abfd) = TRUE; 13089857Sobrien bfd_release (abfd, raw_armap); 13189857Sobrien 132130561Sobrien return TRUE; 13389857Sobrien 13489857Sobrienrelease_raw_armap: 13589857Sobrien bfd_release (abfd, raw_armap); 13689857Sobrienrelease_symdefs: 13789857Sobrien bfd_release (abfd, ardata->symdefs); 138130561Sobrien return FALSE; 13989857Sobrien} 14089857Sobrien 14189857Sobrien/* Write out an Irix 6 armap. The Irix 6 tools are supposed to be 14289857Sobrien able to handle ordinary ELF armaps, but at least on Irix 6.2 the 14389857Sobrien linker crashes. */ 14489857Sobrien 145130561Sobrienbfd_boolean 146130561Sobrienbfd_elf64_archive_write_armap (bfd *arch, 147130561Sobrien unsigned int elength, 148130561Sobrien struct orl *map, 149130561Sobrien unsigned int symbol_count, 150130561Sobrien int stridx) 15189857Sobrien{ 15289857Sobrien unsigned int ranlibsize = (symbol_count * 8) + 8; 15389857Sobrien unsigned int stringsize = stridx; 15489857Sobrien unsigned int mapsize = stringsize + ranlibsize; 15589857Sobrien file_ptr archive_member_file_ptr; 15689857Sobrien bfd *current = arch->archive_head; 15789857Sobrien unsigned int count; 15889857Sobrien struct ar_hdr hdr; 15989857Sobrien int padding; 16089857Sobrien bfd_byte buf[8]; 16189857Sobrien 16289857Sobrien padding = BFD_ALIGN (mapsize, 8) - mapsize; 16389857Sobrien mapsize += padding; 16489857Sobrien 16589857Sobrien /* work out where the first object file will go in the archive */ 16689857Sobrien archive_member_file_ptr = (mapsize 16789857Sobrien + elength 16889857Sobrien + sizeof (struct ar_hdr) 16989857Sobrien + SARMAG); 17089857Sobrien 171218822Sdim memset (&hdr, ' ', sizeof (struct ar_hdr)); 172218822Sdim memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/")); 173218822Sdim _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", 174218822Sdim mapsize); 175218822Sdim _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", 176218822Sdim time (NULL)); 17789857Sobrien /* This, at least, is what Intel coff sets the values to.: */ 178218822Sdim _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0); 179218822Sdim _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0); 180218822Sdim _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0); 181218822Sdim memcpy (hdr.ar_fmag, ARFMAG, 2); 18289857Sobrien 18389857Sobrien /* Write the ar header for this item and the number of symbols */ 18489857Sobrien 185130561Sobrien if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) 18689857Sobrien != sizeof (struct ar_hdr)) 187130561Sobrien return FALSE; 18889857Sobrien 18989857Sobrien bfd_putb64 ((bfd_vma) symbol_count, buf); 190130561Sobrien if (bfd_bwrite (buf, 8, arch) != 8) 191130561Sobrien return FALSE; 19289857Sobrien 19389857Sobrien /* Two passes, first write the file offsets for each symbol - 19489857Sobrien remembering that each offset is on a two byte boundary. */ 19589857Sobrien 19689857Sobrien /* Write out the file offset for the file associated with each 19789857Sobrien symbol, and remember to keep the offsets padded out. */ 19889857Sobrien 19989857Sobrien current = arch->archive_head; 20089857Sobrien count = 0; 201130561Sobrien while (current != NULL && count < symbol_count) 20289857Sobrien { 20389857Sobrien /* For each symbol which is used defined in this object, write out 20489857Sobrien the object file's address in the archive */ 20589857Sobrien 20689857Sobrien while (map[count].u.abfd == current) 20789857Sobrien { 20889857Sobrien bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf); 209130561Sobrien if (bfd_bwrite (buf, 8, arch) != 8) 210130561Sobrien return FALSE; 21189857Sobrien count++; 21289857Sobrien } 21389857Sobrien /* Add size of this archive entry */ 21489857Sobrien archive_member_file_ptr += (arelt_size (current) 21589857Sobrien + sizeof (struct ar_hdr)); 21689857Sobrien /* remember about the even alignment */ 21789857Sobrien archive_member_file_ptr += archive_member_file_ptr % 2; 218218822Sdim current = current->archive_next; 21989857Sobrien } 22089857Sobrien 22189857Sobrien /* now write the strings themselves */ 22289857Sobrien for (count = 0; count < symbol_count; count++) 22389857Sobrien { 22489857Sobrien size_t len = strlen (*map[count].name) + 1; 22589857Sobrien 226130561Sobrien if (bfd_bwrite (*map[count].name, len, arch) != len) 227130561Sobrien return FALSE; 22889857Sobrien } 22989857Sobrien 23089857Sobrien /* The spec says that this should be padded to an 8 byte boundary. 23189857Sobrien However, the Irix 6.2 tools do not appear to do this. */ 23289857Sobrien while (padding != 0) 23389857Sobrien { 234130561Sobrien if (bfd_bwrite ("", 1, arch) != 1) 235130561Sobrien return FALSE; 23689857Sobrien --padding; 23789857Sobrien } 23889857Sobrien 239130561Sobrien return TRUE; 24089857Sobrien} 241