summaryrefslogtreecommitdiffstats
path: root/bfd/coff-rs6000.c
diff options
context:
space:
mode:
authorGeoffrey Keating <geoffk@geoffk.org>2000-02-19 00:59:26 +0000
committerGeoffrey Keating <geoffk@geoffk.org>2000-02-19 00:59:26 +0000
commit5ea1af0d5d96234b6c086f284c2fc66ad58b279b (patch)
tree4fde10d727be7bd97f75ea4ce33be162b7a0123b /bfd/coff-rs6000.c
parentff4e7bb239e88a67baed668fd48e25236fee6b93 (diff)
downloadppe42-binutils-5ea1af0d5d96234b6c086f284c2fc66ad58b279b.tar.gz
ppe42-binutils-5ea1af0d5d96234b6c086f284c2fc66ad58b279b.zip
* coffcode.h (coff_set_arch_mach_hook): Don't use variable-size
arrays. (coff_compute_section_file_positions): Use bfd_free to pair bfd_malloc. (coff_write_object_contents): Likewise. * coff-rs6000.c (xcoff_howto_table_16): New variable. (xcoff_rtype2howto): Handle 16-bit variants of 32-bit relocs.
Diffstat (limited to 'bfd/coff-rs6000.c')
-rw-r--r--bfd/coff-rs6000.c848
1 files changed, 777 insertions, 71 deletions
diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 69230001e4..6f8563f911 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -496,6 +496,55 @@ static reloc_howto_type xcoff_howto_table[] =
false) /* pcrel_offset */
};
+/* These are the first two like the above but for 16-bit relocs. */
+static reloc_howto_type xcoff_howto_table_16[] =
+{
+ /* Standard 16 bit relocation. */
+ HOWTO (0, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_POS_16", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 16 bit relocation, but store negative value. */
+ HOWTO (1, /* type */
+ 0, /* rightshift */
+ -2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_NEG_16", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 16 bit PC relative relocation. */
+ HOWTO (2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ 0, /* special_function */
+ "R_REL_16", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+};
+
static void
xcoff_rtype2howto (relent, internal)
arelent *relent;
@@ -503,6 +552,11 @@ xcoff_rtype2howto (relent, internal)
{
relent->howto = xcoff_howto_table + internal->r_type;
+ if (relent->howto->bitsize != ((unsigned int) internal->r_size & 0x1f) + 1
+ && (internal->r_type
+ < sizeof(xcoff_howto_table_16)/sizeof(xcoff_howto_table_16[0])))
+ relent->howto = xcoff_howto_table_16 + internal->r_type;
+
/* The r_size field of an XCOFF reloc encodes the bitsize of the
relocation, as well as indicating whether it is signed or not.
Doublecheck that the relocation information gathered from the
@@ -591,12 +645,25 @@ xcoff_reloc_type_lookup (abfd, code)
binary number which is the number of entries. This is followed by
a that many four byte binary numbers; each is the file offset of an
entry in the archive. These numbers are followed by a series of
- null terminated strings, which are symbol names. */
+ null terminated strings, which are symbol names.
-/* XCOFF archives use this as a magic string. */
+ AIX 4.3 introduced a new archive format which can handle larger
+ files and also 32- and 64-bit objects in the same archive. The
+ things said above remain true except that there is now more than
+ one global symbol table. The one is used to index 32-bit objects,
+ the other for 64-bit objects.
-#define XCOFFARMAG "<aiaff>\012"
-#define SXCOFFARMAG 8
+ The new archives (recognizable by the new ARMAG string) has larger
+ field lengths so that we cannot really share any code. Also we have
+ to take care that we are not generating the new form of archives
+ on AIX 4.2 or earlier systems. */
+
+/* XCOFF archives use this as a magic string. Note that both strings
+ have the same length. */
+
+#define XCOFFARMAG "<aiaff>\012"
+#define XCOFFARMAGBIG "<bigaf>\012"
+#define SXCOFFARMAG 8
/* This terminates an XCOFF archive member name. */
@@ -629,6 +696,38 @@ struct xcoff_ar_file_hdr
#define SIZEOF_AR_FILE_HDR (5 * 12 + SXCOFFARMAG)
+/* This is the equivalent data structure for the big archive format. */
+
+struct xcoff_ar_file_hdr_big
+{
+ /* Magic string. */
+ char magic[SXCOFFARMAG];
+
+ /* Offset of the member table (decimal ASCII string). */
+ char memoff[20];
+
+ /* Offset of the global symbol table for 32-bit objects (decimal ASCII
+ string). */
+ char symoff[20];
+
+ /* Offset of the global symbol table for 64-bit objects (decimal ASCII
+ string). */
+ char symoff64[20];
+
+ /* Offset of the first member in the archive (decimal ASCII string). */
+ char firstmemoff[20];
+
+ /* Offset of the last member in the archive (decimal ASCII string). */
+ char lastmemoff[20];
+
+ /* Offset of the first member on the free list (decimal ASCII
+ string). */
+ char freeoff[20];
+};
+
+#define SIZEOF_AR_FILE_HDR_BIG (6 * 20 + SXCOFFARMAG)
+
+
/* Each XCOFF archive member starts with this (printable) structure. */
struct xcoff_ar_hdr
@@ -667,16 +766,65 @@ struct xcoff_ar_hdr
#define SIZEOF_AR_HDR (7 * 12 + 4)
+/* The equivalent for the big archive format. */
+
+struct xcoff_ar_hdr_big
+{
+ /* File size not including the header (decimal ASCII string). */
+ char size[20];
+
+ /* File offset of next archive member (decimal ASCII string). */
+ char nextoff[20];
+
+ /* File offset of previous archive member (decimal ASCII string). */
+ char prevoff[20];
+
+ /* File mtime (decimal ASCII string). */
+ char date[12];
+
+ /* File UID (decimal ASCII string). */
+ char uid[12];
+
+ /* File GID (decimal ASCII string). */
+ char gid[12];
+
+ /* File mode (octal ASCII string). */
+ char mode[12];
+
+ /* Length of file name (decimal ASCII string). */
+ char namlen[4];
+
+ /* This structure is followed by the file name. The length of the
+ name is given in the namlen field. If the length of the name is
+ odd, the name is followed by a null byte. The name and optional
+ null byte are followed by XCOFFARFMAG, which is not included in
+ namlen. The contents of the archive member follow; the number of
+ bytes is given in the size field. */
+};
+
+#define SIZEOF_AR_HDR_BIG (3 * 20 + 4 * 12 + 4)
+
+
+/* We often have to distinguish between the old and big file format.
+ Make it a bit cleaner. We can use `xcoff_ardata' here because the
+ `hdr' member has the same size and position in both formats. */
+#define xcoff_big_format_p(abfd) \
+ (xcoff_ardata (abfd)->magic[1] == 'b')
+
/* We store a copy of the xcoff_ar_file_hdr in the tdata field of the
- artdata structure. */
+ artdata structure. Similar for the big archive. */
#define xcoff_ardata(abfd) \
((struct xcoff_ar_file_hdr *) bfd_ardata (abfd)->tdata)
+#define xcoff_ardata_big(abfd) \
+ ((struct xcoff_ar_file_hdr_big *) bfd_ardata (abfd)->tdata)
/* We store a copy of the xcoff_ar_hdr in the arelt_data field of an
- archive element. */
+ archive element. Similar for the big archive. */
#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
#define arch_xhdr(bfd) \
((struct xcoff_ar_hdr *) arch_eltdata (bfd)->arch_header)
+#define arch_xhdr_big(bfd) \
+ ((struct xcoff_ar_hdr_big *) arch_eltdata (bfd)->arch_header)
/* XCOFF archives do not have anything which corresponds to an
extended name table. */
@@ -702,7 +850,6 @@ xcoff_slurp_armap (abfd)
bfd *abfd;
{
file_ptr off;
- struct xcoff_ar_hdr hdr;
size_t namlen;
bfd_size_type sz;
bfd_byte *contents, *cend;
@@ -716,27 +863,64 @@ xcoff_slurp_armap (abfd)
return true;
}
- off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10);
- if (off == 0)
+ if (! xcoff_big_format_p (abfd))
{
- bfd_has_map (abfd) = false;
- return true;
+ /* This is for the old format. */
+ struct xcoff_ar_hdr hdr;
+
+ off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10);
+ if (off == 0)
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ if (bfd_seek (abfd, off, SEEK_SET) != 0)
+ return false;
+
+ /* The symbol table starts with a normal archive header. */
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
+ return false;
+
+ /* Skip the name (normally empty). */
+ namlen = strtol (hdr.namlen, (char **) NULL, 10);
+ if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0)
+ return false;
+
+ sz = strtol (hdr.size, (char **) NULL, 10);
}
+ else
+ {
+ /* This is for the new format. */
+ struct xcoff_ar_hdr_big hdr;
- if (bfd_seek (abfd, off, SEEK_SET) != 0)
- return false;
+ off = strtol (xcoff_ardata_big (abfd)->symoff, (char **) NULL, 10);
+ if (off == 0)
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
- /* The symbol table starts with a normal archive header. */
- if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
- return false;
+ if (bfd_seek (abfd, off, SEEK_SET) != 0)
+ return false;
- /* Skip the name (normally empty). */
- namlen = strtol (hdr.namlen, (char **) NULL, 10);
- if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0)
- return false;
+ /* The symbol table starts with a normal archive header. */
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd)
+ != SIZEOF_AR_HDR_BIG)
+ return false;
+
+ /* Skip the name (normally empty). */
+ namlen = strtol (hdr.namlen, (char **) NULL, 10);
+ if (bfd_seek (abfd, ((namlen + 1) & ~1) + SXCOFFARFMAG, SEEK_CUR) != 0)
+ return false;
+
+ /* XXX This actually has to be a call to strtoll (at least on 32-bit
+ machines) since the field width is 20 and there numbers with more
+ than 32 bits can be represented. */
+ sz = strtol (hdr.size, (char **) NULL, 10);
+ }
/* Read in the entire symbol table. */
- sz = strtol (hdr.size, (char **) NULL, 10);
contents = (bfd_byte *) bfd_alloc (abfd, sz);
if (contents == NULL)
return false;
@@ -789,17 +973,17 @@ static const bfd_target *
xcoff_archive_p (abfd)
bfd *abfd;
{
- struct xcoff_ar_file_hdr hdr;
+ char magic[SXCOFFARMAG];
- if (bfd_read ((PTR) &hdr, SIZEOF_AR_FILE_HDR, 1, abfd)
- != SIZEOF_AR_FILE_HDR)
+ if (bfd_read ((PTR) magic, SXCOFFARMAG, 1, abfd) != SXCOFFARMAG)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
- if (strncmp (hdr.magic, XCOFFARMAG, SXCOFFARMAG) != 0)
+ if (strncmp (magic, XCOFFARMAG, SXCOFFARMAG) != 0
+ && strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0)
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
@@ -814,18 +998,67 @@ xcoff_archive_p (abfd)
if (bfd_ardata (abfd) == (struct artdata *) NULL)
return NULL;
- bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
- (char **) NULL, 10);
bfd_ardata (abfd)->cache = NULL;
bfd_ardata (abfd)->archive_head = NULL;
bfd_ardata (abfd)->symdefs = NULL;
bfd_ardata (abfd)->extended_names = NULL;
- bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR);
- if (bfd_ardata (abfd)->tdata == NULL)
- return NULL;
+ /* Now handle the two formats. */
+ if (magic[1] != 'b')
+ {
+ /* This is the old format. */
+ struct xcoff_ar_file_hdr hdr;
+
+ /* Copy over the magic string. */
+ memcpy (hdr.magic, magic, SXCOFFARMAG);
- memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
+ /* Now read the rest of the file header. */
+ if (bfd_read ((PTR) &hdr.memoff, SIZEOF_AR_FILE_HDR - SXCOFFARMAG, 1,
+ abfd) != SIZEOF_AR_FILE_HDR - SXCOFFARMAG)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
+ (char **) NULL, 10);
+
+ bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR);
+ if (bfd_ardata (abfd)->tdata == NULL)
+ return NULL;
+
+ memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
+ }
+ else
+ {
+ /* This is the new format. */
+ struct xcoff_ar_file_hdr_big hdr;
+
+ /* Copy over the magic string. */
+ memcpy (hdr.magic, magic, SXCOFFARMAG);
+
+ /* Now read the rest of the file header. */
+ if (bfd_read ((PTR) &hdr.memoff, SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG, 1,
+ abfd) != SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ /* XXX This actually has to be a call to strtoll (at least on 32-bit
+ machines) since the field width is 20 and there numbers with more
+ than 32 bits can be represented. */
+ bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
+ (char **) NULL, 10);
+
+ bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR_BIG);
+ if (bfd_ardata (abfd)->tdata == NULL)
+ return NULL;
+
+ memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG);
+ }
if (! xcoff_slurp_armap (abfd))
{
@@ -843,29 +1076,80 @@ static PTR
xcoff_read_ar_hdr (abfd)
bfd *abfd;
{
- struct xcoff_ar_hdr hdr;
size_t namlen;
- struct xcoff_ar_hdr *hdrp;
struct areltdata *ret;
- if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
- return NULL;
-
- namlen = strtol (hdr.namlen, (char **) NULL, 10);
- hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1);
- if (hdrp == NULL)
- return NULL;
- memcpy (hdrp, &hdr, SIZEOF_AR_HDR);
- if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen)
- return NULL;
- ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0';
-
ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata));
if (ret == NULL)
return NULL;
- ret->arch_header = (char *) hdrp;
- ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
- ret->filename = (char *) hdrp + SIZEOF_AR_HDR;
+
+ if (! xcoff_big_format_p (abfd))
+ {
+ struct xcoff_ar_hdr hdr;
+ struct xcoff_ar_hdr *hdrp;
+
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR)
+ {
+ free (ret);
+ return NULL;
+ }
+
+ namlen = strtol (hdr.namlen, (char **) NULL, 10);
+ hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd,
+ SIZEOF_AR_HDR + namlen + 1);
+ if (hdrp == NULL)
+ {
+ free (ret);
+ return NULL;
+ }
+ memcpy (hdrp, &hdr, SIZEOF_AR_HDR);
+ if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen)
+ {
+ free (ret);
+ return NULL;
+ }
+ ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0';
+
+ ret->arch_header = (char *) hdrp;
+ ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
+ ret->filename = (char *) hdrp + SIZEOF_AR_HDR;
+ }
+ else
+ {
+ struct xcoff_ar_hdr_big hdr;
+ struct xcoff_ar_hdr_big *hdrp;
+
+ if (bfd_read ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd)
+ != SIZEOF_AR_HDR_BIG)
+ {
+ free (ret);
+ return NULL;
+ }
+
+ namlen = strtol (hdr.namlen, (char **) NULL, 10);
+ hdrp = (struct xcoff_ar_hdr_big *) bfd_alloc (abfd,
+ SIZEOF_AR_HDR_BIG
+ + namlen + 1);
+ if (hdrp == NULL)
+ {
+ free (ret);
+ return NULL;
+ }
+ memcpy (hdrp, &hdr, SIZEOF_AR_HDR_BIG);
+ if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR_BIG, 1, namlen, abfd) != namlen)
+ {
+ free (ret);
+ return NULL;
+ }
+ ((char *) hdrp)[SIZEOF_AR_HDR_BIG + namlen] = '\0';
+
+ ret->arch_header = (char *) hdrp;
+ /* XXX This actually has to be a call to strtoll (at least on 32-bit
+ machines) since the field width is 20 and there numbers with more
+ than 32 bits can be represented. */
+ ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
+ ret->filename = (char *) hdrp + SIZEOF_AR_HDR_BIG;
+ }
/* Skip over the XCOFFARFMAG at the end of the file name. */
if (bfd_seek (abfd, (namlen & 1) + SXCOFFARFMAG, SEEK_CUR) != 0)
@@ -889,19 +1173,47 @@ xcoff_openr_next_archived_file (archive, last_file)
return NULL;
}
- if (last_file == NULL)
- filestart = bfd_ardata (archive)->first_file_filepos;
+ if (! xcoff_big_format_p (archive))
+ {
+ if (last_file == NULL)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else
+ filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL,
+ 10);
+
+ if (filestart == 0
+ || filestart == strtol (xcoff_ardata (archive)->memoff,
+ (char **) NULL, 10)
+ || filestart == strtol (xcoff_ardata (archive)->symoff,
+ (char **) NULL, 10))
+ {
+ bfd_set_error (bfd_error_no_more_archived_files);
+ return NULL;
+ }
+ }
else
- filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL, 10);
-
- if (filestart == 0
- || filestart == strtol (xcoff_ardata (archive)->memoff,
- (char **) NULL, 10)
- || filestart == strtol (xcoff_ardata (archive)->symoff,
- (char **) NULL, 10))
{
- bfd_set_error (bfd_error_no_more_archived_files);
- return NULL;
+ if (last_file == NULL)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else
+ /* XXX These actually have to be a calls to strtoll (at least
+ on 32-bit machines) since the fields's width is 20 and
+ there numbers with more than 32 bits can be represented. */
+ filestart = strtol (arch_xhdr_big (last_file)->nextoff, (char **) NULL,
+ 10);
+
+ /* XXX These actually have to be calls to strtoll (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with more
+ than 32 bits can be represented. */
+ if (filestart == 0
+ || filestart == strtol (xcoff_ardata_big (archive)->memoff,
+ (char **) NULL, 10)
+ || filestart == strtol (xcoff_ardata_big (archive)->symoff,
+ (char **) NULL, 10))
+ {
+ bfd_set_error (bfd_error_no_more_archived_files);
+ return NULL;
+ }
}
return _bfd_get_elt_at_filepos (archive, filestart);
@@ -914,21 +1226,32 @@ xcoff_generic_stat_arch_elt (abfd, s)
bfd *abfd;
struct stat *s;
{
- struct xcoff_ar_hdr *hdrp;
-
if (abfd->arelt_data == NULL)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
- hdrp = arch_xhdr (abfd);
+ if (! xcoff_big_format_p (abfd))
+ {
+ struct xcoff_ar_hdr *hdrp = arch_xhdr (abfd);
+
+ s->st_mtime = strtol (hdrp->date, (char **) NULL, 10);
+ s->st_uid = strtol (hdrp->uid, (char **) NULL, 10);
+ s->st_gid = strtol (hdrp->gid, (char **) NULL, 10);
+ s->st_mode = strtol (hdrp->mode, (char **) NULL, 8);
+ s->st_size = arch_eltdata (abfd)->parsed_size;
+ }
+ else
+ {
+ struct xcoff_ar_hdr_big *hdrp = arch_xhdr_big (abfd);
- s->st_mtime = strtol (hdrp->date, (char **) NULL, 10);
- s->st_uid = strtol (hdrp->uid, (char **) NULL, 10);
- s->st_gid = strtol (hdrp->gid, (char **) NULL, 10);
- s->st_mode = strtol (hdrp->mode, (char **) NULL, 8);
- s->st_size = arch_eltdata (abfd)->parsed_size;
+ s->st_mtime = strtol (hdrp->date, (char **) NULL, 10);
+ s->st_uid = strtol (hdrp->uid, (char **) NULL, 10);
+ s->st_gid = strtol (hdrp->gid, (char **) NULL, 10);
+ s->st_mode = strtol (hdrp->mode, (char **) NULL, 8);
+ s->st_size = arch_eltdata (abfd)->parsed_size;
+ }
return 0;
}
@@ -955,7 +1278,7 @@ normalize_filename (abfd)
/*ARGSUSED*/
static boolean
-xcoff_write_armap (abfd, elength, map, orl_count, stridx)
+xcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
bfd *abfd;
unsigned int elength ATTRIBUTE_UNUSED;
struct orl *map;
@@ -987,7 +1310,7 @@ xcoff_write_armap (abfd, elength, map, orl_count, stridx)
if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR, 1, abfd) != SIZEOF_AR_HDR
|| bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG)
return false;
-
+
bfd_h_put_32 (abfd, orl_count, buf);
if (bfd_write (buf, 1, 4, abfd) != 4)
return false;
@@ -1039,11 +1362,115 @@ xcoff_write_armap (abfd, elength, map, orl_count, stridx)
return true;
}
+/*ARGSUSED*/
+static boolean
+xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
+ bfd *abfd;
+ unsigned int elength ATTRIBUTE_UNUSED;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
+{
+ struct xcoff_ar_hdr_big hdr;
+ char *p;
+ unsigned char buf[4];
+ bfd *sub;
+ file_ptr fileoff;
+ unsigned int i;
+
+ memset (&hdr, 0, sizeof hdr);
+ /* XXX This call actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx));
+ sprintf (hdr.nextoff, "%d", 0);
+ memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, 12);
+ sprintf (hdr.date, "%d", 0);
+ sprintf (hdr.uid, "%d", 0);
+ sprintf (hdr.gid, "%d", 0);
+ sprintf (hdr.mode, "%d", 0);
+ sprintf (hdr.namlen, "%d", 0);
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR_BIG; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_write ((PTR) &hdr, SIZEOF_AR_HDR_BIG, 1, abfd) != SIZEOF_AR_HDR_BIG
+ || bfd_write (XCOFFARFMAG, 1, SXCOFFARFMAG, abfd) != SXCOFFARFMAG)
+ return false;
+
+ bfd_h_put_32 (abfd, orl_count, buf);
+ if (bfd_write (buf, 1, 4, abfd) != 4)
+ return false;
+
+ sub = abfd->archive_head;
+ fileoff = SIZEOF_AR_FILE_HDR_BIG;
+ i = 0;
+ while (sub != NULL && i < orl_count)
+ {
+ size_t namlen;
+
+ while (((bfd *) (map[i]).pos) == sub)
+ {
+ bfd_h_put_32 (abfd, fileoff, buf);
+ if (bfd_write (buf, 1, 4, abfd) != 4)
+ return false;
+ ++i;
+ }
+ namlen = strlen (normalize_filename (sub));
+ namlen = (namlen + 1) &~ 1;
+ fileoff += (SIZEOF_AR_HDR_BIG
+ + namlen
+ + SXCOFFARFMAG
+ + arelt_size (sub));
+ fileoff = (fileoff + 1) &~ 1;
+ sub = sub->next;
+ }
+
+ for (i = 0; i < orl_count; i++)
+ {
+ const char *name;
+ size_t namlen;
+
+ name = *map[i].name;
+ namlen = strlen (name);
+ if (bfd_write (name, 1, namlen + 1, abfd) != namlen + 1)
+ return false;
+ }
+
+ if ((stridx & 1) != 0)
+ {
+ char b;
+
+ b = '\0';
+ if (bfd_write (&b, 1, 1, abfd) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+/*ARGSUSED*/
+static boolean
+xcoff_write_armap (abfd, elength, map, orl_count, stridx)
+ bfd *abfd;
+ unsigned int elength ATTRIBUTE_UNUSED;
+ struct orl *map;
+ unsigned int orl_count;
+ int stridx;
+{
+ if (! xcoff_big_format_p (abfd))
+ return xcoff_write_armap_old (abfd, elength, map, orl_count, stridx);
+ else
+ return xcoff_write_armap_big (abfd, elength, map, orl_count, stridx);
+}
+
/* Write out an XCOFF archive. We always write an entire archive,
rather than fussing with the freelist and so forth. */
static boolean
-xcoff_write_archive_contents (abfd)
+xcoff_write_archive_contents_old (abfd)
bfd *abfd;
{
struct xcoff_ar_file_hdr fhdr;
@@ -1286,6 +1713,285 @@ xcoff_write_archive_contents (abfd)
return true;
}
+
+static boolean
+xcoff_write_archive_contents_big (abfd)
+ bfd *abfd;
+{
+ struct xcoff_ar_file_hdr_big fhdr;
+ size_t count;
+ size_t total_namlen;
+ file_ptr *offsets;
+ boolean makemap;
+ boolean hasobjects;
+ file_ptr prevoff, nextoff;
+ bfd *sub;
+ unsigned int i;
+ struct xcoff_ar_hdr_big ahdr;
+ bfd_size_type size;
+ char *p;
+ char decbuf[13];
+
+ memset (&fhdr, 0, sizeof fhdr);
+ strncpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
+ sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR_BIG);
+ sprintf (fhdr.freeoff, "%d", 0);
+
+ count = 0;
+ total_namlen = 0;
+ for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
+ {
+ ++count;
+ total_namlen += strlen (normalize_filename (sub)) + 1;
+ }
+ offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr));
+ if (offsets == NULL)
+ return false;
+
+ if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0)
+ return false;
+
+ makemap = bfd_has_map (abfd);
+ hasobjects = false;
+ prevoff = 0;
+ nextoff = SIZEOF_AR_FILE_HDR_BIG;
+ for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++)
+ {
+ const char *name;
+ size_t namlen;
+ struct xcoff_ar_hdr_big *ahdrp;
+ bfd_size_type remaining;
+
+ if (makemap && ! hasobjects)
+ {
+ if (bfd_check_format (sub, bfd_object))
+ hasobjects = true;
+ }
+
+ name = normalize_filename (sub);
+ namlen = strlen (name);
+
+ if (sub->arelt_data != NULL)
+ ahdrp = arch_xhdr_big (sub);
+ else
+ ahdrp = NULL;
+
+ if (ahdrp == NULL)
+ {
+ struct stat s;
+
+ memset (&ahdr, 0, sizeof ahdr);
+ ahdrp = &ahdr;
+ /* XXX This should actually be a call to stat64 (at least on
+ 32-bit machines). */
+ if (stat (bfd_get_filename (sub), &s) != 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return false;
+ }
+
+ /* XXX This call actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (ahdrp->size, "%ld", (long) s.st_size);
+ sprintf (ahdrp->date, "%ld", (long) s.st_mtime);
+ sprintf (ahdrp->uid, "%ld", (long) s.st_uid);
+ sprintf (ahdrp->gid, "%ld", (long) s.st_gid);
+ sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode);
+
+ if (sub->arelt_data == NULL)
+ {
+ sub->arelt_data = bfd_alloc (sub, sizeof (struct areltdata));
+ if (sub->arelt_data == NULL)
+ return false;
+ }
+
+ arch_eltdata (sub)->parsed_size = s.st_size;
+ }
+
+ /* XXX These calls actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (ahdrp->prevoff, "%ld", (long) prevoff);
+ sprintf (ahdrp->namlen, "%ld", (long) namlen);
+
+ /* If the length of the name is odd, we write out the null byte
+ after the name as well. */
+ namlen = (namlen + 1) &~ 1;
+
+ remaining = arelt_size (sub);
+ size = (SIZEOF_AR_HDR_BIG
+ + namlen
+ + SXCOFFARFMAG
+ + remaining);
+
+ BFD_ASSERT (nextoff == bfd_tell (abfd));
+
+ offsets[i] = nextoff;
+
+ prevoff = nextoff;
+ nextoff += size + (size & 1);
+
+ sprintf (ahdrp->nextoff, "%ld", (long) nextoff);
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR_BIG; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_write ((PTR) ahdrp, 1, SIZEOF_AR_HDR_BIG, abfd)
+ != SIZEOF_AR_HDR_BIG
+ || bfd_write ((PTR) name, 1, namlen, abfd) != namlen
+ || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd)
+ != SXCOFFARFMAG))
+ return false;
+
+ if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
+ return false;
+ while (remaining != 0)
+ {
+ bfd_size_type amt;
+ bfd_byte buffer[DEFAULT_BUFFERSIZE];
+
+ amt = sizeof buffer;
+ if (amt > remaining)
+ amt = remaining;
+ if (bfd_read (buffer, 1, amt, sub) != amt
+ || bfd_write (buffer, 1, amt, abfd) != amt)
+ return false;
+ remaining -= amt;
+ }
+
+ if ((size & 1) != 0)
+ {
+ bfd_byte b;
+
+ b = '\0';
+ if (bfd_write (&b, 1, 1, abfd) != 1)
+ return false;
+ }
+ }
+
+ /* XXX This call actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
+
+ /* Write out the member table. */
+
+ BFD_ASSERT (nextoff == bfd_tell (abfd));
+ /* XXX This call actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (fhdr.memoff, "%ld", (long) nextoff);
+
+ memset (&ahdr, 0, sizeof ahdr);
+ /* XXX The next two calls actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen));
+ sprintf (ahdr.prevoff, "%ld", (long) prevoff);
+ sprintf (ahdr.date, "%d", 0);
+ sprintf (ahdr.uid, "%d", 0);
+ sprintf (ahdr.gid, "%d", 0);
+ sprintf (ahdr.mode, "%d", 0);
+ sprintf (ahdr.namlen, "%d", 0);
+
+ size = (SIZEOF_AR_HDR_BIG
+ + 12
+ + count * 12
+ + total_namlen
+ + SXCOFFARFMAG);
+
+ prevoff = nextoff;
+ nextoff += size + (size & 1);
+
+ if (makemap && hasobjects)
+ /* XXX This call actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (ahdr.nextoff, "%ld", (long) nextoff);
+ else
+ sprintf (ahdr.nextoff, "%d", 0);
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR_BIG; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_write ((PTR) &ahdr, 1, SIZEOF_AR_HDR_BIG, abfd) != SIZEOF_AR_HDR_BIG
+ || (bfd_write ((PTR) XCOFFARFMAG, 1, SXCOFFARFMAG, abfd)
+ != SXCOFFARFMAG))
+ return false;
+
+ sprintf (decbuf, "%-12ld", (long) count);
+ if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12)
+ return false;
+ for (i = 0; i < count; i++)
+ {
+ sprintf (decbuf, "%-12ld", (long) offsets[i]);
+ if (bfd_write ((PTR) decbuf, 1, 12, abfd) != 12)
+ return false;
+ }
+ for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
+ {
+ const char *name;
+ size_t namlen;
+
+ name = normalize_filename (sub);
+ namlen = strlen (name);
+ if (bfd_write ((PTR) name, 1, namlen + 1, abfd) != namlen + 1)
+ return false;
+ }
+ if ((size & 1) != 0)
+ {
+ bfd_byte b;
+
+ b = '\0';
+ if (bfd_write ((PTR) &b, 1, 1, abfd) != 1)
+ return false;
+ }
+
+ /* Write out the armap, if appropriate. */
+
+ if (! makemap || ! hasobjects)
+ sprintf (fhdr.symoff, "%d", 0);
+ else
+ {
+ BFD_ASSERT (nextoff == bfd_tell (abfd));
+ /* XXX This call actually should use %lld (at least on 32-bit
+ machines) since the fields's width is 20 and there numbers with
+ more than 32 bits can be represented. */
+ sprintf (fhdr.symoff, "%ld", (long) nextoff);
+ bfd_ardata (abfd)->tdata = (PTR) &fhdr;
+ if (! _bfd_compute_and_write_armap (abfd, 0))
+ return false;
+ }
+
+ /* Write out the archive file header. */
+
+ /* We need spaces, not null bytes, in the header. */
+ for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR_BIG; p++)
+ if (*p == '\0')
+ *p = ' ';
+
+ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
+ || (bfd_write ((PTR) &fhdr, SIZEOF_AR_FILE_HDR_BIG, 1, abfd) !=
+ SIZEOF_AR_FILE_HDR_BIG))
+ return false;
+
+ return true;
+}
+
+static boolean
+xcoff_write_archive_contents (abfd)
+ bfd *abfd;
+{
+ if (! xcoff_big_format_p (abfd))
+ return xcoff_write_archive_contents_old (abfd);
+ else
+ return xcoff_write_archive_contents_big (abfd);
+}
/* We can't use the usual coff_sizeof_headers routine, because AIX
always uses an a.out header. */
@@ -1378,7 +2084,7 @@ const bfd_target
#else
"aixcoff-rs6000", /* name */
#endif
- bfd_target_coff_flavour,
+ bfd_target_coff_flavour,
BFD_ENDIAN_BIG, /* data byte order is big */
BFD_ENDIAN_BIG, /* header byte order is big */
OpenPOWER on IntegriCloud