xref: /openbsd-src/gnu/usr.bin/binutils/bfd/archive64.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1d2201f2fSdrahn /* MIPS-specific support for 64-bit ELF
2*cf2f2c56Smiod    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3d2201f2fSdrahn    Free Software Foundation, Inc.
4d2201f2fSdrahn    Ian Lance Taylor, Cygnus Support
5d2201f2fSdrahn    Linker support added by Mark Mitchell, CodeSourcery, LLC.
6d2201f2fSdrahn    <mark@codesourcery.com>
7d2201f2fSdrahn 
8d2201f2fSdrahn This file is part of BFD, the Binary File Descriptor library.
9d2201f2fSdrahn 
10d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
11d2201f2fSdrahn it under the terms of the GNU General Public License as published by
12d2201f2fSdrahn the Free Software Foundation; either version 2 of the License, or
13d2201f2fSdrahn (at your option) any later version.
14d2201f2fSdrahn 
15d2201f2fSdrahn This program is distributed in the hope that it will be useful,
16d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
17d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18d2201f2fSdrahn GNU General Public License for more details.
19d2201f2fSdrahn 
20d2201f2fSdrahn You should have received a copy of the GNU General Public License
21d2201f2fSdrahn along with this program; if not, write to the Free Software
22d2201f2fSdrahn Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23d2201f2fSdrahn 
24d2201f2fSdrahn /* This file supports the 64-bit (MIPS) ELF archives.  */
25d2201f2fSdrahn 
26d2201f2fSdrahn #include "bfd.h"
27d2201f2fSdrahn #include "sysdep.h"
28d2201f2fSdrahn #include "libbfd.h"
29d2201f2fSdrahn #include "aout/ar.h"
30d2201f2fSdrahn 
31d2201f2fSdrahn /* Irix 6 defines a 64bit archive map format, so that they can
32d2201f2fSdrahn    have archives more than 4 GB in size.  */
33d2201f2fSdrahn 
34*cf2f2c56Smiod bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
35d2201f2fSdrahn bfd_boolean bfd_elf64_archive_write_armap
36*cf2f2c56Smiod   (bfd *, unsigned int, struct orl *, unsigned int, int);
37d2201f2fSdrahn 
38d2201f2fSdrahn /* Read an Irix 6 armap.  */
39d2201f2fSdrahn 
40d2201f2fSdrahn bfd_boolean
bfd_elf64_archive_slurp_armap(bfd * abfd)41*cf2f2c56Smiod bfd_elf64_archive_slurp_armap (bfd *abfd)
42d2201f2fSdrahn {
43d2201f2fSdrahn   struct artdata *ardata = bfd_ardata (abfd);
44d2201f2fSdrahn   char nextname[17];
45d2201f2fSdrahn   file_ptr arhdrpos;
46d2201f2fSdrahn   bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize;
47d2201f2fSdrahn   struct areltdata *mapdata;
48d2201f2fSdrahn   bfd_byte int_buf[8];
49d2201f2fSdrahn   char *stringbase;
50d2201f2fSdrahn   bfd_byte *raw_armap = NULL;
51d2201f2fSdrahn   carsym *carsyms;
52d2201f2fSdrahn   bfd_size_type amt;
53d2201f2fSdrahn 
54d2201f2fSdrahn   ardata->symdefs = NULL;
55d2201f2fSdrahn 
56d2201f2fSdrahn   /* Get the name of the first element.  */
57d2201f2fSdrahn   arhdrpos = bfd_tell (abfd);
58*cf2f2c56Smiod   i = bfd_bread (nextname, 16, abfd);
59d2201f2fSdrahn   if (i == 0)
60d2201f2fSdrahn     return TRUE;
61d2201f2fSdrahn   if (i != 16)
62d2201f2fSdrahn     return FALSE;
63d2201f2fSdrahn 
64d2201f2fSdrahn   if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
65d2201f2fSdrahn     return FALSE;
66d2201f2fSdrahn 
67d2201f2fSdrahn   /* Archives with traditional armaps are still permitted.  */
68d2201f2fSdrahn   if (strncmp (nextname, "/               ", 16) == 0)
69d2201f2fSdrahn     return bfd_slurp_armap (abfd);
70d2201f2fSdrahn 
71d2201f2fSdrahn   if (strncmp (nextname, "/SYM64/         ", 16) != 0)
72d2201f2fSdrahn     {
73d2201f2fSdrahn       bfd_has_map (abfd) = FALSE;
74d2201f2fSdrahn       return TRUE;
75d2201f2fSdrahn     }
76d2201f2fSdrahn 
77d2201f2fSdrahn   mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
78d2201f2fSdrahn   if (mapdata == NULL)
79d2201f2fSdrahn     return FALSE;
80d2201f2fSdrahn   parsed_size = mapdata->parsed_size;
81*cf2f2c56Smiod   bfd_release (abfd, mapdata);
82d2201f2fSdrahn 
83*cf2f2c56Smiod   if (bfd_bread (int_buf, 8, abfd) != 8)
84d2201f2fSdrahn     {
85d2201f2fSdrahn       if (bfd_get_error () != bfd_error_system_call)
86d2201f2fSdrahn 	bfd_set_error (bfd_error_malformed_archive);
87d2201f2fSdrahn       return FALSE;
88d2201f2fSdrahn     }
89d2201f2fSdrahn 
90d2201f2fSdrahn   nsymz = bfd_getb64 (int_buf);
91d2201f2fSdrahn   stringsize = parsed_size - 8 * nsymz - 8;
92d2201f2fSdrahn 
93d2201f2fSdrahn   carsym_size = nsymz * sizeof (carsym);
94d2201f2fSdrahn   ptrsize = 8 * nsymz;
95d2201f2fSdrahn 
96d2201f2fSdrahn   amt = carsym_size + stringsize + 1;
97*cf2f2c56Smiod   ardata->symdefs = bfd_zalloc (abfd, amt);
98d2201f2fSdrahn   if (ardata->symdefs == NULL)
99d2201f2fSdrahn     return FALSE;
100d2201f2fSdrahn   carsyms = ardata->symdefs;
101d2201f2fSdrahn   stringbase = ((char *) ardata->symdefs) + carsym_size;
102d2201f2fSdrahn 
103*cf2f2c56Smiod   raw_armap = bfd_alloc (abfd, ptrsize);
104d2201f2fSdrahn   if (raw_armap == NULL)
105d2201f2fSdrahn     goto release_symdefs;
106d2201f2fSdrahn 
107d2201f2fSdrahn   if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
108d2201f2fSdrahn       || bfd_bread (stringbase, stringsize, abfd) != stringsize)
109d2201f2fSdrahn     {
110d2201f2fSdrahn       if (bfd_get_error () != bfd_error_system_call)
111d2201f2fSdrahn 	bfd_set_error (bfd_error_malformed_archive);
112d2201f2fSdrahn       goto release_raw_armap;
113d2201f2fSdrahn     }
114d2201f2fSdrahn 
115d2201f2fSdrahn   for (i = 0; i < nsymz; i++)
116d2201f2fSdrahn     {
117d2201f2fSdrahn       carsyms->file_offset = bfd_getb64 (raw_armap + i * 8);
118d2201f2fSdrahn       carsyms->name = stringbase;
119d2201f2fSdrahn       stringbase += strlen (stringbase) + 1;
120d2201f2fSdrahn       ++carsyms;
121d2201f2fSdrahn     }
122d2201f2fSdrahn   *stringbase = '\0';
123d2201f2fSdrahn 
124d2201f2fSdrahn   ardata->symdef_count = nsymz;
125d2201f2fSdrahn   ardata->first_file_filepos = bfd_tell (abfd);
126d2201f2fSdrahn   /* Pad to an even boundary if you have to.  */
127d2201f2fSdrahn   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
128d2201f2fSdrahn 
129d2201f2fSdrahn   bfd_has_map (abfd) = TRUE;
130d2201f2fSdrahn   bfd_release (abfd, raw_armap);
131d2201f2fSdrahn 
132d2201f2fSdrahn   return TRUE;
133d2201f2fSdrahn 
134d2201f2fSdrahn release_raw_armap:
135d2201f2fSdrahn   bfd_release (abfd, raw_armap);
136d2201f2fSdrahn release_symdefs:
137d2201f2fSdrahn   bfd_release (abfd, ardata->symdefs);
138d2201f2fSdrahn   return FALSE;
139d2201f2fSdrahn }
140d2201f2fSdrahn 
141d2201f2fSdrahn /* Write out an Irix 6 armap.  The Irix 6 tools are supposed to be
142d2201f2fSdrahn    able to handle ordinary ELF armaps, but at least on Irix 6.2 the
143d2201f2fSdrahn    linker crashes.  */
144d2201f2fSdrahn 
145d2201f2fSdrahn bfd_boolean
bfd_elf64_archive_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int symbol_count,int stridx)146*cf2f2c56Smiod bfd_elf64_archive_write_armap (bfd *arch,
147*cf2f2c56Smiod 			       unsigned int elength,
148*cf2f2c56Smiod 			       struct orl *map,
149*cf2f2c56Smiod 			       unsigned int symbol_count,
150*cf2f2c56Smiod 			       int stridx)
151d2201f2fSdrahn {
152d2201f2fSdrahn   unsigned int ranlibsize = (symbol_count * 8) + 8;
153d2201f2fSdrahn   unsigned int stringsize = stridx;
154d2201f2fSdrahn   unsigned int mapsize = stringsize + ranlibsize;
155d2201f2fSdrahn   file_ptr archive_member_file_ptr;
156d2201f2fSdrahn   bfd *current = arch->archive_head;
157d2201f2fSdrahn   unsigned int count;
158d2201f2fSdrahn   struct ar_hdr hdr;
159d2201f2fSdrahn   unsigned int i;
160d2201f2fSdrahn   int padding;
161d2201f2fSdrahn   bfd_byte buf[8];
162d2201f2fSdrahn 
163d2201f2fSdrahn   padding = BFD_ALIGN (mapsize, 8) - mapsize;
164d2201f2fSdrahn   mapsize += padding;
165d2201f2fSdrahn 
166d2201f2fSdrahn   /* work out where the first object file will go in the archive */
167d2201f2fSdrahn   archive_member_file_ptr = (mapsize
168d2201f2fSdrahn 			     + elength
169d2201f2fSdrahn 			     + sizeof (struct ar_hdr)
170d2201f2fSdrahn 			     + SARMAG);
171d2201f2fSdrahn 
172*cf2f2c56Smiod   memset (&hdr, 0, sizeof (struct ar_hdr));
173d2201f2fSdrahn   strcpy (hdr.ar_name, "/SYM64/");
174d2201f2fSdrahn   sprintf (hdr.ar_size, "%-10d", (int) mapsize);
175d2201f2fSdrahn   sprintf (hdr.ar_date, "%ld", (long) time (NULL));
176d2201f2fSdrahn   /* This, at least, is what Intel coff sets the values to.: */
177d2201f2fSdrahn   sprintf ((hdr.ar_uid), "%d", 0);
178d2201f2fSdrahn   sprintf ((hdr.ar_gid), "%d", 0);
179d2201f2fSdrahn   sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0);
180d2201f2fSdrahn   strncpy (hdr.ar_fmag, ARFMAG, 2);
181d2201f2fSdrahn 
182d2201f2fSdrahn   for (i = 0; i < sizeof (struct ar_hdr); i++)
183d2201f2fSdrahn     if (((char *) (&hdr))[i] == '\0')
184d2201f2fSdrahn       (((char *) (&hdr))[i]) = ' ';
185d2201f2fSdrahn 
186d2201f2fSdrahn   /* Write the ar header for this item and the number of symbols */
187d2201f2fSdrahn 
188*cf2f2c56Smiod   if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
189d2201f2fSdrahn       != sizeof (struct ar_hdr))
190d2201f2fSdrahn     return FALSE;
191d2201f2fSdrahn 
192d2201f2fSdrahn   bfd_putb64 ((bfd_vma) symbol_count, buf);
193*cf2f2c56Smiod   if (bfd_bwrite (buf, 8, arch) != 8)
194d2201f2fSdrahn     return FALSE;
195d2201f2fSdrahn 
196d2201f2fSdrahn   /* Two passes, first write the file offsets for each symbol -
197d2201f2fSdrahn      remembering that each offset is on a two byte boundary.  */
198d2201f2fSdrahn 
199d2201f2fSdrahn   /* Write out the file offset for the file associated with each
200d2201f2fSdrahn      symbol, and remember to keep the offsets padded out.  */
201d2201f2fSdrahn 
202d2201f2fSdrahn   current = arch->archive_head;
203d2201f2fSdrahn   count = 0;
204*cf2f2c56Smiod   while (current != NULL && count < symbol_count)
205d2201f2fSdrahn     {
206d2201f2fSdrahn       /* For each symbol which is used defined in this object, write out
207d2201f2fSdrahn 	 the object file's address in the archive */
208d2201f2fSdrahn 
209d2201f2fSdrahn       while (map[count].u.abfd == current)
210d2201f2fSdrahn 	{
211d2201f2fSdrahn 	  bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf);
212*cf2f2c56Smiod 	  if (bfd_bwrite (buf, 8, arch) != 8)
213d2201f2fSdrahn 	    return FALSE;
214d2201f2fSdrahn 	  count++;
215d2201f2fSdrahn 	}
216d2201f2fSdrahn       /* Add size of this archive entry */
217d2201f2fSdrahn       archive_member_file_ptr += (arelt_size (current)
218d2201f2fSdrahn 				  + sizeof (struct ar_hdr));
219d2201f2fSdrahn       /* remember about the even alignment */
220d2201f2fSdrahn       archive_member_file_ptr += archive_member_file_ptr % 2;
221d2201f2fSdrahn       current = current->next;
222d2201f2fSdrahn     }
223d2201f2fSdrahn 
224d2201f2fSdrahn   /* now write the strings themselves */
225d2201f2fSdrahn   for (count = 0; count < symbol_count; count++)
226d2201f2fSdrahn     {
227d2201f2fSdrahn       size_t len = strlen (*map[count].name) + 1;
228d2201f2fSdrahn 
229*cf2f2c56Smiod       if (bfd_bwrite (*map[count].name, len, arch) != len)
230d2201f2fSdrahn 	return FALSE;
231d2201f2fSdrahn     }
232d2201f2fSdrahn 
233d2201f2fSdrahn   /* The spec says that this should be padded to an 8 byte boundary.
234d2201f2fSdrahn      However, the Irix 6.2 tools do not appear to do this.  */
235d2201f2fSdrahn   while (padding != 0)
236d2201f2fSdrahn     {
237*cf2f2c56Smiod       if (bfd_bwrite ("", 1, arch) != 1)
238d2201f2fSdrahn 	return FALSE;
239d2201f2fSdrahn       --padding;
240d2201f2fSdrahn     }
241d2201f2fSdrahn 
242d2201f2fSdrahn   return TRUE;
243d2201f2fSdrahn }
244