summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2009-06-02 19:06:56 +0000
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2009-06-02 19:06:56 +0000
commitcabc7147afe4990f585fd1eb83ea4f2c7f92b522 (patch)
tree866fc7cba54f627d859513db2f05cc0ceeb96db2
parent329cbab59d9bb1bfbfc5f7ff268456618474d51f (diff)
downloadgcc-cabc7147afe4990f585fd1eb83ea4f2c7f92b522.tar.gz
gcc/
* Makefile.in (COLLECT2_OBJS): Add collect2-aix.o. (collect2.o): Depend on collect2-aix.h. (collect2-aix.o): New rule. * collect2-aix.h: New file. * collect2-aix.c: Likewise. * collect2.c: Include collect2-aix.h. Don't undefine OBJECT_FORMAT_COFF if CROSS_AIX_SUPPORT is defined. Guard native includes with #ifndef CROSS_DIRECTORY_STRUCTURE. Use TARGET_AIX_VERSION instead of _AIX51. * config/rs6000/aix43.h (TARGET_AIX_VERSION): Define. * config/rs6000/aix51.h (TARGET_AIX_VERSION): Likewise. * config/rs6000/aix52.h (TARGET_AIX_VERSION): Likewise. * config/rs6000/aix53.h (TARGET_AIX_VERSION): Likewise. * config/rs6000/aix61.h (TARGET_AIX_VERSION): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@148096 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/Makefile.in9
-rw-r--r--gcc/collect2-aix.c371
-rw-r--r--gcc/collect2-aix.h301
-rw-r--r--gcc/collect2.c7
-rw-r--r--gcc/config/rs6000/aix43.h2
-rw-r--r--gcc/config/rs6000/aix51.h2
-rw-r--r--gcc/config/rs6000/aix52.h2
-rw-r--r--gcc/config/rs6000/aix53.h2
-rw-r--r--gcc/config/rs6000/aix61.h2
10 files changed, 711 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d56760b6d8c..06f8e77d3f0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
2009-06-02 Richard Sandiford <r.sandiford@uk.ibm.com>
+ * Makefile.in (COLLECT2_OBJS): Add collect2-aix.o.
+ (collect2.o): Depend on collect2-aix.h.
+ (collect2-aix.o): New rule.
+ * collect2-aix.h: New file.
+ * collect2-aix.c: Likewise.
+ * collect2.c: Include collect2-aix.h. Don't undefine
+ OBJECT_FORMAT_COFF if CROSS_AIX_SUPPORT is defined.
+ Guard native includes with #ifndef CROSS_DIRECTORY_STRUCTURE.
+ Use TARGET_AIX_VERSION instead of _AIX51.
+ * config/rs6000/aix43.h (TARGET_AIX_VERSION): Define.
+ * config/rs6000/aix51.h (TARGET_AIX_VERSION): Likewise.
+ * config/rs6000/aix52.h (TARGET_AIX_VERSION): Likewise.
+ * config/rs6000/aix53.h (TARGET_AIX_VERSION): Likewise.
+ * config/rs6000/aix61.h (TARGET_AIX_VERSION): Likewise.
+
+2009-06-02 Richard Sandiford <r.sandiford@uk.ibm.com>
+
* collect2.c (ignore_library): Avoid premature post-increment
and null deference.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e76e256c78d..381c189960c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1897,7 +1897,7 @@ ebitmap.o: ebitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(EBITMAP_H) $(RTL_H) $(FLAGS_H) $(OBSTACK_H)
sparseset.o: sparseset.c $(SYSTEM_H) sparseset.h $(CONFIG_H)
-COLLECT2_OBJS = collect2.o tlink.o intl.o version.o
+COLLECT2_OBJS = collect2.o collect2-aix.o tlink.o intl.o version.o
COLLECT2_LIBS = @COLLECT2_LIBS@
collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
# Don't try modifying collect2 (aka ld) in place--it might be linking this.
@@ -1906,10 +1906,13 @@ collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
mv -f T$@ $@
collect2.o : collect2.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h \
- $(OBSTACK_H) $(DEMANGLE_H) collect2.h version.h
+ $(OBSTACK_H) $(DEMANGLE_H) collect2.h collect2-aix.h version.h
$(COMPILER) $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) \
-DTARGET_MACHINE=\"$(target_noncanonical)\" \
- -c $(srcdir)/collect2.c $(OUTPUT_OPTION)
+ -c $(srcdir)/collect2.c $(OUTPUT_OPTION) @TARGET_SYSTEM_ROOT_DEFINE@
+
+collect2-aix.o : collect2-aix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+ collect2-aix.h
tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(OBSTACK_H) collect2.h intl.h
diff --git a/gcc/collect2-aix.c b/gcc/collect2-aix.c
new file mode 100644
index 00000000000..7d25e7e6b89
--- /dev/null
+++ b/gcc/collect2-aix.c
@@ -0,0 +1,371 @@
+/* AIX cross support for collect2.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "collect2-aix.h"
+
+#ifdef CROSS_AIX_SUPPORT
+
+#include <sys/mman.h>
+
+/* Read SIZE bytes starting at DATA as a big-endian value. */
+
+static inline bfd_vma
+read_value (char *data, unsigned int size)
+{
+ bfd_vma value;
+ unsigned int i;
+
+ value = 0;
+ for (i = 0; i < size; i++)
+ {
+ value <<= 8;
+ value += (unsigned char) data[i];
+ }
+ return value;
+}
+
+/* FIELD is a char array. Read the contents as a big-endian integer. */
+#define READ_FIELD(FIELD) \
+ read_value (FIELD, sizeof (FIELD))
+
+/* OBJECT is a char pointer to an in-file object of type struct TYPE.
+ Return the address of field FIELD. */
+#define OBJECT_FIELD(OBJECT, TYPE, FIELD) \
+ (OBJECT) + offsetof (struct TYPE, FIELD)
+
+/* Return the size of FIELD, which is a field of struct TYPE. */
+#define FIELD_SIZE(TYPE, FIELD) \
+ sizeof (((struct TYPE *) (0))->FIELD)
+
+/* OBJECT is a char pointer to an in-file object of type struct TYPE.
+ Read the value of field FIELD as a big-endian integer. */
+#define READ_OBJECT(OBJECT, TYPE, FIELD) \
+ read_value (OBJECT_FIELD (OBJECT, TYPE, FIELD), FIELD_SIZE (TYPE, FIELD))
+
+/* Copy FIELD from an external structure of type TYPE at address FROM
+ to an internal structure pointed to by TO. */
+#define COPY_FIELD(TO, FROM, TYPE, FIELD) \
+ ((TO)->FIELD = READ_OBJECT (FROM, TYPE, FIELD))
+
+/* Return true if STRING is less than SIZE bytes long. EXTRA_TERMINATOR
+ is another character (besides '\0') that acts as a terminator,
+ or '\0' if none. */
+
+static bool
+string_within_bounds_p (const char *string, size_t size, char extra_terminator)
+{
+ const char *p;
+
+ for (p = string; p < string + size; p++)
+ if (*p == '\0' || *p == extra_terminator)
+ return true;
+ return false;
+}
+
+/* STRING is a pointer to a char array. Try to read its value as an
+ ASCII-encoded integer. On success, return true and store the result
+ in TARGET. */
+#define PARSE_INTEGER(TARGET, STRING) \
+ (string_within_bounds_p (&(STRING)[0], sizeof (STRING), ' ') \
+ && ((TARGET) = strtoul (STRING, NULL, 0), true))
+
+/* Check that LDFILE's current object has SIZE bytes starting at OFFSET. */
+
+static inline bool
+within_object_p (LDFILE *ldfile, size_t offset, size_t size)
+{
+ return offset <= ldfile->object_size && offset + size <= ldfile->object_size;
+}
+
+/* Try to read the file header for an XCOFF object at OFFSET bytes into
+ LDFILE. The object is expected to be OBJECT_SIZE bytes in size.
+ If the object is a member of an archive, NEXT_MEMBER is the offset
+ of the next member, otherwise it is -1.
+
+ Return true on success, recording the object information in LDFILE. */
+
+static bool
+read_xcoff_object (LDFILE *ldfile, size_t offset, size_t object_size,
+ off_t next_member)
+{
+ struct internal_filehdr *internal;
+ char *external;
+ void *map;
+ size_t page_size;
+
+ /* First try to map the file into memory. */
+ page_size = getpagesize ();
+ ldfile->page_offset = offset & (page_size - 1);
+ map = mmap (NULL, object_size + ldfile->page_offset, PROT_READ,
+ MAP_SHARED, ldfile->fd, offset - ldfile->page_offset);
+ if (map == MAP_FAILED)
+ return false;
+
+ /* Record the success. */
+ ldfile->object = (char *) map + ldfile->page_offset;
+ ldfile->object_size = object_size;
+ ldfile->next_member = next_member;
+
+ /* Read the magic value to determine the type of file. */
+ if (!within_object_p (ldfile, 0, F_MAGIC_SIZE))
+ return false;
+
+ internal = &ldfile->filehdr;
+ external = ldfile->object;
+ internal->f_magic = read_value (external, F_MAGIC_SIZE);
+ if (internal->f_magic == U802TOCMAGIC)
+ {
+ if (!within_object_p (ldfile, 0, sizeof (struct external_filehdr_32)))
+ return false;
+
+ COPY_FIELD (internal, external, external_filehdr_32, f_nscns);
+ COPY_FIELD (internal, external, external_filehdr_32, f_timdat);
+ COPY_FIELD (internal, external, external_filehdr_32, f_symptr);
+ COPY_FIELD (internal, external, external_filehdr_32, f_nsyms);
+ COPY_FIELD (internal, external, external_filehdr_32, f_opthdr);
+ COPY_FIELD (internal, external, external_filehdr_32, f_flags);
+ return true;
+ }
+ else if (internal->f_magic == U803XTOCMAGIC
+ || internal->f_magic == U64_TOCMAGIC)
+ {
+ if (!within_object_p (ldfile, 0, sizeof (struct external_filehdr_64)))
+ return false;
+
+ COPY_FIELD (internal, external, external_filehdr_64, f_nscns);
+ COPY_FIELD (internal, external, external_filehdr_64, f_timdat);
+ COPY_FIELD (internal, external, external_filehdr_64, f_symptr);
+ COPY_FIELD (internal, external, external_filehdr_64, f_nsyms);
+ COPY_FIELD (internal, external, external_filehdr_64, f_opthdr);
+ COPY_FIELD (internal, external, external_filehdr_64, f_flags);
+ return true;
+ }
+ return false;
+}
+
+/* Try to read an archive member at OFFSET bytes into LDFILE.
+ Return true on success, recording the member and object
+ information in LDFILE. */
+
+static bool
+read_archive_member (LDFILE *ldfile, size_t offset)
+{
+ struct external_big_ar_member member;
+ size_t namlen;
+ size_t size;
+ off_t next_member;
+
+ if (lseek (ldfile->fd, offset, SEEK_SET) >= 0
+ && read (ldfile->fd, &member, sizeof (member)) == sizeof (member)
+ && PARSE_INTEGER (namlen, member.ar_namlen)
+ /* Stop once we reach the member table entry, which has a name
+ of length 0. */
+ && namlen > 0
+ && PARSE_INTEGER (size, member.ar_size)
+ && PARSE_INTEGER (next_member, member.ar_nextoff))
+ {
+ /* The archive is followed by an even-padded name, then by
+ a magic string of length SXCOFFARFMAG. The object itself
+ starts after that. */
+ offset += sizeof (member) + namlen + SXCOFFARFMAG;
+ offset += offset & 1;
+ return read_xcoff_object (ldfile, offset, size, next_member);
+ }
+ return false;
+}
+
+/* Try to treat LDFILE as a non-empty big archive. Return true
+ on success, storing the member and object information for
+ the first member in LDFILE. */
+
+static bool
+read_big_archive (LDFILE *ldfile)
+{
+ struct external_big_ar_filehdr filehdr;
+ size_t offset;
+
+ return (lseek (ldfile->fd, 0L, SEEK_SET) == 0
+ && read (ldfile->fd, &filehdr, sizeof (filehdr)) == sizeof (filehdr)
+ && memcmp (filehdr.fl_magic, FL_MAGIC_BIG_AR, FL_MAGIC_SIZE) == 0
+ && PARSE_INTEGER (offset, filehdr.fl_firstmemoff)
+ && read_archive_member (ldfile, offset));
+}
+
+/* LDFILE is a zero-initialized structure. Try to open FILENAME,
+ returning true on success. */
+
+static bool
+open_file (LDFILE *ldfile, const char *filename)
+{
+ struct stat st;
+
+ ldfile->fd = open (filename, O_RDONLY);
+ if (ldfile->fd < 0)
+ return false;
+
+ if (read_big_archive (ldfile))
+ return true;
+
+ if (fstat (ldfile->fd, &st) < 0)
+ return false;
+
+ return read_xcoff_object (ldfile, 0, st.st_size, -1);
+}
+
+/* Release the memory associated with the current object, if one has
+ been mapped. */
+
+static void
+free_object (LDFILE *ldfile)
+{
+ if (ldfile->object)
+ munmap (ldfile->object - ldfile->page_offset,
+ ldfile->object_size + ldfile->page_offset);
+}
+
+/* Free LDFILE and all resources associated with it. */
+
+static void
+free_ldfile (LDFILE *ldfile)
+{
+ if (ldfile->fd >= 0)
+ close (ldfile->fd);
+ XDELETE (ldfile);
+}
+
+/* Implement the API-defined ldopen function. */
+
+LDFILE *
+ldopen (char *filename, LDFILE *ldfile)
+{
+ if (ldfile == NULL)
+ {
+ ldfile = XCNEW (LDFILE);
+ if (!open_file (ldfile, filename))
+ {
+ free_object (ldfile);
+ free_ldfile (ldfile);
+ return NULL;
+ }
+ }
+ return ldfile;
+}
+
+/* Implement the API-defined ldtbread function. */
+
+int
+ldtbread (LDFILE *ldfile, long index, SYMENT *internal)
+{
+ size_t offset, name_length;
+ char *external;
+
+ /* Make sure that the symbol index is valid. */
+ if (index < 0 || index >= HEADER (ldfile).f_nsyms)
+ return FAILURE;
+
+ /* Work out the offset of the symbol table entry. */
+ offset = HEADER (ldfile).f_symptr + index * sizeof (struct external_syment);
+ if (!within_object_p (ldfile, offset, sizeof (struct external_syment)))
+ return FAILURE;
+
+ /* Read all the fields. The format differs between 32-bit and
+ 64-bit files. */
+ external = ldfile->object + offset;
+ if (HEADER (ldfile).f_magic == U802TOCMAGIC)
+ {
+ /* Copy the n_zeroes/n_offset interpretation. */
+ internal->n_zeroes = READ_OBJECT (external, external_syment,
+ u.xcoff32.u.u.n_zeroes);
+ internal->n_offset = READ_OBJECT (external, external_syment,
+ u.xcoff32.u.u.n_offset);
+
+ /* Copy the n_name interpretation. The internal version has room
+ for a null terminator. */
+ name_length = FIELD_SIZE (external_syment, u.xcoff32.u.n_name);
+ memcpy (internal->n_name,
+ external + offsetof (struct external_syment, u.xcoff32.u.n_name),
+ name_length);
+ internal->n_name[name_length] = 0;
+
+ internal->n_value = READ_OBJECT (external, external_syment,
+ u.xcoff32.n_value);
+ }
+ else
+ {
+ internal->n_zeroes = 0;
+ internal->n_offset = READ_OBJECT (external, external_syment,
+ u.xcoff64.n_offset);
+ internal->n_value = READ_OBJECT (external, external_syment,
+ u.xcoff64.n_value);
+ }
+ COPY_FIELD (internal, external, external_syment, n_scnum);
+ COPY_FIELD (internal, external, external_syment, n_type);
+ COPY_FIELD (internal, external, external_syment, n_sclass);
+ COPY_FIELD (internal, external, external_syment, n_numaux);
+ return SUCCESS;
+}
+
+/* Implement the API-defined ldgetname function. */
+
+char *
+ldgetname (LDFILE *ldfile, SYMENT *symbol)
+{
+ char *name;
+ size_t offset;
+
+ /* If the zeroes field is nonzero, the name is in the symbol table
+ entry itself. */
+ if (symbol->n_zeroes != 0)
+ return symbol->n_name;
+
+ /* Otherwise, the symbol table entry contains an offset into the
+ string table, which starts after the end of the symbol table. */
+ offset = (HEADER (ldfile).f_symptr
+ + HEADER (ldfile).f_nsyms * sizeof (struct external_syment)
+ + symbol->n_offset);
+ if (offset >= ldfile->object_size)
+ return NULL;
+
+ /* Make sure that the name is entirely contained within the object. */
+ name = ldfile->object + offset;
+ if (!string_within_bounds_p (name, ldfile->object_size - offset, '\0'))
+ return NULL;
+
+ return name;
+}
+
+/* Implement the API-defined ldclose function. */
+
+int
+ldclose (LDFILE *ldfile)
+{
+ free_object (ldfile);
+ if (ldfile->next_member >= 0
+ && read_archive_member (ldfile, ldfile->next_member))
+ return FAILURE;
+
+ free_ldfile (ldfile);
+ return SUCCESS;
+}
+
+#endif
diff --git a/gcc/collect2-aix.h b/gcc/collect2-aix.h
new file mode 100644
index 00000000000..1ab313d0f34
--- /dev/null
+++ b/gcc/collect2-aix.h
@@ -0,0 +1,301 @@
+/* AIX cross support for collect2.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* collect2-aix.c requires mmap support. It should otherwise be
+ fairly portable. */
+#if defined(CROSS_DIRECTORY_STRUCTURE) \
+ && defined(TARGET_AIX_VERSION) \
+ && HAVE_MMAP
+
+#define CROSS_AIX_SUPPORT 1
+
+/* -------------------------------------------------------------------------
+ Definitions adapted from bfd. (Fairly heavily adapted in some cases.)
+ ------------------------------------------------------------------------- */
+
+/* Compatiblity types for bfd. */
+typedef unsigned HOST_WIDE_INT bfd_vma;
+
+/* The size of an archive's fl_magic field. */
+#define FL_MAGIC_SIZE 8
+
+/* The expected contents of fl_magic for big archives. */
+#define FL_MAGIC_BIG_AR "<bigaf>\012"
+
+/* The size of each offset string in the header of a big archive. */
+#define AR_BIG_OFFSET_SIZE 20
+
+/* The format of the file header in a "big" XCOFF archive. */
+struct external_big_ar_filehdr
+{
+ /* Magic string. */
+ char fl_magic[FL_MAGIC_SIZE];
+
+ /* Offset of the member table (decimal ASCII string). */
+ char fl_memoff[AR_BIG_OFFSET_SIZE];
+
+ /* Offset of the global symbol table for 32-bit objects (decimal ASCII
+ string). */
+ char fl_symoff[AR_BIG_OFFSET_SIZE];
+
+ /* Offset of the global symbol table for 64-bit objects (decimal ASCII
+ string). */
+ char fl_symoff64[AR_BIG_OFFSET_SIZE];
+
+ /* Offset of the first member in the archive (decimal ASCII string). */
+ char fl_firstmemoff[AR_BIG_OFFSET_SIZE];
+
+ /* Offset of the last member in the archive (decimal ASCII string). */
+ char fl_lastmemoff[AR_BIG_OFFSET_SIZE];
+
+ /* Offset of the first member on the free list (decimal ASCII
+ string). */
+ char fl_freeoff[AR_BIG_OFFSET_SIZE];
+};
+
+/* Each archive name is followed by this many bytes of magic string. */
+#define SXCOFFARFMAG 2
+
+/* The format of a member header in a "big" XCOFF archive. */
+struct external_big_ar_member
+{
+ /* File size not including the header (decimal ASCII string). */
+ char ar_size[AR_BIG_OFFSET_SIZE];
+
+ /* File offset of next archive member (decimal ASCII string). */
+ char ar_nextoff[AR_BIG_OFFSET_SIZE];
+
+ /* File offset of previous archive member (decimal ASCII string). */
+ char ar_prevoff[AR_BIG_OFFSET_SIZE];
+
+ /* File mtime (decimal ASCII string). */
+ char ar_date[12];
+
+ /* File UID (decimal ASCII string). */
+ char ar_uid[12];
+
+ /* File GID (decimal ASCII string). */
+ char ar_gid[12];
+
+ /* File mode (octal ASCII string). */
+ char ar_mode[12];
+
+ /* Length of file name (decimal ASCII string). */
+ char ar_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. */
+};
+
+/* The known values of f_magic in an XCOFF file header. */
+#define U802WRMAGIC 0730 /* Writeable text segments. */
+#define U802ROMAGIC 0735 /* Readonly sharable text segments. */
+#define U802TOCMAGIC 0737 /* Readonly text segments and TOC. */
+#define U803XTOCMAGIC 0757 /* Aix 4.3 64-bit XCOFF. */
+#define U64_TOCMAGIC 0767 /* AIX 5+ 64-bit XCOFF. */
+
+/* The number of bytes in an XCOFF file's f_magic field. */
+#define F_MAGIC_SIZE 2
+
+/* The format of a 32-bit XCOFF file header. */
+struct external_filehdr_32
+{
+ /* The magic number. */
+ char f_magic[F_MAGIC_SIZE];
+
+ /* The number of sections. */
+ char f_nscns[2];
+
+ /* Time & date stamp. */
+ char f_timdat[4];
+
+ /* The offset of the symbol table from the start of the file. */
+ char f_symptr[4];
+
+ /* The number of entries in the symbol table. */
+ char f_nsyms[4];
+
+ /* The size of the auxillary header. */
+ char f_opthdr[2];
+
+ /* Flags. */
+ char f_flags[2];
+};
+
+/* The format of a 64-bit XCOFF file header. */
+struct external_filehdr_64
+{
+ /* The magic number. */
+ char f_magic[F_MAGIC_SIZE];
+
+ /* The number of sections. */
+ char f_nscns[2];
+
+ /* Time & date stamp. */
+ char f_timdat[4];
+
+ /* The offset of the symbol table from the start of the file. */
+ char f_symptr[8];
+
+ /* The size of the auxillary header. */
+ char f_opthdr[2];
+
+ /* Flags. */
+ char f_flags[2];
+
+ /* The number of entries in the symbol table. */
+ char f_nsyms[4];
+};
+
+/* An internal representation of the XCOFF file header. */
+struct internal_filehdr
+{
+ unsigned short f_magic;
+ unsigned short f_nscns;
+ long f_timdat;
+ bfd_vma f_symptr;
+ long f_nsyms;
+ unsigned short f_opthdr;
+ unsigned short f_flags;
+};
+
+/* Symbol classes have their names in the debug section if this flag
+ is set. */
+#define DBXMASK 0x80
+
+/* The format of an XCOFF symbol-table entry. */
+struct external_syment
+{
+ union {
+ struct {
+ union {
+ /* The name of the symbol. There is an implicit null character
+ after the end of the array. */
+ char n_name[8];
+ struct {
+ /* If n_zeroes is zero, n_offset is the offset the name from
+ the start of the string table. */
+ char n_zeroes[4];
+ char n_offset[4];
+ } u;
+ } u;
+
+ /* The symbol's value. */
+ char n_value[4];
+ } xcoff32;
+ struct {
+ /* The symbol's value. */
+ char n_value[8];
+
+ /* The offset of the symbol from the start of the string table. */
+ char n_offset[4];
+ } xcoff64;
+ } u;
+
+ /* The number of the section to which this symbol belongs. */
+ char n_scnum[2];
+
+ /* The type of symbol. (It can be interpreted as an n_lang
+ and an n_cpu byte, but we don't care about that here.) */
+ char n_type[2];
+
+ /* The class of symbol (a C_* value). */
+ char n_sclass[1];
+
+ /* The number of auxillary symbols attached to this entry. */
+ char n_numaux[1];
+};
+
+/* Definitions required by collect2. */
+#define C_EXT 2
+
+#define F_SHROBJ 0x2000
+
+#define N_UNDEF ((short) 0)
+#define N_TMASK 060
+#define N_BTSHFT 4
+
+#define DT_NON 0
+#define DT_FCN 2
+
+/* -------------------------------------------------------------------------
+ Local code.
+ ------------------------------------------------------------------------- */
+
+/* An internal representation of an XCOFF symbol-table entry,
+ which is associated with the API-defined SYMENT type. */
+struct internal_syment
+{
+ char n_name[9];
+ unsigned int n_zeroes;
+ bfd_vma n_offset;
+ bfd_vma n_value;
+ short n_scnum;
+ unsigned short n_flags;
+ unsigned short n_type;
+ unsigned char n_sclass;
+ unsigned char n_numaux;
+};
+typedef struct internal_syment SYMENT;
+
+/* The internal representation of the API-defined LDFILE type. */
+struct internal_ldfile
+{
+ /* The file handle for the associated file, or -1 if it hasn't been
+ opened yet. */
+ int fd;
+
+ /* The start of the current XCOFF object, if one has been mapped
+ into memory. Null otherwise. */
+ char *object;
+
+ /* The offset of OBJECT from the start of the containing page. */
+ size_t page_offset;
+
+ /* The size of the file pointed to by OBJECT. Valid iff OFFSET
+ is nonnull. */
+ size_t object_size;
+
+ /* The offset of the next member in an archive after OBJECT,
+ or -1 if this isn't an archive. Valid iff OFFSET is nonnull. */
+ off_t next_member;
+
+ /* The parsed version of the XCOFF file header. */
+ struct internal_filehdr filehdr;
+};
+typedef struct internal_ldfile LDFILE;
+
+/* The API allows the file header to be directly accessed via this macro. */
+#define HEADER(FILE) ((FILE)->filehdr)
+
+/* API-defined return codes. SUCCESS must be > 0 and FAILURE must be <= 0. */
+#define SUCCESS 1
+#define FAILURE 0
+
+/* API-defined functions. */
+extern LDFILE *ldopen (char *, LDFILE *);
+extern char *ldgetname (LDFILE *, SYMENT *);
+extern int ldtbread (LDFILE *, long, SYMENT *);
+extern int ldclose (LDFILE *);
+
+#endif
diff --git a/gcc/collect2.c b/gcc/collect2.c
index a500147e563..660664dd29a 100644
--- a/gcc/collect2.c
+++ b/gcc/collect2.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#define COLLECT
#include "collect2.h"
+#include "collect2-aix.h"
#include "demangle.h"
#include "obstack.h"
#include "intl.h"
@@ -54,7 +55,9 @@ along with GCC; see the file COPYING3. If not see
cross-versions are in the proper directories. */
#ifdef CROSS_DIRECTORY_STRUCTURE
+#ifndef CROSS_AIX_SUPPORT
#undef OBJECT_FORMAT_COFF
+#endif
#undef MD_EXEC_PREFIX
#undef REAL_LD_FILE_NAME
#undef REAL_NM_FILE_NAME
@@ -72,6 +75,7 @@ along with GCC; see the file COPYING3. If not see
#ifdef OBJECT_FORMAT_COFF
+#ifndef CROSS_DIRECTORY_STRUCTURE
#include <a.out.h>
#include <ar.h>
@@ -86,6 +90,7 @@ along with GCC; see the file COPYING3. If not see
#endif
#include <ldfcn.h>
+#endif
/* Some systems have an ISCOFF macro, but others do not. In some cases
the macro may be wrong. MY_ISCOFF is defined in tm.h files for machines
@@ -2409,7 +2414,7 @@ scan_libraries (const char *prog_name)
# define GCC_SYMZERO(X) 0
/* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */
-#ifdef _AIX51
+#if TARGET_AIX_VERSION >= 51
# define GCC_CHECK_HDR(X) \
((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
|| (HEADER (X).f_magic == 0767 && aix64_flag))
diff --git a/gcc/config/rs6000/aix43.h b/gcc/config/rs6000/aix43.h
index 4b769ca8d87..bbe23373060 100644
--- a/gcc/config/rs6000/aix43.h
+++ b/gcc/config/rs6000/aix43.h
@@ -187,3 +187,5 @@ do { \
/* This target uses the aix64.opt file. */
#define TARGET_USES_AIX64_OPT 1
+
+#define TARGET_AIX_VERSION 43
diff --git a/gcc/config/rs6000/aix51.h b/gcc/config/rs6000/aix51.h
index 7bac90a3f00..32bdbb41f28 100644
--- a/gcc/config/rs6000/aix51.h
+++ b/gcc/config/rs6000/aix51.h
@@ -191,3 +191,5 @@ do { \
but does not have crtbegin/end. */
#define TARGET_USE_JCR_SECTION 0
+
+#define TARGET_AIX_VERSION 51
diff --git a/gcc/config/rs6000/aix52.h b/gcc/config/rs6000/aix52.h
index e1fcfa9516b..8d6c2411621 100644
--- a/gcc/config/rs6000/aix52.h
+++ b/gcc/config/rs6000/aix52.h
@@ -201,3 +201,5 @@ extern long long int atoll(const char *);
but does not have crtbegin/end. */
#define TARGET_USE_JCR_SECTION 0
+
+#define TARGET_AIX_VERSION 52
diff --git a/gcc/config/rs6000/aix53.h b/gcc/config/rs6000/aix53.h
index e941fa48277..6172e76aad2 100644
--- a/gcc/config/rs6000/aix53.h
+++ b/gcc/config/rs6000/aix53.h
@@ -197,3 +197,5 @@ extern long long int atoll(const char *);
but does not have crtbegin/end. */
#define TARGET_USE_JCR_SECTION 0
+
+#define TARGET_AIX_VERSION 53
diff --git a/gcc/config/rs6000/aix61.h b/gcc/config/rs6000/aix61.h
index f3f31ac6e14..c0899d8c513 100644
--- a/gcc/config/rs6000/aix61.h
+++ b/gcc/config/rs6000/aix61.h
@@ -202,3 +202,5 @@ extern long long int atoll(const char *);
/* Default to 128 bit long double. */
#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 128
+
+#define TARGET_AIX_VERSION 61