archive64.c revision 130562
1169689Skan/* MIPS-specific support for 64-bit ELF
2169689Skan   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3169689Skan   Free Software Foundation, Inc.
4169689Skan   Ian Lance Taylor, Cygnus Support
5169689Skan   Linker support added by Mark Mitchell, CodeSourcery, LLC.
6169689Skan   <mark@codesourcery.com>
7169689Skan
8169689SkanThis file is part of BFD, the Binary File Descriptor library.
9169689Skan
10169689SkanThis program is free software; you can redistribute it and/or modify
11169689Skanit under the terms of the GNU General Public License as published by
12169689Skanthe Free Software Foundation; either version 2 of the License, or
13169689Skan(at your option) any later version.
14169689Skan
15169689SkanThis program is distributed in the hope that it will be useful,
16169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
17169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18169689SkanGNU General Public License for more details.
19169689Skan
20169689SkanYou should have received a copy of the GNU General Public License
21169689Skanalong with this program; if not, write to the Free Software
22169689SkanFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23169689Skan
24169689Skan/* This file supports the 64-bit (MIPS) ELF archives.  */
25169689Skan
26169689Skan#include "bfd.h"
27169689Skan#include "sysdep.h"
28169689Skan#include "libbfd.h"
29169689Skan#include "aout/ar.h"
30169689Skan
31169689Skan/* Irix 6 defines a 64bit archive map format, so that they can
32169689Skan   have archives more than 4 GB in size.  */
33169689Skan
34169689Skanbfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
35169689Skanbfd_boolean bfd_elf64_archive_write_armap
36169689Skan  (bfd *, unsigned int, struct orl *, unsigned int, int);
37169689Skan
38169689Skan/* Read an Irix 6 armap.  */
39169689Skan
40169689Skanbfd_boolean
41169689Skanbfd_elf64_archive_slurp_armap (bfd *abfd)
42169689Skan{
43169689Skan  struct artdata *ardata = bfd_ardata (abfd);
44169689Skan  char nextname[17];
45169689Skan  file_ptr arhdrpos;
46169689Skan  bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
47169689Skan  struct areltdata *mapdata;
48169689Skan  bfd_byte int_buf[8];
49169689Skan  char *stringbase;
50169689Skan  bfd_byte *raw_armap = NULL;
51169689Skan  carsym *carsyms;
52169689Skan  bfd_size_type amt;
53169689Skan
54169689Skan  ardata->symdefs = NULL;
55169689Skan
56169689Skan  /* Get the name of the first element.  */
57169689Skan  arhdrpos = bfd_tell (abfd);
58169689Skan  i = bfd_bread (nextname, 16, abfd);
59169689Skan  if (i == 0)
60169689Skan    return TRUE;
61169689Skan  if (i != 16)
62169689Skan    return FALSE;
63169689Skan
64169689Skan  if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
65169689Skan    return FALSE;
66169689Skan
67169689Skan  /* Archives with traditional armaps are still permitted.  */
68169689Skan  if (strncmp (nextname, "/               ", 16) == 0)
69169689Skan    return bfd_slurp_armap (abfd);
70169689Skan
71169689Skan  if (strncmp (nextname, "/SYM64/         ", 16) != 0)
72169689Skan    {
73169689Skan      bfd_has_map (abfd) = FALSE;
74169689Skan      return TRUE;
75169689Skan    }
76169689Skan
77169689Skan  mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
78169689Skan  if (mapdata == NULL)
79169689Skan    return FALSE;
80169689Skan  parsed_size = mapdata->parsed_size;
81169689Skan  bfd_release (abfd, mapdata);
82169689Skan
83169689Skan  if (bfd_bread (int_buf, 8, abfd) != 8)
84169689Skan    {
85169689Skan      if (bfd_get_error () != bfd_error_system_call)
86169689Skan	bfd_set_error (bfd_error_malformed_archive);
87169689Skan      return FALSE;
88169689Skan    }
89169689Skan
90169689Skan  nsymz = bfd_getb64 (int_buf);
91169689Skan  stringsize = parsed_size - 8 * nsymz - 8;
92169689Skan
93169689Skan  carsym_size = nsymz * sizeof (carsym);
94169689Skan  ptrsize = 8 * nsymz;
95169689Skan
96169689Skan  amt = carsym_size + stringsize + 1;
97169689Skan  ardata->symdefs = bfd_zalloc (abfd, amt);
98169689Skan  if (ardata->symdefs == NULL)
99169689Skan    return FALSE;
100169689Skan  carsyms = ardata->symdefs;
101169689Skan  stringbase = ((char *) ardata->symdefs) + carsym_size;
102169689Skan
103169689Skan  raw_armap = bfd_alloc (abfd, ptrsize);
104169689Skan  if (raw_armap == NULL)
105169689Skan    goto release_symdefs;
106169689Skan
107169689Skan  if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
108169689Skan      || bfd_bread (stringbase, stringsize, abfd) != stringsize)
109169689Skan    {
110169689Skan      if (bfd_get_error () != bfd_error_system_call)
111169689Skan	bfd_set_error (bfd_error_malformed_archive);
112169689Skan      goto release_raw_armap;
113169689Skan    }
114169689Skan
115169689Skan  for (i = 0; i < nsymz; i++)
116169689Skan    {
117169689Skan      carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
118169689Skan      carsyms->name = stringbase;
119169689Skan      stringbase += strlen (stringbase) + 1;
120169689Skan      ++carsyms;
121169689Skan    }
122169689Skan  *stringbase = '\0';
123169689Skan
124169689Skan  ardata->symdef_count = nsymz;
125169689Skan  ardata->first_file_filepos = bfd_tell (abfd);
126169689Skan  /* Pad to an even boundary if you have to.  */
127169689Skan  ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
128169689Skan
129169689Skan  bfd_has_map (abfd) = TRUE;
130169689Skan  bfd_release (abfd, raw_armap);
131169689Skan
132169689Skan  return TRUE;
133169689Skan
134169689Skanrelease_raw_armap:
135169689Skan  bfd_release (abfd, raw_armap);
136169689Skanrelease_symdefs:
137169689Skan  bfd_release (abfd, ardata->symdefs);
138169689Skan  return FALSE;
139169689Skan}
140169689Skan
141169689Skan/* Write out an Irix 6 armap.  The Irix 6 tools are supposed to be
142169689Skan   able to handle ordinary ELF armaps, but at least on Irix 6.2 the
143169689Skan   linker crashes.  */
144169689Skan
145169689Skanbfd_boolean
146169689Skanbfd_elf64_archive_write_armap (bfd *arch,
147169689Skan			       unsigned int elength,
148169689Skan			       struct orl *map,
149169689Skan			       unsigned int symbol_count,
150169689Skan			       int stridx)
151169689Skan{
152169689Skan  unsigned int ranlibsize = (symbol_count * 8) + 8;
153169689Skan  unsigned int stringsize = stridx;
154169689Skan  unsigned int mapsize = stringsize + ranlibsize;
155169689Skan  file_ptr archive_member_file_ptr;
156169689Skan  bfd *current = arch->archive_head;
157169689Skan  unsigned int count;
158169689Skan  struct ar_hdr hdr;
159169689Skan  unsigned int i;
160169689Skan  int padding;
161169689Skan  bfd_byte buf[8];
162169689Skan
163169689Skan  padding = BFD_ALIGN (mapsize, 8) - mapsize;
164169689Skan  mapsize += padding;
165169689Skan
166169689Skan  /* work out where the first object file will go in the archive */
167169689Skan  archive_member_file_ptr = (mapsize
168169689Skan			     + elength
169169689Skan			     + sizeof (struct ar_hdr)
170169689Skan			     + SARMAG);
171169689Skan
172169689Skan  memset (&hdr, 0, sizeof (struct ar_hdr));
173169689Skan  strcpy (hdr.ar_name, "/SYM64/");
174169689Skan  sprintf (hdr.ar_size, "%-10d", (int) mapsize);
175169689Skan  sprintf (hdr.ar_date, "%ld", (long) time (NULL));
176169689Skan  /* This, at least, is what Intel coff sets the values to.: */
177169689Skan  sprintf ((hdr.ar_uid), "%d", 0);
178169689Skan  sprintf ((hdr.ar_gid), "%d", 0);
179169689Skan  sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0);
180169689Skan  strncpy (hdr.ar_fmag, ARFMAG, 2);
181169689Skan
182169689Skan  for (i = 0; i < sizeof (struct ar_hdr); i++)
183169689Skan    if (((char *) (&hdr))[i] == '\0')
184169689Skan      (((char *) (&hdr))[i]) = ' ';
185169689Skan
186169689Skan  /* Write the ar header for this item and the number of symbols */
187169689Skan
188169689Skan  if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
189169689Skan      != sizeof (struct ar_hdr))
190169689Skan    return FALSE;
191169689Skan
192169689Skan  bfd_putb64 ((bfd_vma) symbol_count, buf);
193169689Skan  if (bfd_bwrite (buf, 8, arch) != 8)
194169689Skan    return FALSE;
195169689Skan
196169689Skan  /* Two passes, first write the file offsets for each symbol -
197169689Skan     remembering that each offset is on a two byte boundary.  */
198169689Skan
199169689Skan  /* Write out the file offset for the file associated with each
200169689Skan     symbol, and remember to keep the offsets padded out.  */
201169689Skan
202169689Skan  current = arch->archive_head;
203169689Skan  count = 0;
204169689Skan  while (current != NULL && count < symbol_count)
205169689Skan    {
206169689Skan      /* For each symbol which is used defined in this object, write out
207169689Skan	 the object file's address in the archive */
208169689Skan
209169689Skan      while (map[count].u.abfd == current)
210169689Skan	{
211169689Skan	  bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf);
212169689Skan	  if (bfd_bwrite (buf, 8, arch) != 8)
213169689Skan	    return FALSE;
214169689Skan	  count++;
215169689Skan	}
216169689Skan      /* Add size of this archive entry */
217169689Skan      archive_member_file_ptr += (arelt_size (current)
218169689Skan				  + sizeof (struct ar_hdr));
219169689Skan      /* remember about the even alignment */
220169689Skan      archive_member_file_ptr += archive_member_file_ptr % 2;
221169689Skan      current = current->next;
222169689Skan    }
223169689Skan
224169689Skan  /* now write the strings themselves */
225169689Skan  for (count = 0; count < symbol_count; count++)
226169689Skan    {
227169689Skan      size_t len = strlen (*map[count].name) + 1;
228169689Skan
229169689Skan      if (bfd_bwrite (*map[count].name, len, arch) != len)
230169689Skan	return FALSE;
231169689Skan    }
232169689Skan
233169689Skan  /* The spec says that this should be padded to an 8 byte boundary.
234169689Skan     However, the Irix 6.2 tools do not appear to do this.  */
235169689Skan  while (padding != 0)
236169689Skan    {
237169689Skan      if (bfd_bwrite ("", 1, arch) != 1)
238169689Skan	return FALSE;
239169689Skan      --padding;
240169689Skan    }
241169689Skan
242169689Skan  return TRUE;
243169689Skan}
244169689Skan