+ return TRUE;
+}
+\f
+/* Do final adjustments to the filehdr and the aouthdr. This routine
+ sets the dynamic bits in the file header. */
+
+static bfd_boolean
+alpha_adjust_headers (bfd *abfd,
+ struct internal_filehdr *fhdr,
+ struct internal_aouthdr *ahdr ATTRIBUTE_UNUSED)
+{
+ if ((abfd->flags & (DYNAMIC | EXEC_P)) == (DYNAMIC | EXEC_P))
+ fhdr->f_flags |= F_ALPHA_CALL_SHARED;
+ else if ((abfd->flags & DYNAMIC) != 0)
+ fhdr->f_flags |= F_ALPHA_SHARABLE;
+ return TRUE;
+}
+\f
+/* Archive handling. In OSF/1 (or Digital Unix) v3.2, Digital
+ introduced archive packing, in which the elements in an archive are
+ optionally compressed using a simple dictionary scheme. We know
+ how to read such archives, but we don't write them. */
+
+#define alpha_ecoff_slurp_armap _bfd_ecoff_slurp_armap
+#define alpha_ecoff_slurp_extended_name_table \
+ _bfd_ecoff_slurp_extended_name_table
+#define alpha_ecoff_construct_extended_name_table \
+ _bfd_ecoff_construct_extended_name_table
+#define alpha_ecoff_truncate_arname _bfd_ecoff_truncate_arname
+#define alpha_ecoff_write_armap _bfd_ecoff_write_armap
+#define alpha_ecoff_write_ar_hdr _bfd_generic_write_ar_hdr
+#define alpha_ecoff_generic_stat_arch_elt _bfd_ecoff_generic_stat_arch_elt
+#define alpha_ecoff_update_armap_timestamp _bfd_ecoff_update_armap_timestamp
+
+/* A compressed file uses this instead of ARFMAG. */
+
+#define ARFZMAG "Z\012"
+
+/* Read an archive header. This is like the standard routine, but it
+ also accepts ARFZMAG. */
+
+static void *
+alpha_ecoff_read_ar_hdr (bfd *abfd)
+{
+ struct areltdata *ret;
+ struct ar_hdr *h;
+
+ ret = (struct areltdata *) _bfd_generic_read_ar_hdr_mag (abfd, ARFZMAG);
+ if (ret == NULL)
+ return NULL;
+
+ h = (struct ar_hdr *) ret->arch_header;
+ if (strncmp (h->ar_fmag, ARFZMAG, 2) == 0)
+ {
+ bfd_byte ab[8];
+
+ /* This is a compressed file. We must set the size correctly.
+ The size is the eight bytes after the dummy file header. */
+ if (bfd_seek (abfd, (file_ptr) FILHSZ, SEEK_CUR) != 0
+ || bfd_bread (ab, (bfd_size_type) 8, abfd) != 8
+ || bfd_seek (abfd, (file_ptr) (- (FILHSZ + 8)), SEEK_CUR) != 0)
+ return NULL;
+
+ ret->parsed_size = H_GET_64 (abfd, ab);
+ }
+
+ return ret;
+}
+
+/* Get an archive element at a specified file position. This is where
+ we uncompress the archive element if necessary. */
+
+static bfd *
+alpha_ecoff_get_elt_at_filepos (bfd *archive, file_ptr filepos)
+{
+ bfd *nbfd = NULL;
+ struct areltdata *tdata;
+ struct ar_hdr *hdr;
+ bfd_byte ab[8];
+ bfd_size_type size;
+ bfd_byte *buf, *p;
+ struct bfd_in_memory *bim;
+
+ buf = NULL;
+ nbfd = _bfd_get_elt_at_filepos (archive, filepos);
+ if (nbfd == NULL)
+ goto error_return;
+
+ if ((nbfd->flags & BFD_IN_MEMORY) != 0)
+ {
+ /* We have already expanded this BFD. */
+ return nbfd;
+ }
+
+ tdata = (struct areltdata *) nbfd->arelt_data;
+ hdr = (struct ar_hdr *) tdata->arch_header;
+ if (strncmp (hdr->ar_fmag, ARFZMAG, 2) != 0)
+ return nbfd;
+
+ /* We must uncompress this element. We do this by copying it into a
+ memory buffer, and making bfd_bread and bfd_seek use that buffer.
+ This can use a lot of memory, but it's simpler than getting a
+ temporary file, making that work with the file descriptor caching
+ code, and making sure that it is deleted at all appropriate
+ times. It can be changed if it ever becomes important. */
+
+ /* The compressed file starts with a dummy ECOFF file header. */
+ if (bfd_seek (nbfd, (file_ptr) FILHSZ, SEEK_SET) != 0)
+ goto error_return;
+
+ /* The next eight bytes are the real file size. */
+ if (bfd_bread (ab, (bfd_size_type) 8, nbfd) != 8)
+ goto error_return;
+ size = H_GET_64 (nbfd, ab);
+
+ if (size != 0)
+ {
+ bfd_size_type left;
+ bfd_byte dict[4096];
+ unsigned int h;
+ bfd_byte b;
+
+ buf = (bfd_byte *) bfd_malloc (size);
+ if (buf == NULL)
+ goto error_return;
+ p = buf;
+
+ left = size;
+
+ /* I don't know what the next eight bytes are for. */
+ if (bfd_bread (ab, (bfd_size_type) 8, nbfd) != 8)
+ goto error_return;
+
+ /* This is the uncompression algorithm. It's a simple
+ dictionary based scheme in which each character is predicted
+ by a hash of the previous three characters. A control byte
+ indicates whether the character is predicted or whether it
+ appears in the input stream; each control byte manages the
+ next eight bytes in the output stream. */
+ memset (dict, 0, sizeof dict);
+ h = 0;
+ while (bfd_bread (&b, (bfd_size_type) 1, nbfd) == 1)
+ {
+ unsigned int i;
+
+ for (i = 0; i < 8; i++, b >>= 1)
+ {
+ bfd_byte n;
+
+ if ((b & 1) == 0)
+ n = dict[h];
+ else
+ {
+ if (! bfd_bread (&n, (bfd_size_type) 1, nbfd))
+ goto error_return;
+ dict[h] = n;
+ }
+
+ *p++ = n;
+
+ --left;
+ if (left == 0)
+ break;
+
+ h <<= 4;
+ h ^= n;
+ h &= sizeof dict - 1;
+ }
+
+ if (left == 0)
+ break;
+ }
+ }
+
+ /* Now the uncompressed file contents are in buf. */
+ bim = ((struct bfd_in_memory *)
+ bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory)));
+ if (bim == NULL)
+ goto error_return;
+ bim->size = size;
+ bim->buffer = buf;
+
+ nbfd->mtime_set = TRUE;
+ nbfd->mtime = strtol (hdr->ar_date, (char **) NULL, 10);
+
+ nbfd->flags |= BFD_IN_MEMORY;
+ nbfd->iostream = bim;
+ nbfd->iovec = &_bfd_memory_iovec;
+ nbfd->origin = 0;
+ BFD_ASSERT (! nbfd->cacheable);
+
+ return nbfd;
+
+ error_return:
+ if (buf != NULL)
+ free (buf);
+ if (nbfd != NULL)
+ bfd_close (nbfd);
+ return NULL;
+}
+
+/* Open the next archived file. */
+
+static bfd *
+alpha_ecoff_openr_next_archived_file (bfd *archive, bfd *last_file)
+{
+ file_ptr filestart;
+
+ if (last_file == NULL)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else
+ {
+ struct areltdata *t;
+ struct ar_hdr *h;
+ bfd_size_type size;
+
+ /* We can't use arelt_size here, because that uses parsed_size,
+ which is the uncompressed size. We need the compressed size. */
+ t = (struct areltdata *) last_file->arelt_data;
+ h = (struct ar_hdr *) t->arch_header;
+ size = strtol (h->ar_size, (char **) NULL, 10);
+
+ /* Pad to an even boundary...
+ Note that last_file->origin can be odd in the case of
+ BSD-4.4-style element with a long odd size. */
+ filestart = last_file->proxy_origin + size;
+ filestart += filestart % 2;
+ }
+
+ return alpha_ecoff_get_elt_at_filepos (archive, filestart);
+}
+
+/* Open the archive file given an index into the armap. */
+
+static bfd *
+alpha_ecoff_get_elt_at_index (bfd *abfd, symindex sym_index)
+{
+ carsym *entry;
+
+ entry = bfd_ardata (abfd)->symdefs + sym_index;
+ return alpha_ecoff_get_elt_at_filepos (abfd, entry->file_offset);