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