184865Sobrien/* BFD back-end for IBM RS/6000 "XCOFF" files.
2218822Sdim   Copyright 1990-1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
384865Sobrien   Free Software Foundation, Inc.
4218822Sdim   Written by Metin G. Ozisik, Mimi Phuong-Thao Vo, and John Gilmore.
584865Sobrien   Archive support from Damon A. Permezel.
684865Sobrien   Contributed by IBM Corporation and Cygnus Support.
784865Sobrien
884865SobrienThis file is part of BFD, the Binary File Descriptor library.
984865Sobrien
1084865SobrienThis program is free software; you can redistribute it and/or modify
1184865Sobrienit under the terms of the GNU General Public License as published by
1284865Sobrienthe Free Software Foundation; either version 2 of the License, or
1384865Sobrien(at your option) any later version.
1484865Sobrien
1584865SobrienThis program is distributed in the hope that it will be useful,
1684865Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1784865SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1884865SobrienGNU General Public License for more details.
1984865Sobrien
2084865SobrienYou should have received a copy of the GNU General Public License
2184865Sobrienalong with this program; if not, write to the Free Software
22218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2384865Sobrien
24218822Sdim#include "sysdep.h"
2584865Sobrien#include "bfd.h"
2689857Sobrien#include "bfdlink.h"
2784865Sobrien#include "libbfd.h"
2884865Sobrien#include "coff/internal.h"
2989857Sobrien#include "coff/xcoff.h"
3084865Sobrien#include "coff/rs6000.h"
3184865Sobrien#include "libcoff.h"
3289857Sobrien#include "libxcoff.h"
3384865Sobrien
34130561Sobrienextern bfd_boolean _bfd_xcoff_mkobject
35130561Sobrien  PARAMS ((bfd *));
36130561Sobrienextern bfd_boolean _bfd_xcoff_copy_private_bfd_data
37130561Sobrien  PARAMS ((bfd *, bfd *));
38130561Sobrienextern bfd_boolean _bfd_xcoff_is_local_label_name
39130561Sobrien  PARAMS ((bfd *, const char *));
4089857Sobrienextern reloc_howto_type *_bfd_xcoff_reloc_type_lookup
4189857Sobrien  PARAMS ((bfd *, bfd_reloc_code_real_type));
42130561Sobrienextern bfd_boolean _bfd_xcoff_slurp_armap
43130561Sobrien  PARAMS ((bfd *));
44130561Sobrienextern const bfd_target *_bfd_xcoff_archive_p
45130561Sobrien  PARAMS ((bfd *));
46130561Sobrienextern PTR _bfd_xcoff_read_ar_hdr
47130561Sobrien  PARAMS ((bfd *));
48130561Sobrienextern bfd *_bfd_xcoff_openr_next_archived_file
49130561Sobrien  PARAMS ((bfd *, bfd *));
50130561Sobrienextern int _bfd_xcoff_stat_arch_elt
51130561Sobrien  PARAMS ((bfd *, struct stat *));
52130561Sobrienextern bfd_boolean _bfd_xcoff_write_armap
5389857Sobrien  PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
54130561Sobrienextern bfd_boolean _bfd_xcoff_write_archive_contents
55130561Sobrien  PARAMS ((bfd *));
56130561Sobrienextern int _bfd_xcoff_sizeof_headers
57218822Sdim  PARAMS ((bfd *, struct bfd_link_info *));
58130561Sobrienextern void _bfd_xcoff_swap_sym_in
59130561Sobrien  PARAMS ((bfd *, PTR, PTR));
60130561Sobrienextern unsigned int _bfd_xcoff_swap_sym_out
61130561Sobrien  PARAMS ((bfd *, PTR, PTR));
62130561Sobrienextern void _bfd_xcoff_swap_aux_in
63130561Sobrien  PARAMS ((bfd *, PTR, int, int, int, int, PTR));
64130561Sobrienextern unsigned int _bfd_xcoff_swap_aux_out
65130561Sobrien  PARAMS ((bfd *, PTR, int, int, int, int, PTR));
66130561Sobrienstatic void xcoff_swap_reloc_in
67130561Sobrien  PARAMS ((bfd *, PTR, PTR));
68130561Sobrienstatic unsigned int xcoff_swap_reloc_out
69130561Sobrien  PARAMS ((bfd *, PTR, PTR));
7089857Sobrien
71104834Sobrien/* Forward declare xcoff_rtype2howto for coffcode.h macro.  */
72130561Sobrienvoid xcoff_rtype2howto
73130561Sobrien  PARAMS ((arelent *, struct internal_reloc *));
7489857Sobrien
7589857Sobrien/* coffcode.h needs these to be defined.  */
7689857Sobrien#define RS6000COFF_C 1
7789857Sobrien
7889857Sobrien#define SELECT_RELOC(internal, howto)					\
7989857Sobrien  {									\
8089857Sobrien    internal.r_type = howto->type;					\
8189857Sobrien    internal.r_size =							\
8289857Sobrien      ((howto->complain_on_overflow == complain_overflow_signed		\
8389857Sobrien	? 0x80								\
8489857Sobrien	: 0)								\
8589857Sobrien       | (howto->bitsize - 1));						\
8689857Sobrien  }
8789857Sobrien
8889857Sobrien#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
8989857Sobrien#define COFF_LONG_FILENAMES
9089857Sobrien#define NO_COFF_SYMBOLS
91104834Sobrien#define RTYPE2HOWTO(cache_ptr, dst) xcoff_rtype2howto (cache_ptr, dst)
9289857Sobrien#define coff_mkobject _bfd_xcoff_mkobject
9389857Sobrien#define coff_bfd_copy_private_bfd_data _bfd_xcoff_copy_private_bfd_data
9489857Sobrien#define coff_bfd_is_local_label_name _bfd_xcoff_is_local_label_name
9589857Sobrien#define coff_bfd_reloc_type_lookup _bfd_xcoff_reloc_type_lookup
96218822Sdim#define coff_bfd_reloc_name_lookup _bfd_xcoff_reloc_name_lookup
9789857Sobrien#ifdef AIX_CORE
98130561Sobrienextern const bfd_target * rs6000coff_core_p
99130561Sobrien  PARAMS ((bfd *abfd));
100130561Sobrienextern bfd_boolean rs6000coff_core_file_matches_executable_p
101104834Sobrien  PARAMS ((bfd *cbfd, bfd *ebfd));
102130561Sobrienextern char *rs6000coff_core_file_failing_command
103130561Sobrien  PARAMS ((bfd *abfd));
104130561Sobrienextern int rs6000coff_core_file_failing_signal
105130561Sobrien  PARAMS ((bfd *abfd));
10689857Sobrien#define CORE_FILE_P rs6000coff_core_p
10789857Sobrien#define coff_core_file_failing_command \
10889857Sobrien  rs6000coff_core_file_failing_command
10989857Sobrien#define coff_core_file_failing_signal \
11089857Sobrien  rs6000coff_core_file_failing_signal
11189857Sobrien#define coff_core_file_matches_executable_p \
11289857Sobrien  rs6000coff_core_file_matches_executable_p
11389857Sobrien#else
11489857Sobrien#define CORE_FILE_P _bfd_dummy_target
11589857Sobrien#define coff_core_file_failing_command \
11689857Sobrien  _bfd_nocore_core_file_failing_command
11789857Sobrien#define coff_core_file_failing_signal \
11889857Sobrien  _bfd_nocore_core_file_failing_signal
11989857Sobrien#define coff_core_file_matches_executable_p \
12089857Sobrien  _bfd_nocore_core_file_matches_executable_p
12189857Sobrien#endif
12289857Sobrien#define coff_SWAP_sym_in _bfd_xcoff_swap_sym_in
12389857Sobrien#define coff_SWAP_sym_out _bfd_xcoff_swap_sym_out
12489857Sobrien#define coff_SWAP_aux_in _bfd_xcoff_swap_aux_in
12589857Sobrien#define coff_SWAP_aux_out _bfd_xcoff_swap_aux_out
126104834Sobrien#define coff_swap_reloc_in xcoff_swap_reloc_in
127104834Sobrien#define coff_swap_reloc_out xcoff_swap_reloc_out
128104834Sobrien#define NO_COFF_RELOCS
12989857Sobrien
13089857Sobrien#include "coffcode.h"
13189857Sobrien
13284865Sobrien/* The main body of code is in coffcode.h.  */
13384865Sobrien
134130561Sobrienstatic const char *normalize_filename
135130561Sobrien  PARAMS ((bfd *));
136130561Sobrienstatic bfd_boolean xcoff_write_armap_old
13789857Sobrien  PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
138130561Sobrienstatic bfd_boolean xcoff_write_armap_big
13989857Sobrien  PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
140130561Sobrienstatic bfd_boolean xcoff_write_archive_contents_old
141130561Sobrien  PARAMS ((bfd *));
142130561Sobrienstatic bfd_boolean xcoff_write_archive_contents_big
143130561Sobrien  PARAMS ((bfd *));
14489857Sobrienstatic void xcoff_swap_ldhdr_in
14589857Sobrien  PARAMS ((bfd *, const PTR, struct internal_ldhdr *));
14689857Sobrienstatic void xcoff_swap_ldhdr_out
14789857Sobrien  PARAMS ((bfd *, const struct internal_ldhdr *, PTR));
14889857Sobrienstatic void xcoff_swap_ldsym_in
14989857Sobrien  PARAMS ((bfd *, const PTR, struct internal_ldsym *));
15089857Sobrienstatic void xcoff_swap_ldsym_out
15189857Sobrien  PARAMS ((bfd *, const struct internal_ldsym *, PTR));
15289857Sobrienstatic void xcoff_swap_ldrel_in
15389857Sobrien  PARAMS ((bfd *, const PTR, struct internal_ldrel *));
15489857Sobrienstatic void xcoff_swap_ldrel_out
15589857Sobrien  PARAMS ((bfd *, const struct internal_ldrel *, PTR));
156130561Sobrienstatic bfd_boolean xcoff_ppc_relocate_section
15789857Sobrien  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
15889857Sobrien	   struct internal_reloc *, struct internal_syment *, asection **));
159130561Sobrienstatic bfd_boolean _bfd_xcoff_put_ldsymbol_name
16089857Sobrien  PARAMS ((bfd *, struct xcoff_loader_info *, struct internal_ldsym *,
16189857Sobrien	   const char *));
16289857Sobrienstatic asection *xcoff_create_csect_from_smclas
16389857Sobrien  PARAMS ((bfd *, union internal_auxent *, const char *));
164130561Sobrienstatic bfd_boolean xcoff_is_lineno_count_overflow
165130561Sobrien  PARAMS ((bfd *, bfd_vma));
166130561Sobrienstatic bfd_boolean xcoff_is_reloc_count_overflow
167130561Sobrien  PARAMS ((bfd *, bfd_vma));
16889857Sobrienstatic bfd_vma xcoff_loader_symbol_offset
16989857Sobrien  PARAMS ((bfd *, struct internal_ldhdr *));
17089857Sobrienstatic bfd_vma xcoff_loader_reloc_offset
17189857Sobrien  PARAMS ((bfd *, struct internal_ldhdr *));
172130561Sobrienstatic bfd_boolean xcoff_generate_rtinit
173130561Sobrien  PARAMS ((bfd *, const char *, const char *, bfd_boolean));
174130561Sobrienstatic bfd_boolean do_pad
175130561Sobrien  PARAMS ((bfd *, unsigned int));
176130561Sobrienstatic bfd_boolean do_copy
177130561Sobrien  PARAMS ((bfd *, bfd *));
178130561Sobrienstatic bfd_boolean do_shared_object_padding
179218822Sdim  PARAMS ((bfd *, bfd *, file_ptr *, int));
18084865Sobrien
181104834Sobrien/* Relocation functions */
182130561Sobrienstatic bfd_boolean xcoff_reloc_type_br
183130561Sobrien  PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
18489857Sobrien
185130561Sobrienstatic bfd_boolean xcoff_complain_overflow_dont_func
186104834Sobrien  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
187130561Sobrienstatic bfd_boolean xcoff_complain_overflow_bitfield_func
188104834Sobrien  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
189130561Sobrienstatic bfd_boolean xcoff_complain_overflow_signed_func
190104834Sobrien  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
191130561Sobrienstatic bfd_boolean xcoff_complain_overflow_unsigned_func
192104834Sobrien  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
193104834Sobrien
194130561Sobrienbfd_boolean (*xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION])
195104834Sobrien  PARAMS ((XCOFF_RELOC_FUNCTION_ARGS)) =
196104834Sobrien{
197130561Sobrien  xcoff_reloc_type_pos,	 /* R_POS   (0x00) */
198130561Sobrien  xcoff_reloc_type_neg,	 /* R_NEG   (0x01) */
199130561Sobrien  xcoff_reloc_type_rel,	 /* R_REL   (0x02) */
200130561Sobrien  xcoff_reloc_type_toc,	 /* R_TOC   (0x03) */
201104834Sobrien  xcoff_reloc_type_fail, /* R_RTB   (0x04) */
202130561Sobrien  xcoff_reloc_type_toc,	 /* R_GL    (0x05) */
203130561Sobrien  xcoff_reloc_type_toc,	 /* R_TCL   (0x06) */
204130561Sobrien  xcoff_reloc_type_fail, /*	    (0x07) */
205130561Sobrien  xcoff_reloc_type_ba,	 /* R_BA    (0x08) */
206130561Sobrien  xcoff_reloc_type_fail, /*	    (0x09) */
207130561Sobrien  xcoff_reloc_type_br,	 /* R_BR    (0x0a) */
208130561Sobrien  xcoff_reloc_type_fail, /*	    (0x0b) */
209130561Sobrien  xcoff_reloc_type_pos,	 /* R_RL    (0x0c) */
210130561Sobrien  xcoff_reloc_type_pos,	 /* R_RLA   (0x0d) */
211130561Sobrien  xcoff_reloc_type_fail, /*	    (0x0e) */
212104834Sobrien  xcoff_reloc_type_noop, /* R_REF   (0x0f) */
213130561Sobrien  xcoff_reloc_type_fail, /*	    (0x10) */
214130561Sobrien  xcoff_reloc_type_fail, /*	    (0x11) */
215130561Sobrien  xcoff_reloc_type_toc,	 /* R_TRL   (0x12) */
216130561Sobrien  xcoff_reloc_type_toc,	 /* R_TRLA  (0x13) */
217104834Sobrien  xcoff_reloc_type_fail, /* R_RRTBI (0x14) */
218104834Sobrien  xcoff_reloc_type_fail, /* R_RRTBA (0x15) */
219130561Sobrien  xcoff_reloc_type_ba,	 /* R_CAI   (0x16) */
220104834Sobrien  xcoff_reloc_type_crel, /* R_CREL  (0x17) */
221130561Sobrien  xcoff_reloc_type_ba,	 /* R_RBA   (0x18) */
222130561Sobrien  xcoff_reloc_type_ba,	 /* R_RBAC  (0x19) */
223130561Sobrien  xcoff_reloc_type_br,	 /* R_RBR   (0x1a) */
224130561Sobrien  xcoff_reloc_type_ba,	 /* R_RBRC  (0x1b) */
225104834Sobrien};
226104834Sobrien
227130561Sobrienbfd_boolean (*xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW])
228104834Sobrien  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS)) =
229104834Sobrien{
230104834Sobrien  xcoff_complain_overflow_dont_func,
231104834Sobrien  xcoff_complain_overflow_bitfield_func,
232104834Sobrien  xcoff_complain_overflow_signed_func,
233104834Sobrien  xcoff_complain_overflow_unsigned_func,
234104834Sobrien};
235104834Sobrien
23684865Sobrien/* We use our own tdata type.  Its first field is the COFF tdata type,
23784865Sobrien   so the COFF routines are compatible.  */
23884865Sobrien
239130561Sobrienbfd_boolean
24084865Sobrien_bfd_xcoff_mkobject (abfd)
24184865Sobrien     bfd *abfd;
24284865Sobrien{
24384865Sobrien  coff_data_type *coff;
24489857Sobrien  bfd_size_type amt = sizeof (struct xcoff_tdata);
24584865Sobrien
24689857Sobrien  abfd->tdata.xcoff_obj_data = (struct xcoff_tdata *) bfd_zalloc (abfd, amt);
24784865Sobrien  if (abfd->tdata.xcoff_obj_data == NULL)
248130561Sobrien    return FALSE;
24984865Sobrien  coff = coff_data (abfd);
25084865Sobrien  coff->symbols = (coff_symbol_type *) NULL;
25184865Sobrien  coff->conversion_table = (unsigned int *) NULL;
25284865Sobrien  coff->raw_syments = (struct coff_ptr_struct *) NULL;
25384865Sobrien  coff->relocbase = 0;
25484865Sobrien
25584865Sobrien  xcoff_data (abfd)->modtype = ('1' << 8) | 'L';
25684865Sobrien
25784865Sobrien  /* We set cputype to -1 to indicate that it has not been
25884865Sobrien     initialized.  */
25984865Sobrien  xcoff_data (abfd)->cputype = -1;
26084865Sobrien
26184865Sobrien  xcoff_data (abfd)->csects = NULL;
26284865Sobrien  xcoff_data (abfd)->debug_indices = NULL;
26384865Sobrien
26489857Sobrien  /* text section alignment is different than the default */
265104834Sobrien  bfd_xcoff_text_align_power (abfd) = 2;
26689857Sobrien
267130561Sobrien  return TRUE;
26884865Sobrien}
26984865Sobrien
27084865Sobrien/* Copy XCOFF data from one BFD to another.  */
27184865Sobrien
272130561Sobrienbfd_boolean
27384865Sobrien_bfd_xcoff_copy_private_bfd_data (ibfd, obfd)
27484865Sobrien     bfd *ibfd;
27584865Sobrien     bfd *obfd;
27684865Sobrien{
27784865Sobrien  struct xcoff_tdata *ix, *ox;
27884865Sobrien  asection *sec;
27984865Sobrien
28084865Sobrien  if (ibfd->xvec != obfd->xvec)
281130561Sobrien    return TRUE;
28284865Sobrien  ix = xcoff_data (ibfd);
28384865Sobrien  ox = xcoff_data (obfd);
28484865Sobrien  ox->full_aouthdr = ix->full_aouthdr;
28584865Sobrien  ox->toc = ix->toc;
28684865Sobrien  if (ix->sntoc == 0)
28784865Sobrien    ox->sntoc = 0;
28884865Sobrien  else
28984865Sobrien    {
29084865Sobrien      sec = coff_section_from_bfd_index (ibfd, ix->sntoc);
29184865Sobrien      if (sec == NULL)
29284865Sobrien	ox->sntoc = 0;
29384865Sobrien      else
29484865Sobrien	ox->sntoc = sec->output_section->target_index;
29584865Sobrien    }
29684865Sobrien  if (ix->snentry == 0)
29784865Sobrien    ox->snentry = 0;
29884865Sobrien  else
29984865Sobrien    {
30084865Sobrien      sec = coff_section_from_bfd_index (ibfd, ix->snentry);
30184865Sobrien      if (sec == NULL)
30284865Sobrien	ox->snentry = 0;
30384865Sobrien      else
30484865Sobrien	ox->snentry = sec->output_section->target_index;
30584865Sobrien    }
306104834Sobrien  bfd_xcoff_text_align_power (obfd) = bfd_xcoff_text_align_power (ibfd);
307104834Sobrien  bfd_xcoff_data_align_power (obfd) = bfd_xcoff_data_align_power (ibfd);
30884865Sobrien  ox->modtype = ix->modtype;
30984865Sobrien  ox->cputype = ix->cputype;
31084865Sobrien  ox->maxdata = ix->maxdata;
31184865Sobrien  ox->maxstack = ix->maxstack;
312130561Sobrien  return TRUE;
31384865Sobrien}
31484865Sobrien
31584865Sobrien/* I don't think XCOFF really has a notion of local labels based on
31684865Sobrien   name.  This will mean that ld -X doesn't actually strip anything.
31784865Sobrien   The AIX native linker does not have a -X option, and it ignores the
31884865Sobrien   -x option.  */
31984865Sobrien
320130561Sobrienbfd_boolean
32184865Sobrien_bfd_xcoff_is_local_label_name (abfd, name)
32284865Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
32384865Sobrien     const char *name ATTRIBUTE_UNUSED;
32484865Sobrien{
325130561Sobrien  return FALSE;
32684865Sobrien}
32784865Sobrien
32884865Sobrienvoid
32984865Sobrien_bfd_xcoff_swap_sym_in (abfd, ext1, in1)
330130561Sobrien     bfd *abfd;
33184865Sobrien     PTR ext1;
33284865Sobrien     PTR in1;
33384865Sobrien{
33484865Sobrien  SYMENT *ext = (SYMENT *)ext1;
33589857Sobrien  struct internal_syment * in = (struct internal_syment *)in1;
33684865Sobrien
33784865Sobrien  if (ext->e.e_name[0] != 0)
33884865Sobrien    {
339130561Sobrien      memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN);
34084865Sobrien    }
34184865Sobrien  else
34284865Sobrien    {
34384865Sobrien      in->_n._n_n._n_zeroes = 0;
34489857Sobrien      in->_n._n_n._n_offset = H_GET_32 (abfd, ext->e.e.e_offset);
34584865Sobrien    }
34684865Sobrien
34789857Sobrien  in->n_value = H_GET_32 (abfd, ext->e_value);
34889857Sobrien  in->n_scnum = H_GET_16 (abfd, ext->e_scnum);
34989857Sobrien  in->n_type = H_GET_16 (abfd, ext->e_type);
35089857Sobrien  in->n_sclass = H_GET_8 (abfd, ext->e_sclass);
35189857Sobrien  in->n_numaux = H_GET_8 (abfd, ext->e_numaux);
35284865Sobrien}
35384865Sobrien
35484865Sobrienunsigned int
35584865Sobrien_bfd_xcoff_swap_sym_out (abfd, inp, extp)
356130561Sobrien     bfd *abfd;
357130561Sobrien     PTR inp;
358130561Sobrien     PTR extp;
35984865Sobrien{
36084865Sobrien  struct internal_syment *in = (struct internal_syment *)inp;
36184865Sobrien  SYMENT *ext =(SYMENT *)extp;
36284865Sobrien
36384865Sobrien  if (in->_n._n_name[0] != 0)
36484865Sobrien    {
365130561Sobrien      memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN);
36684865Sobrien    }
36784865Sobrien  else
36884865Sobrien    {
36989857Sobrien      H_PUT_32 (abfd, 0, ext->e.e.e_zeroes);
37089857Sobrien      H_PUT_32 (abfd, in->_n._n_n._n_offset, ext->e.e.e_offset);
37184865Sobrien    }
37284865Sobrien
37389857Sobrien  H_PUT_32 (abfd, in->n_value, ext->e_value);
37489857Sobrien  H_PUT_16 (abfd, in->n_scnum, ext->e_scnum);
37589857Sobrien  H_PUT_16 (abfd, in->n_type, ext->e_type);
37689857Sobrien  H_PUT_8 (abfd, in->n_sclass, ext->e_sclass);
37789857Sobrien  H_PUT_8 (abfd, in->n_numaux, ext->e_numaux);
37884865Sobrien  return bfd_coff_symesz (abfd);
37984865Sobrien}
38084865Sobrien
38184865Sobrienvoid
38284865Sobrien_bfd_xcoff_swap_aux_in (abfd, ext1, type, class, indx, numaux, in1)
383130561Sobrien     bfd *abfd;
384130561Sobrien     PTR ext1;
385130561Sobrien     int type;
386130561Sobrien     int class;
387130561Sobrien     int indx;
388130561Sobrien     int numaux;
389130561Sobrien     PTR in1;
39084865Sobrien{
39189857Sobrien  AUXENT * ext = (AUXENT *)ext1;
39284865Sobrien  union internal_auxent *in = (union internal_auxent *)in1;
39384865Sobrien
39489857Sobrien  switch (class)
39589857Sobrien    {
39684865Sobrien    case C_FILE:
39789857Sobrien      if (ext->x_file.x_fname[0] == 0)
39889857Sobrien	{
39984865Sobrien	  in->x_file.x_n.x_zeroes = 0;
40084865Sobrien	  in->x_file.x_n.x_offset =
40189857Sobrien	    H_GET_32 (abfd, ext->x_file.x_n.x_offset);
40289857Sobrien	}
40389857Sobrien      else
40489857Sobrien	{
40589857Sobrien	  if (numaux > 1)
40689857Sobrien	    {
40789857Sobrien	      if (indx == 0)
40889857Sobrien		memcpy (in->x_file.x_fname, ext->x_file.x_fname,
40989857Sobrien			numaux * sizeof (AUXENT));
41089857Sobrien	    }
41189857Sobrien	  else
41289857Sobrien	    {
41389857Sobrien	      memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN);
41489857Sobrien	    }
41589857Sobrien	}
41684865Sobrien      goto end;
41784865Sobrien
41884865Sobrien      /* RS/6000 "csect" auxents */
41984865Sobrien    case C_EXT:
42084865Sobrien    case C_HIDEXT:
42184865Sobrien      if (indx + 1 == numaux)
42284865Sobrien	{
42389857Sobrien	  in->x_csect.x_scnlen.l = H_GET_32 (abfd, ext->x_csect.x_scnlen);
42489857Sobrien	  in->x_csect.x_parmhash = H_GET_32 (abfd, ext->x_csect.x_parmhash);
42589857Sobrien	  in->x_csect.x_snhash   = H_GET_16 (abfd, ext->x_csect.x_snhash);
42684865Sobrien	  /* We don't have to hack bitfields in x_smtyp because it's
42784865Sobrien	     defined by shifts-and-ands, which are equivalent on all
42884865Sobrien	     byte orders.  */
42989857Sobrien	  in->x_csect.x_smtyp    = H_GET_8 (abfd, ext->x_csect.x_smtyp);
43089857Sobrien	  in->x_csect.x_smclas   = H_GET_8 (abfd, ext->x_csect.x_smclas);
43189857Sobrien	  in->x_csect.x_stab     = H_GET_32 (abfd, ext->x_csect.x_stab);
43289857Sobrien	  in->x_csect.x_snstab   = H_GET_16 (abfd, ext->x_csect.x_snstab);
43384865Sobrien	  goto end;
43484865Sobrien	}
43584865Sobrien      break;
43684865Sobrien
43784865Sobrien    case C_STAT:
43884865Sobrien    case C_LEAFSTAT:
43984865Sobrien    case C_HIDDEN:
44089857Sobrien      if (type == T_NULL)
44189857Sobrien	{
44289857Sobrien	  in->x_scn.x_scnlen = H_GET_32 (abfd, ext->x_scn.x_scnlen);
44389857Sobrien	  in->x_scn.x_nreloc = H_GET_16 (abfd, ext->x_scn.x_nreloc);
44489857Sobrien	  in->x_scn.x_nlinno = H_GET_16 (abfd, ext->x_scn.x_nlinno);
44584865Sobrien	  /* PE defines some extra fields; we zero them out for
446130561Sobrien	     safety.  */
44784865Sobrien	  in->x_scn.x_checksum = 0;
44884865Sobrien	  in->x_scn.x_associated = 0;
44984865Sobrien	  in->x_scn.x_comdat = 0;
45084865Sobrien
45184865Sobrien	  goto end;
45284865Sobrien	}
45384865Sobrien      break;
45484865Sobrien    }
45584865Sobrien
45689857Sobrien  in->x_sym.x_tagndx.l = H_GET_32 (abfd, ext->x_sym.x_tagndx);
45789857Sobrien  in->x_sym.x_tvndx = H_GET_16 (abfd, ext->x_sym.x_tvndx);
45884865Sobrien
45984865Sobrien  if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
46084865Sobrien    {
46189857Sobrien      in->x_sym.x_fcnary.x_fcn.x_lnnoptr =
46289857Sobrien	H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr);
46389857Sobrien      in->x_sym.x_fcnary.x_fcn.x_endndx.l =
46489857Sobrien	H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_endndx);
46584865Sobrien    }
46684865Sobrien  else
46784865Sobrien    {
46884865Sobrien      in->x_sym.x_fcnary.x_ary.x_dimen[0] =
46989857Sobrien	H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[0]);
47084865Sobrien      in->x_sym.x_fcnary.x_ary.x_dimen[1] =
47189857Sobrien	H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[1]);
47284865Sobrien      in->x_sym.x_fcnary.x_ary.x_dimen[2] =
47389857Sobrien	H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[2]);
47484865Sobrien      in->x_sym.x_fcnary.x_ary.x_dimen[3] =
47589857Sobrien	H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[3]);
47684865Sobrien    }
47784865Sobrien
47889857Sobrien  if (ISFCN (type))
47989857Sobrien    {
48089857Sobrien      in->x_sym.x_misc.x_fsize = H_GET_32 (abfd, ext->x_sym.x_misc.x_fsize);
48189857Sobrien    }
48289857Sobrien  else
48389857Sobrien    {
48489857Sobrien      in->x_sym.x_misc.x_lnsz.x_lnno =
48589857Sobrien	H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_lnno);
48689857Sobrien      in->x_sym.x_misc.x_lnsz.x_size =
48789857Sobrien	H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_size);
48889857Sobrien    }
48989857Sobrien
49089857Sobrien end: ;
49189857Sobrien  /* The semicolon is because MSVC doesn't like labels at
49284865Sobrien     end of block.  */
49384865Sobrien}
49484865Sobrien
49589857Sobrien
496130561Sobrienunsigned int _bfd_xcoff_swap_aux_out
497130561Sobrien  PARAMS ((bfd *, PTR, int, int, int, int, PTR));
49889857Sobrien
49984865Sobrienunsigned int
50084865Sobrien_bfd_xcoff_swap_aux_out (abfd, inp, type, class, indx, numaux, extp)
50189857Sobrien     bfd * abfd;
50289857Sobrien     PTR   inp;
50384865Sobrien     int   type;
50484865Sobrien     int   class;
50584865Sobrien     int   indx ATTRIBUTE_UNUSED;
50684865Sobrien     int   numaux ATTRIBUTE_UNUSED;
50789857Sobrien     PTR   extp;
50884865Sobrien{
50984865Sobrien  union internal_auxent *in = (union internal_auxent *)inp;
51084865Sobrien  AUXENT *ext = (AUXENT *)extp;
51184865Sobrien
512130561Sobrien  memset ((PTR)ext, 0, bfd_coff_auxesz (abfd));
51384865Sobrien  switch (class)
51484865Sobrien    {
51589857Sobrien    case C_FILE:
51689857Sobrien      if (in->x_file.x_fname[0] == 0)
51789857Sobrien	{
51889857Sobrien	  H_PUT_32 (abfd, 0, ext->x_file.x_n.x_zeroes);
51989857Sobrien	  H_PUT_32 (abfd, in->x_file.x_n.x_offset, ext->x_file.x_n.x_offset);
52089857Sobrien	}
52189857Sobrien      else
52289857Sobrien	{
52389857Sobrien	  memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN);
52489857Sobrien	}
52589857Sobrien      goto end;
52684865Sobrien
52789857Sobrien      /* RS/6000 "csect" auxents */
52889857Sobrien    case C_EXT:
52989857Sobrien    case C_HIDEXT:
53089857Sobrien      if (indx + 1 == numaux)
53189857Sobrien	{
53289857Sobrien	  H_PUT_32 (abfd, in->x_csect.x_scnlen.l, ext->x_csect.x_scnlen);
53389857Sobrien	  H_PUT_32 (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash);
53489857Sobrien	  H_PUT_16 (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash);
53589857Sobrien	  /* We don't have to hack bitfields in x_smtyp because it's
53689857Sobrien	     defined by shifts-and-ands, which are equivalent on all
53789857Sobrien	     byte orders.  */
53889857Sobrien	  H_PUT_8 (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp);
53989857Sobrien	  H_PUT_8 (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas);
54089857Sobrien	  H_PUT_32 (abfd, in->x_csect.x_stab, ext->x_csect.x_stab);
54189857Sobrien	  H_PUT_16 (abfd, in->x_csect.x_snstab, ext->x_csect.x_snstab);
54289857Sobrien	  goto end;
54389857Sobrien	}
54489857Sobrien      break;
54584865Sobrien
54689857Sobrien    case C_STAT:
54789857Sobrien    case C_LEAFSTAT:
54889857Sobrien    case C_HIDDEN:
54989857Sobrien      if (type == T_NULL)
55089857Sobrien	{
55189857Sobrien	  H_PUT_32 (abfd, in->x_scn.x_scnlen, ext->x_scn.x_scnlen);
55289857Sobrien	  H_PUT_16 (abfd, in->x_scn.x_nreloc, ext->x_scn.x_nreloc);
55389857Sobrien	  H_PUT_16 (abfd, in->x_scn.x_nlinno, ext->x_scn.x_nlinno);
55489857Sobrien	  goto end;
55589857Sobrien	}
55689857Sobrien      break;
55784865Sobrien    }
55884865Sobrien
55989857Sobrien  H_PUT_32 (abfd, in->x_sym.x_tagndx.l, ext->x_sym.x_tagndx);
56089857Sobrien  H_PUT_16 (abfd, in->x_sym.x_tvndx, ext->x_sym.x_tvndx);
56184865Sobrien
56284865Sobrien  if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
56384865Sobrien    {
56489857Sobrien      H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr,
56589857Sobrien		ext->x_sym.x_fcnary.x_fcn.x_lnnoptr);
56689857Sobrien      H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l,
56789857Sobrien		ext->x_sym.x_fcnary.x_fcn.x_endndx);
56884865Sobrien    }
56984865Sobrien  else
57084865Sobrien    {
57189857Sobrien      H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0],
57289857Sobrien		ext->x_sym.x_fcnary.x_ary.x_dimen[0]);
57389857Sobrien      H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1],
57489857Sobrien		ext->x_sym.x_fcnary.x_ary.x_dimen[1]);
57589857Sobrien      H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2],
57689857Sobrien		ext->x_sym.x_fcnary.x_ary.x_dimen[2]);
57789857Sobrien      H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3],
57889857Sobrien		ext->x_sym.x_fcnary.x_ary.x_dimen[3]);
57984865Sobrien    }
58084865Sobrien
58184865Sobrien  if (ISFCN (type))
58289857Sobrien    H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, ext->x_sym.x_misc.x_fsize);
58384865Sobrien  else
58484865Sobrien    {
58589857Sobrien      H_PUT_16 (abfd, in->x_sym.x_misc.x_lnsz.x_lnno,
58689857Sobrien		ext->x_sym.x_misc.x_lnsz.x_lnno);
58789857Sobrien      H_PUT_16 (abfd, in->x_sym.x_misc.x_lnsz.x_size,
58889857Sobrien		ext->x_sym.x_misc.x_lnsz.x_size);
58984865Sobrien    }
59084865Sobrien
59184865Sobrienend:
59284865Sobrien  return bfd_coff_auxesz (abfd);
59384865Sobrien}
59489857Sobrien
59589857Sobrien
59684865Sobrien
59784865Sobrien/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
59884865Sobrien   bitsize and whether they are signed or not, along with a
59984865Sobrien   conventional type.  This table is for the types, which are used for
60084865Sobrien   different algorithms for putting in the reloc.  Many of these
60184865Sobrien   relocs need special_function entries, which I have not written.  */
60284865Sobrien
60384865Sobrien
60484865Sobrienreloc_howto_type xcoff_howto_table[] =
60584865Sobrien{
60684865Sobrien  /* Standard 32 bit relocation.  */
607130561Sobrien  HOWTO (R_POS,			/* type */
608130561Sobrien	 0,			/* rightshift */
609130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
610130561Sobrien	 32,			/* bitsize */
611130561Sobrien	 FALSE,			/* pc_relative */
612130561Sobrien	 0,			/* bitpos */
61384865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
614130561Sobrien	 0,			/* special_function */
615130561Sobrien	 "R_POS",		/* name */
616130561Sobrien	 TRUE,			/* partial_inplace */
617130561Sobrien	 0xffffffff,		/* src_mask */
618130561Sobrien	 0xffffffff,		/* dst_mask */
619130561Sobrien	 FALSE),		/* pcrel_offset */
62084865Sobrien
62184865Sobrien  /* 32 bit relocation, but store negative value.  */
622130561Sobrien  HOWTO (R_NEG,			/* type */
623130561Sobrien	 0,			/* rightshift */
624130561Sobrien	 -2,			/* size (0 = byte, 1 = short, 2 = long) */
625130561Sobrien	 32,			/* bitsize */
626130561Sobrien	 FALSE,			/* pc_relative */
627130561Sobrien	 0,			/* bitpos */
62884865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
629130561Sobrien	 0,			/* special_function */
630130561Sobrien	 "R_NEG",		/* name */
631130561Sobrien	 TRUE,			/* partial_inplace */
632130561Sobrien	 0xffffffff,		/* src_mask */
633130561Sobrien	 0xffffffff,		/* dst_mask */
634130561Sobrien	 FALSE),		/* pcrel_offset */
63584865Sobrien
63684865Sobrien  /* 32 bit PC relative relocation.  */
637130561Sobrien  HOWTO (R_REL,			/* type */
638130561Sobrien	 0,			/* rightshift */
639130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
640130561Sobrien	 32,			/* bitsize */
641130561Sobrien	 TRUE,			/* pc_relative */
642130561Sobrien	 0,			/* bitpos */
64384865Sobrien	 complain_overflow_signed, /* complain_on_overflow */
644130561Sobrien	 0,			/* special_function */
645130561Sobrien	 "R_REL",		/* name */
646130561Sobrien	 TRUE,			/* partial_inplace */
647130561Sobrien	 0xffffffff,		/* src_mask */
648130561Sobrien	 0xffffffff,		/* dst_mask */
649130561Sobrien	 FALSE),		/* pcrel_offset */
65084865Sobrien
65184865Sobrien  /* 16 bit TOC relative relocation.  */
652130561Sobrien  HOWTO (R_TOC,			/* type */
653130561Sobrien	 0,			/* rightshift */
654130561Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
655130561Sobrien	 16,			/* bitsize */
656130561Sobrien	 FALSE,			/* pc_relative */
657130561Sobrien	 0,			/* bitpos */
65884865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
659130561Sobrien	 0,			/* special_function */
660130561Sobrien	 "R_TOC",		/* name */
661130561Sobrien	 TRUE,			/* partial_inplace */
662130561Sobrien	 0xffff,		/* src_mask */
663130561Sobrien	 0xffff,		/* dst_mask */
664130561Sobrien	 FALSE),		/* pcrel_offset */
66584865Sobrien
66684865Sobrien  /* I don't really know what this is.  */
667130561Sobrien  HOWTO (R_RTB,			/* type */
668130561Sobrien	 1,			/* rightshift */
669130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
670130561Sobrien	 32,			/* bitsize */
671130561Sobrien	 FALSE,			/* pc_relative */
672130561Sobrien	 0,			/* bitpos */
67384865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
674130561Sobrien	 0,			/* special_function */
675130561Sobrien	 "R_RTB",		/* name */
676130561Sobrien	 TRUE,			/* partial_inplace */
677130561Sobrien	 0xffffffff,		/* src_mask */
678130561Sobrien	 0xffffffff,		/* dst_mask */
679130561Sobrien	 FALSE),		/* pcrel_offset */
68084865Sobrien
68184865Sobrien  /* External TOC relative symbol.  */
682130561Sobrien  HOWTO (R_GL,			/* type */
683130561Sobrien	 0,			/* rightshift */
684104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
685130561Sobrien	 16,			/* bitsize */
686130561Sobrien	 FALSE,			/* pc_relative */
687130561Sobrien	 0,			/* bitpos */
68884865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
689130561Sobrien	 0,			/* special_function */
690130561Sobrien	 "R_GL",		/* name */
691130561Sobrien	 TRUE,			/* partial_inplace */
692130561Sobrien	 0xffff,		/* src_mask */
693130561Sobrien	 0xffff,		/* dst_mask */
694130561Sobrien	 FALSE),		/* pcrel_offset */
69584865Sobrien
696130561Sobrien  /* Local TOC relative symbol.	 */
697130561Sobrien  HOWTO (R_TCL,			/* type */
698130561Sobrien	 0,			/* rightshift */
699104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
700130561Sobrien	 16,			/* bitsize */
701130561Sobrien	 FALSE,			/* pc_relative */
702130561Sobrien	 0,			/* bitpos */
70384865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
704130561Sobrien	 0,			/* special_function */
705130561Sobrien	 "R_TCL",		/* name */
706130561Sobrien	 TRUE,			/* partial_inplace */
707130561Sobrien	 0xffff,		/* src_mask */
708130561Sobrien	 0xffff,		/* dst_mask */
709130561Sobrien	 FALSE),		/* pcrel_offset */
71084865Sobrien
71184865Sobrien  EMPTY_HOWTO (7),
71284865Sobrien
71384865Sobrien  /* Non modifiable absolute branch.  */
714130561Sobrien  HOWTO (R_BA,			/* type */
715130561Sobrien	 0,			/* rightshift */
716130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
717130561Sobrien	 26,			/* bitsize */
718130561Sobrien	 FALSE,			/* pc_relative */
719130561Sobrien	 0,			/* bitpos */
72084865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
721130561Sobrien	 0,			/* special_function */
722130561Sobrien	 "R_BA_26",		/* name */
723130561Sobrien	 TRUE,			/* partial_inplace */
724104834Sobrien	 0x03fffffc,		/* src_mask */
725104834Sobrien	 0x03fffffc,		/* dst_mask */
726130561Sobrien	 FALSE),		/* pcrel_offset */
72784865Sobrien
72884865Sobrien  EMPTY_HOWTO (9),
72984865Sobrien
73084865Sobrien  /* Non modifiable relative branch.  */
731130561Sobrien  HOWTO (R_BR,			/* type */
732130561Sobrien	 0,			/* rightshift */
733130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
734130561Sobrien	 26,			/* bitsize */
735130561Sobrien	 TRUE,			/* pc_relative */
736130561Sobrien	 0,			/* bitpos */
73784865Sobrien	 complain_overflow_signed, /* complain_on_overflow */
738130561Sobrien	 0,			/* special_function */
739130561Sobrien	 "R_BR",		/* name */
740130561Sobrien	 TRUE,			/* partial_inplace */
741130561Sobrien	 0x03fffffc,		/* src_mask */
742130561Sobrien	 0x03fffffc,		/* dst_mask */
743130561Sobrien	 FALSE),		/* pcrel_offset */
74484865Sobrien
74584865Sobrien  EMPTY_HOWTO (0xb),
74684865Sobrien
74784865Sobrien  /* Indirect load.  */
748130561Sobrien  HOWTO (R_RL,			/* type */
749130561Sobrien	 0,			/* rightshift */
750104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
751130561Sobrien	 16,			/* bitsize */
752130561Sobrien	 FALSE,			/* pc_relative */
753130561Sobrien	 0,			/* bitpos */
75484865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
755130561Sobrien	 0,			/* special_function */
756130561Sobrien	 "R_RL",		/* name */
757130561Sobrien	 TRUE,			/* partial_inplace */
758130561Sobrien	 0xffff,		/* src_mask */
759130561Sobrien	 0xffff,		/* dst_mask */
760130561Sobrien	 FALSE),		/* pcrel_offset */
76184865Sobrien
76284865Sobrien  /* Load address.  */
763130561Sobrien  HOWTO (R_RLA,			/* type */
764130561Sobrien	 0,			/* rightshift */
765104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
766130561Sobrien	 16,			/* bitsize */
767130561Sobrien	 FALSE,			/* pc_relative */
768130561Sobrien	 0,			/* bitpos */
76984865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
770130561Sobrien	 0,			/* special_function */
771130561Sobrien	 "R_RLA",		/* name */
772130561Sobrien	 TRUE,			/* partial_inplace */
773130561Sobrien	 0xffff,		/* src_mask */
774130561Sobrien	 0xffff,		/* dst_mask */
775130561Sobrien	 FALSE),		/* pcrel_offset */
77684865Sobrien
77784865Sobrien  EMPTY_HOWTO (0xe),
77884865Sobrien
77984865Sobrien  /* Non-relocating reference.  */
780130561Sobrien  HOWTO (R_REF,			/* type */
781130561Sobrien	 0,			/* rightshift */
782130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
783130561Sobrien	 32,			/* bitsize */
784130561Sobrien	 FALSE,			/* pc_relative */
785130561Sobrien	 0,			/* bitpos */
786104834Sobrien	 complain_overflow_dont, /* complain_on_overflow */
787130561Sobrien	 0,			/* special_function */
788130561Sobrien	 "R_REF",		/* name */
789130561Sobrien	 FALSE,			/* partial_inplace */
790130561Sobrien	 0,			/* src_mask */
791130561Sobrien	 0,			/* dst_mask */
792130561Sobrien	 FALSE),		/* pcrel_offset */
79384865Sobrien
79484865Sobrien  EMPTY_HOWTO (0x10),
79584865Sobrien  EMPTY_HOWTO (0x11),
79684865Sobrien
79784865Sobrien  /* TOC relative indirect load.  */
798130561Sobrien  HOWTO (R_TRL,			/* type */
799130561Sobrien	 0,			/* rightshift */
800104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
801130561Sobrien	 16,			/* bitsize */
802130561Sobrien	 FALSE,			/* pc_relative */
803130561Sobrien	 0,			/* bitpos */
80484865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
805130561Sobrien	 0,			/* special_function */
806130561Sobrien	 "R_TRL",		/* name */
807130561Sobrien	 TRUE,			/* partial_inplace */
808130561Sobrien	 0xffff,		/* src_mask */
809130561Sobrien	 0xffff,		/* dst_mask */
810130561Sobrien	 FALSE),		/* pcrel_offset */
81184865Sobrien
81284865Sobrien  /* TOC relative load address.  */
813130561Sobrien  HOWTO (R_TRLA,		/* type */
814130561Sobrien	 0,			/* rightshift */
815104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
816130561Sobrien	 16,			/* bitsize */
817130561Sobrien	 FALSE,			/* pc_relative */
818130561Sobrien	 0,			/* bitpos */
81984865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
820130561Sobrien	 0,			/* special_function */
821130561Sobrien	 "R_TRLA",		/* name */
822130561Sobrien	 TRUE,			/* partial_inplace */
823130561Sobrien	 0xffff,		/* src_mask */
824130561Sobrien	 0xffff,		/* dst_mask */
825130561Sobrien	 FALSE),		/* pcrel_offset */
82684865Sobrien
82784865Sobrien  /* Modifiable relative branch.  */
828130561Sobrien  HOWTO (R_RRTBI,		 /* type */
829130561Sobrien	 1,			/* rightshift */
830130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
831130561Sobrien	 32,			/* bitsize */
832130561Sobrien	 FALSE,			/* pc_relative */
833130561Sobrien	 0,			/* bitpos */
83484865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
835130561Sobrien	 0,			/* special_function */
836130561Sobrien	 "R_RRTBI",		/* name */
837130561Sobrien	 TRUE,			/* partial_inplace */
838130561Sobrien	 0xffffffff,		/* src_mask */
839130561Sobrien	 0xffffffff,		/* dst_mask */
840130561Sobrien	 FALSE),		/* pcrel_offset */
84184865Sobrien
84284865Sobrien  /* Modifiable absolute branch.  */
843130561Sobrien  HOWTO (R_RRTBA,		 /* type */
844130561Sobrien	 1,			/* rightshift */
845130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
846130561Sobrien	 32,			/* bitsize */
847130561Sobrien	 FALSE,			/* pc_relative */
848130561Sobrien	 0,			/* bitpos */
84984865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
850130561Sobrien	 0,			/* special_function */
851130561Sobrien	 "R_RRTBA",		/* name */
852130561Sobrien	 TRUE,			/* partial_inplace */
853130561Sobrien	 0xffffffff,		/* src_mask */
854130561Sobrien	 0xffffffff,		/* dst_mask */
855130561Sobrien	 FALSE),		/* pcrel_offset */
85684865Sobrien
85784865Sobrien  /* Modifiable call absolute indirect.  */
858130561Sobrien  HOWTO (R_CAI,			/* type */
859130561Sobrien	 0,			/* rightshift */
860104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
861130561Sobrien	 16,			/* bitsize */
862130561Sobrien	 FALSE,			/* pc_relative */
863130561Sobrien	 0,			/* bitpos */
86484865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
865130561Sobrien	 0,			/* special_function */
866130561Sobrien	 "R_CAI",		/* name */
867130561Sobrien	 TRUE,			/* partial_inplace */
868130561Sobrien	 0xffff,		/* src_mask */
869130561Sobrien	 0xffff,		/* dst_mask */
870130561Sobrien	 FALSE),		/* pcrel_offset */
87184865Sobrien
87284865Sobrien  /* Modifiable call relative.  */
873130561Sobrien  HOWTO (R_CREL,		/* type */
874130561Sobrien	 0,			/* rightshift */
875104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
876130561Sobrien	 16,			/* bitsize */
877130561Sobrien	 FALSE,			/* pc_relative */
878130561Sobrien	 0,			/* bitpos */
87984865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
880130561Sobrien	 0,			/* special_function */
881130561Sobrien	 "R_CREL",		/* name */
882130561Sobrien	 TRUE,			/* partial_inplace */
883130561Sobrien	 0xffff,		/* src_mask */
884130561Sobrien	 0xffff,		/* dst_mask */
885130561Sobrien	 FALSE),		/* pcrel_offset */
88684865Sobrien
88784865Sobrien  /* Modifiable branch absolute.  */
888130561Sobrien  HOWTO (R_RBA,			/* type */
889130561Sobrien	 0,			/* rightshift */
890130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
891130561Sobrien	 26,			/* bitsize */
892130561Sobrien	 FALSE,			/* pc_relative */
893130561Sobrien	 0,			/* bitpos */
89484865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
895130561Sobrien	 0,			/* special_function */
896130561Sobrien	 "R_RBA",		/* name */
897130561Sobrien	 TRUE,			/* partial_inplace */
898104834Sobrien	 0x03fffffc,		/* src_mask */
899104834Sobrien	 0x03fffffc,		/* dst_mask */
900130561Sobrien	 FALSE),		/* pcrel_offset */
90184865Sobrien
90284865Sobrien  /* Modifiable branch absolute.  */
903130561Sobrien  HOWTO (R_RBAC,		/* type */
904130561Sobrien	 0,			/* rightshift */
905130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
906130561Sobrien	 32,			/* bitsize */
907130561Sobrien	 FALSE,			/* pc_relative */
908130561Sobrien	 0,			/* bitpos */
90984865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
910130561Sobrien	 0,			/* special_function */
911130561Sobrien	 "R_RBAC",		/* name */
912130561Sobrien	 TRUE,			/* partial_inplace */
913104834Sobrien	 0xffffffff,		/* src_mask */
914104834Sobrien	 0xffffffff,		/* dst_mask */
915130561Sobrien	 FALSE),		/* pcrel_offset */
91684865Sobrien
91784865Sobrien  /* Modifiable branch relative.  */
918130561Sobrien  HOWTO (R_RBR,			/* type */
919130561Sobrien	 0,			/* rightshift */
920130561Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
921130561Sobrien	 26,			/* bitsize */
922130561Sobrien	 FALSE,			/* pc_relative */
923130561Sobrien	 0,			/* bitpos */
92484865Sobrien	 complain_overflow_signed, /* complain_on_overflow */
925130561Sobrien	 0,			/* special_function */
926130561Sobrien	 "R_RBR_26",		/* name */
927130561Sobrien	 TRUE,			/* partial_inplace */
928104834Sobrien	 0x03fffffc,		/* src_mask */
929104834Sobrien	 0x03fffffc,		/* dst_mask */
930130561Sobrien	 FALSE),		/* pcrel_offset */
93184865Sobrien
93284865Sobrien  /* Modifiable branch absolute.  */
933130561Sobrien  HOWTO (R_RBRC,		/* type */
934130561Sobrien	 0,			/* rightshift */
935104834Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
936130561Sobrien	 16,			/* bitsize */
937130561Sobrien	 FALSE,			/* pc_relative */
938130561Sobrien	 0,			/* bitpos */
93984865Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
940130561Sobrien	 0,			/* special_function */
941130561Sobrien	 "R_RBRC",		/* name */
942130561Sobrien	 TRUE,			/* partial_inplace */
943130561Sobrien	 0xffff,		/* src_mask */
944130561Sobrien	 0xffff,		/* dst_mask */
945130561Sobrien	 FALSE),		/* pcrel_offset */
94689857Sobrien
947104834Sobrien  /* 16 bit Non modifiable absolute branch.  */
948130561Sobrien  HOWTO (R_BA,			/* type */
949130561Sobrien	 0,			/* rightshift */
950130561Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
951130561Sobrien	 16,			/* bitsize */
952130561Sobrien	 FALSE,			/* pc_relative */
953130561Sobrien	 0,			/* bitpos */
954104834Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
955130561Sobrien	 0,			/* special_function */
956130561Sobrien	 "R_BA_16",		/* name */
957130561Sobrien	 TRUE,			/* partial_inplace */
958130561Sobrien	 0xfffc,		/* src_mask */
959130561Sobrien	 0xfffc,		/* dst_mask */
960130561Sobrien	 FALSE),		/* pcrel_offset */
96184865Sobrien
962104834Sobrien  /* Modifiable branch relative.  */
963130561Sobrien  HOWTO (R_RBR,			/* type */
964130561Sobrien	 0,			/* rightshift */
965130561Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
966130561Sobrien	 16,			/* bitsize */
967130561Sobrien	 FALSE,			/* pc_relative */
968130561Sobrien	 0,			/* bitpos */
969104834Sobrien	 complain_overflow_signed, /* complain_on_overflow */
970130561Sobrien	 0,			/* special_function */
971130561Sobrien	 "R_RBR_16",		/* name */
972130561Sobrien	 TRUE,			/* partial_inplace */
973130561Sobrien	 0xffff,		/* src_mask */
974130561Sobrien	 0xffff,		/* dst_mask */
975130561Sobrien	 FALSE),		/* pcrel_offset */
976104834Sobrien
977104834Sobrien  /* Modifiable branch relative.  */
978130561Sobrien  HOWTO (R_RBA,			/* type */
979130561Sobrien	 0,			/* rightshift */
980130561Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
981130561Sobrien	 16,			/* bitsize */
982130561Sobrien	 FALSE,			/* pc_relative */
983130561Sobrien	 0,			/* bitpos */
984104834Sobrien	 complain_overflow_signed, /* complain_on_overflow */
985130561Sobrien	 0,			/* special_function */
986130561Sobrien	 "R_RBA_16",		/* name */
987130561Sobrien	 TRUE,			/* partial_inplace */
988130561Sobrien	 0xffff,		/* src_mask */
989130561Sobrien	 0xffff,		/* dst_mask */
990130561Sobrien	 FALSE),		/* pcrel_offset */
991104834Sobrien
99284865Sobrien};
99384865Sobrien
99484865Sobrienvoid
995104834Sobrienxcoff_rtype2howto (relent, internal)
99684865Sobrien     arelent *relent;
99784865Sobrien     struct internal_reloc *internal;
99884865Sobrien{
999104834Sobrien  if (internal->r_type > R_RBRC)
100089857Sobrien    abort ();
100184865Sobrien
1002104834Sobrien  /* Default howto layout works most of the time */
1003104834Sobrien  relent->howto = &xcoff_howto_table[internal->r_type];
1004130561Sobrien
1005130561Sobrien  /* Special case some 16 bit reloc */
1006104834Sobrien  if (15 == (internal->r_size & 0x1f))
1007104834Sobrien    {
1008130561Sobrien      if (R_BA == internal->r_type)
1009104834Sobrien	relent->howto = &xcoff_howto_table[0x1c];
1010130561Sobrien      else if (R_RBR == internal->r_type)
1011104834Sobrien	relent->howto = &xcoff_howto_table[0x1d];
1012130561Sobrien      else if (R_RBA == internal->r_type)
1013104834Sobrien	relent->howto = &xcoff_howto_table[0x1e];
1014104834Sobrien    }
1015130561Sobrien
101684865Sobrien  /* The r_size field of an XCOFF reloc encodes the bitsize of the
101784865Sobrien     relocation, as well as indicating whether it is signed or not.
101884865Sobrien     Doublecheck that the relocation information gathered from the
101984865Sobrien     type matches this information.  The bitsize is not significant
102084865Sobrien     for R_REF relocs.  */
102184865Sobrien  if (relent->howto->dst_mask != 0
102284865Sobrien      && (relent->howto->bitsize
1023104834Sobrien	  != ((unsigned int) internal->r_size & 0x1f) + 1))
102484865Sobrien    abort ();
102584865Sobrien}
102684865Sobrien
102784865Sobrienreloc_howto_type *
102884865Sobrien_bfd_xcoff_reloc_type_lookup (abfd, code)
102984865Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
103084865Sobrien     bfd_reloc_code_real_type code;
103184865Sobrien{
103284865Sobrien  switch (code)
103384865Sobrien    {
103484865Sobrien    case BFD_RELOC_PPC_B26:
103584865Sobrien      return &xcoff_howto_table[0xa];
1036104834Sobrien    case BFD_RELOC_PPC_BA16:
1037104834Sobrien      return &xcoff_howto_table[0x1c];
103884865Sobrien    case BFD_RELOC_PPC_BA26:
103984865Sobrien      return &xcoff_howto_table[8];
104084865Sobrien    case BFD_RELOC_PPC_TOC16:
104184865Sobrien      return &xcoff_howto_table[3];
104284865Sobrien    case BFD_RELOC_32:
104384865Sobrien    case BFD_RELOC_CTOR:
104484865Sobrien      return &xcoff_howto_table[0];
104584865Sobrien    default:
104684865Sobrien      return NULL;
104784865Sobrien    }
104884865Sobrien}
104989857Sobrien
1050218822Sdimstatic reloc_howto_type *
1051218822Sdim_bfd_xcoff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1052218822Sdim			      const char *r_name)
1053218822Sdim{
1054218822Sdim  unsigned int i;
1055218822Sdim
1056218822Sdim  for (i = 0;
1057218822Sdim       i < sizeof (xcoff_howto_table) / sizeof (xcoff_howto_table[0]);
1058218822Sdim       i++)
1059218822Sdim    if (xcoff_howto_table[i].name != NULL
1060218822Sdim	&& strcasecmp (xcoff_howto_table[i].name, r_name) == 0)
1061218822Sdim      return &xcoff_howto_table[i];
1062218822Sdim
1063218822Sdim  return NULL;
1064218822Sdim}
106584865Sobrien
106684865Sobrien/* XCOFF archive support.  The original version of this code was by
106784865Sobrien   Damon A. Permezel.  It was enhanced to permit cross support, and
106884865Sobrien   writing archive files, by Ian Lance Taylor, Cygnus Support.
106984865Sobrien
107084865Sobrien   XCOFF uses its own archive format.  Everything is hooked together
107184865Sobrien   with file offset links, so it is possible to rapidly update an
107284865Sobrien   archive in place.  Of course, we don't do that.  An XCOFF archive
107384865Sobrien   has a real file header, not just an ARMAG string.  The structure of
107484865Sobrien   the file header and of each archive header appear below.
107584865Sobrien
107684865Sobrien   An XCOFF archive also has a member table, which is a list of
107784865Sobrien   elements in the archive (you can get that by looking through the
107884865Sobrien   linked list, but you have to read a lot more of the file).  The
107984865Sobrien   member table has a normal archive header with an empty name.  It is
108084865Sobrien   normally (and perhaps must be) the second to last entry in the
108184865Sobrien   archive.  The member table data is almost printable ASCII.  It
108284865Sobrien   starts with a 12 character decimal string which is the number of
108384865Sobrien   entries in the table.  For each entry it has a 12 character decimal
108484865Sobrien   string which is the offset in the archive of that member.  These
108584865Sobrien   entries are followed by a series of null terminated strings which
108684865Sobrien   are the member names for each entry.
108784865Sobrien
108884865Sobrien   Finally, an XCOFF archive has a global symbol table, which is what
108984865Sobrien   we call the armap.  The global symbol table has a normal archive
109084865Sobrien   header with an empty name.  It is normally (and perhaps must be)
109184865Sobrien   the last entry in the archive.  The contents start with a four byte
109284865Sobrien   binary number which is the number of entries.  This is followed by
109384865Sobrien   a that many four byte binary numbers; each is the file offset of an
109484865Sobrien   entry in the archive.  These numbers are followed by a series of
109584865Sobrien   null terminated strings, which are symbol names.
109684865Sobrien
109784865Sobrien   AIX 4.3 introduced a new archive format which can handle larger
109884865Sobrien   files and also 32- and 64-bit objects in the same archive.  The
109984865Sobrien   things said above remain true except that there is now more than
110084865Sobrien   one global symbol table.  The one is used to index 32-bit objects,
110184865Sobrien   the other for 64-bit objects.
110284865Sobrien
110384865Sobrien   The new archives (recognizable by the new ARMAG string) has larger
110484865Sobrien   field lengths so that we cannot really share any code.  Also we have
110584865Sobrien   to take care that we are not generating the new form of archives
110684865Sobrien   on AIX 4.2 or earlier systems.  */
110784865Sobrien
110884865Sobrien/* XCOFF archives use this as a magic string.  Note that both strings
110984865Sobrien   have the same length.  */
111084865Sobrien
1111104834Sobrien/* Set the magic for archive.  */
111284865Sobrien
1113130561Sobrienbfd_boolean
1114104834Sobrienbfd_xcoff_ar_archive_set_magic (abfd, magic)
1115104834Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
1116104834Sobrien     char *magic ATTRIBUTE_UNUSED;
1117104834Sobrien{
1118104834Sobrien  /* Not supported yet.  */
1119130561Sobrien  return FALSE;
1120104834Sobrien /* bfd_xcoff_archive_set_magic (abfd, magic); */
1121104834Sobrien}
112284865Sobrien
112384865Sobrien/* Read in the armap of an XCOFF archive.  */
112484865Sobrien
1125130561Sobrienbfd_boolean
112684865Sobrien_bfd_xcoff_slurp_armap (abfd)
112784865Sobrien     bfd *abfd;
112884865Sobrien{
112984865Sobrien  file_ptr off;
113084865Sobrien  size_t namlen;
113184865Sobrien  bfd_size_type sz;
113284865Sobrien  bfd_byte *contents, *cend;
113384865Sobrien  bfd_vma c, i;
113484865Sobrien  carsym *arsym;
113584865Sobrien  bfd_byte *p;
113684865Sobrien
113784865Sobrien  if (xcoff_ardata (abfd) == NULL)
113884865Sobrien    {
1139130561Sobrien      bfd_has_map (abfd) = FALSE;
1140130561Sobrien      return TRUE;
114184865Sobrien    }
114284865Sobrien
114384865Sobrien  if (! xcoff_big_format_p (abfd))
114484865Sobrien    {
114584865Sobrien      /* This is for the old format.  */
114684865Sobrien      struct xcoff_ar_hdr hdr;
114784865Sobrien
114884865Sobrien      off = strtol (xcoff_ardata (abfd)->symoff, (char **) NULL, 10);
114984865Sobrien      if (off == 0)
115084865Sobrien	{
1151130561Sobrien	  bfd_has_map (abfd) = FALSE;
1152130561Sobrien	  return TRUE;
115384865Sobrien	}
115484865Sobrien
115584865Sobrien      if (bfd_seek (abfd, off, SEEK_SET) != 0)
1156130561Sobrien	return FALSE;
115784865Sobrien
115884865Sobrien      /* The symbol table starts with a normal archive header.  */
115989857Sobrien      if (bfd_bread ((PTR) &hdr, (bfd_size_type) SIZEOF_AR_HDR, abfd)
116089857Sobrien	  != SIZEOF_AR_HDR)
1161130561Sobrien	return FALSE;
116284865Sobrien
116384865Sobrien      /* Skip the name (normally empty).  */
116484865Sobrien      namlen = strtol (hdr.namlen, (char **) NULL, 10);
116589857Sobrien      off = ((namlen + 1) & ~ (size_t) 1) + SXCOFFARFMAG;
116689857Sobrien      if (bfd_seek (abfd, off, SEEK_CUR) != 0)
1167130561Sobrien	return FALSE;
116884865Sobrien
116984865Sobrien      sz = strtol (hdr.size, (char **) NULL, 10);
117084865Sobrien
117184865Sobrien      /* Read in the entire symbol table.  */
117284865Sobrien      contents = (bfd_byte *) bfd_alloc (abfd, sz);
117384865Sobrien      if (contents == NULL)
1174130561Sobrien	return FALSE;
117589857Sobrien      if (bfd_bread ((PTR) contents, sz, abfd) != sz)
1176130561Sobrien	return FALSE;
117784865Sobrien
117884865Sobrien      /* The symbol table starts with a four byte count.  */
117989857Sobrien      c = H_GET_32 (abfd, contents);
118084865Sobrien
118184865Sobrien      if (c * 4 >= sz)
118284865Sobrien	{
118384865Sobrien	  bfd_set_error (bfd_error_bad_value);
1184130561Sobrien	  return FALSE;
118584865Sobrien	}
118684865Sobrien
118789857Sobrien      bfd_ardata (abfd)->symdefs =
118889857Sobrien	((carsym *) bfd_alloc (abfd, c * sizeof (carsym)));
118984865Sobrien      if (bfd_ardata (abfd)->symdefs == NULL)
1190130561Sobrien	return FALSE;
119184865Sobrien
119284865Sobrien      /* After the count comes a list of four byte file offsets.  */
119384865Sobrien      for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 4;
119484865Sobrien	   i < c;
119584865Sobrien	   ++i, ++arsym, p += 4)
119689857Sobrien	arsym->file_offset = H_GET_32 (abfd, p);
119784865Sobrien    }
119884865Sobrien  else
119984865Sobrien    {
120084865Sobrien      /* This is for the new format.  */
120184865Sobrien      struct xcoff_ar_hdr_big hdr;
120284865Sobrien
120384865Sobrien      off = strtol (xcoff_ardata_big (abfd)->symoff, (char **) NULL, 10);
120484865Sobrien      if (off == 0)
120584865Sobrien	{
1206130561Sobrien	  bfd_has_map (abfd) = FALSE;
1207130561Sobrien	  return TRUE;
120884865Sobrien	}
120984865Sobrien
121084865Sobrien      if (bfd_seek (abfd, off, SEEK_SET) != 0)
1211130561Sobrien	return FALSE;
121284865Sobrien
121384865Sobrien      /* The symbol table starts with a normal archive header.  */
121489857Sobrien      if (bfd_bread ((PTR) &hdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
121584865Sobrien	  != SIZEOF_AR_HDR_BIG)
1216130561Sobrien	return FALSE;
121784865Sobrien
121884865Sobrien      /* Skip the name (normally empty).  */
121984865Sobrien      namlen = strtol (hdr.namlen, (char **) NULL, 10);
122089857Sobrien      off = ((namlen + 1) & ~ (size_t) 1) + SXCOFFARFMAG;
122189857Sobrien      if (bfd_seek (abfd, off, SEEK_CUR) != 0)
1222130561Sobrien	return FALSE;
122384865Sobrien
122484865Sobrien      /* XXX This actually has to be a call to strtoll (at least on 32-bit
122584865Sobrien	 machines) since the field width is 20 and there numbers with more
122684865Sobrien	 than 32 bits can be represented.  */
122784865Sobrien      sz = strtol (hdr.size, (char **) NULL, 10);
122884865Sobrien
122984865Sobrien      /* Read in the entire symbol table.  */
123084865Sobrien      contents = (bfd_byte *) bfd_alloc (abfd, sz);
123184865Sobrien      if (contents == NULL)
1232130561Sobrien	return FALSE;
123389857Sobrien      if (bfd_bread ((PTR) contents, sz, abfd) != sz)
1234130561Sobrien	return FALSE;
123584865Sobrien
123684865Sobrien      /* The symbol table starts with an eight byte count.  */
123789857Sobrien      c = H_GET_64 (abfd, contents);
123884865Sobrien
123984865Sobrien      if (c * 8 >= sz)
124084865Sobrien	{
124184865Sobrien	  bfd_set_error (bfd_error_bad_value);
1242130561Sobrien	  return FALSE;
124384865Sobrien	}
124484865Sobrien
124589857Sobrien      bfd_ardata (abfd)->symdefs =
124689857Sobrien	((carsym *) bfd_alloc (abfd, c * sizeof (carsym)));
124784865Sobrien      if (bfd_ardata (abfd)->symdefs == NULL)
1248130561Sobrien	return FALSE;
124984865Sobrien
125084865Sobrien      /* After the count comes a list of eight byte file offsets.  */
125184865Sobrien      for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 8;
125284865Sobrien	   i < c;
125384865Sobrien	   ++i, ++arsym, p += 8)
125489857Sobrien	arsym->file_offset = H_GET_64 (abfd, p);
125584865Sobrien    }
125684865Sobrien
125784865Sobrien  /* After the file offsets come null terminated symbol names.  */
125884865Sobrien  cend = contents + sz;
125984865Sobrien  for (i = 0, arsym = bfd_ardata (abfd)->symdefs;
126084865Sobrien       i < c;
126184865Sobrien       ++i, ++arsym, p += strlen ((char *) p) + 1)
126284865Sobrien    {
126384865Sobrien      if (p >= cend)
126484865Sobrien	{
126584865Sobrien	  bfd_set_error (bfd_error_bad_value);
1266130561Sobrien	  return FALSE;
126784865Sobrien	}
126884865Sobrien      arsym->name = (char *) p;
126984865Sobrien    }
127084865Sobrien
127184865Sobrien  bfd_ardata (abfd)->symdef_count = c;
1272130561Sobrien  bfd_has_map (abfd) = TRUE;
127384865Sobrien
1274130561Sobrien  return TRUE;
127584865Sobrien}
127684865Sobrien
127784865Sobrien/* See if this is an XCOFF archive.  */
127884865Sobrien
127984865Sobrienconst bfd_target *
128084865Sobrien_bfd_xcoff_archive_p (abfd)
128184865Sobrien     bfd *abfd;
128284865Sobrien{
1283104834Sobrien  struct artdata *tdata_hold;
128484865Sobrien  char magic[SXCOFFARMAG];
1285104834Sobrien  bfd_size_type amt = SXCOFFARMAG;
128684865Sobrien
1287104834Sobrien  if (bfd_bread ((PTR) magic, amt, abfd) != amt)
128884865Sobrien    {
128984865Sobrien      if (bfd_get_error () != bfd_error_system_call)
129084865Sobrien	bfd_set_error (bfd_error_wrong_format);
129184865Sobrien      return NULL;
129284865Sobrien    }
129384865Sobrien
129484865Sobrien  if (strncmp (magic, XCOFFARMAG, SXCOFFARMAG) != 0
129584865Sobrien      && strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0)
129684865Sobrien    {
129784865Sobrien      bfd_set_error (bfd_error_wrong_format);
129884865Sobrien      return NULL;
129984865Sobrien    }
130084865Sobrien
1301104834Sobrien  tdata_hold = bfd_ardata (abfd);
1302104834Sobrien
130389857Sobrien  amt = sizeof (struct artdata);
1304104834Sobrien  bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt);
130584865Sobrien  if (bfd_ardata (abfd) == (struct artdata *) NULL)
1306104834Sobrien    goto error_ret_restore;
130784865Sobrien
1308218822Sdim  /* Cleared by bfd_zalloc above.
1309218822Sdim     bfd_ardata (abfd)->cache = NULL;
1310218822Sdim     bfd_ardata (abfd)->archive_head = NULL;
1311218822Sdim     bfd_ardata (abfd)->symdefs = NULL;
1312218822Sdim     bfd_ardata (abfd)->extended_names = NULL;
1313218822Sdim     bfd_ardata (abfd)->extended_names_size = 0;  */
131484865Sobrien
131584865Sobrien  /* Now handle the two formats.  */
131684865Sobrien  if (magic[1] != 'b')
131784865Sobrien    {
131884865Sobrien      /* This is the old format.  */
131984865Sobrien      struct xcoff_ar_file_hdr hdr;
132084865Sobrien
132184865Sobrien      /* Copy over the magic string.  */
132284865Sobrien      memcpy (hdr.magic, magic, SXCOFFARMAG);
132384865Sobrien
132484865Sobrien      /* Now read the rest of the file header.  */
1325104834Sobrien      amt = SIZEOF_AR_FILE_HDR - SXCOFFARMAG;
1326104834Sobrien      if (bfd_bread ((PTR) &hdr.memoff, amt, abfd) != amt)
132784865Sobrien	{
132884865Sobrien	  if (bfd_get_error () != bfd_error_system_call)
132984865Sobrien	    bfd_set_error (bfd_error_wrong_format);
1330104834Sobrien	  goto error_ret;
133184865Sobrien	}
133284865Sobrien
133384865Sobrien      bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
133484865Sobrien						      (char **) NULL, 10);
133584865Sobrien
133689857Sobrien      amt = SIZEOF_AR_FILE_HDR;
133789857Sobrien      bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt);
133884865Sobrien      if (bfd_ardata (abfd)->tdata == NULL)
1339104834Sobrien	goto error_ret;
134084865Sobrien
134184865Sobrien      memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
134284865Sobrien    }
134384865Sobrien  else
134484865Sobrien    {
134584865Sobrien      /* This is the new format.  */
134684865Sobrien      struct xcoff_ar_file_hdr_big hdr;
134784865Sobrien
134884865Sobrien      /* Copy over the magic string.  */
134984865Sobrien      memcpy (hdr.magic, magic, SXCOFFARMAG);
135084865Sobrien
135184865Sobrien      /* Now read the rest of the file header.  */
1352104834Sobrien      amt = SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG;
1353104834Sobrien      if (bfd_bread ((PTR) &hdr.memoff, amt, abfd) != amt)
135484865Sobrien	{
135584865Sobrien	  if (bfd_get_error () != bfd_error_system_call)
135684865Sobrien	    bfd_set_error (bfd_error_wrong_format);
1357104834Sobrien	  goto error_ret;
135884865Sobrien	}
135984865Sobrien
1360104834Sobrien      bfd_ardata (abfd)->first_file_filepos = bfd_scan_vma (hdr.firstmemoff,
1361104834Sobrien							    (const char **) 0,
1362104834Sobrien							    10);
136384865Sobrien
136489857Sobrien      amt = SIZEOF_AR_FILE_HDR_BIG;
136589857Sobrien      bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt);
136684865Sobrien      if (bfd_ardata (abfd)->tdata == NULL)
1367104834Sobrien	goto error_ret;
136884865Sobrien
136984865Sobrien      memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG);
137084865Sobrien    }
137184865Sobrien
137284865Sobrien  if (! _bfd_xcoff_slurp_armap (abfd))
137384865Sobrien    {
1374104834Sobrien    error_ret:
137584865Sobrien      bfd_release (abfd, bfd_ardata (abfd));
1376104834Sobrien    error_ret_restore:
1377104834Sobrien      bfd_ardata (abfd) = tdata_hold;
137884865Sobrien      return NULL;
137984865Sobrien    }
138084865Sobrien
138184865Sobrien  return abfd->xvec;
138284865Sobrien}
138384865Sobrien
138484865Sobrien/* Read the archive header in an XCOFF archive.  */
138584865Sobrien
138684865SobrienPTR
138784865Sobrien_bfd_xcoff_read_ar_hdr (abfd)
138884865Sobrien     bfd *abfd;
138984865Sobrien{
139089857Sobrien  bfd_size_type namlen;
139184865Sobrien  struct areltdata *ret;
139289857Sobrien  bfd_size_type amt = sizeof (struct areltdata);
139384865Sobrien
139489857Sobrien  ret = (struct areltdata *) bfd_alloc (abfd, amt);
139584865Sobrien  if (ret == NULL)
139684865Sobrien    return NULL;
139784865Sobrien
139884865Sobrien  if (! xcoff_big_format_p (abfd))
139984865Sobrien    {
140084865Sobrien      struct xcoff_ar_hdr hdr;
140184865Sobrien      struct xcoff_ar_hdr *hdrp;
140284865Sobrien
140389857Sobrien      if (bfd_bread ((PTR) &hdr, (bfd_size_type) SIZEOF_AR_HDR, abfd)
140489857Sobrien	  != SIZEOF_AR_HDR)
140584865Sobrien	{
140684865Sobrien	  free (ret);
140784865Sobrien	  return NULL;
140884865Sobrien	}
140984865Sobrien
141084865Sobrien      namlen = strtol (hdr.namlen, (char **) NULL, 10);
141189857Sobrien      amt = SIZEOF_AR_HDR + namlen + 1;
141289857Sobrien      hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd, amt);
141384865Sobrien      if (hdrp == NULL)
141484865Sobrien	{
141584865Sobrien	  free (ret);
141684865Sobrien	  return NULL;
141784865Sobrien	}
141884865Sobrien      memcpy (hdrp, &hdr, SIZEOF_AR_HDR);
141989857Sobrien      if (bfd_bread ((char *) hdrp + SIZEOF_AR_HDR, namlen, abfd) != namlen)
142084865Sobrien	{
142184865Sobrien	  free (ret);
142284865Sobrien	  return NULL;
142384865Sobrien	}
142484865Sobrien      ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0';
142584865Sobrien
142684865Sobrien      ret->arch_header = (char *) hdrp;
142784865Sobrien      ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
142884865Sobrien      ret->filename = (char *) hdrp + SIZEOF_AR_HDR;
142984865Sobrien    }
143084865Sobrien  else
143184865Sobrien    {
143284865Sobrien      struct xcoff_ar_hdr_big hdr;
143384865Sobrien      struct xcoff_ar_hdr_big *hdrp;
143484865Sobrien
143589857Sobrien      if (bfd_bread ((PTR) &hdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
143684865Sobrien	  != SIZEOF_AR_HDR_BIG)
143784865Sobrien	{
143884865Sobrien	  free (ret);
143984865Sobrien	  return NULL;
144084865Sobrien	}
144184865Sobrien
144284865Sobrien      namlen = strtol (hdr.namlen, (char **) NULL, 10);
144389857Sobrien      amt = SIZEOF_AR_HDR_BIG + namlen + 1;
144489857Sobrien      hdrp = (struct xcoff_ar_hdr_big *) bfd_alloc (abfd, amt);
144584865Sobrien      if (hdrp == NULL)
144684865Sobrien	{
144784865Sobrien	  free (ret);
144884865Sobrien	  return NULL;
144984865Sobrien	}
145084865Sobrien      memcpy (hdrp, &hdr, SIZEOF_AR_HDR_BIG);
145189857Sobrien      if (bfd_bread ((char *) hdrp + SIZEOF_AR_HDR_BIG, namlen, abfd) != namlen)
145284865Sobrien	{
145384865Sobrien	  free (ret);
145484865Sobrien	  return NULL;
145584865Sobrien	}
145684865Sobrien      ((char *) hdrp)[SIZEOF_AR_HDR_BIG + namlen] = '\0';
145784865Sobrien
145884865Sobrien      ret->arch_header = (char *) hdrp;
145984865Sobrien      /* XXX This actually has to be a call to strtoll (at least on 32-bit
146084865Sobrien	 machines) since the field width is 20 and there numbers with more
146184865Sobrien	 than 32 bits can be represented.  */
146284865Sobrien      ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
146384865Sobrien      ret->filename = (char *) hdrp + SIZEOF_AR_HDR_BIG;
146484865Sobrien    }
146584865Sobrien
146684865Sobrien  /* Skip over the XCOFFARFMAG at the end of the file name.  */
146789857Sobrien  if (bfd_seek (abfd, (file_ptr) ((namlen & 1) + SXCOFFARFMAG), SEEK_CUR) != 0)
146884865Sobrien    return NULL;
146984865Sobrien
147084865Sobrien  return (PTR) ret;
147184865Sobrien}
147284865Sobrien
147384865Sobrien/* Open the next element in an XCOFF archive.  */
147484865Sobrien
147584865Sobrienbfd *
147684865Sobrien_bfd_xcoff_openr_next_archived_file (archive, last_file)
147784865Sobrien     bfd *archive;
147884865Sobrien     bfd *last_file;
147984865Sobrien{
148084865Sobrien  file_ptr filestart;
148184865Sobrien
148284865Sobrien  if (xcoff_ardata (archive) == NULL)
148384865Sobrien    {
148484865Sobrien      bfd_set_error (bfd_error_invalid_operation);
148584865Sobrien      return NULL;
148684865Sobrien    }
148784865Sobrien
148884865Sobrien  if (! xcoff_big_format_p (archive))
148984865Sobrien    {
149084865Sobrien      if (last_file == NULL)
149184865Sobrien	filestart = bfd_ardata (archive)->first_file_filepos;
149284865Sobrien      else
149384865Sobrien	filestart = strtol (arch_xhdr (last_file)->nextoff, (char **) NULL,
149484865Sobrien			    10);
149584865Sobrien
149684865Sobrien      if (filestart == 0
149784865Sobrien	  || filestart == strtol (xcoff_ardata (archive)->memoff,
149884865Sobrien				  (char **) NULL, 10)
149984865Sobrien	  || filestart == strtol (xcoff_ardata (archive)->symoff,
150084865Sobrien				  (char **) NULL, 10))
150184865Sobrien	{
150284865Sobrien	  bfd_set_error (bfd_error_no_more_archived_files);
150384865Sobrien	  return NULL;
150484865Sobrien	}
150584865Sobrien    }
150684865Sobrien  else
150784865Sobrien    {
150884865Sobrien      if (last_file == NULL)
150984865Sobrien	filestart = bfd_ardata (archive)->first_file_filepos;
151084865Sobrien      else
151184865Sobrien	/* XXX These actually have to be a calls to strtoll (at least
151284865Sobrien	   on 32-bit machines) since the fields's width is 20 and
151384865Sobrien	   there numbers with more than 32 bits can be represented.  */
151484865Sobrien	filestart = strtol (arch_xhdr_big (last_file)->nextoff, (char **) NULL,
151584865Sobrien			    10);
151684865Sobrien
151784865Sobrien      /* XXX These actually have to be calls to strtoll (at least on 32-bit
151884865Sobrien	 machines) since the fields's width is 20 and there numbers with more
151984865Sobrien	 than 32 bits can be represented.  */
152084865Sobrien      if (filestart == 0
152184865Sobrien	  || filestart == strtol (xcoff_ardata_big (archive)->memoff,
152284865Sobrien				  (char **) NULL, 10)
152384865Sobrien	  || filestart == strtol (xcoff_ardata_big (archive)->symoff,
152484865Sobrien				  (char **) NULL, 10))
152584865Sobrien	{
152684865Sobrien	  bfd_set_error (bfd_error_no_more_archived_files);
152784865Sobrien	  return NULL;
152884865Sobrien	}
152984865Sobrien    }
153084865Sobrien
153184865Sobrien  return _bfd_get_elt_at_filepos (archive, filestart);
153284865Sobrien}
153384865Sobrien
153484865Sobrien/* Stat an element in an XCOFF archive.  */
153584865Sobrien
153684865Sobrienint
153792828Sobrien_bfd_xcoff_stat_arch_elt (abfd, s)
153884865Sobrien     bfd *abfd;
153984865Sobrien     struct stat *s;
154084865Sobrien{
154184865Sobrien  if (abfd->arelt_data == NULL)
154284865Sobrien    {
154384865Sobrien      bfd_set_error (bfd_error_invalid_operation);
154484865Sobrien      return -1;
154584865Sobrien    }
154684865Sobrien
154792828Sobrien  if (! xcoff_big_format_p (abfd->my_archive))
154884865Sobrien    {
154984865Sobrien      struct xcoff_ar_hdr *hdrp = arch_xhdr (abfd);
155084865Sobrien
155184865Sobrien      s->st_mtime = strtol (hdrp->date, (char **) NULL, 10);
155284865Sobrien      s->st_uid = strtol (hdrp->uid, (char **) NULL, 10);
155384865Sobrien      s->st_gid = strtol (hdrp->gid, (char **) NULL, 10);
155484865Sobrien      s->st_mode = strtol (hdrp->mode, (char **) NULL, 8);
155584865Sobrien      s->st_size = arch_eltdata (abfd)->parsed_size;
155684865Sobrien    }
155784865Sobrien  else
155884865Sobrien    {
155984865Sobrien      struct xcoff_ar_hdr_big *hdrp = arch_xhdr_big (abfd);
156084865Sobrien
156184865Sobrien      s->st_mtime = strtol (hdrp->date, (char **) NULL, 10);
156284865Sobrien      s->st_uid = strtol (hdrp->uid, (char **) NULL, 10);
156384865Sobrien      s->st_gid = strtol (hdrp->gid, (char **) NULL, 10);
156484865Sobrien      s->st_mode = strtol (hdrp->mode, (char **) NULL, 8);
156584865Sobrien      s->st_size = arch_eltdata (abfd)->parsed_size;
156684865Sobrien    }
156784865Sobrien
156884865Sobrien  return 0;
156984865Sobrien}
157084865Sobrien
157184865Sobrien/* Normalize a file name for inclusion in an archive.  */
157284865Sobrien
157384865Sobrienstatic const char *
157484865Sobriennormalize_filename (abfd)
157584865Sobrien     bfd *abfd;
157684865Sobrien{
157784865Sobrien  const char *file;
157884865Sobrien  const char *filename;
157984865Sobrien
158084865Sobrien  file = bfd_get_filename (abfd);
158184865Sobrien  filename = strrchr (file, '/');
158284865Sobrien  if (filename != NULL)
158384865Sobrien    filename++;
158484865Sobrien  else
158584865Sobrien    filename = file;
158684865Sobrien  return filename;
158784865Sobrien}
158884865Sobrien
158984865Sobrien/* Write out an XCOFF armap.  */
159084865Sobrien
1591130561Sobrienstatic bfd_boolean
159284865Sobrienxcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
159384865Sobrien     bfd *abfd;
159484865Sobrien     unsigned int elength ATTRIBUTE_UNUSED;
159584865Sobrien     struct orl *map;
159684865Sobrien     unsigned int orl_count;
159784865Sobrien     int stridx;
159884865Sobrien{
159984865Sobrien  struct xcoff_ar_hdr hdr;
160084865Sobrien  char *p;
160184865Sobrien  unsigned char buf[4];
160284865Sobrien  bfd *sub;
160384865Sobrien  file_ptr fileoff;
160484865Sobrien  unsigned int i;
160584865Sobrien
160684865Sobrien  memset (&hdr, 0, sizeof hdr);
160784865Sobrien  sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx));
160884865Sobrien  sprintf (hdr.nextoff, "%d", 0);
160989857Sobrien  memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, XCOFFARMAG_ELEMENT_SIZE);
161084865Sobrien  sprintf (hdr.date, "%d", 0);
161184865Sobrien  sprintf (hdr.uid, "%d", 0);
161284865Sobrien  sprintf (hdr.gid, "%d", 0);
161384865Sobrien  sprintf (hdr.mode, "%d", 0);
161484865Sobrien  sprintf (hdr.namlen, "%d", 0);
161584865Sobrien
161684865Sobrien  /* We need spaces, not null bytes, in the header.  */
161784865Sobrien  for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR; p++)
161884865Sobrien    if (*p == '\0')
161984865Sobrien      *p = ' ';
162084865Sobrien
162189857Sobrien  if (bfd_bwrite ((PTR) &hdr, (bfd_size_type) SIZEOF_AR_HDR, abfd)
162289857Sobrien      != SIZEOF_AR_HDR
162389857Sobrien      || (bfd_bwrite (XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd)
162489857Sobrien	  != SXCOFFARFMAG))
1625130561Sobrien    return FALSE;
162684865Sobrien
162789857Sobrien  H_PUT_32 (abfd, orl_count, buf);
162889857Sobrien  if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4)
1629130561Sobrien    return FALSE;
163084865Sobrien
163184865Sobrien  sub = abfd->archive_head;
163284865Sobrien  fileoff = SIZEOF_AR_FILE_HDR;
163384865Sobrien  i = 0;
163484865Sobrien  while (sub != NULL && i < orl_count)
163584865Sobrien    {
163684865Sobrien      size_t namlen;
163784865Sobrien
163889857Sobrien      while (map[i].u.abfd == sub)
163984865Sobrien	{
164089857Sobrien	  H_PUT_32 (abfd, fileoff, buf);
164189857Sobrien	  if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4)
1642130561Sobrien	    return FALSE;
164384865Sobrien	  ++i;
164484865Sobrien	}
164584865Sobrien      namlen = strlen (normalize_filename (sub));
164689857Sobrien      namlen = (namlen + 1) &~ (size_t) 1;
164784865Sobrien      fileoff += (SIZEOF_AR_HDR
164884865Sobrien		  + namlen
164984865Sobrien		  + SXCOFFARFMAG
165084865Sobrien		  + arelt_size (sub));
165184865Sobrien      fileoff = (fileoff + 1) &~ 1;
1652218822Sdim      sub = sub->archive_next;
165384865Sobrien    }
165484865Sobrien
165584865Sobrien  for (i = 0; i < orl_count; i++)
165684865Sobrien    {
165784865Sobrien      const char *name;
165884865Sobrien      size_t namlen;
165984865Sobrien
166084865Sobrien      name = *map[i].name;
166184865Sobrien      namlen = strlen (name);
166289857Sobrien      if (bfd_bwrite (name, (bfd_size_type) (namlen + 1), abfd) != namlen + 1)
1663130561Sobrien	return FALSE;
166484865Sobrien    }
166584865Sobrien
166684865Sobrien  if ((stridx & 1) != 0)
166784865Sobrien    {
166884865Sobrien      char b;
166984865Sobrien
167084865Sobrien      b = '\0';
167189857Sobrien      if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
1672130561Sobrien	return FALSE;
167384865Sobrien    }
167484865Sobrien
1675130561Sobrien  return TRUE;
167684865Sobrien}
167784865Sobrien
167889857Sobrienstatic char buff20[XCOFFARMAGBIG_ELEMENT_SIZE + 1];
167989857Sobrien#define FMT20  "%-20lld"
168089857Sobrien#define FMT12  "%-12d"
168189857Sobrien#define FMT12_OCTAL  "%-12o"
168289857Sobrien#define FMT4  "%-4d"
168389857Sobrien#define PRINT20(d, v) \
168489857Sobrien  sprintf (buff20, FMT20, (long long)(v)), \
168589857Sobrien  memcpy ((void *) (d), buff20, 20)
168689857Sobrien
168789857Sobrien#define PRINT12(d, v) \
168889857Sobrien  sprintf (buff20, FMT12, (int)(v)), \
1689130561Sobrien  memcpy ((void *) (d), buff20, 12)
169089857Sobrien
169189857Sobrien#define PRINT12_OCTAL(d, v) \
169289857Sobrien  sprintf (buff20, FMT12_OCTAL, (unsigned int)(v)), \
169389857Sobrien  memcpy ((void *) (d), buff20, 12)
169489857Sobrien
169589857Sobrien#define PRINT4(d, v) \
169689857Sobrien  sprintf (buff20, FMT4, (int)(v)), \
1697130561Sobrien  memcpy ((void *) (d), buff20, 4)
169889857Sobrien
169989857Sobrien#define READ20(d, v) \
170089857Sobrien  buff20[20] = 0, \
170189857Sobrien  memcpy (buff20, (d), 20), \
170289857Sobrien  (v) = bfd_scan_vma (buff20, (const char **) NULL, 10)
170389857Sobrien
1704130561Sobrienstatic bfd_boolean
1705104834Sobriendo_pad (abfd, number)
1706104834Sobrien     bfd *abfd;
1707104834Sobrien     unsigned int number;
1708104834Sobrien{
1709104834Sobrien  bfd_byte b = 0;
1710104834Sobrien
1711104834Sobrien  /* Limit pad to <= 4096.  */
1712104834Sobrien  if (number > 4096)
1713130561Sobrien    return FALSE;
1714104834Sobrien
1715104834Sobrien  while (number--)
1716104834Sobrien    if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
1717130561Sobrien      return FALSE;
1718104834Sobrien
1719130561Sobrien  return TRUE;
1720104834Sobrien}
1721104834Sobrien
1722130561Sobrienstatic bfd_boolean
1723104834Sobriendo_copy (out_bfd, in_bfd)
1724104834Sobrien     bfd *out_bfd;
1725104834Sobrien     bfd *in_bfd;
1726104834Sobrien{
1727104834Sobrien  bfd_size_type remaining;
1728104834Sobrien  bfd_byte buffer[DEFAULT_BUFFERSIZE];
1729104834Sobrien
1730104834Sobrien  if (bfd_seek (in_bfd, (file_ptr) 0, SEEK_SET) != 0)
1731130561Sobrien    return FALSE;
1732104834Sobrien
1733104834Sobrien  remaining = arelt_size (in_bfd);
1734104834Sobrien
1735104834Sobrien  while (remaining >= DEFAULT_BUFFERSIZE)
1736104834Sobrien    {
1737104834Sobrien      if (bfd_bread (buffer, DEFAULT_BUFFERSIZE, in_bfd) != DEFAULT_BUFFERSIZE
1738104834Sobrien	  || bfd_bwrite (buffer, DEFAULT_BUFFERSIZE, out_bfd) != DEFAULT_BUFFERSIZE)
1739130561Sobrien	return FALSE;
1740104834Sobrien
1741104834Sobrien      remaining -= DEFAULT_BUFFERSIZE;
1742104834Sobrien    }
1743104834Sobrien
1744104834Sobrien  if (remaining)
1745104834Sobrien    {
1746130561Sobrien      if (bfd_bread (buffer, remaining, in_bfd) != remaining
1747104834Sobrien	  || bfd_bwrite (buffer, remaining, out_bfd) != remaining)
1748130561Sobrien	return FALSE;
1749104834Sobrien    }
1750104834Sobrien
1751130561Sobrien  return TRUE;
1752104834Sobrien}
1753104834Sobrien
1754130561Sobrienstatic bfd_boolean
1755104834Sobriendo_shared_object_padding (out_bfd, in_bfd, offset, ar_header_size)
1756104834Sobrien     bfd *out_bfd;
1757104834Sobrien     bfd *in_bfd;
1758218822Sdim     file_ptr *offset;
1759104834Sobrien     int ar_header_size;
1760104834Sobrien{
1761104834Sobrien  if (bfd_check_format (in_bfd, bfd_object)
1762104834Sobrien      && bfd_get_flavour (in_bfd) == bfd_target_xcoff_flavour
1763104834Sobrien      && (in_bfd->flags & DYNAMIC) != 0)
1764104834Sobrien    {
1765104834Sobrien      bfd_size_type pad = 0;
1766104834Sobrien      int text_align_power;
1767104834Sobrien
1768104834Sobrien      text_align_power = bfd_xcoff_text_align_power (in_bfd);
1769104834Sobrien
1770104834Sobrien      pad = 1 << text_align_power;
1771104834Sobrien      pad -= (*offset + ar_header_size) & (pad - 1);
1772104834Sobrien
1773104834Sobrien      if (! do_pad (out_bfd, pad))
1774130561Sobrien	return FALSE;
1775104834Sobrien
1776104834Sobrien      *offset += pad;
1777104834Sobrien    }
1778104834Sobrien
1779130561Sobrien  return TRUE;
1780104834Sobrien}
1781104834Sobrien
1782130561Sobrienstatic bfd_boolean
178389857Sobrienxcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
178484865Sobrien     bfd *abfd;
178589857Sobrien     unsigned int elength ATTRIBUTE_UNUSED;
178684865Sobrien     struct orl *map;
178784865Sobrien     unsigned int orl_count;
178889857Sobrien     int stridx;
178984865Sobrien{
179089857Sobrien  struct xcoff_ar_file_hdr_big *fhdr;
179189857Sobrien  bfd_vma i, sym_32, sym_64, str_32, str_64;
179284865Sobrien  const bfd_arch_info_type *arch_info = NULL;
179389857Sobrien  bfd *current_bfd;
179489857Sobrien  size_t string_length;
1795218822Sdim  file_ptr nextoff, prevoff;
1796130561Sobrien
179789857Sobrien  /* First, we look through the symbols and work out which are
179889857Sobrien     from 32-bit objects and which from 64-bit ones.  */
179989857Sobrien  sym_32 = sym_64 = str_32 = str_64 = 0;
180084865Sobrien
180189857Sobrien  current_bfd = abfd->archive_head;
180289857Sobrien  if (current_bfd != NULL)
180389857Sobrien    arch_info = bfd_get_arch_info (current_bfd);
180489857Sobrien    i = 0;
180589857Sobrien    while (current_bfd != NULL && i < orl_count)
180689857Sobrien    {
180789857Sobrien      while (map[i].u.abfd == current_bfd)
180889857Sobrien	{
180989857Sobrien	  string_length = strlen (*map[i].name) + 1;
181084865Sobrien
181189857Sobrien	  if (arch_info->bits_per_address == 64)
181289857Sobrien	    {
181389857Sobrien	      sym_64++;
181489857Sobrien	      str_64 += string_length;
181589857Sobrien	    }
181689857Sobrien	  else
181789857Sobrien	    {
181889857Sobrien	      sym_32++;
181989857Sobrien	      str_32 += string_length;
182089857Sobrien	    }
182189857Sobrien	  i++;
182289857Sobrien	}
1823218822Sdim      current_bfd = current_bfd->archive_next;
182489857Sobrien      if (current_bfd != NULL)
182589857Sobrien	arch_info = bfd_get_arch_info (current_bfd);
182689857Sobrien    }
182784865Sobrien
182889857Sobrien  /* A quick sanity check... */
182989857Sobrien  BFD_ASSERT (sym_64 + sym_32 == orl_count);
183089857Sobrien  /* Explicit cast to int for compiler.  */
183189857Sobrien  BFD_ASSERT ((int)(str_64 + str_32) == stridx);
183284865Sobrien
183389857Sobrien  fhdr = xcoff_ardata_big (abfd);
183484865Sobrien
183589857Sobrien  /* xcoff_write_archive_contents_big passes nextoff in symoff. */
183689857Sobrien  READ20 (fhdr->memoff, prevoff);
183789857Sobrien  READ20 (fhdr->symoff, nextoff);
183884865Sobrien
183989857Sobrien  BFD_ASSERT (nextoff == bfd_tell (abfd));
184089857Sobrien
1841130561Sobrien  /* Write out the symbol table.
1842130561Sobrien     Layout :
1843130561Sobrien
184489857Sobrien     standard big archive header
1845130561Sobrien     0x0000		      ar_size	[0x14]
1846130561Sobrien     0x0014		      ar_nxtmem [0x14]
1847130561Sobrien     0x0028		      ar_prvmem [0x14]
1848130561Sobrien     0x003C		      ar_date	[0x0C]
1849130561Sobrien     0x0048		      ar_uid	[0x0C]
1850130561Sobrien     0x0054		      ar_gid	[0x0C]
1851130561Sobrien     0x0060		      ar_mod	[0x0C]
1852130561Sobrien     0x006C		      ar_namelen[0x04]
1853130561Sobrien     0x0070		      ar_fmag	[SXCOFFARFMAG]
1854130561Sobrien
1855130561Sobrien     Symbol table
1856130561Sobrien     0x0072		      num_syms	[0x08], binary
1857130561Sobrien     0x0078		      offsets	[0x08 * num_syms], binary
1858130561Sobrien     0x0086 + 0x08 * num_syms names	[??]
1859130561Sobrien     ??			      pad to even bytes.
186089857Sobrien  */
186189857Sobrien
1862130561Sobrien  if (sym_32)
186384865Sobrien    {
186489857Sobrien      struct xcoff_ar_hdr_big *hdr;
1865218822Sdim      char *symbol_table;
1866218822Sdim      char *st;
186789857Sobrien      file_ptr fileoff;
186884865Sobrien
1869130561Sobrien      bfd_vma symbol_table_size =
187089857Sobrien	SIZEOF_AR_HDR_BIG
187189857Sobrien	+ SXCOFFARFMAG
1872130561Sobrien	+ 8
1873130561Sobrien	+ 8 * sym_32
187489857Sobrien	+ str_32 + (str_32 & 1);
187589857Sobrien
1876218822Sdim      symbol_table = bfd_zmalloc (symbol_table_size);
187789857Sobrien      if (symbol_table == NULL)
1878130561Sobrien	return FALSE;
187989857Sobrien
188089857Sobrien      hdr = (struct xcoff_ar_hdr_big *) symbol_table;
1881130561Sobrien
188289857Sobrien      PRINT20 (hdr->size, 8 + 8 * sym_32 + str_32 + (str_32 & 1));
1883130561Sobrien
188489857Sobrien      if (sym_64)
188589857Sobrien	PRINT20 (hdr->nextoff, nextoff + symbol_table_size);
188684865Sobrien      else
188789857Sobrien	PRINT20 (hdr->nextoff, 0);
188884865Sobrien
188989857Sobrien      PRINT20 (hdr->prevoff, prevoff);
189089857Sobrien      PRINT12 (hdr->date, 0);
189189857Sobrien      PRINT12 (hdr->uid, 0);
189289857Sobrien      PRINT12 (hdr->gid, 0);
189389857Sobrien      PRINT12 (hdr->mode, 0);
189489857Sobrien      PRINT4 (hdr->namlen, 0) ;
189584865Sobrien
189689857Sobrien      st = symbol_table + SIZEOF_AR_HDR_BIG;
189789857Sobrien      memcpy (st, XCOFFARFMAG, SXCOFFARFMAG);
189889857Sobrien      st += SXCOFFARFMAG;
189984865Sobrien
190089857Sobrien      bfd_h_put_64 (abfd, sym_32, st);
190189857Sobrien      st += 8;
1902130561Sobrien
190389857Sobrien      /* loop over the 32 bit offsets */
190489857Sobrien      current_bfd = abfd->archive_head;
190589857Sobrien      if (current_bfd != NULL)
190689857Sobrien	arch_info = bfd_get_arch_info (current_bfd);
190789857Sobrien      fileoff = SIZEOF_AR_FILE_HDR_BIG;
190889857Sobrien      i = 0;
190989857Sobrien      while (current_bfd != NULL && i < orl_count)
191089857Sobrien	{
191189857Sobrien	  while (map[i].u.abfd == current_bfd)
191289857Sobrien	    {
191389857Sobrien	      if (arch_info->bits_per_address == 32)
191489857Sobrien		{
191589857Sobrien		  bfd_h_put_64 (abfd, fileoff, st);
191689857Sobrien		  st += 8;
191789857Sobrien		}
191889857Sobrien	      i++;
191989857Sobrien	    }
192089857Sobrien	  string_length = strlen (normalize_filename (current_bfd));
192189857Sobrien	  string_length += string_length & 1;
192289857Sobrien	  fileoff += (SIZEOF_AR_HDR_BIG
192389857Sobrien		      + string_length
192489857Sobrien		      + SXCOFFARFMAG
192589857Sobrien		      + arelt_size (current_bfd));
192689857Sobrien	  fileoff += fileoff & 1;
1927218822Sdim	  current_bfd = current_bfd->archive_next;
192889857Sobrien	  if (current_bfd != NULL)
192989857Sobrien	    arch_info = bfd_get_arch_info (current_bfd);
193089857Sobrien	}
193184865Sobrien
193289857Sobrien      /* loop over the 32 bit symbol names */
193389857Sobrien      current_bfd = abfd->archive_head;
193489857Sobrien      if (current_bfd != NULL)
193589857Sobrien	arch_info = bfd_get_arch_info (current_bfd);
193689857Sobrien      i = 0;
193789857Sobrien      while (current_bfd != NULL && i < orl_count)
193889857Sobrien	{
193989857Sobrien	  while (map[i].u.abfd == current_bfd)
194089857Sobrien	    {
194189857Sobrien	      if (arch_info->bits_per_address == 32)
194289857Sobrien		{
194389857Sobrien		  string_length = sprintf (st, "%s", *map[i].name);
194489857Sobrien		  st += string_length + 1;
194589857Sobrien		}
194689857Sobrien	      i++;
194789857Sobrien	    }
1948218822Sdim	  current_bfd = current_bfd->archive_next;
194989857Sobrien	  if (current_bfd != NULL)
195089857Sobrien	    arch_info = bfd_get_arch_info (current_bfd);
195189857Sobrien	}
195284865Sobrien
195389857Sobrien      bfd_bwrite (symbol_table, symbol_table_size, abfd);
195489857Sobrien
195589857Sobrien      free (symbol_table);
195689857Sobrien
195789857Sobrien      prevoff = nextoff;
195889857Sobrien      nextoff = nextoff + symbol_table_size;
195984865Sobrien    }
1960130561Sobrien  else
196189857Sobrien    PRINT20 (fhdr->symoff, 0);
1962130561Sobrien
1963130561Sobrien  if (sym_64)
196484865Sobrien    {
196589857Sobrien      struct xcoff_ar_hdr_big *hdr;
1966218822Sdim      char *symbol_table;
1967218822Sdim      char *st;
196889857Sobrien      file_ptr fileoff;
196984865Sobrien
1970130561Sobrien      bfd_vma symbol_table_size =
197189857Sobrien	SIZEOF_AR_HDR_BIG
197289857Sobrien	+ SXCOFFARFMAG
1973130561Sobrien	+ 8
1974130561Sobrien	+ 8 * sym_64
197589857Sobrien	+ str_64 + (str_64 & 1);
197689857Sobrien
1977218822Sdim      symbol_table = bfd_zmalloc (symbol_table_size);
197889857Sobrien      if (symbol_table == NULL)
1979130561Sobrien	return FALSE;
198084865Sobrien
198189857Sobrien      hdr = (struct xcoff_ar_hdr_big *) symbol_table;
198284865Sobrien
198389857Sobrien      PRINT20 (hdr->size, 8 + 8 * sym_64 + str_64 + (str_64 & 1));
198489857Sobrien      PRINT20 (hdr->nextoff, 0);
198589857Sobrien      PRINT20 (hdr->prevoff, prevoff);
198689857Sobrien      PRINT12 (hdr->date, 0);
198789857Sobrien      PRINT12 (hdr->uid, 0);
198889857Sobrien      PRINT12 (hdr->gid, 0);
198989857Sobrien      PRINT12 (hdr->mode, 0);
199089857Sobrien      PRINT4 (hdr->namlen, 0);
199184865Sobrien
199289857Sobrien      st = symbol_table + SIZEOF_AR_HDR_BIG;
199389857Sobrien      memcpy (st, XCOFFARFMAG, SXCOFFARFMAG);
199489857Sobrien      st += SXCOFFARFMAG;
199589857Sobrien
199689857Sobrien      bfd_h_put_64 (abfd, sym_64, st);
199789857Sobrien      st += 8;
1998130561Sobrien
199989857Sobrien      /* loop over the 64 bit offsets */
200089857Sobrien      current_bfd = abfd->archive_head;
200189857Sobrien      if (current_bfd != NULL)
200289857Sobrien	arch_info = bfd_get_arch_info (current_bfd);
200389857Sobrien      fileoff = SIZEOF_AR_FILE_HDR_BIG;
200489857Sobrien      i = 0;
200589857Sobrien      while (current_bfd != NULL && i < orl_count)
200684865Sobrien	{
200789857Sobrien	  while (map[i].u.abfd == current_bfd)
200889857Sobrien	    {
200989857Sobrien	      if (arch_info->bits_per_address == 64)
201089857Sobrien		{
201189857Sobrien		  bfd_h_put_64 (abfd, fileoff, st);
201289857Sobrien		  st += 8;
201389857Sobrien		}
201489857Sobrien	      i++;
201589857Sobrien	    }
201689857Sobrien	  string_length = strlen (normalize_filename (current_bfd));
201789857Sobrien	  string_length += string_length & 1;
201889857Sobrien	  fileoff += (SIZEOF_AR_HDR_BIG
201989857Sobrien		      + string_length
202089857Sobrien		      + SXCOFFARFMAG
202189857Sobrien		      + arelt_size (current_bfd));
202289857Sobrien	  fileoff += fileoff & 1;
2023218822Sdim	  current_bfd = current_bfd->archive_next;
202489857Sobrien	  if (current_bfd != NULL)
202589857Sobrien	    arch_info = bfd_get_arch_info (current_bfd);
202684865Sobrien	}
202789857Sobrien
202889857Sobrien      /* loop over the 64 bit symbol names */
202989857Sobrien      current_bfd = abfd->archive_head;
203089857Sobrien      if (current_bfd != NULL)
203189857Sobrien	arch_info = bfd_get_arch_info (current_bfd);
203289857Sobrien      i = 0;
203389857Sobrien      while (current_bfd != NULL && i < orl_count)
203484865Sobrien	{
203589857Sobrien	  while (map[i].u.abfd == current_bfd)
203689857Sobrien	    {
203789857Sobrien	      if (arch_info->bits_per_address == 64)
203889857Sobrien		{
203989857Sobrien		  string_length = sprintf (st, "%s", *map[i].name);
204089857Sobrien		  st += string_length + 1;
204189857Sobrien		}
204289857Sobrien	      i++;
204389857Sobrien	    }
2044218822Sdim	  current_bfd = current_bfd->archive_next;
204589857Sobrien	  if (current_bfd != NULL)
204689857Sobrien	    arch_info = bfd_get_arch_info (current_bfd);
204784865Sobrien	}
204884865Sobrien
204989857Sobrien      bfd_bwrite (symbol_table, symbol_table_size, abfd);
205084865Sobrien
205189857Sobrien      free (symbol_table);
205289857Sobrien
205389857Sobrien      PRINT20 (fhdr->symoff64, nextoff);
205489857Sobrien    }
2055130561Sobrien  else
205689857Sobrien    PRINT20 (fhdr->symoff64, 0);
2057130561Sobrien
2058130561Sobrien  return TRUE;
205984865Sobrien}
206084865Sobrien
2061130561Sobrienbfd_boolean
206284865Sobrien_bfd_xcoff_write_armap (abfd, elength, map, orl_count, stridx)
206384865Sobrien     bfd *abfd;
206484865Sobrien     unsigned int elength ATTRIBUTE_UNUSED;
206584865Sobrien     struct orl *map;
206684865Sobrien     unsigned int orl_count;
206784865Sobrien     int stridx;
206884865Sobrien{
206984865Sobrien  if (! xcoff_big_format_p (abfd))
207084865Sobrien    return xcoff_write_armap_old (abfd, elength, map, orl_count, stridx);
207184865Sobrien  else
207284865Sobrien    return xcoff_write_armap_big (abfd, elength, map, orl_count, stridx);
207384865Sobrien}
207484865Sobrien
207584865Sobrien/* Write out an XCOFF archive.  We always write an entire archive,
207684865Sobrien   rather than fussing with the freelist and so forth.  */
207784865Sobrien
2078130561Sobrienstatic bfd_boolean
207984865Sobrienxcoff_write_archive_contents_old (abfd)
208084865Sobrien     bfd *abfd;
208184865Sobrien{
208284865Sobrien  struct xcoff_ar_file_hdr fhdr;
208389857Sobrien  bfd_size_type count;
208489857Sobrien  bfd_size_type total_namlen;
208584865Sobrien  file_ptr *offsets;
2086130561Sobrien  bfd_boolean makemap;
2087130561Sobrien  bfd_boolean hasobjects;
2088218822Sdim  file_ptr prevoff, nextoff;
208984865Sobrien  bfd *sub;
209089857Sobrien  size_t i;
209184865Sobrien  struct xcoff_ar_hdr ahdr;
209284865Sobrien  bfd_size_type size;
209384865Sobrien  char *p;
209489857Sobrien  char decbuf[XCOFFARMAG_ELEMENT_SIZE + 1];
209584865Sobrien
209684865Sobrien  memset (&fhdr, 0, sizeof fhdr);
2097218822Sdim  (void) strncpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG);
209884865Sobrien  sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR);
209984865Sobrien  sprintf (fhdr.freeoff, "%d", 0);
210084865Sobrien
210184865Sobrien  count = 0;
210284865Sobrien  total_namlen = 0;
2103218822Sdim  for (sub = abfd->archive_head; sub != NULL; sub = sub->archive_next)
210484865Sobrien    {
210584865Sobrien      ++count;
210684865Sobrien      total_namlen += strlen (normalize_filename (sub)) + 1;
210784865Sobrien    }
210884865Sobrien  offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr));
210984865Sobrien  if (offsets == NULL)
2110130561Sobrien    return FALSE;
211184865Sobrien
211289857Sobrien  if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR, SEEK_SET) != 0)
2113130561Sobrien    return FALSE;
211484865Sobrien
211584865Sobrien  makemap = bfd_has_map (abfd);
2116130561Sobrien  hasobjects = FALSE;
211784865Sobrien  prevoff = 0;
211884865Sobrien  nextoff = SIZEOF_AR_FILE_HDR;
2119218822Sdim  for (sub = abfd->archive_head, i = 0;
2120218822Sdim       sub != NULL;
2121218822Sdim       sub = sub->archive_next, i++)
212284865Sobrien    {
212384865Sobrien      const char *name;
212489857Sobrien      bfd_size_type namlen;
212584865Sobrien      struct xcoff_ar_hdr *ahdrp;
212684865Sobrien      bfd_size_type remaining;
212784865Sobrien
212884865Sobrien      if (makemap && ! hasobjects)
212984865Sobrien	{
213084865Sobrien	  if (bfd_check_format (sub, bfd_object))
2131130561Sobrien	    hasobjects = TRUE;
213284865Sobrien	}
213384865Sobrien
213484865Sobrien      name = normalize_filename (sub);
213584865Sobrien      namlen = strlen (name);
213684865Sobrien
213784865Sobrien      if (sub->arelt_data != NULL)
213884865Sobrien	ahdrp = arch_xhdr (sub);
213984865Sobrien      else
214084865Sobrien	ahdrp = NULL;
214184865Sobrien
214284865Sobrien      if (ahdrp == NULL)
214384865Sobrien	{
214484865Sobrien	  struct stat s;
214584865Sobrien
214684865Sobrien	  memset (&ahdr, 0, sizeof ahdr);
214784865Sobrien	  ahdrp = &ahdr;
214884865Sobrien	  if (stat (bfd_get_filename (sub), &s) != 0)
214984865Sobrien	    {
215084865Sobrien	      bfd_set_error (bfd_error_system_call);
2151130561Sobrien	      return FALSE;
215284865Sobrien	    }
215384865Sobrien
215484865Sobrien	  sprintf (ahdrp->size, "%ld", (long) s.st_size);
215584865Sobrien	  sprintf (ahdrp->date, "%ld", (long) s.st_mtime);
215684865Sobrien	  sprintf (ahdrp->uid, "%ld", (long) s.st_uid);
215784865Sobrien	  sprintf (ahdrp->gid, "%ld", (long) s.st_gid);
215884865Sobrien	  sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode);
215984865Sobrien
216084865Sobrien	  if (sub->arelt_data == NULL)
216184865Sobrien	    {
216289857Sobrien	      size = sizeof (struct areltdata);
216389857Sobrien	      sub->arelt_data = bfd_alloc (sub, size);
216484865Sobrien	      if (sub->arelt_data == NULL)
2165130561Sobrien		return FALSE;
216684865Sobrien	    }
216784865Sobrien
216884865Sobrien	  arch_eltdata (sub)->parsed_size = s.st_size;
216984865Sobrien	}
217084865Sobrien
217184865Sobrien      sprintf (ahdrp->prevoff, "%ld", (long) prevoff);
217284865Sobrien      sprintf (ahdrp->namlen, "%ld", (long) namlen);
217384865Sobrien
217484865Sobrien      /* If the length of the name is odd, we write out the null byte
2175130561Sobrien	 after the name as well.  */
217689857Sobrien      namlen = (namlen + 1) &~ (bfd_size_type) 1;
217784865Sobrien
217884865Sobrien      remaining = arelt_size (sub);
217984865Sobrien      size = (SIZEOF_AR_HDR
218084865Sobrien	      + namlen
218184865Sobrien	      + SXCOFFARFMAG
218284865Sobrien	      + remaining);
218384865Sobrien
218484865Sobrien      BFD_ASSERT (nextoff == bfd_tell (abfd));
218584865Sobrien
218684865Sobrien      offsets[i] = nextoff;
218784865Sobrien
218884865Sobrien      prevoff = nextoff;
218984865Sobrien      nextoff += size + (size & 1);
219084865Sobrien
219184865Sobrien      sprintf (ahdrp->nextoff, "%ld", (long) nextoff);
219284865Sobrien
219384865Sobrien      /* We need spaces, not null bytes, in the header.  */
219484865Sobrien      for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR; p++)
219584865Sobrien	if (*p == '\0')
219684865Sobrien	  *p = ' ';
219784865Sobrien
219889857Sobrien      if ((bfd_bwrite ((PTR) ahdrp, (bfd_size_type) SIZEOF_AR_HDR, abfd)
219989857Sobrien	   != SIZEOF_AR_HDR)
2200130561Sobrien	  || bfd_bwrite ((PTR) name, namlen, abfd) != namlen
2201130561Sobrien	  || bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG,
2202130561Sobrien			 abfd) != SXCOFFARFMAG)
2203130561Sobrien	return FALSE;
220484865Sobrien
220584865Sobrien      if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
2206130561Sobrien	return FALSE;
220784865Sobrien
2208104834Sobrien      if (! do_copy (abfd, sub))
2209130561Sobrien	return FALSE;
2210130561Sobrien
2211104834Sobrien      if (! do_pad (abfd, size & 1))
2212130561Sobrien	return FALSE;
221384865Sobrien    }
221484865Sobrien
221584865Sobrien  sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
221684865Sobrien
221784865Sobrien  /* Write out the member table.  */
221884865Sobrien
221984865Sobrien  BFD_ASSERT (nextoff == bfd_tell (abfd));
222084865Sobrien  sprintf (fhdr.memoff, "%ld", (long) nextoff);
222184865Sobrien
222284865Sobrien  memset (&ahdr, 0, sizeof ahdr);
2223104834Sobrien  sprintf (ahdr.size, "%ld", (long) (XCOFFARMAG_ELEMENT_SIZE
2224104834Sobrien				     + count * XCOFFARMAG_ELEMENT_SIZE
2225104834Sobrien				     + total_namlen));
222684865Sobrien  sprintf (ahdr.prevoff, "%ld", (long) prevoff);
222784865Sobrien  sprintf (ahdr.date, "%d", 0);
222884865Sobrien  sprintf (ahdr.uid, "%d", 0);
222984865Sobrien  sprintf (ahdr.gid, "%d", 0);
223084865Sobrien  sprintf (ahdr.mode, "%d", 0);
223184865Sobrien  sprintf (ahdr.namlen, "%d", 0);
223284865Sobrien
223384865Sobrien  size = (SIZEOF_AR_HDR
223489857Sobrien	  + XCOFFARMAG_ELEMENT_SIZE
223589857Sobrien	  + count * XCOFFARMAG_ELEMENT_SIZE
223684865Sobrien	  + total_namlen
223784865Sobrien	  + SXCOFFARFMAG);
223884865Sobrien
223984865Sobrien  prevoff = nextoff;
224084865Sobrien  nextoff += size + (size & 1);
224184865Sobrien
224284865Sobrien  if (makemap && hasobjects)
224384865Sobrien    sprintf (ahdr.nextoff, "%ld", (long) nextoff);
224484865Sobrien  else
224584865Sobrien    sprintf (ahdr.nextoff, "%d", 0);
224684865Sobrien
224784865Sobrien  /* We need spaces, not null bytes, in the header.  */
224884865Sobrien  for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR; p++)
224984865Sobrien    if (*p == '\0')
225084865Sobrien      *p = ' ';
225184865Sobrien
225289857Sobrien  if ((bfd_bwrite ((PTR) &ahdr, (bfd_size_type) SIZEOF_AR_HDR, abfd)
225389857Sobrien       != SIZEOF_AR_HDR)
225489857Sobrien      || (bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd)
225584865Sobrien	  != SXCOFFARFMAG))
2256130561Sobrien    return FALSE;
225784865Sobrien
225884865Sobrien  sprintf (decbuf, "%-12ld", (long) count);
225989857Sobrien  if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) XCOFFARMAG_ELEMENT_SIZE, abfd)
226089857Sobrien      != XCOFFARMAG_ELEMENT_SIZE)
2261130561Sobrien    return FALSE;
226289857Sobrien  for (i = 0; i < (size_t) count; i++)
226384865Sobrien    {
226484865Sobrien      sprintf (decbuf, "%-12ld", (long) offsets[i]);
2265130561Sobrien      if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) XCOFFARMAG_ELEMENT_SIZE,
226689857Sobrien		      abfd) != XCOFFARMAG_ELEMENT_SIZE)
2267130561Sobrien	return FALSE;
226884865Sobrien    }
2269218822Sdim  for (sub = abfd->archive_head; sub != NULL; sub = sub->archive_next)
227084865Sobrien    {
227184865Sobrien      const char *name;
227289857Sobrien      bfd_size_type namlen;
227384865Sobrien
227484865Sobrien      name = normalize_filename (sub);
227584865Sobrien      namlen = strlen (name);
227689857Sobrien      if (bfd_bwrite ((PTR) name, namlen + 1, abfd) != namlen + 1)
2277130561Sobrien	return FALSE;
227884865Sobrien    }
227984865Sobrien
2280104834Sobrien  if (! do_pad (abfd, size & 1))
2281130561Sobrien    return FALSE;
228284865Sobrien
228384865Sobrien  /* Write out the armap, if appropriate.  */
228484865Sobrien  if (! makemap || ! hasobjects)
228584865Sobrien    sprintf (fhdr.symoff, "%d", 0);
228684865Sobrien  else
228784865Sobrien    {
228884865Sobrien      BFD_ASSERT (nextoff == bfd_tell (abfd));
228984865Sobrien      sprintf (fhdr.symoff, "%ld", (long) nextoff);
229084865Sobrien      bfd_ardata (abfd)->tdata = (PTR) &fhdr;
229184865Sobrien      if (! _bfd_compute_and_write_armap (abfd, 0))
2292130561Sobrien	return FALSE;
229384865Sobrien    }
229484865Sobrien
229584865Sobrien  /* Write out the archive file header.  */
229684865Sobrien
229784865Sobrien  /* We need spaces, not null bytes, in the header.  */
229884865Sobrien  for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR; p++)
229984865Sobrien    if (*p == '\0')
230084865Sobrien      *p = ' ';
230184865Sobrien
230284865Sobrien  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
230389857Sobrien      || (bfd_bwrite ((PTR) &fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR, abfd)
230489857Sobrien	  != SIZEOF_AR_FILE_HDR))
2305130561Sobrien    return FALSE;
230684865Sobrien
2307130561Sobrien  return TRUE;
230884865Sobrien}
230984865Sobrien
2310130561Sobrienstatic bfd_boolean
231184865Sobrienxcoff_write_archive_contents_big (abfd)
231284865Sobrien     bfd *abfd;
231384865Sobrien{
231484865Sobrien  struct xcoff_ar_file_hdr_big fhdr;
231589857Sobrien  bfd_size_type count;
231689857Sobrien  bfd_size_type total_namlen;
231784865Sobrien  file_ptr *offsets;
2318130561Sobrien  bfd_boolean makemap;
2319130561Sobrien  bfd_boolean hasobjects;
2320218822Sdim  file_ptr prevoff, nextoff;
232189857Sobrien  bfd *current_bfd;
232289857Sobrien  size_t i;
232389857Sobrien  struct xcoff_ar_hdr_big *hdr, ahdr;
232484865Sobrien  bfd_size_type size;
2325218822Sdim  char *member_table, *mt;
232689857Sobrien  bfd_vma member_table_size;
232784865Sobrien
2328104834Sobrien  memset (&fhdr, 0, SIZEOF_AR_FILE_HDR_BIG);
232989857Sobrien  memcpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
233084865Sobrien
2331104834Sobrien  if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0)
2332130561Sobrien    return FALSE;
2333130561Sobrien
2334104834Sobrien  /* Calculate count and total_namlen.  */
2335104834Sobrien  makemap = bfd_has_map (abfd);
2336130561Sobrien  hasobjects = FALSE;
2337130561Sobrien  for (current_bfd = abfd->archive_head, count = 0, total_namlen = 0;
2338130561Sobrien       current_bfd != NULL;
2339218822Sdim       current_bfd = current_bfd->archive_next, count++)
2340104834Sobrien    {
2341104834Sobrien      total_namlen += strlen (normalize_filename (current_bfd)) + 1;
234289857Sobrien
2343104834Sobrien      if (makemap
2344104834Sobrien	  && ! hasobjects
2345104834Sobrien	  && bfd_check_format (current_bfd, bfd_object))
2346130561Sobrien	hasobjects = TRUE;
2347104834Sobrien    }
2348104834Sobrien
234989857Sobrien  offsets = NULL;
235089857Sobrien  if (count)
235184865Sobrien    {
235289857Sobrien      offsets = (file_ptr *) bfd_malloc (count * sizeof (file_ptr));
235389857Sobrien      if (offsets == NULL)
2354130561Sobrien	return FALSE;
235584865Sobrien    }
235684865Sobrien
235784865Sobrien  prevoff = 0;
235884865Sobrien  nextoff = SIZEOF_AR_FILE_HDR_BIG;
2359130561Sobrien  for (current_bfd = abfd->archive_head, i = 0;
2360130561Sobrien       current_bfd != NULL;
2361218822Sdim       current_bfd = current_bfd->archive_next, i++)
236284865Sobrien    {
236384865Sobrien      const char *name;
236489857Sobrien      bfd_size_type namlen;
236584865Sobrien      struct xcoff_ar_hdr_big *ahdrp;
236684865Sobrien      bfd_size_type remaining;
236784865Sobrien
236889857Sobrien      name = normalize_filename (current_bfd);
236984865Sobrien      namlen = strlen (name);
237084865Sobrien
237189857Sobrien      if (current_bfd->arelt_data != NULL)
237289857Sobrien	ahdrp = arch_xhdr_big (current_bfd);
237384865Sobrien      else
237484865Sobrien	ahdrp = NULL;
237584865Sobrien
237684865Sobrien      if (ahdrp == NULL)
237784865Sobrien	{
237884865Sobrien	  struct stat s;
237984865Sobrien
238084865Sobrien	  ahdrp = &ahdr;
238184865Sobrien	  /* XXX This should actually be a call to stat64 (at least on
2382130561Sobrien	     32-bit machines).
238389857Sobrien	     XXX This call will fail if the original object is not found.  */
238489857Sobrien	  if (stat (bfd_get_filename (current_bfd), &s) != 0)
238584865Sobrien	    {
238684865Sobrien	      bfd_set_error (bfd_error_system_call);
2387130561Sobrien	      return FALSE;
238884865Sobrien	    }
238984865Sobrien
239089857Sobrien	  PRINT20 (ahdrp->size, s.st_size);
239189857Sobrien	  PRINT12 (ahdrp->date, s.st_mtime);
239289857Sobrien	  PRINT12 (ahdrp->uid,  s.st_uid);
239389857Sobrien	  PRINT12 (ahdrp->gid,  s.st_gid);
239489857Sobrien	  PRINT12_OCTAL (ahdrp->mode, s.st_mode);
239584865Sobrien
239689857Sobrien	  if (current_bfd->arelt_data == NULL)
239784865Sobrien	    {
239889857Sobrien	      size = sizeof (struct areltdata);
239989857Sobrien	      current_bfd->arelt_data = bfd_alloc (current_bfd, size);
240089857Sobrien	      if (current_bfd->arelt_data == NULL)
2401130561Sobrien		return FALSE;
240284865Sobrien	    }
240384865Sobrien
240489857Sobrien	  arch_eltdata (current_bfd)->parsed_size = s.st_size;
240584865Sobrien	}
240684865Sobrien
240789857Sobrien      PRINT20 (ahdrp->prevoff, prevoff);
240889857Sobrien      PRINT4 (ahdrp->namlen, namlen);
240984865Sobrien
241084865Sobrien      /* If the length of the name is odd, we write out the null byte
2411130561Sobrien	 after the name as well.  */
241289857Sobrien      namlen = (namlen + 1) &~ (bfd_size_type) 1;
241384865Sobrien
241489857Sobrien      remaining = arelt_size (current_bfd);
241584865Sobrien      size = (SIZEOF_AR_HDR_BIG
241684865Sobrien	      + namlen
241784865Sobrien	      + SXCOFFARFMAG
241884865Sobrien	      + remaining);
241984865Sobrien
242084865Sobrien      BFD_ASSERT (nextoff == bfd_tell (abfd));
242184865Sobrien
2422104834Sobrien      /* Check for xcoff shared objects.
2423104834Sobrien	 Their text section needs to be aligned wrt the archive file position.
2424104834Sobrien	 This requires extra padding before the archive header.  */
2425104834Sobrien      if (! do_shared_object_padding (abfd, current_bfd, & nextoff,
2426130561Sobrien				      SIZEOF_AR_HDR_BIG + namlen
2427104834Sobrien				      + SXCOFFARFMAG))
2428130561Sobrien	return FALSE;
2429104834Sobrien
243084865Sobrien      offsets[i] = nextoff;
243184865Sobrien
243284865Sobrien      prevoff = nextoff;
243384865Sobrien      nextoff += size + (size & 1);
243484865Sobrien
243589857Sobrien      PRINT20 (ahdrp->nextoff, nextoff);
243684865Sobrien
243789857Sobrien      if ((bfd_bwrite ((PTR) ahdrp, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
243889857Sobrien	   != SIZEOF_AR_HDR_BIG)
243989857Sobrien	  || bfd_bwrite ((PTR) name, (bfd_size_type) namlen, abfd) != namlen
2440130561Sobrien	  || (bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG,
244189857Sobrien			  abfd) != SXCOFFARFMAG))
2442130561Sobrien	return FALSE;
244384865Sobrien
244489857Sobrien      if (bfd_seek (current_bfd, (file_ptr) 0, SEEK_SET) != 0)
2445130561Sobrien	return FALSE;
244684865Sobrien
2447104834Sobrien      if (! do_copy (abfd, current_bfd))
2448130561Sobrien	return FALSE;
2449130561Sobrien
2450104834Sobrien      if (! do_pad (abfd, size & 1))
2451130561Sobrien	return FALSE;
2452104834Sobrien    }
245384865Sobrien
2454104834Sobrien  if (count)
2455104834Sobrien    {
2456104834Sobrien      PRINT20 (fhdr.firstmemoff, offsets[0]);
2457104834Sobrien      PRINT20 (fhdr.lastmemoff, prevoff);
245884865Sobrien    }
245984865Sobrien
2460130561Sobrien  /* Write out the member table.
2461130561Sobrien     Layout :
246284865Sobrien
246389857Sobrien     standard big archive header
2464130561Sobrien     0x0000		      ar_size	[0x14]
2465130561Sobrien     0x0014		      ar_nxtmem [0x14]
2466130561Sobrien     0x0028		      ar_prvmem [0x14]
2467130561Sobrien     0x003C		      ar_date	[0x0C]
2468130561Sobrien     0x0048		      ar_uid	[0x0C]
2469130561Sobrien     0x0054		      ar_gid	[0x0C]
2470130561Sobrien     0x0060		      ar_mod	[0x0C]
2471130561Sobrien     0x006C		      ar_namelen[0x04]
2472130561Sobrien     0x0070		      ar_fmag	[0x02]
247389857Sobrien
2474130561Sobrien     Member table
2475130561Sobrien     0x0072		      count	[0x14]
2476130561Sobrien     0x0086		      offsets	[0x14 * counts]
2477130561Sobrien     0x0086 + 0x14 * counts   names	[??]
2478130561Sobrien     ??			      pad to even bytes.
247989857Sobrien   */
248089857Sobrien
248184865Sobrien  BFD_ASSERT (nextoff == bfd_tell (abfd));
248284865Sobrien
248389857Sobrien  member_table_size = (SIZEOF_AR_HDR_BIG
248489857Sobrien		       + SXCOFFARFMAG
248589857Sobrien		       + XCOFFARMAGBIG_ELEMENT_SIZE
248689857Sobrien		       + count * XCOFFARMAGBIG_ELEMENT_SIZE
248789857Sobrien		       + total_namlen);
248884865Sobrien
248989857Sobrien  member_table_size += member_table_size & 1;
2490218822Sdim  member_table = bfd_zmalloc (member_table_size);
249189857Sobrien  if (member_table == NULL)
2492130561Sobrien    return FALSE;
249384865Sobrien
249489857Sobrien  hdr = (struct xcoff_ar_hdr_big *) member_table;
249584865Sobrien
2496104834Sobrien  PRINT20 (hdr->size, (XCOFFARMAGBIG_ELEMENT_SIZE
2497104834Sobrien		       + count * XCOFFARMAGBIG_ELEMENT_SIZE
2498104834Sobrien		       + total_namlen + (total_namlen & 1)));
2499130561Sobrien  if (makemap && hasobjects)
250089857Sobrien    PRINT20 (hdr->nextoff, nextoff + member_table_size);
250184865Sobrien  else
250289857Sobrien    PRINT20 (hdr->nextoff, 0);
250389857Sobrien  PRINT20 (hdr->prevoff, prevoff);
250489857Sobrien  PRINT12 (hdr->date, 0);
250589857Sobrien  PRINT12 (hdr->uid, 0);
250689857Sobrien  PRINT12 (hdr->gid, 0);
250789857Sobrien  PRINT12 (hdr->mode, 0);
250889857Sobrien  PRINT4 (hdr->namlen, 0);
2509130561Sobrien
251089857Sobrien  mt = member_table + SIZEOF_AR_HDR_BIG;
251189857Sobrien  memcpy (mt, XCOFFARFMAG, SXCOFFARFMAG);
251289857Sobrien  mt += SXCOFFARFMAG;
251384865Sobrien
251489857Sobrien  PRINT20 (mt, count);
251589857Sobrien  mt += XCOFFARMAGBIG_ELEMENT_SIZE;
251689857Sobrien  for (i = 0; i < (size_t) count; i++)
251789857Sobrien    {
251889857Sobrien      PRINT20 (mt, offsets[i]);
251989857Sobrien      mt += XCOFFARMAGBIG_ELEMENT_SIZE;
252089857Sobrien    }
252184865Sobrien
2522130561Sobrien  if (count)
252384865Sobrien    {
252489857Sobrien      free (offsets);
252589857Sobrien      offsets = NULL;
252684865Sobrien    }
252789857Sobrien
2528218822Sdim  for (current_bfd = abfd->archive_head;
2529218822Sdim       current_bfd != NULL;
2530218822Sdim       current_bfd = current_bfd->archive_next)
253184865Sobrien    {
253284865Sobrien      const char *name;
253384865Sobrien      size_t namlen;
253484865Sobrien
253589857Sobrien      name = normalize_filename (current_bfd);
2536130561Sobrien      namlen = sprintf (mt, "%s", name);
253789857Sobrien      mt += namlen + 1;
253884865Sobrien    }
2539130561Sobrien
254089857Sobrien  if (bfd_bwrite (member_table, member_table_size, abfd) != member_table_size)
2541130561Sobrien    return FALSE;
254284865Sobrien
254389857Sobrien  free (member_table);
254484865Sobrien
254589857Sobrien  PRINT20 (fhdr.memoff, nextoff);
254689857Sobrien
254789857Sobrien  prevoff = nextoff;
254889857Sobrien  nextoff += member_table_size;
254989857Sobrien
255084865Sobrien  /* Write out the armap, if appropriate.  */
255184865Sobrien
2552130561Sobrien  if (! makemap || ! hasobjects)
255389857Sobrien    PRINT20 (fhdr.symoff, 0);
255484865Sobrien  else
255584865Sobrien    {
255684865Sobrien      BFD_ASSERT (nextoff == bfd_tell (abfd));
255789857Sobrien
255889857Sobrien      /* Save nextoff in fhdr.symoff so the armap routine can use it.  */
255989857Sobrien      PRINT20 (fhdr.symoff, nextoff);
2560130561Sobrien
256184865Sobrien      bfd_ardata (abfd)->tdata = (PTR) &fhdr;
256284865Sobrien      if (! _bfd_compute_and_write_armap (abfd, 0))
2563130561Sobrien	return FALSE;
256484865Sobrien    }
256584865Sobrien
256684865Sobrien  /* Write out the archive file header.  */
256784865Sobrien
256884865Sobrien  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
2569130561Sobrien      || (bfd_bwrite ((PTR) &fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR_BIG,
257089857Sobrien		      abfd) != SIZEOF_AR_FILE_HDR_BIG))
2571130561Sobrien    return FALSE;
2572130561Sobrien
2573130561Sobrien  return TRUE;
257484865Sobrien}
257584865Sobrien
2576130561Sobrienbfd_boolean
257784865Sobrien_bfd_xcoff_write_archive_contents (abfd)
257884865Sobrien     bfd *abfd;
257984865Sobrien{
258084865Sobrien  if (! xcoff_big_format_p (abfd))
258184865Sobrien    return xcoff_write_archive_contents_old (abfd);
258284865Sobrien  else
258384865Sobrien    return xcoff_write_archive_contents_big (abfd);
258484865Sobrien}
258584865Sobrien
258684865Sobrien/* We can't use the usual coff_sizeof_headers routine, because AIX
258784865Sobrien   always uses an a.out header.  */
258884865Sobrien
258984865Sobrienint
2590218822Sdim_bfd_xcoff_sizeof_headers (bfd *abfd,
2591218822Sdim			   struct bfd_link_info *info ATTRIBUTE_UNUSED)
259284865Sobrien{
259384865Sobrien  int size;
259484865Sobrien
259584865Sobrien  size = FILHSZ;
259684865Sobrien  if (xcoff_data (abfd)->full_aouthdr)
259784865Sobrien    size += AOUTSZ;
259884865Sobrien  else
259984865Sobrien    size += SMALL_AOUTSZ;
260084865Sobrien  size += abfd->section_count * SCNHSZ;
260184865Sobrien  return size;
260284865Sobrien}
260389857Sobrien
260489857Sobrien/* Routines to swap information in the XCOFF .loader section.  If we
260589857Sobrien   ever need to write an XCOFF loader, this stuff will need to be
260689857Sobrien   moved to another file shared by the linker (which XCOFF calls the
260789857Sobrien   ``binder'') and the loader.  */
260889857Sobrien
260989857Sobrien/* Swap in the ldhdr structure.  */
261089857Sobrien
261189857Sobrienstatic void
261289857Sobrienxcoff_swap_ldhdr_in (abfd, s, dst)
261389857Sobrien     bfd *abfd;
261489857Sobrien     const PTR s;
261589857Sobrien     struct internal_ldhdr *dst;
261689857Sobrien{
261789857Sobrien  const struct external_ldhdr *src = (const struct external_ldhdr *) s;
261889857Sobrien
261989857Sobrien  dst->l_version = bfd_get_32 (abfd, src->l_version);
262089857Sobrien  dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms);
262189857Sobrien  dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc);
262289857Sobrien  dst->l_istlen = bfd_get_32 (abfd, src->l_istlen);
262389857Sobrien  dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid);
262489857Sobrien  dst->l_impoff = bfd_get_32 (abfd, src->l_impoff);
262589857Sobrien  dst->l_stlen = bfd_get_32 (abfd, src->l_stlen);
262689857Sobrien  dst->l_stoff = bfd_get_32 (abfd, src->l_stoff);
262789857Sobrien}
262889857Sobrien
262989857Sobrien/* Swap out the ldhdr structure.  */
263089857Sobrien
263189857Sobrienstatic void
263289857Sobrienxcoff_swap_ldhdr_out (abfd, src, d)
263389857Sobrien     bfd *abfd;
263489857Sobrien     const struct internal_ldhdr *src;
263589857Sobrien     PTR d;
263689857Sobrien{
263789857Sobrien  struct external_ldhdr *dst = (struct external_ldhdr *) d;
263889857Sobrien
263989857Sobrien  bfd_put_32 (abfd, (bfd_vma) src->l_version, dst->l_version);
264089857Sobrien  bfd_put_32 (abfd, src->l_nsyms, dst->l_nsyms);
264189857Sobrien  bfd_put_32 (abfd, src->l_nreloc, dst->l_nreloc);
264289857Sobrien  bfd_put_32 (abfd, src->l_istlen, dst->l_istlen);
264389857Sobrien  bfd_put_32 (abfd, src->l_nimpid, dst->l_nimpid);
264489857Sobrien  bfd_put_32 (abfd, src->l_impoff, dst->l_impoff);
264589857Sobrien  bfd_put_32 (abfd, src->l_stlen, dst->l_stlen);
264689857Sobrien  bfd_put_32 (abfd, src->l_stoff, dst->l_stoff);
264789857Sobrien}
264889857Sobrien
264989857Sobrien/* Swap in the ldsym structure.  */
265089857Sobrien
265189857Sobrienstatic void
265289857Sobrienxcoff_swap_ldsym_in (abfd, s, dst)
265389857Sobrien     bfd *abfd;
265489857Sobrien     const PTR s;
265589857Sobrien     struct internal_ldsym *dst;
265689857Sobrien{
265789857Sobrien  const struct external_ldsym *src = (const struct external_ldsym *) s;
265889857Sobrien
265989857Sobrien  if (bfd_get_32 (abfd, src->_l._l_l._l_zeroes) != 0) {
266089857Sobrien    memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN);
266189857Sobrien  } else {
266289857Sobrien    dst->_l._l_l._l_zeroes = 0;
266389857Sobrien    dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->_l._l_l._l_offset);
266489857Sobrien  }
266589857Sobrien  dst->l_value = bfd_get_32 (abfd, src->l_value);
266689857Sobrien  dst->l_scnum = bfd_get_16 (abfd, src->l_scnum);
266789857Sobrien  dst->l_smtype = bfd_get_8 (abfd, src->l_smtype);
266889857Sobrien  dst->l_smclas = bfd_get_8 (abfd, src->l_smclas);
266989857Sobrien  dst->l_ifile = bfd_get_32 (abfd, src->l_ifile);
267089857Sobrien  dst->l_parm = bfd_get_32 (abfd, src->l_parm);
267189857Sobrien}
267289857Sobrien
267389857Sobrien/* Swap out the ldsym structure.  */
267489857Sobrien
267589857Sobrienstatic void
267689857Sobrienxcoff_swap_ldsym_out (abfd, src, d)
267789857Sobrien     bfd *abfd;
267889857Sobrien     const struct internal_ldsym *src;
267989857Sobrien     PTR d;
268089857Sobrien{
268189857Sobrien  struct external_ldsym *dst = (struct external_ldsym *) d;
268289857Sobrien
268389857Sobrien  if (src->_l._l_l._l_zeroes != 0)
268489857Sobrien    memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN);
268589857Sobrien  else
268689857Sobrien    {
268789857Sobrien      bfd_put_32 (abfd, (bfd_vma) 0, dst->_l._l_l._l_zeroes);
268889857Sobrien      bfd_put_32 (abfd, (bfd_vma) src->_l._l_l._l_offset,
268989857Sobrien		  dst->_l._l_l._l_offset);
269089857Sobrien    }
269189857Sobrien  bfd_put_32 (abfd, src->l_value, dst->l_value);
269289857Sobrien  bfd_put_16 (abfd, (bfd_vma) src->l_scnum, dst->l_scnum);
269389857Sobrien  bfd_put_8 (abfd, src->l_smtype, dst->l_smtype);
269489857Sobrien  bfd_put_8 (abfd, src->l_smclas, dst->l_smclas);
269589857Sobrien  bfd_put_32 (abfd, src->l_ifile, dst->l_ifile);
269689857Sobrien  bfd_put_32 (abfd, src->l_parm, dst->l_parm);
269789857Sobrien}
269889857Sobrien
2699104834Sobrienstatic void
2700104834Sobrienxcoff_swap_reloc_in (abfd, s, d)
2701104834Sobrien     bfd *abfd;
2702104834Sobrien     PTR s;
2703104834Sobrien     PTR d;
2704104834Sobrien{
2705104834Sobrien  struct external_reloc *src = (struct external_reloc *) s;
2706104834Sobrien  struct internal_reloc *dst = (struct internal_reloc *) d;
2707104834Sobrien
2708104834Sobrien  memset (dst, 0, sizeof (struct internal_reloc));
2709104834Sobrien
2710104834Sobrien  dst->r_vaddr = bfd_get_32 (abfd, src->r_vaddr);
2711104834Sobrien  dst->r_symndx = bfd_get_32 (abfd, src->r_symndx);
2712104834Sobrien  dst->r_size = bfd_get_8 (abfd, src->r_size);
2713104834Sobrien  dst->r_type = bfd_get_8 (abfd, src->r_type);
2714104834Sobrien}
2715104834Sobrien
2716104834Sobrienstatic unsigned int
2717104834Sobrienxcoff_swap_reloc_out (abfd, s, d)
2718104834Sobrien     bfd *abfd;
2719104834Sobrien     PTR s;
2720104834Sobrien     PTR d;
2721104834Sobrien{
2722104834Sobrien  struct internal_reloc *src = (struct internal_reloc *) s;
2723104834Sobrien  struct external_reloc *dst = (struct external_reloc *) d;
2724104834Sobrien
2725104834Sobrien  bfd_put_32 (abfd, src->r_vaddr, dst->r_vaddr);
2726104834Sobrien  bfd_put_32 (abfd, src->r_symndx, dst->r_symndx);
2727104834Sobrien  bfd_put_8 (abfd, src->r_type, dst->r_type);
2728104834Sobrien  bfd_put_8 (abfd, src->r_size, dst->r_size);
2729104834Sobrien
2730104834Sobrien  return bfd_coff_relsz (abfd);
2731104834Sobrien}
2732104834Sobrien
273389857Sobrien/* Swap in the ldrel structure.  */
273489857Sobrien
273589857Sobrienstatic void
273689857Sobrienxcoff_swap_ldrel_in (abfd, s, dst)
273789857Sobrien     bfd *abfd;
273889857Sobrien     const PTR s;
273989857Sobrien     struct internal_ldrel *dst;
274089857Sobrien{
274189857Sobrien  const struct external_ldrel *src = (const struct external_ldrel *) s;
274289857Sobrien
274389857Sobrien  dst->l_vaddr = bfd_get_32 (abfd, src->l_vaddr);
274489857Sobrien  dst->l_symndx = bfd_get_32 (abfd, src->l_symndx);
274589857Sobrien  dst->l_rtype = bfd_get_16 (abfd, src->l_rtype);
274689857Sobrien  dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm);
274789857Sobrien}
274889857Sobrien
274989857Sobrien/* Swap out the ldrel structure.  */
275089857Sobrien
275189857Sobrienstatic void
275289857Sobrienxcoff_swap_ldrel_out (abfd, src, d)
275389857Sobrien     bfd *abfd;
275489857Sobrien     const struct internal_ldrel *src;
275589857Sobrien     PTR d;
275689857Sobrien{
275789857Sobrien  struct external_ldrel *dst = (struct external_ldrel *) d;
275889857Sobrien
275989857Sobrien  bfd_put_32 (abfd, src->l_vaddr, dst->l_vaddr);
276089857Sobrien  bfd_put_32 (abfd, src->l_symndx, dst->l_symndx);
276189857Sobrien  bfd_put_16 (abfd, (bfd_vma) src->l_rtype, dst->l_rtype);
276289857Sobrien  bfd_put_16 (abfd, (bfd_vma) src->l_rsecnm, dst->l_rsecnm);
276389857Sobrien}
276489857Sobrien
276589857Sobrien
2766130561Sobrienbfd_boolean
2767130561Sobrienxcoff_reloc_type_noop (input_bfd, input_section, output_bfd, rel, sym, howto,
2768104834Sobrien		       val, addend, relocation, contents)
2769104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
2770104834Sobrien     asection *input_section ATTRIBUTE_UNUSED;
2771104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2772104834Sobrien     struct internal_reloc *rel ATTRIBUTE_UNUSED;
2773104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2774104834Sobrien     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
2775104834Sobrien     bfd_vma val ATTRIBUTE_UNUSED;
2776104834Sobrien     bfd_vma addend ATTRIBUTE_UNUSED;
2777104834Sobrien     bfd_vma *relocation ATTRIBUTE_UNUSED;
2778104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2779104834Sobrien{
2780130561Sobrien  return TRUE;
2781104834Sobrien}
278289857Sobrien
2783130561Sobrienbfd_boolean
2784130561Sobrienxcoff_reloc_type_fail (input_bfd, input_section, output_bfd, rel, sym, howto,
2785104834Sobrien		       val, addend, relocation, contents)
2786104834Sobrien     bfd *input_bfd;
2787104834Sobrien     asection *input_section ATTRIBUTE_UNUSED;
2788104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2789104834Sobrien     struct internal_reloc *rel;
2790104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2791104834Sobrien     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
2792104834Sobrien     bfd_vma val ATTRIBUTE_UNUSED;
2793104834Sobrien     bfd_vma addend ATTRIBUTE_UNUSED;
2794104834Sobrien     bfd_vma *relocation ATTRIBUTE_UNUSED;
2795104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2796104834Sobrien{
2797104834Sobrien  (*_bfd_error_handler)
2798104834Sobrien    (_("%s: unsupported relocation type 0x%02x"),
2799104834Sobrien     bfd_get_filename (input_bfd), (unsigned int) rel->r_type);
2800104834Sobrien  bfd_set_error (bfd_error_bad_value);
2801130561Sobrien  return FALSE;
2802104834Sobrien}
2803104834Sobrien
2804130561Sobrienbfd_boolean
2805130561Sobrienxcoff_reloc_type_pos (input_bfd, input_section, output_bfd, rel, sym, howto,
2806104834Sobrien		      val, addend, relocation, contents)
2807104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
2808104834Sobrien     asection *input_section ATTRIBUTE_UNUSED;
2809104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2810104834Sobrien     struct internal_reloc *rel ATTRIBUTE_UNUSED;
2811104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2812104834Sobrien     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
2813104834Sobrien     bfd_vma val;
2814104834Sobrien     bfd_vma addend;
2815104834Sobrien     bfd_vma *relocation;
2816104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2817104834Sobrien{
2818104834Sobrien  *relocation = val + addend;
2819130561Sobrien  return TRUE;
2820104834Sobrien}
2821104834Sobrien
2822130561Sobrienbfd_boolean
2823130561Sobrienxcoff_reloc_type_neg (input_bfd, input_section, output_bfd, rel, sym, howto,
2824104834Sobrien		      val, addend, relocation, contents)
2825104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
2826104834Sobrien     asection *input_section ATTRIBUTE_UNUSED;
2827104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2828104834Sobrien     struct internal_reloc *rel ATTRIBUTE_UNUSED;
2829104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2830104834Sobrien     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
2831104834Sobrien     bfd_vma val;
2832104834Sobrien     bfd_vma addend;
2833104834Sobrien     bfd_vma *relocation;
2834104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2835104834Sobrien{
2836104834Sobrien  *relocation = addend - val;
2837130561Sobrien  return TRUE;
2838104834Sobrien}
2839104834Sobrien
2840130561Sobrienbfd_boolean
2841130561Sobrienxcoff_reloc_type_rel (input_bfd, input_section, output_bfd, rel, sym, howto,
2842104834Sobrien		      val, addend, relocation, contents)
2843104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
2844104834Sobrien     asection *input_section;
2845104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2846104834Sobrien     struct internal_reloc *rel ATTRIBUTE_UNUSED;
2847104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2848104834Sobrien     struct reloc_howto_struct *howto;
2849104834Sobrien     bfd_vma val;
2850104834Sobrien     bfd_vma addend;
2851104834Sobrien     bfd_vma *relocation;
2852104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2853104834Sobrien{
2854130561Sobrien  howto->pc_relative = TRUE;
2855104834Sobrien
2856104834Sobrien  /* A PC relative reloc includes the section address.  */
2857104834Sobrien  addend += input_section->vma;
2858104834Sobrien
2859104834Sobrien  *relocation = val + addend;
2860104834Sobrien  *relocation -= (input_section->output_section->vma
2861104834Sobrien		  + input_section->output_offset);
2862130561Sobrien  return TRUE;
2863104834Sobrien}
2864104834Sobrien
2865130561Sobrienbfd_boolean
2866130561Sobrienxcoff_reloc_type_toc (input_bfd, input_section, output_bfd, rel, sym, howto,
2867104834Sobrien		      val, addend, relocation, contents)
2868104834Sobrien     bfd *input_bfd;
2869104834Sobrien     asection *input_section ATTRIBUTE_UNUSED;
2870104834Sobrien     bfd *output_bfd;
2871104834Sobrien     struct internal_reloc *rel;
2872104834Sobrien     struct internal_syment *sym;
2873104834Sobrien     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
2874104834Sobrien     bfd_vma val;
2875104834Sobrien     bfd_vma addend ATTRIBUTE_UNUSED;
2876104834Sobrien     bfd_vma *relocation;
2877104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2878104834Sobrien{
2879104834Sobrien  struct xcoff_link_hash_entry *h;
2880104834Sobrien
2881130561Sobrien  if (0 > rel->r_symndx)
2882130561Sobrien    return FALSE;
2883104834Sobrien
2884104834Sobrien  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
2885104834Sobrien
2886104834Sobrien  if (h != NULL && h->smclas != XMC_TD)
2887104834Sobrien    {
2888104834Sobrien      if (h->toc_section == NULL)
2889104834Sobrien	{
2890104834Sobrien	  (*_bfd_error_handler)
2891104834Sobrien	    (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
2892104834Sobrien	     bfd_get_filename (input_bfd), rel->r_vaddr,
2893104834Sobrien	     h->root.root.string);
2894104834Sobrien	  bfd_set_error (bfd_error_bad_value);
2895130561Sobrien	  return FALSE;
2896104834Sobrien	}
2897130561Sobrien
2898104834Sobrien      BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
2899104834Sobrien      val = (h->toc_section->output_section->vma
2900104834Sobrien	      + h->toc_section->output_offset);
2901104834Sobrien    }
2902130561Sobrien
2903104834Sobrien  *relocation = ((val - xcoff_data (output_bfd)->toc)
2904104834Sobrien		 - (sym->n_value - xcoff_data (input_bfd)->toc));
2905130561Sobrien  return TRUE;
2906104834Sobrien}
2907104834Sobrien
2908130561Sobrienbfd_boolean
2909130561Sobrienxcoff_reloc_type_ba (input_bfd, input_section, output_bfd, rel, sym, howto,
2910104834Sobrien		     val, addend, relocation, contents)
2911104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
2912104834Sobrien     asection *input_section ATTRIBUTE_UNUSED;
2913104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2914104834Sobrien     struct internal_reloc *rel ATTRIBUTE_UNUSED;
2915104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2916104834Sobrien     struct reloc_howto_struct *howto;
2917104834Sobrien     bfd_vma val;
2918104834Sobrien     bfd_vma addend;
2919104834Sobrien     bfd_vma *relocation;
2920104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
2921104834Sobrien{
2922104834Sobrien  howto->src_mask &= ~3;
2923104834Sobrien  howto->dst_mask = howto->src_mask;
2924104834Sobrien
2925104834Sobrien  *relocation = val + addend;
2926104834Sobrien
2927130561Sobrien  return TRUE;
2928104834Sobrien}
2929104834Sobrien
2930130561Sobrienstatic bfd_boolean
2931130561Sobrienxcoff_reloc_type_br (input_bfd, input_section, output_bfd, rel, sym, howto,
2932104834Sobrien		     val, addend, relocation, contents)
2933104834Sobrien     bfd *input_bfd;
2934104834Sobrien     asection *input_section;
2935104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
2936104834Sobrien     struct internal_reloc *rel;
2937104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
2938104834Sobrien     struct reloc_howto_struct *howto;
2939104834Sobrien     bfd_vma val;
2940104834Sobrien     bfd_vma addend;
2941104834Sobrien     bfd_vma *relocation;
2942104834Sobrien     bfd_byte *contents;
2943104834Sobrien{
2944104834Sobrien  struct xcoff_link_hash_entry *h;
2945104834Sobrien
2946130561Sobrien  if (0 > rel->r_symndx)
2947130561Sobrien    return FALSE;
2948104834Sobrien
2949104834Sobrien  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
2950104834Sobrien
2951104834Sobrien  /* If we see an R_BR or R_RBR reloc which is jumping to global
2952104834Sobrien     linkage code, and it is followed by an appropriate cror nop
2953104834Sobrien     instruction, we replace the cror with lwz r2,20(r1).  This
2954104834Sobrien     restores the TOC after the glink code.  Contrariwise, if the
2955104834Sobrien     call is followed by a lwz r2,20(r1), but the call is not
2956104834Sobrien     going to global linkage code, we can replace the load with a
2957104834Sobrien     cror.  */
2958130561Sobrien  if (NULL != h
2959130561Sobrien      && bfd_link_hash_defined == h->root.type
2960218822Sdim      && rel->r_vaddr - input_section->vma + 8 <= input_section->size)
2961104834Sobrien    {
2962104834Sobrien      bfd_byte *pnext;
2963104834Sobrien      unsigned long next;
2964130561Sobrien
2965104834Sobrien      pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
2966104834Sobrien      next = bfd_get_32 (input_bfd, pnext);
2967130561Sobrien
2968104834Sobrien      /* The _ptrgl function is magic.  It is used by the AIX
2969104834Sobrien	 compiler to call a function through a pointer.  */
2970104834Sobrien      if (h->smclas == XMC_GL || strcmp (h->root.root.string, "._ptrgl") == 0)
2971104834Sobrien	{
2972130561Sobrien	  if (next == 0x4def7b82			/* cror 15,15,15 */
2973130561Sobrien	      || next == 0x4ffffb82			/* cror 31,31,31 */
2974130561Sobrien	      || next == 0x60000000)			/* ori r0,r0,0 */
2975130561Sobrien	    bfd_put_32 (input_bfd, 0x80410014, pnext);	/* lwz r1,20(r1) */
2976130561Sobrien
2977104834Sobrien	}
2978104834Sobrien      else
2979130561Sobrien	{
2980130561Sobrien	  if (next == 0x80410014)			/* lwz r1,20(r1) */
2981130561Sobrien	    bfd_put_32 (input_bfd, 0x60000000, pnext);	/* ori r0,r0,0 */
2982130561Sobrien	}
2983130561Sobrien    }
2984130561Sobrien  else if (NULL != h && bfd_link_hash_undefined == h->root.type)
2985104834Sobrien    {
2986104834Sobrien      /* Normally, this relocation is against a defined symbol.  In the
2987104834Sobrien	 case where this is a partial link and the output section offset
2988130561Sobrien	 is greater than 2^25, the linker will return an invalid error
2989104834Sobrien	 message that the relocation has been truncated.  Yes it has been
2990130561Sobrien	 truncated but no it not important.  For this case, disable the
2991104834Sobrien	 overflow checking. */
2992130561Sobrien
2993104834Sobrien      howto->complain_on_overflow = complain_overflow_dont;
2994104834Sobrien    }
2995130561Sobrien
2996130561Sobrien  howto->pc_relative = TRUE;
2997104834Sobrien  howto->src_mask &= ~3;
2998104834Sobrien  howto->dst_mask = howto->src_mask;
2999104834Sobrien
3000104834Sobrien  /* A PC relative reloc includes the section address.  */
3001104834Sobrien  addend += input_section->vma;
3002130561Sobrien
3003104834Sobrien  *relocation = val + addend;
3004104834Sobrien  *relocation -= (input_section->output_section->vma
3005104834Sobrien		  + input_section->output_offset);
3006130561Sobrien  return TRUE;
3007104834Sobrien}
3008104834Sobrien
3009130561Sobrienbfd_boolean
3010130561Sobrienxcoff_reloc_type_crel (input_bfd, input_section, output_bfd, rel, sym, howto,
3011104834Sobrien		       val, addend, relocation, contents)
3012104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
3013104834Sobrien     asection *input_section;
3014104834Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
3015104834Sobrien     struct internal_reloc *rel ATTRIBUTE_UNUSED;
3016104834Sobrien     struct internal_syment *sym ATTRIBUTE_UNUSED;
3017104834Sobrien     struct reloc_howto_struct *howto;
3018104834Sobrien     bfd_vma val ATTRIBUTE_UNUSED;
3019104834Sobrien     bfd_vma addend;
3020104834Sobrien     bfd_vma *relocation;
3021104834Sobrien     bfd_byte *contents ATTRIBUTE_UNUSED;
3022104834Sobrien{
3023130561Sobrien  howto->pc_relative = TRUE;
3024104834Sobrien  howto->src_mask &= ~3;
3025104834Sobrien  howto->dst_mask = howto->src_mask;
3026104834Sobrien
3027104834Sobrien  /* A PC relative reloc includes the section address.  */
3028104834Sobrien  addend += input_section->vma;
3029104834Sobrien
3030104834Sobrien  *relocation = val + addend;
3031104834Sobrien  *relocation -= (input_section->output_section->vma
3032104834Sobrien		  + input_section->output_offset);
3033130561Sobrien  return TRUE;
3034104834Sobrien}
3035104834Sobrien
3036130561Sobrienstatic bfd_boolean
3037130561Sobrienxcoff_complain_overflow_dont_func (input_bfd, val, relocation, howto)
3038104834Sobrien     bfd *input_bfd ATTRIBUTE_UNUSED;
3039104834Sobrien     bfd_vma val ATTRIBUTE_UNUSED;
3040104834Sobrien     bfd_vma relocation ATTRIBUTE_UNUSED;
3041104834Sobrien     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
3042104834Sobrien{
3043130561Sobrien  return FALSE;
3044104834Sobrien}
3045104834Sobrien
3046130561Sobrienstatic bfd_boolean
3047130561Sobrienxcoff_complain_overflow_bitfield_func (input_bfd, val, relocation, howto)
3048104834Sobrien     bfd *input_bfd;
3049104834Sobrien     bfd_vma val;
3050104834Sobrien     bfd_vma relocation;
3051130561Sobrien     struct reloc_howto_struct *howto;
3052104834Sobrien{
3053104834Sobrien  bfd_vma addrmask, fieldmask, signmask, ss;
3054104834Sobrien  bfd_vma a, b, sum;
3055130561Sobrien
3056104834Sobrien  /* Get the values to be added together.  For signed and unsigned
3057104834Sobrien     relocations, we assume that all values should be truncated to
3058104834Sobrien     the size of an address.  For bitfields, all the bits matter.
3059104834Sobrien     See also bfd_check_overflow.  */
3060104834Sobrien  fieldmask = N_ONES (howto->bitsize);
3061104834Sobrien  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
3062104834Sobrien  a = relocation;
3063104834Sobrien  b = val & howto->src_mask;
3064104834Sobrien
3065104834Sobrien  /* Much like unsigned, except no trimming with addrmask.  In
3066104834Sobrien     addition, the sum overflows if there is a carry out of
3067104834Sobrien     the bfd_vma, i.e., the sum is less than either input
3068104834Sobrien     operand.  */
3069104834Sobrien  a >>= howto->rightshift;
3070104834Sobrien  b >>= howto->bitpos;
3071130561Sobrien
3072104834Sobrien  /* Bitfields are sometimes used for signed numbers; for
3073104834Sobrien     example, a 13-bit field sometimes represents values in
3074104834Sobrien     0..8191 and sometimes represents values in -4096..4095.
3075104834Sobrien     If the field is signed and a is -4095 (0x1001) and b is
3076104834Sobrien     -1 (0x1fff), the sum is -4096 (0x1000), but (0x1001 +
3077104834Sobrien     0x1fff is 0x3000).  It's not clear how to handle this
3078104834Sobrien     everywhere, since there is not way to know how many bits
3079104834Sobrien     are significant in the relocation, but the original code
3080104834Sobrien     assumed that it was fully sign extended, and we will keep
3081104834Sobrien     that assumption.  */
3082104834Sobrien  signmask = (fieldmask >> 1) + 1;
3083130561Sobrien
3084104834Sobrien  if ((a & ~ fieldmask) != 0)
3085104834Sobrien    {
3086104834Sobrien      /* Some bits out of the field are set.  This might not
3087104834Sobrien	 be a problem: if this is a signed bitfield, it is OK
3088104834Sobrien	 iff all the high bits are set, including the sign
3089104834Sobrien	 bit.  We'll try setting all but the most significant
3090104834Sobrien	 bit in the original relocation value: if this is all
3091104834Sobrien	 ones, we are OK, assuming a signed bitfield.  */
3092104834Sobrien      ss = (signmask << howto->rightshift) - 1;
3093104834Sobrien      if ((ss | relocation) != ~ (bfd_vma) 0)
3094130561Sobrien	return TRUE;
3095104834Sobrien      a &= fieldmask;
3096104834Sobrien    }
3097130561Sobrien
3098104834Sobrien  /* We just assume (b & ~ fieldmask) == 0.  */
3099130561Sobrien
3100104834Sobrien  /* We explicitly permit wrap around if this relocation
3101104834Sobrien     covers the high bit of an address.  The Linux kernel
3102104834Sobrien     relies on it, and it is the only way to write assembler
3103104834Sobrien     code which can run when loaded at a location 0x80000000
3104104834Sobrien     away from the location at which it is linked.  */
3105104834Sobrien  if (howto->bitsize + howto->rightshift
3106104834Sobrien      == bfd_arch_bits_per_address (input_bfd))
3107130561Sobrien    return FALSE;
3108130561Sobrien
3109104834Sobrien  sum = a + b;
3110104834Sobrien  if (sum < a || (sum & ~ fieldmask) != 0)
3111104834Sobrien    {
3112104834Sobrien      /* There was a carry out, or the field overflow.  Test
3113104834Sobrien	 for signed operands again.  Here is the overflow test
3114104834Sobrien	 is as for complain_overflow_signed.  */
3115104834Sobrien      if (((~ (a ^ b)) & (a ^ sum)) & signmask)
3116130561Sobrien	return TRUE;
3117104834Sobrien    }
3118130561Sobrien
3119130561Sobrien  return FALSE;
3120104834Sobrien}
3121104834Sobrien
3122130561Sobrienstatic bfd_boolean
3123130561Sobrienxcoff_complain_overflow_signed_func (input_bfd, val, relocation, howto)
3124104834Sobrien     bfd *input_bfd;
3125104834Sobrien     bfd_vma val;
3126104834Sobrien     bfd_vma relocation;
3127104834Sobrien     struct reloc_howto_struct *howto;
3128104834Sobrien{
3129104834Sobrien  bfd_vma addrmask, fieldmask, signmask, ss;
3130104834Sobrien  bfd_vma a, b, sum;
3131130561Sobrien
3132104834Sobrien  /* Get the values to be added together.  For signed and unsigned
3133104834Sobrien     relocations, we assume that all values should be truncated to
3134104834Sobrien     the size of an address.  For bitfields, all the bits matter.
3135104834Sobrien     See also bfd_check_overflow.  */
3136104834Sobrien  fieldmask = N_ONES (howto->bitsize);
3137104834Sobrien  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
3138104834Sobrien  a = relocation;
3139104834Sobrien  b = val & howto->src_mask;
3140104834Sobrien
3141104834Sobrien  a = (a & addrmask) >> howto->rightshift;
3142130561Sobrien
3143104834Sobrien  /* If any sign bits are set, all sign bits must be set.
3144104834Sobrien     That is, A must be a valid negative address after
3145104834Sobrien     shifting.  */
3146104834Sobrien  signmask = ~ (fieldmask >> 1);
3147104834Sobrien  ss = a & signmask;
3148104834Sobrien  if (ss != 0 && ss != ((addrmask >> howto->rightshift) & signmask))
3149130561Sobrien    return TRUE;
3150130561Sobrien
3151104834Sobrien  /* We only need this next bit of code if the sign bit of B
3152104834Sobrien     is below the sign bit of A.  This would only happen if
3153104834Sobrien     SRC_MASK had fewer bits than BITSIZE.  Note that if
3154104834Sobrien     SRC_MASK has more bits than BITSIZE, we can get into
3155104834Sobrien     trouble; we would need to verify that B is in range, as
3156104834Sobrien     we do for A above.  */
3157104834Sobrien  signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;
3158104834Sobrien  if ((b & signmask) != 0)
3159104834Sobrien    {
3160104834Sobrien      /* Set all the bits above the sign bit.  */
3161104834Sobrien      b -= signmask <<= 1;
3162104834Sobrien    }
3163130561Sobrien
3164104834Sobrien  b = (b & addrmask) >> howto->bitpos;
3165130561Sobrien
3166104834Sobrien  /* Now we can do the addition.  */
3167104834Sobrien  sum = a + b;
3168130561Sobrien
3169104834Sobrien  /* See if the result has the correct sign.  Bits above the
3170104834Sobrien     sign bit are junk now; ignore them.  If the sum is
3171104834Sobrien     positive, make sure we did not have all negative inputs;
3172104834Sobrien     if the sum is negative, make sure we did not have all
3173104834Sobrien     positive inputs.  The test below looks only at the sign
3174104834Sobrien     bits, and it really just
3175104834Sobrien     SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM)
3176104834Sobrien  */
3177104834Sobrien  signmask = (fieldmask >> 1) + 1;
3178104834Sobrien  if (((~ (a ^ b)) & (a ^ sum)) & signmask)
3179130561Sobrien    return TRUE;
3180130561Sobrien
3181130561Sobrien  return FALSE;
3182104834Sobrien}
3183104834Sobrien
3184130561Sobrienstatic bfd_boolean
3185130561Sobrienxcoff_complain_overflow_unsigned_func (input_bfd, val, relocation, howto)
3186104834Sobrien     bfd *input_bfd;
3187104834Sobrien     bfd_vma val;
3188104834Sobrien     bfd_vma relocation;
3189130561Sobrien     struct reloc_howto_struct *howto;
3190104834Sobrien{
3191104834Sobrien  bfd_vma addrmask, fieldmask;
3192104834Sobrien  bfd_vma a, b, sum;
3193130561Sobrien
3194104834Sobrien  /* Get the values to be added together.  For signed and unsigned
3195104834Sobrien     relocations, we assume that all values should be truncated to
3196104834Sobrien     the size of an address.  For bitfields, all the bits matter.
3197104834Sobrien     See also bfd_check_overflow.  */
3198104834Sobrien  fieldmask = N_ONES (howto->bitsize);
3199104834Sobrien  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
3200104834Sobrien  a = relocation;
3201104834Sobrien  b = val & howto->src_mask;
3202104834Sobrien
3203104834Sobrien  /* Checking for an unsigned overflow is relatively easy:
3204104834Sobrien     trim the addresses and add, and trim the result as well.
3205104834Sobrien     Overflow is normally indicated when the result does not
3206104834Sobrien     fit in the field.  However, we also need to consider the
3207104834Sobrien     case when, e.g., fieldmask is 0x7fffffff or smaller, an
3208104834Sobrien     input is 0x80000000, and bfd_vma is only 32 bits; then we
3209104834Sobrien     will get sum == 0, but there is an overflow, since the
3210104834Sobrien     inputs did not fit in the field.  Instead of doing a
3211104834Sobrien     separate test, we can check for this by or-ing in the
3212104834Sobrien     operands when testing for the sum overflowing its final
3213104834Sobrien     field.  */
3214104834Sobrien  a = (a & addrmask) >> howto->rightshift;
3215104834Sobrien  b = (b & addrmask) >> howto->bitpos;
3216104834Sobrien  sum = (a + b) & addrmask;
3217104834Sobrien  if ((a | b | sum) & ~ fieldmask)
3218130561Sobrien    return TRUE;
3219130561Sobrien
3220130561Sobrien  return FALSE;
3221104834Sobrien}
3222104834Sobrien
322389857Sobrien/* This is the relocation function for the RS/6000/POWER/PowerPC.
322489857Sobrien   This is currently the only processor which uses XCOFF; I hope that
3225130561Sobrien   will never change.
322689857Sobrien
3227104834Sobrien   I took the relocation type definitions from two documents:
3228104834Sobrien   the PowerPC AIX Version 4 Application Binary Interface, First
3229104834Sobrien   Edition (April 1992), and the PowerOpen ABI, Big-Endian
3230104834Sobrien   32-Bit Hardware Implementation (June 30, 1994).  Differences
3231130561Sobrien   between the documents are noted below.
3232104834Sobrien
3233130561Sobrien   Unsupported r_type's
3234104834Sobrien
3235104834Sobrien   R_RTB:
3236104834Sobrien   R_RRTBI:
3237104834Sobrien   R_RRTBA:
3238130561Sobrien
3239104834Sobrien   These relocs are defined by the PowerPC ABI to be
3240104834Sobrien   relative branches which use half of the difference
3241104834Sobrien   between the symbol and the program counter.  I can't
3242104834Sobrien   quite figure out when this is useful.  These relocs are
3243130561Sobrien   not defined by the PowerOpen ABI.
3244104834Sobrien
3245104834Sobrien   Supported r_type's
3246104834Sobrien
3247104834Sobrien   R_POS:
3248104834Sobrien   Simple positive relocation.
3249104834Sobrien
3250104834Sobrien   R_NEG:
3251130561Sobrien   Simple negative relocation.
3252104834Sobrien
3253104834Sobrien   R_REL:
3254104834Sobrien   Simple PC relative relocation.
3255104834Sobrien
3256104834Sobrien   R_TOC:
3257104834Sobrien   TOC relative relocation.  The value in the instruction in
3258104834Sobrien   the input file is the offset from the input file TOC to
3259104834Sobrien   the desired location.  We want the offset from the final
3260104834Sobrien   TOC to the desired location.  We have:
3261104834Sobrien   isym = iTOC + in
3262104834Sobrien   iinsn = in + o
3263104834Sobrien   osym = oTOC + on
3264104834Sobrien   oinsn = on + o
3265104834Sobrien   so we must change insn by on - in.
3266104834Sobrien
3267104834Sobrien   R_GL:
3268104834Sobrien   GL linkage relocation.  The value of this relocation
3269130561Sobrien   is the address of the entry in the TOC section.
3270104834Sobrien
3271104834Sobrien   R_TCL:
3272104834Sobrien   Local object TOC address.  I can't figure out the
3273130561Sobrien   difference between this and case R_GL.
3274104834Sobrien
3275104834Sobrien   R_TRL:
3276104834Sobrien   TOC relative relocation.  A TOC relative load instruction
3277104834Sobrien   which may be changed to a load address instruction.
3278130561Sobrien   FIXME: We don't currently implement this optimization.
3279104834Sobrien
3280104834Sobrien   R_TRLA:
3281104834Sobrien   TOC relative relocation.  This is a TOC relative load
3282104834Sobrien   address instruction which may be changed to a load
3283104834Sobrien   instruction.  FIXME: I don't know if this is the correct
3284104834Sobrien   implementation.
3285104834Sobrien
3286104834Sobrien   R_BA:
3287104834Sobrien   Absolute branch.  We don't want to mess with the lower
3288130561Sobrien   two bits of the instruction.
3289104834Sobrien
3290104834Sobrien   R_CAI:
3291104834Sobrien   The PowerPC ABI defines this as an absolute call which
3292104834Sobrien   may be modified to become a relative call.  The PowerOpen
3293130561Sobrien   ABI does not define this relocation type.
3294130561Sobrien
3295104834Sobrien   R_RBA:
3296104834Sobrien   Absolute branch which may be modified to become a
3297130561Sobrien   relative branch.
3298104834Sobrien
3299104834Sobrien   R_RBAC:
3300104834Sobrien   The PowerPC ABI defines this as an absolute branch to a
3301104834Sobrien   fixed address which may be modified to an absolute branch
3302104834Sobrien   to a symbol.  The PowerOpen ABI does not define this
3303130561Sobrien   relocation type.
3304104834Sobrien
3305104834Sobrien   R_RBRC:
3306104834Sobrien   The PowerPC ABI defines this as an absolute branch to a
3307104834Sobrien   fixed address which may be modified to a relative branch.
3308130561Sobrien   The PowerOpen ABI does not define this relocation type.
3309104834Sobrien
3310104834Sobrien   R_BR:
3311104834Sobrien   Relative branch.  We don't want to mess with the lower
3312130561Sobrien   two bits of the instruction.
3313104834Sobrien
3314104834Sobrien   R_CREL:
3315104834Sobrien   The PowerPC ABI defines this as a relative call which may
3316104834Sobrien   be modified to become an absolute call.  The PowerOpen
3317130561Sobrien   ABI does not define this relocation type.
3318104834Sobrien
3319104834Sobrien   R_RBR:
3320104834Sobrien   A relative branch which may be modified to become an
3321104834Sobrien   absolute branch.  FIXME: We don't implement this,
3322104834Sobrien   although we should for symbols of storage mapping class
3323130561Sobrien   XMC_XO.
3324104834Sobrien
3325104834Sobrien   R_RL:
3326104834Sobrien   The PowerPC AIX ABI describes this as a load which may be
3327104834Sobrien   changed to a load address.  The PowerOpen ABI says this
3328130561Sobrien   is the same as case R_POS.
3329104834Sobrien
3330104834Sobrien   R_RLA:
3331104834Sobrien   The PowerPC AIX ABI describes this as a load address
3332104834Sobrien   which may be changed to a load.  The PowerOpen ABI says
3333130561Sobrien   this is the same as R_POS.
3334104834Sobrien*/
3335104834Sobrien
3336130561Sobrienbfd_boolean
333789857Sobrienxcoff_ppc_relocate_section (output_bfd, info, input_bfd,
333889857Sobrien			    input_section, contents, relocs, syms,
333989857Sobrien			    sections)
334089857Sobrien     bfd *output_bfd;
334189857Sobrien     struct bfd_link_info *info;
334289857Sobrien     bfd *input_bfd;
334389857Sobrien     asection *input_section;
334489857Sobrien     bfd_byte *contents;
334589857Sobrien     struct internal_reloc *relocs;
334689857Sobrien     struct internal_syment *syms;
334789857Sobrien     asection **sections;
334889857Sobrien{
334989857Sobrien  struct internal_reloc *rel;
335089857Sobrien  struct internal_reloc *relend;
335189857Sobrien
335289857Sobrien  rel = relocs;
335389857Sobrien  relend = rel + input_section->reloc_count;
335489857Sobrien  for (; rel < relend; rel++)
335589857Sobrien    {
335689857Sobrien      long symndx;
335789857Sobrien      struct xcoff_link_hash_entry *h;
335889857Sobrien      struct internal_syment *sym;
335989857Sobrien      bfd_vma addend;
336089857Sobrien      bfd_vma val;
336189857Sobrien      struct reloc_howto_struct howto;
3362104834Sobrien      bfd_vma relocation;
3363104834Sobrien      bfd_vma value_to_relocate;
3364104834Sobrien      bfd_vma address;
3365104834Sobrien      bfd_byte *location;
336689857Sobrien
336789857Sobrien      /* Relocation type R_REF is a special relocation type which is
3368130561Sobrien	 merely used to prevent garbage collection from occurring for
3369130561Sobrien	 the csect including the symbol which it references.  */
337089857Sobrien      if (rel->r_type == R_REF)
337189857Sobrien	continue;
337289857Sobrien
3373104834Sobrien      /* howto */
337489857Sobrien      howto.type = rel->r_type;
337589857Sobrien      howto.rightshift = 0;
337689857Sobrien      howto.bitsize = (rel->r_size & 0x1f) + 1;
3377104834Sobrien      howto.size = howto.bitsize > 16 ? 2 : 1;
3378130561Sobrien      howto.pc_relative = FALSE;
337989857Sobrien      howto.bitpos = 0;
3380104834Sobrien      howto.complain_on_overflow = (rel->r_size & 0x80
3381104834Sobrien				    ? complain_overflow_signed
3382104834Sobrien				    : complain_overflow_bitfield);
338389857Sobrien      howto.special_function = NULL;
338489857Sobrien      howto.name = "internal";
3385130561Sobrien      howto.partial_inplace = TRUE;
3386130561Sobrien      howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
3387130561Sobrien      howto.pcrel_offset = FALSE;
338889857Sobrien
3389104834Sobrien      /* symbol */
339089857Sobrien      val = 0;
3391104834Sobrien      addend = 0;
3392104834Sobrien      h = NULL;
3393104834Sobrien      sym = NULL;
3394130561Sobrien      symndx = rel->r_symndx;
339589857Sobrien
3396130561Sobrien      if (-1 != symndx)
339789857Sobrien	{
339889857Sobrien	  asection *sec;
3399130561Sobrien
3400104834Sobrien	  h = obj_xcoff_sym_hashes (input_bfd)[symndx];
3401104834Sobrien	  sym = syms + symndx;
3402104834Sobrien	  addend = - sym->n_value;
3403130561Sobrien
3404130561Sobrien	  if (NULL == h)
340589857Sobrien	    {
340689857Sobrien	      sec = sections[symndx];
340789857Sobrien	      /* Hack to make sure we use the right TOC anchor value
3408104834Sobrien		 if this reloc is against the TOC anchor.  */
340989857Sobrien	      if (sec->name[3] == '0'
3410104834Sobrien		  && strcmp (sec->name, ".tc0") == 0)
3411104834Sobrien		val = xcoff_data (output_bfd)->toc;
341289857Sobrien	      else
3413104834Sobrien		val = (sec->output_section->vma
3414104834Sobrien		       + sec->output_offset
3415104834Sobrien		       + sym->n_value
3416104834Sobrien		       - sec->vma);
3417130561Sobrien	    }
3418130561Sobrien	  else
3419104834Sobrien	    {
3420130561Sobrien	      if (h->root.type == bfd_link_hash_defined
3421130561Sobrien		  || h->root.type == bfd_link_hash_defweak)
342289857Sobrien		{
3423104834Sobrien		  sec = h->root.u.def.section;
3424104834Sobrien		  val = (h->root.u.def.value
3425104834Sobrien			 + sec->output_section->vma
3426104834Sobrien			 + sec->output_offset);
3427130561Sobrien		}
3428130561Sobrien	      else if (h->root.type == bfd_link_hash_common)
3429104834Sobrien		{
3430104834Sobrien		  sec = h->root.u.c.p->section;
343189857Sobrien		  val = (sec->output_section->vma
3432104834Sobrien			 + sec->output_offset);
3433130561Sobrien
3434130561Sobrien		}
3435130561Sobrien	      else if ((0 == (h->flags & (XCOFF_DEF_DYNAMIC | XCOFF_IMPORT)))
3436130561Sobrien		       && ! info->relocatable)
3437104834Sobrien		{
3438104834Sobrien		  if (! ((*info->callbacks->undefined_symbol)
3439104834Sobrien			 (info, h->root.root.string, input_bfd, input_section,
3440130561Sobrien			  rel->r_vaddr - input_section->vma, TRUE)))
3441130561Sobrien		    return FALSE;
3442130561Sobrien
3443104834Sobrien		  /* Don't try to process the reloc.  It can't help, and
3444104834Sobrien		     it may generate another error.  */
3445104834Sobrien		  continue;
344689857Sobrien		}
344789857Sobrien	    }
344889857Sobrien	}
344989857Sobrien
3450130561Sobrien      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
3451104834Sobrien	  || !((*xcoff_calculate_relocation[rel->r_type])
3452130561Sobrien	       (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
3453130561Sobrien		addend, &relocation, contents)))
3454130561Sobrien	return FALSE;
3455130561Sobrien
3456104834Sobrien      /* address */
3457104834Sobrien      address = rel->r_vaddr - input_section->vma;
3458104834Sobrien      location = contents + address;
3459130561Sobrien
3460218822Sdim      if (address > input_section->size)
3461130561Sobrien	abort ();
346289857Sobrien
3463104834Sobrien      /* Get the value we are going to relocate.  */
3464104834Sobrien      if (1 == howto.size)
3465104834Sobrien	value_to_relocate = bfd_get_16 (input_bfd, location);
3466130561Sobrien      else
3467104834Sobrien	value_to_relocate = bfd_get_32 (input_bfd, location);
3468130561Sobrien
3469130561Sobrien      /* overflow.
3470130561Sobrien
3471104834Sobrien	 FIXME: We may drop bits during the addition
3472104834Sobrien	 which we don't check for.  We must either check at every single
3473104834Sobrien	 operation, which would be tedious, or we must do the computations
3474104834Sobrien	 in a type larger than bfd_vma, which would be inefficient.  */
3475130561Sobrien
3476104834Sobrien      if ((unsigned int) howto.complain_on_overflow
3477104834Sobrien	  >= XCOFF_MAX_COMPLAIN_OVERFLOW)
3478130561Sobrien	abort ();
347989857Sobrien
3480104834Sobrien      if (((*xcoff_complain_overflow[howto.complain_on_overflow])
3481130561Sobrien	   (input_bfd, value_to_relocate, relocation, &howto)))
348289857Sobrien	{
3483104834Sobrien	  const char *name;
3484104834Sobrien	  char buf[SYMNMLEN + 1];
3485104834Sobrien	  char reloc_type_name[10];
3486130561Sobrien
3487130561Sobrien	  if (symndx == -1)
348889857Sobrien	    {
3489104834Sobrien	      name = "*ABS*";
3490130561Sobrien	    }
3491130561Sobrien	  else if (h != NULL)
349289857Sobrien	    {
3493218822Sdim	      name = NULL;
3494130561Sobrien	    }
3495130561Sobrien	  else
349689857Sobrien	    {
3497104834Sobrien	      name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
3498104834Sobrien	      if (name == NULL)
3499104834Sobrien		name = "UNKNOWN";
350089857Sobrien	    }
3501104834Sobrien	  sprintf (reloc_type_name, "0x%02x", rel->r_type);
3502130561Sobrien
3503104834Sobrien	  if (! ((*info->callbacks->reloc_overflow)
3504218822Sdim		 (info, (h ? &h->root : NULL), name, reloc_type_name,
3505218822Sdim		  (bfd_vma) 0, input_bfd, input_section,
3506218822Sdim		  rel->r_vaddr - input_section->vma)))
3507130561Sobrien	    return FALSE;
350889857Sobrien	}
3509130561Sobrien
3510104834Sobrien      /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE.  */
3511104834Sobrien      value_to_relocate = ((value_to_relocate & ~howto.dst_mask)
3512104834Sobrien			   | (((value_to_relocate & howto.src_mask)
3513104834Sobrien			       + relocation) & howto.dst_mask));
3514130561Sobrien
3515104834Sobrien      /* Put the value back in the object file.  */
3516104834Sobrien      if (1 == howto.size)
3517104834Sobrien	bfd_put_16 (input_bfd, value_to_relocate, location);
3518130561Sobrien      else
3519104834Sobrien	bfd_put_32 (input_bfd, value_to_relocate, location);
352089857Sobrien    }
352189857Sobrien
3522130561Sobrien  return TRUE;
352389857Sobrien}
352489857Sobrien
3525130561Sobrienstatic bfd_boolean
352689857Sobrien_bfd_xcoff_put_ldsymbol_name (abfd, ldinfo, ldsym, name)
352789857Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
352889857Sobrien	 struct xcoff_loader_info *ldinfo;
352989857Sobrien	 struct internal_ldsym *ldsym;
353089857Sobrien	 const char *name;
353189857Sobrien{
353289857Sobrien  size_t len;
353389857Sobrien  len = strlen (name);
353489857Sobrien
353589857Sobrien  if (len <= SYMNMLEN)
353689857Sobrien    strncpy (ldsym->_l._l_name, name, SYMNMLEN);
353789857Sobrien  else
353889857Sobrien    {
353989857Sobrien      if (ldinfo->string_size + len + 3 > ldinfo->string_alc)
354089857Sobrien	{
354189857Sobrien	  bfd_size_type newalc;
3542218822Sdim	  char *newstrings;
354389857Sobrien
354489857Sobrien	  newalc = ldinfo->string_alc * 2;
354589857Sobrien	  if (newalc == 0)
354689857Sobrien	    newalc = 32;
354789857Sobrien	  while (ldinfo->string_size + len + 3 > newalc)
354889857Sobrien	    newalc *= 2;
354989857Sobrien
3550218822Sdim	  newstrings = bfd_realloc (ldinfo->strings, newalc);
355189857Sobrien	  if (newstrings == NULL)
355289857Sobrien	    {
3553130561Sobrien	      ldinfo->failed = TRUE;
3554130561Sobrien	      return FALSE;
355589857Sobrien	    }
355689857Sobrien	  ldinfo->string_alc = newalc;
355789857Sobrien	  ldinfo->strings = newstrings;
355889857Sobrien	}
355989857Sobrien
356089857Sobrien      bfd_put_16 (ldinfo->output_bfd, (bfd_vma) (len + 1),
356189857Sobrien		  ldinfo->strings + ldinfo->string_size);
356289857Sobrien      strcpy (ldinfo->strings + ldinfo->string_size + 2, name);
356389857Sobrien      ldsym->_l._l_l._l_zeroes = 0;
356489857Sobrien      ldsym->_l._l_l._l_offset = ldinfo->string_size + 2;
356589857Sobrien      ldinfo->string_size += len + 3;
356689857Sobrien    }
356789857Sobrien
3568130561Sobrien  return TRUE;
356989857Sobrien}
357089857Sobrien
3571130561Sobrienstatic bfd_boolean
357289857Sobrien_bfd_xcoff_put_symbol_name (bfd *abfd, struct bfd_strtab_hash *strtab,
357389857Sobrien			    struct internal_syment *sym,
357489857Sobrien			    const char *name)
357589857Sobrien{
357689857Sobrien  if (strlen (name) <= SYMNMLEN)
357789857Sobrien    {
357889857Sobrien      strncpy (sym->_n._n_name, name, SYMNMLEN);
357989857Sobrien    }
358089857Sobrien  else
358189857Sobrien    {
3582130561Sobrien      bfd_boolean hash;
358389857Sobrien      bfd_size_type indx;
358489857Sobrien
3585130561Sobrien      hash = TRUE;
358689857Sobrien      if ((abfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
3587130561Sobrien	hash = FALSE;
3588130561Sobrien      indx = _bfd_stringtab_add (strtab, name, hash, FALSE);
358989857Sobrien      if (indx == (bfd_size_type) -1)
3590130561Sobrien	return FALSE;
359189857Sobrien      sym->_n._n_n._n_zeroes = 0;
359289857Sobrien      sym->_n._n_n._n_offset = STRING_SIZE_SIZE + indx;
359389857Sobrien    }
3594130561Sobrien  return TRUE;
359589857Sobrien}
359689857Sobrien
359789857Sobrienstatic asection *
359889857Sobrienxcoff_create_csect_from_smclas (abfd, aux, symbol_name)
359989857Sobrien     bfd *abfd;
360089857Sobrien     union internal_auxent *aux;
360189857Sobrien     const char *symbol_name;
360289857Sobrien{
360389857Sobrien  asection *return_value = NULL;
360489857Sobrien
360589857Sobrien  /* .sv64 = x_smclas == 17
360689857Sobrien     This is an invalid csect for 32 bit apps.  */
360789857Sobrien  static const char *names[19] =
360889857Sobrien  {
360989857Sobrien    ".pr", ".ro", ".db", ".tc", ".ua", ".rw", ".gl", ".xo",
361089857Sobrien    ".sv", ".bs", ".ds", ".uc", ".ti", ".tb", NULL, ".tc0",
361189857Sobrien    ".td", NULL, ".sv3264"
361289857Sobrien  };
361389857Sobrien
3614104834Sobrien  if ((19 >= aux->x_csect.x_smclas)
3615104834Sobrien      && (NULL != names[aux->x_csect.x_smclas]))
361689857Sobrien    {
361789857Sobrien      return_value = bfd_make_section_anyway
361889857Sobrien	(abfd, names[aux->x_csect.x_smclas]);
361989857Sobrien    }
362089857Sobrien  else
362189857Sobrien    {
362289857Sobrien      (*_bfd_error_handler)
3623218822Sdim	(_("%B: symbol `%s' has unrecognized smclas %d"),
3624218822Sdim	 abfd, symbol_name, aux->x_csect.x_smclas);
362589857Sobrien      bfd_set_error (bfd_error_bad_value);
362689857Sobrien    }
362789857Sobrien
362889857Sobrien  return return_value;
362989857Sobrien}
363089857Sobrien
3631130561Sobrienstatic bfd_boolean
363289857Sobrienxcoff_is_lineno_count_overflow (abfd, value)
363389857Sobrien    bfd *abfd ATTRIBUTE_UNUSED;
363489857Sobrien	bfd_vma value;
363589857Sobrien{
363689857Sobrien  if (0xffff <= value)
3637130561Sobrien    return TRUE;
363889857Sobrien
3639130561Sobrien  return FALSE;
364089857Sobrien}
364189857Sobrien
3642130561Sobrienstatic bfd_boolean
364389857Sobrienxcoff_is_reloc_count_overflow (abfd, value)
364489857Sobrien    bfd *abfd ATTRIBUTE_UNUSED;
364589857Sobrien	bfd_vma value;
364689857Sobrien{
364789857Sobrien  if (0xffff <= value)
3648130561Sobrien    return TRUE;
364989857Sobrien
3650130561Sobrien  return FALSE;
365189857Sobrien}
365289857Sobrien
365389857Sobrienstatic bfd_vma
365489857Sobrienxcoff_loader_symbol_offset (abfd, ldhdr)
365589857Sobrien    bfd *abfd;
365689857Sobrien    struct internal_ldhdr *ldhdr ATTRIBUTE_UNUSED;
365789857Sobrien{
3658130561Sobrien  return bfd_xcoff_ldhdrsz (abfd);
365989857Sobrien}
366089857Sobrien
366189857Sobrienstatic bfd_vma
366289857Sobrienxcoff_loader_reloc_offset (abfd, ldhdr)
366389857Sobrien    bfd *abfd;
366489857Sobrien    struct internal_ldhdr *ldhdr;
366589857Sobrien{
3666104834Sobrien  return bfd_xcoff_ldhdrsz (abfd) + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (abfd);
366789857Sobrien}
366889857Sobrien
3669130561Sobrienstatic bfd_boolean
3670104834Sobrienxcoff_generate_rtinit  (abfd, init, fini, rtld)
367189857Sobrien     bfd *abfd;
367289857Sobrien     const char *init;
367389857Sobrien     const char *fini;
3674130561Sobrien     bfd_boolean rtld;
367589857Sobrien{
367689857Sobrien  bfd_byte filehdr_ext[FILHSZ];
367789857Sobrien  bfd_byte scnhdr_ext[SCNHSZ];
3678104834Sobrien  bfd_byte syment_ext[SYMESZ * 10];
3679104834Sobrien  bfd_byte reloc_ext[RELSZ * 3];
368089857Sobrien  bfd_byte *data_buffer;
368189857Sobrien  bfd_size_type data_buffer_size;
368291041Sobrien  bfd_byte *string_table = NULL, *st_tmp = NULL;
368389857Sobrien  bfd_size_type string_table_size;
368489857Sobrien  bfd_vma val;
368589857Sobrien  size_t initsz, finisz;
368689857Sobrien  struct internal_filehdr filehdr;
368789857Sobrien  struct internal_scnhdr scnhdr;
368889857Sobrien  struct internal_syment syment;
368989857Sobrien  union internal_auxent auxent;
369089857Sobrien  struct internal_reloc reloc;
3691130561Sobrien
369289857Sobrien  char *data_name = ".data";
369389857Sobrien  char *rtinit_name = "__rtinit";
3694104834Sobrien  char *rtld_name = "__rtld";
3695130561Sobrien
3696104834Sobrien  if (! bfd_xcoff_rtinit_size (abfd))
3697130561Sobrien    return FALSE;
369889857Sobrien
369989857Sobrien  initsz = (init == NULL ? 0 : 1 + strlen (init));
370089857Sobrien  finisz = (fini == NULL ? 0 : 1 + strlen (fini));
370189857Sobrien
370289857Sobrien  /* file header */
370389857Sobrien  memset (filehdr_ext, 0, FILHSZ);
370489857Sobrien  memset (&filehdr, 0, sizeof (struct internal_filehdr));
370589857Sobrien  filehdr.f_magic = bfd_xcoff_magic_number (abfd);
3706130561Sobrien  filehdr.f_nscns = 1;
370789857Sobrien  filehdr.f_timdat = 0;
3708104834Sobrien  filehdr.f_nsyms = 0;  /* at least 6, no more than 10 */
370989857Sobrien  filehdr.f_symptr = 0; /* set below */
371089857Sobrien  filehdr.f_opthdr = 0;
371189857Sobrien  filehdr.f_flags = 0;
371289857Sobrien
371389857Sobrien  /* section header */
371489857Sobrien  memset (scnhdr_ext, 0, SCNHSZ);
371589857Sobrien  memset (&scnhdr, 0, sizeof (struct internal_scnhdr));
371689857Sobrien  memcpy (scnhdr.s_name, data_name, strlen (data_name));
371789857Sobrien  scnhdr.s_paddr = 0;
371889857Sobrien  scnhdr.s_vaddr = 0;
371989857Sobrien  scnhdr.s_size = 0;    /* set below */
372089857Sobrien  scnhdr.s_scnptr = FILHSZ + SCNHSZ;
372189857Sobrien  scnhdr.s_relptr = 0;  /* set below */
372289857Sobrien  scnhdr.s_lnnoptr = 0;
372389857Sobrien  scnhdr.s_nreloc = 0;  /* either 1 or 2 */
372489857Sobrien  scnhdr.s_nlnno = 0;
372589857Sobrien  scnhdr.s_flags = STYP_DATA;
372689857Sobrien
3727130561Sobrien  /* .data
3728130561Sobrien     0x0000	      0x00000000 : rtl
3729130561Sobrien     0x0004	      0x00000010 : offset to init, or 0
3730130561Sobrien     0x0008	      0x00000028 : offset to fini, or 0
3731130561Sobrien     0x000C	      0x0000000C : size of descriptor
3732130561Sobrien     0x0010	      0x00000000 : init, needs a reloc
3733130561Sobrien     0x0014	      0x00000040 : offset to init name
3734130561Sobrien     0x0018	      0x00000000 : flags, padded to a word
3735130561Sobrien     0x001C	      0x00000000 : empty init
3736130561Sobrien     0x0020	      0x00000000 :
3737130561Sobrien     0x0024	      0x00000000 :
3738130561Sobrien     0x0028	      0x00000000 : fini, needs a reloc
3739130561Sobrien     0x002C	      0x00000??? : offset to fini name
3740130561Sobrien     0x0030	      0x00000000 : flags, padded to a word
3741130561Sobrien     0x0034	      0x00000000 : empty fini
3742130561Sobrien     0x0038	      0x00000000 :
3743130561Sobrien     0x003C	      0x00000000 :
3744130561Sobrien     0x0040	      init name
374589857Sobrien     0x0040 + initsz  fini name */
374689857Sobrien
374789857Sobrien  data_buffer_size = 0x0040 + initsz + finisz;
3748130561Sobrien  data_buffer_size = (data_buffer_size + 7) &~ (bfd_size_type) 7;
374989857Sobrien  data_buffer = NULL;
3750104834Sobrien  data_buffer = (bfd_byte *) bfd_zmalloc (data_buffer_size);
375189857Sobrien  if (data_buffer == NULL)
3752130561Sobrien    return FALSE;
375389857Sobrien
3754130561Sobrien  if (initsz)
375589857Sobrien    {
375689857Sobrien      val = 0x10;
375789857Sobrien      bfd_h_put_32 (abfd, val, &data_buffer[0x04]);
375889857Sobrien      val = 0x40;
375989857Sobrien      bfd_h_put_32 (abfd, val, &data_buffer[0x14]);
376089857Sobrien      memcpy (&data_buffer[val], init, initsz);
376189857Sobrien    }
376289857Sobrien
3763130561Sobrien  if (finisz)
376489857Sobrien    {
376589857Sobrien      val = 0x28;
376689857Sobrien      bfd_h_put_32 (abfd, val, &data_buffer[0x08]);
376789857Sobrien      val = 0x40 + initsz;
376889857Sobrien      bfd_h_put_32 (abfd, val, &data_buffer[0x2C]);
376989857Sobrien      memcpy (&data_buffer[val], fini, finisz);
377089857Sobrien    }
377189857Sobrien
377289857Sobrien  val = 0x0C;
377389857Sobrien  bfd_h_put_32 (abfd, val, &data_buffer[0x0C]);
377489857Sobrien
377589857Sobrien  scnhdr.s_size = data_buffer_size;
377689857Sobrien
377789857Sobrien  /* string table */
377889857Sobrien  string_table_size = 0;
3779130561Sobrien  if (initsz > 9)
378089857Sobrien    string_table_size += initsz;
378189857Sobrien  if (finisz > 9)
378289857Sobrien    string_table_size += finisz;
378389857Sobrien  if (string_table_size)
378489857Sobrien    {
378589857Sobrien      string_table_size += 4;
3786104834Sobrien      string_table = (bfd_byte *) bfd_zmalloc (string_table_size);
3787104834Sobrien      if (string_table == NULL)
3788130561Sobrien	return FALSE;
3789104834Sobrien
379089857Sobrien      val = string_table_size;
379189857Sobrien      bfd_h_put_32 (abfd, val, &string_table[0]);
379289857Sobrien      st_tmp = string_table + 4;
379389857Sobrien    }
3794130561Sobrien
3795130561Sobrien  /* symbols
379689857Sobrien     0. .data csect
379789857Sobrien     2. __rtinit
3798130561Sobrien     4. init function
3799130561Sobrien     6. fini function
3800104834Sobrien     8. __rtld  */
3801104834Sobrien  memset (syment_ext, 0, 10 * SYMESZ);
3802104834Sobrien  memset (reloc_ext, 0, 3 * RELSZ);
380389857Sobrien
380489857Sobrien  /* .data csect */
380589857Sobrien  memset (&syment, 0, sizeof (struct internal_syment));
380689857Sobrien  memset (&auxent, 0, sizeof (union internal_auxent));
380789857Sobrien  memcpy (syment._n._n_name, data_name, strlen (data_name));
380889857Sobrien  syment.n_scnum = 1;
380989857Sobrien  syment.n_sclass = C_HIDEXT;
381089857Sobrien  syment.n_numaux = 1;
381189857Sobrien  auxent.x_csect.x_scnlen.l = data_buffer_size;
381289857Sobrien  auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD;
381389857Sobrien  auxent.x_csect.x_smclas = XMC_RW;
3814130561Sobrien  bfd_coff_swap_sym_out (abfd, &syment,
381589857Sobrien			 &syment_ext[filehdr.f_nsyms * SYMESZ]);
3816130561Sobrien  bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0,
3817130561Sobrien			 syment.n_numaux,
381889857Sobrien			 &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]);
381989857Sobrien  filehdr.f_nsyms += 2;
382089857Sobrien
382189857Sobrien  /* __rtinit */
382289857Sobrien  memset (&syment, 0, sizeof (struct internal_syment));
382389857Sobrien  memset (&auxent, 0, sizeof (union internal_auxent));
382489857Sobrien  memcpy (syment._n._n_name, rtinit_name, strlen (rtinit_name));
382589857Sobrien  syment.n_scnum = 1;
382689857Sobrien  syment.n_sclass = C_EXT;
382789857Sobrien  syment.n_numaux = 1;
382889857Sobrien  auxent.x_csect.x_smtyp = XTY_LD;
382989857Sobrien  auxent.x_csect.x_smclas = XMC_RW;
3830130561Sobrien  bfd_coff_swap_sym_out (abfd, &syment,
383189857Sobrien			 &syment_ext[filehdr.f_nsyms * SYMESZ]);
3832130561Sobrien  bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0,
3833130561Sobrien			 syment.n_numaux,
383489857Sobrien			 &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]);
383589857Sobrien  filehdr.f_nsyms += 2;
383689857Sobrien
383789857Sobrien  /* init */
3838130561Sobrien  if (initsz)
383989857Sobrien    {
384089857Sobrien      memset (&syment, 0, sizeof (struct internal_syment));
384189857Sobrien      memset (&auxent, 0, sizeof (union internal_auxent));
384289857Sobrien
3843130561Sobrien      if (initsz > 9)
384489857Sobrien	{
384589857Sobrien	  syment._n._n_n._n_offset = st_tmp - string_table;
384689857Sobrien	  memcpy (st_tmp, init, initsz);
384789857Sobrien	  st_tmp += initsz;
384889857Sobrien	}
384989857Sobrien      else
385089857Sobrien	memcpy (syment._n._n_name, init, initsz - 1);
385189857Sobrien
385289857Sobrien      syment.n_sclass = C_EXT;
385389857Sobrien      syment.n_numaux = 1;
3854130561Sobrien      bfd_coff_swap_sym_out (abfd, &syment,
385589857Sobrien			     &syment_ext[filehdr.f_nsyms * SYMESZ]);
3856130561Sobrien      bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0,
3857130561Sobrien			     syment.n_numaux,
385889857Sobrien			     &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]);
385989857Sobrien
386089857Sobrien      /* reloc */
386189857Sobrien      memset (&reloc, 0, sizeof (struct internal_reloc));
386289857Sobrien      reloc.r_vaddr = 0x0010;
386389857Sobrien      reloc.r_symndx = filehdr.f_nsyms;
386489857Sobrien      reloc.r_type = R_POS;
386589857Sobrien      reloc.r_size = 31;
386689857Sobrien      bfd_coff_swap_reloc_out (abfd, &reloc, &reloc_ext[0]);
386789857Sobrien
386889857Sobrien      filehdr.f_nsyms += 2;
386989857Sobrien      scnhdr.s_nreloc += 1;
387089857Sobrien    }
3871130561Sobrien
387289857Sobrien  /* fini */
3873130561Sobrien  if (finisz)
387489857Sobrien    {
387589857Sobrien      memset (&syment, 0, sizeof (struct internal_syment));
387689857Sobrien      memset (&auxent, 0, sizeof (union internal_auxent));
387789857Sobrien
3878130561Sobrien      if (finisz > 9)
387989857Sobrien	{
388089857Sobrien	  syment._n._n_n._n_offset = st_tmp - string_table;
388189857Sobrien	  memcpy (st_tmp, fini, finisz);
388289857Sobrien	  st_tmp += finisz;
388389857Sobrien	}
388489857Sobrien      else
388589857Sobrien	memcpy (syment._n._n_name, fini, finisz - 1);
388689857Sobrien
388789857Sobrien      syment.n_sclass = C_EXT;
388889857Sobrien      syment.n_numaux = 1;
3889130561Sobrien      bfd_coff_swap_sym_out (abfd, &syment,
389089857Sobrien			     &syment_ext[filehdr.f_nsyms * SYMESZ]);
3891130561Sobrien      bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0,
3892130561Sobrien			     syment.n_numaux,
389389857Sobrien			     &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]);
389489857Sobrien
389589857Sobrien      /* reloc */
389689857Sobrien      memset (&reloc, 0, sizeof (struct internal_reloc));
389789857Sobrien      reloc.r_vaddr = 0x0028;
389889857Sobrien      reloc.r_symndx = filehdr.f_nsyms;
389989857Sobrien      reloc.r_type = R_POS;
390089857Sobrien      reloc.r_size = 31;
3901130561Sobrien      bfd_coff_swap_reloc_out (abfd, &reloc,
390289857Sobrien			       &reloc_ext[scnhdr.s_nreloc * RELSZ]);
390389857Sobrien
390489857Sobrien      filehdr.f_nsyms += 2;
390589857Sobrien      scnhdr.s_nreloc += 1;
390689857Sobrien    }
390789857Sobrien
3908104834Sobrien  if (rtld)
3909104834Sobrien    {
3910104834Sobrien      memset (&syment, 0, sizeof (struct internal_syment));
3911104834Sobrien      memset (&auxent, 0, sizeof (union internal_auxent));
3912104834Sobrien      memcpy (syment._n._n_name, rtld_name, strlen (rtld_name));
3913104834Sobrien      syment.n_sclass = C_EXT;
3914104834Sobrien      syment.n_numaux = 1;
3915130561Sobrien      bfd_coff_swap_sym_out (abfd, &syment,
3916104834Sobrien			     &syment_ext[filehdr.f_nsyms * SYMESZ]);
3917130561Sobrien      bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0,
3918130561Sobrien			     syment.n_numaux,
3919104834Sobrien			     &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]);
3920104834Sobrien
3921104834Sobrien      /* reloc */
3922104834Sobrien      memset (&reloc, 0, sizeof (struct internal_reloc));
3923104834Sobrien      reloc.r_vaddr = 0x0000;
3924104834Sobrien      reloc.r_symndx = filehdr.f_nsyms;
3925104834Sobrien      reloc.r_type = R_POS;
3926104834Sobrien      reloc.r_size = 31;
3927130561Sobrien      bfd_coff_swap_reloc_out (abfd, &reloc,
3928104834Sobrien			       &reloc_ext[scnhdr.s_nreloc * RELSZ]);
3929104834Sobrien
3930104834Sobrien      filehdr.f_nsyms += 2;
3931104834Sobrien      scnhdr.s_nreloc += 1;
3932104834Sobrien    }
3933104834Sobrien
393489857Sobrien  scnhdr.s_relptr = scnhdr.s_scnptr + data_buffer_size;
393589857Sobrien  filehdr.f_symptr = scnhdr.s_relptr + scnhdr.s_nreloc * RELSZ;
393689857Sobrien
393789857Sobrien  bfd_coff_swap_filehdr_out (abfd, &filehdr, filehdr_ext);
393889857Sobrien  bfd_bwrite (filehdr_ext, FILHSZ, abfd);
393989857Sobrien  bfd_coff_swap_scnhdr_out (abfd, &scnhdr, scnhdr_ext);
394089857Sobrien  bfd_bwrite (scnhdr_ext, SCNHSZ, abfd);
394189857Sobrien  bfd_bwrite (data_buffer, data_buffer_size, abfd);
394289857Sobrien  bfd_bwrite (reloc_ext, scnhdr.s_nreloc * RELSZ, abfd);
394389857Sobrien  bfd_bwrite (syment_ext, filehdr.f_nsyms * SYMESZ, abfd);
394489857Sobrien  bfd_bwrite (string_table, string_table_size, abfd);
394589857Sobrien
394689857Sobrien  free (data_buffer);
394789857Sobrien  data_buffer = NULL;
394889857Sobrien
3949130561Sobrien  return TRUE;
395089857Sobrien}
395189857Sobrien
395289857Sobrien
395389857Sobrienstatic reloc_howto_type xcoff_dynamic_reloc =
3954130561SobrienHOWTO (0,			/* type */
3955130561Sobrien       0,			/* rightshift */
3956130561Sobrien       2,			/* size (0 = byte, 1 = short, 2 = long) */
3957130561Sobrien       32,			/* bitsize */
3958130561Sobrien       FALSE,			/* pc_relative */
3959130561Sobrien       0,			/* bitpos */
396089857Sobrien       complain_overflow_bitfield, /* complain_on_overflow */
3961130561Sobrien       0,			/* special_function */
3962130561Sobrien       "R_POS",			/* name */
3963130561Sobrien       TRUE,			/* partial_inplace */
3964130561Sobrien       0xffffffff,		/* src_mask */
3965130561Sobrien       0xffffffff,		/* dst_mask */
3966130561Sobrien       FALSE);			/* pcrel_offset */
396789857Sobrien
396889857Sobrien/*  glink
396989857Sobrien
397089857Sobrien   The first word of global linkage code must be modified by filling in
397189857Sobrien   the correct TOC offset.  */
397289857Sobrien
397389857Sobrienstatic unsigned long xcoff_glink_code[9] =
397489857Sobrien  {
397589857Sobrien    0x81820000,	/* lwz r12,0(r2) */
397689857Sobrien    0x90410014,	/* stw r2,20(r1) */
397789857Sobrien    0x800c0000,	/* lwz r0,0(r12) */
397889857Sobrien    0x804c0004,	/* lwz r2,4(r12) */
397989857Sobrien    0x7c0903a6,	/* mtctr r0 */
398089857Sobrien    0x4e800420,	/* bctr */
398189857Sobrien    0x00000000,	/* start of traceback table */
398289857Sobrien    0x000c8000,	/* traceback table */
398389857Sobrien    0x00000000,	/* traceback table */
398489857Sobrien  };
398589857Sobrien
398689857Sobrien
398789857Sobrienstatic const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
398889857Sobrien  {
398989857Sobrien    { /* COFF backend, defined in libcoff.h.  */
3990104834Sobrien      _bfd_xcoff_swap_aux_in,
3991104834Sobrien      _bfd_xcoff_swap_sym_in,
3992104834Sobrien      coff_swap_lineno_in,
3993104834Sobrien      _bfd_xcoff_swap_aux_out,
3994104834Sobrien      _bfd_xcoff_swap_sym_out,
3995104834Sobrien      coff_swap_lineno_out,
3996104834Sobrien      xcoff_swap_reloc_out,
3997104834Sobrien      coff_swap_filehdr_out,
3998104834Sobrien      coff_swap_aouthdr_out,
3999104834Sobrien      coff_swap_scnhdr_out,
4000104834Sobrien      FILHSZ,
4001104834Sobrien      AOUTSZ,
4002104834Sobrien      SCNHSZ,
4003104834Sobrien      SYMESZ,
4004104834Sobrien      AUXESZ,
4005104834Sobrien      RELSZ,
4006104834Sobrien      LINESZ,
4007104834Sobrien      FILNMLEN,
4008130561Sobrien      TRUE,			/* _bfd_coff_long_filenames */
4009130561Sobrien      FALSE,			/* _bfd_coff_long_section_names */
4010104834Sobrien      3,			/* _bfd_coff_default_section_alignment_power */
4011130561Sobrien      FALSE,			/* _bfd_coff_force_symnames_in_strings */
4012130561Sobrien      2,			/* _bfd_coff_debug_string_prefix_length */
4013104834Sobrien      coff_swap_filehdr_in,
4014104834Sobrien      coff_swap_aouthdr_in,
4015104834Sobrien      coff_swap_scnhdr_in,
4016104834Sobrien      xcoff_swap_reloc_in,
4017104834Sobrien      coff_bad_format_hook,
4018104834Sobrien      coff_set_arch_mach_hook,
4019104834Sobrien      coff_mkobject_hook,
4020104834Sobrien      styp_to_sec_flags,
4021104834Sobrien      coff_set_alignment_hook,
4022104834Sobrien      coff_slurp_symbol_table,
4023104834Sobrien      symname_in_debug_hook,
4024104834Sobrien      coff_pointerize_aux_hook,
4025104834Sobrien      coff_print_aux,
4026104834Sobrien      dummy_reloc16_extra_cases,
4027104834Sobrien      dummy_reloc16_estimate,
4028130561Sobrien      NULL,			/* bfd_coff_sym_is_global */
4029104834Sobrien      coff_compute_section_file_positions,
4030130561Sobrien      NULL,			/* _bfd_coff_start_final_link */
4031104834Sobrien      xcoff_ppc_relocate_section,
4032104834Sobrien      coff_rtype_to_howto,
4033104834Sobrien      NULL,			/* _bfd_coff_adjust_symndx */
4034104834Sobrien      _bfd_generic_link_add_one_symbol,
4035104834Sobrien      coff_link_output_has_begun,
4036104834Sobrien      coff_final_link_postscript
403789857Sobrien    },
403889857Sobrien
4039130561Sobrien    0x01DF,			/* magic number */
4040104834Sobrien    bfd_arch_rs6000,
4041104834Sobrien    bfd_mach_rs6k,
404289857Sobrien
404389857Sobrien    /* Function pointers to xcoff specific swap routines.  */
4044104834Sobrien    xcoff_swap_ldhdr_in,
4045104834Sobrien    xcoff_swap_ldhdr_out,
4046104834Sobrien    xcoff_swap_ldsym_in,
4047104834Sobrien    xcoff_swap_ldsym_out,
4048104834Sobrien    xcoff_swap_ldrel_in,
4049104834Sobrien    xcoff_swap_ldrel_out,
405089857Sobrien
405189857Sobrien    /* Sizes.  */
4052104834Sobrien    LDHDRSZ,
4053104834Sobrien    LDSYMSZ,
4054104834Sobrien    LDRELSZ,
4055130561Sobrien    12,				/* _xcoff_function_descriptor_size */
4056104834Sobrien    SMALL_AOUTSZ,
405789857Sobrien
4058130561Sobrien    /* Versions.  */
4059130561Sobrien    1,				/* _xcoff_ldhdr_version */
406089857Sobrien
4061104834Sobrien    _bfd_xcoff_put_symbol_name,
4062104834Sobrien    _bfd_xcoff_put_ldsymbol_name,
4063104834Sobrien    &xcoff_dynamic_reloc,
4064104834Sobrien    xcoff_create_csect_from_smclas,
406589857Sobrien
406689857Sobrien    /* Lineno and reloc count overflow.  */
406789857Sobrien    xcoff_is_lineno_count_overflow,
406889857Sobrien    xcoff_is_reloc_count_overflow,
406989857Sobrien
407089857Sobrien    xcoff_loader_symbol_offset,
407189857Sobrien    xcoff_loader_reloc_offset,
407289857Sobrien
407389857Sobrien    /* glink.  */
4074130561Sobrien    &xcoff_glink_code[0],
4075104834Sobrien    36,				/* _xcoff_glink_size */
407689857Sobrien
407789857Sobrien    /* rtinit */
4078130561Sobrien    64,				/* _xcoff_rtinit_size */
4079104834Sobrien    xcoff_generate_rtinit,
4080130561Sobrien  };
408189857Sobrien
4082104834Sobrien/* The transfer vector that leads the outside world to all of the above.  */
408389857Sobrienconst bfd_target rs6000coff_vec =
4084130561Sobrien  {
4085130561Sobrien    "aixcoff-rs6000",
4086130561Sobrien    bfd_target_xcoff_flavour,
4087130561Sobrien    BFD_ENDIAN_BIG,		/* data byte order is big */
4088130561Sobrien    BFD_ENDIAN_BIG,		/* header byte order is big */
408989857Sobrien
4090104834Sobrien    (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC
4091104834Sobrien     | HAS_SYMS | HAS_LOCALS | WP_TEXT),
409289857Sobrien
4093130561Sobrien    SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA,
4094130561Sobrien    0,				/* leading char */
4095130561Sobrien    '/',			/* ar_pad_char */
4096104834Sobrien    15,				/* ar_max_namelen */
409789857Sobrien
4098130561Sobrien    /* data */
4099104834Sobrien    bfd_getb64,
4100104834Sobrien    bfd_getb_signed_64,
4101104834Sobrien    bfd_putb64,
4102104834Sobrien    bfd_getb32,
4103104834Sobrien    bfd_getb_signed_32,
4104104834Sobrien    bfd_putb32,
4105104834Sobrien    bfd_getb16,
4106104834Sobrien    bfd_getb_signed_16,
4107104834Sobrien    bfd_putb16,
410889857Sobrien
4109130561Sobrien    /* hdrs */
4110104834Sobrien    bfd_getb64,
4111104834Sobrien    bfd_getb_signed_64,
4112104834Sobrien    bfd_putb64,
4113104834Sobrien    bfd_getb32,
4114104834Sobrien    bfd_getb_signed_32,
4115104834Sobrien    bfd_putb32,
4116104834Sobrien    bfd_getb16,
4117104834Sobrien    bfd_getb_signed_16,
4118104834Sobrien    bfd_putb16,
411989857Sobrien
4120130561Sobrien    { /* bfd_check_format */
4121130561Sobrien      _bfd_dummy_target,
4122130561Sobrien      coff_object_p,
4123130561Sobrien      _bfd_xcoff_archive_p,
4124130561Sobrien      CORE_FILE_P
4125130561Sobrien    },
412689857Sobrien
4127130561Sobrien    { /* bfd_set_format */
4128130561Sobrien      bfd_false,
4129130561Sobrien      coff_mkobject,
4130130561Sobrien      _bfd_generic_mkarchive,
4131130561Sobrien      bfd_false
4132130561Sobrien    },
413389857Sobrien
4134130561Sobrien    {/* bfd_write_contents */
4135130561Sobrien      bfd_false,
4136130561Sobrien      coff_write_object_contents,
4137130561Sobrien      _bfd_xcoff_write_archive_contents,
4138130561Sobrien      bfd_false
4139130561Sobrien    },
414089857Sobrien
4141130561Sobrien    /* Generic */
4142104834Sobrien    bfd_true,
4143104834Sobrien    bfd_true,
4144104834Sobrien    coff_new_section_hook,
4145104834Sobrien    _bfd_generic_get_section_contents,
4146130561Sobrien    _bfd_generic_get_section_contents_in_window,
414789857Sobrien
4148130561Sobrien    /* Copy */
4149104834Sobrien    _bfd_xcoff_copy_private_bfd_data,
4150130561Sobrien    ((bfd_boolean (*) (bfd *, bfd *)) bfd_true),
4151218822Sdim    _bfd_generic_init_private_section_data,
4152130561Sobrien    ((bfd_boolean (*) (bfd *, asection *, bfd *, asection *)) bfd_true),
4153130561Sobrien    ((bfd_boolean (*) (bfd *, asymbol *, bfd *, asymbol *)) bfd_true),
4154218822Sdim    ((bfd_boolean (*) (bfd *, bfd *)) bfd_true),
4155130561Sobrien    ((bfd_boolean (*) (bfd *, flagword)) bfd_true),
4156130561Sobrien    ((bfd_boolean (*) (bfd *, void * )) bfd_true),
415789857Sobrien
4158130561Sobrien    /* Core */
4159104834Sobrien    coff_core_file_failing_command,
4160104834Sobrien    coff_core_file_failing_signal,
4161130561Sobrien    coff_core_file_matches_executable_p,
416289857Sobrien
4163130561Sobrien    /* Archive */
4164104834Sobrien    _bfd_xcoff_slurp_armap,
4165104834Sobrien    bfd_false,
4166130561Sobrien    ((bfd_boolean (*) (bfd *, char **, bfd_size_type *, const char **)) bfd_false),
4167104834Sobrien    bfd_dont_truncate_arname,
4168104834Sobrien    _bfd_xcoff_write_armap,
4169104834Sobrien    _bfd_xcoff_read_ar_hdr,
4170104834Sobrien    _bfd_xcoff_openr_next_archived_file,
4171104834Sobrien    _bfd_generic_get_elt_at_index,
4172104834Sobrien    _bfd_xcoff_stat_arch_elt,
4173104834Sobrien    bfd_true,
417489857Sobrien
4175130561Sobrien    /* Symbols */
4176104834Sobrien    coff_get_symtab_upper_bound,
4177130561Sobrien    coff_canonicalize_symtab,
4178104834Sobrien    coff_make_empty_symbol,
4179104834Sobrien    coff_print_symbol,
4180104834Sobrien    coff_get_symbol_info,
4181104834Sobrien    _bfd_xcoff_is_local_label_name,
4182218822Sdim    coff_bfd_is_target_special_symbol,
4183104834Sobrien    coff_get_lineno,
4184104834Sobrien    coff_find_nearest_line,
4185218822Sdim    _bfd_generic_find_line,
4186218822Sdim    coff_find_inliner_info,
4187104834Sobrien    coff_bfd_make_debug_symbol,
4188104834Sobrien    _bfd_generic_read_minisymbols,
4189104834Sobrien    _bfd_generic_minisymbol_to_symbol,
419089857Sobrien
4191130561Sobrien    /* Reloc */
4192104834Sobrien    coff_get_reloc_upper_bound,
4193104834Sobrien    coff_canonicalize_reloc,
4194104834Sobrien    _bfd_xcoff_reloc_type_lookup,
4195218822Sdim    _bfd_xcoff_reloc_name_lookup,
419689857Sobrien
4197130561Sobrien    /* Write */
4198104834Sobrien    coff_set_arch_mach,
4199104834Sobrien    coff_set_section_contents,
420089857Sobrien
4201130561Sobrien    /* Link */
4202104834Sobrien    _bfd_xcoff_sizeof_headers,
4203130561Sobrien    bfd_generic_get_relocated_section_contents,
4204104834Sobrien    bfd_generic_relax_section,
4205104834Sobrien    _bfd_xcoff_bfd_link_hash_table_create,
4206104834Sobrien    _bfd_generic_link_hash_table_free,
4207104834Sobrien    _bfd_xcoff_bfd_link_add_symbols,
4208104834Sobrien    _bfd_generic_link_just_syms,
4209104834Sobrien    _bfd_xcoff_bfd_final_link,
4210104834Sobrien    _bfd_generic_link_split_section,
4211104834Sobrien    bfd_generic_gc_sections,
4212104834Sobrien    bfd_generic_merge_sections,
4213218822Sdim    bfd_generic_is_group_section,
4214104834Sobrien    bfd_generic_discard_group,
4215218822Sdim    _bfd_generic_section_already_linked,
421689857Sobrien
4217130561Sobrien    /* Dynamic */
4218130561Sobrien    _bfd_xcoff_get_dynamic_symtab_upper_bound,
4219104834Sobrien    _bfd_xcoff_canonicalize_dynamic_symtab,
4220218822Sdim    _bfd_nodynamic_get_synthetic_symtab,
4221104834Sobrien    _bfd_xcoff_get_dynamic_reloc_upper_bound,
4222104834Sobrien    _bfd_xcoff_canonicalize_dynamic_reloc,
422389857Sobrien
4224130561Sobrien    /* Opposite endian version, none exists */
4225130561Sobrien    NULL,
422689857Sobrien
4227130561Sobrien    (void *) &bfd_xcoff_backend_data,
4228130561Sobrien  };
422989857Sobrien
4230104834Sobrien/* xcoff-powermac target
4231104834Sobrien   Old target.
4232104834Sobrien   Only difference between this target and the rs6000 target is the
4233104834Sobrien   the default architecture and machine type used in coffcode.h
4234104834Sobrien
4235104834Sobrien   PowerPC Macs use the same magic numbers as RS/6000
4236104834Sobrien   (because that's how they were bootstrapped originally),
4237104834Sobrien   but they are always PowerPC architecture.  */
423889857Sobrienstatic const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data =
4239130561Sobrien  {
4240104834Sobrien    { /* COFF backend, defined in libcoff.h.  */
4241104834Sobrien      _bfd_xcoff_swap_aux_in,
4242104834Sobrien      _bfd_xcoff_swap_sym_in,
4243104834Sobrien      coff_swap_lineno_in,
4244104834Sobrien      _bfd_xcoff_swap_aux_out,
4245104834Sobrien      _bfd_xcoff_swap_sym_out,
4246104834Sobrien      coff_swap_lineno_out,
4247104834Sobrien      xcoff_swap_reloc_out,
4248104834Sobrien      coff_swap_filehdr_out,
4249104834Sobrien      coff_swap_aouthdr_out,
4250104834Sobrien      coff_swap_scnhdr_out,
4251104834Sobrien      FILHSZ,
4252104834Sobrien      AOUTSZ,
4253104834Sobrien      SCNHSZ,
4254104834Sobrien      SYMESZ,
4255104834Sobrien      AUXESZ,
4256104834Sobrien      RELSZ,
4257104834Sobrien      LINESZ,
4258104834Sobrien      FILNMLEN,
4259130561Sobrien      TRUE,			/* _bfd_coff_long_filenames */
4260130561Sobrien      FALSE,			/* _bfd_coff_long_section_names */
4261104834Sobrien      3,			/* _bfd_coff_default_section_alignment_power */
4262130561Sobrien      FALSE,			/* _bfd_coff_force_symnames_in_strings */
4263130561Sobrien      2,			/* _bfd_coff_debug_string_prefix_length */
4264104834Sobrien      coff_swap_filehdr_in,
4265104834Sobrien      coff_swap_aouthdr_in,
4266104834Sobrien      coff_swap_scnhdr_in,
4267104834Sobrien      xcoff_swap_reloc_in,
4268104834Sobrien      coff_bad_format_hook,
4269104834Sobrien      coff_set_arch_mach_hook,
4270104834Sobrien      coff_mkobject_hook,
4271104834Sobrien      styp_to_sec_flags,
4272104834Sobrien      coff_set_alignment_hook,
4273104834Sobrien      coff_slurp_symbol_table,
4274104834Sobrien      symname_in_debug_hook,
4275104834Sobrien      coff_pointerize_aux_hook,
4276104834Sobrien      coff_print_aux,
4277104834Sobrien      dummy_reloc16_extra_cases,
4278104834Sobrien      dummy_reloc16_estimate,
4279130561Sobrien      NULL,			/* bfd_coff_sym_is_global */
4280130561Sobrien      coff_compute_section_file_positions,
4281130561Sobrien      NULL,			/* _bfd_coff_start_final_link */
4282104834Sobrien      xcoff_ppc_relocate_section,
4283104834Sobrien      coff_rtype_to_howto,
4284104834Sobrien      NULL,			/* _bfd_coff_adjust_symndx */
4285104834Sobrien      _bfd_generic_link_add_one_symbol,
4286104834Sobrien      coff_link_output_has_begun,
4287104834Sobrien      coff_final_link_postscript
4288130561Sobrien    },
428989857Sobrien
4290130561Sobrien    0x01DF,			/* magic number */
4291104834Sobrien    bfd_arch_powerpc,
4292104834Sobrien    bfd_mach_ppc,
429389857Sobrien
4294104834Sobrien    /* Function pointers to xcoff specific swap routines.  */
4295104834Sobrien    xcoff_swap_ldhdr_in,
4296104834Sobrien    xcoff_swap_ldhdr_out,
4297104834Sobrien    xcoff_swap_ldsym_in,
4298104834Sobrien    xcoff_swap_ldsym_out,
4299104834Sobrien    xcoff_swap_ldrel_in,
4300104834Sobrien    xcoff_swap_ldrel_out,
430189857Sobrien
4302104834Sobrien    /* Sizes.  */
4303104834Sobrien    LDHDRSZ,
4304104834Sobrien    LDSYMSZ,
4305104834Sobrien    LDRELSZ,
4306130561Sobrien    12,				/* _xcoff_function_descriptor_size */
4307104834Sobrien    SMALL_AOUTSZ,
430889857Sobrien
4309104834Sobrien    /* Versions.  */
4310130561Sobrien    1,				/* _xcoff_ldhdr_version */
431189857Sobrien
4312104834Sobrien    _bfd_xcoff_put_symbol_name,
4313104834Sobrien    _bfd_xcoff_put_ldsymbol_name,
4314104834Sobrien    &xcoff_dynamic_reloc,
4315104834Sobrien    xcoff_create_csect_from_smclas,
431689857Sobrien
4317104834Sobrien    /* Lineno and reloc count overflow.  */
4318130561Sobrien    xcoff_is_lineno_count_overflow,
4319130561Sobrien    xcoff_is_reloc_count_overflow,
432089857Sobrien
4321130561Sobrien    xcoff_loader_symbol_offset,
4322130561Sobrien    xcoff_loader_reloc_offset,
432389857Sobrien
4324104834Sobrien    /* glink.  */
4325130561Sobrien    &xcoff_glink_code[0],
4326104834Sobrien    36,				/* _xcoff_glink_size */
432789857Sobrien
4328130561Sobrien    /* rtinit */
4329130561Sobrien    0,				/* _xcoff_rtinit_size */
4330104834Sobrien    xcoff_generate_rtinit,
4331130561Sobrien  };
433289857Sobrien
4333130561Sobrien/* The transfer vector that leads the outside world to all of the above.  */
433489857Sobrienconst bfd_target pmac_xcoff_vec =
4335130561Sobrien  {
4336130561Sobrien    "xcoff-powermac",
4337130561Sobrien    bfd_target_xcoff_flavour,
4338130561Sobrien    BFD_ENDIAN_BIG,		/* data byte order is big */
4339130561Sobrien    BFD_ENDIAN_BIG,		/* header byte order is big */
434089857Sobrien
4341104834Sobrien    (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC
4342104834Sobrien     | HAS_SYMS | HAS_LOCALS | WP_TEXT),
434389857Sobrien
4344130561Sobrien    SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA,
4345130561Sobrien    0,				/* leading char */
4346130561Sobrien    '/',			/* ar_pad_char */
4347104834Sobrien    15,				/* ar_max_namelen */
434889857Sobrien
4349130561Sobrien    /* data */
4350104834Sobrien    bfd_getb64,
4351104834Sobrien    bfd_getb_signed_64,
4352104834Sobrien    bfd_putb64,
4353104834Sobrien    bfd_getb32,
4354104834Sobrien    bfd_getb_signed_32,
4355104834Sobrien    bfd_putb32,
4356104834Sobrien    bfd_getb16,
4357104834Sobrien    bfd_getb_signed_16,
4358104834Sobrien    bfd_putb16,
435989857Sobrien
4360130561Sobrien    /* hdrs */
4361104834Sobrien    bfd_getb64,
4362104834Sobrien    bfd_getb_signed_64,
4363104834Sobrien    bfd_putb64,
4364104834Sobrien    bfd_getb32,
4365104834Sobrien    bfd_getb_signed_32,
4366104834Sobrien    bfd_putb32,
4367104834Sobrien    bfd_getb16,
4368104834Sobrien    bfd_getb_signed_16,
4369104834Sobrien    bfd_putb16,
437089857Sobrien
4371130561Sobrien    { /* bfd_check_format */
4372130561Sobrien      _bfd_dummy_target,
4373130561Sobrien      coff_object_p,
4374130561Sobrien      _bfd_xcoff_archive_p,
4375130561Sobrien      CORE_FILE_P
4376130561Sobrien    },
437789857Sobrien
4378130561Sobrien    { /* bfd_set_format */
4379130561Sobrien      bfd_false,
4380130561Sobrien      coff_mkobject,
4381130561Sobrien      _bfd_generic_mkarchive,
4382130561Sobrien      bfd_false
4383130561Sobrien    },
438489857Sobrien
4385130561Sobrien    {/* bfd_write_contents */
4386130561Sobrien      bfd_false,
4387130561Sobrien      coff_write_object_contents,
4388130561Sobrien      _bfd_xcoff_write_archive_contents,
4389130561Sobrien      bfd_false
4390130561Sobrien    },
439189857Sobrien
4392130561Sobrien    /* Generic */
4393104834Sobrien    bfd_true,
4394104834Sobrien    bfd_true,
4395104834Sobrien    coff_new_section_hook,
4396104834Sobrien    _bfd_generic_get_section_contents,
4397130561Sobrien    _bfd_generic_get_section_contents_in_window,
439889857Sobrien
4399130561Sobrien    /* Copy */
4400104834Sobrien    _bfd_xcoff_copy_private_bfd_data,
4401130561Sobrien    ((bfd_boolean (*) (bfd *, bfd *)) bfd_true),
4402218822Sdim    _bfd_generic_init_private_section_data,
4403130561Sobrien    ((bfd_boolean (*) (bfd *, asection *, bfd *, asection *)) bfd_true),
4404130561Sobrien    ((bfd_boolean (*) (bfd *, asymbol *, bfd *, asymbol *)) bfd_true),
4405218822Sdim    ((bfd_boolean (*) (bfd *, bfd *)) bfd_true),
4406130561Sobrien    ((bfd_boolean (*) (bfd *, flagword)) bfd_true),
4407130561Sobrien    ((bfd_boolean (*) (bfd *, void * )) bfd_true),
440889857Sobrien
4409130561Sobrien    /* Core */
4410104834Sobrien    coff_core_file_failing_command,
4411104834Sobrien    coff_core_file_failing_signal,
4412130561Sobrien    coff_core_file_matches_executable_p,
441389857Sobrien
4414130561Sobrien    /* Archive */
4415104834Sobrien    _bfd_xcoff_slurp_armap,
4416104834Sobrien    bfd_false,
4417130561Sobrien    ((bfd_boolean (*) (bfd *, char **, bfd_size_type *, const char **)) bfd_false),
4418104834Sobrien    bfd_dont_truncate_arname,
4419104834Sobrien    _bfd_xcoff_write_armap,
4420104834Sobrien    _bfd_xcoff_read_ar_hdr,
4421104834Sobrien    _bfd_xcoff_openr_next_archived_file,
4422104834Sobrien    _bfd_generic_get_elt_at_index,
4423104834Sobrien    _bfd_xcoff_stat_arch_elt,
4424104834Sobrien    bfd_true,
442589857Sobrien
4426130561Sobrien    /* Symbols */
4427104834Sobrien    coff_get_symtab_upper_bound,
4428130561Sobrien    coff_canonicalize_symtab,
4429104834Sobrien    coff_make_empty_symbol,
4430104834Sobrien    coff_print_symbol,
4431104834Sobrien    coff_get_symbol_info,
4432104834Sobrien    _bfd_xcoff_is_local_label_name,
4433218822Sdim    coff_bfd_is_target_special_symbol,
4434104834Sobrien    coff_get_lineno,
4435104834Sobrien    coff_find_nearest_line,
4436218822Sdim    _bfd_generic_find_line,
4437218822Sdim    coff_find_inliner_info,
4438104834Sobrien    coff_bfd_make_debug_symbol,
4439104834Sobrien    _bfd_generic_read_minisymbols,
4440104834Sobrien    _bfd_generic_minisymbol_to_symbol,
444189857Sobrien
4442130561Sobrien    /* Reloc */
4443104834Sobrien    coff_get_reloc_upper_bound,
4444104834Sobrien    coff_canonicalize_reloc,
4445104834Sobrien    _bfd_xcoff_reloc_type_lookup,
4446218822Sdim    _bfd_xcoff_reloc_name_lookup,
444789857Sobrien
4448130561Sobrien    /* Write */
4449104834Sobrien    coff_set_arch_mach,
4450104834Sobrien    coff_set_section_contents,
445189857Sobrien
4452130561Sobrien    /* Link */
4453104834Sobrien    _bfd_xcoff_sizeof_headers,
4454130561Sobrien    bfd_generic_get_relocated_section_contents,
4455104834Sobrien    bfd_generic_relax_section,
4456104834Sobrien    _bfd_xcoff_bfd_link_hash_table_create,
4457104834Sobrien    _bfd_generic_link_hash_table_free,
4458104834Sobrien    _bfd_xcoff_bfd_link_add_symbols,
4459104834Sobrien    _bfd_generic_link_just_syms,
4460104834Sobrien    _bfd_xcoff_bfd_final_link,
4461104834Sobrien    _bfd_generic_link_split_section,
4462104834Sobrien    bfd_generic_gc_sections,
4463104834Sobrien    bfd_generic_merge_sections,
4464218822Sdim    bfd_generic_is_group_section,
4465104834Sobrien    bfd_generic_discard_group,
4466218822Sdim    _bfd_generic_section_already_linked,
446789857Sobrien
4468130561Sobrien    /* Dynamic */
4469130561Sobrien    _bfd_xcoff_get_dynamic_symtab_upper_bound,
4470104834Sobrien    _bfd_xcoff_canonicalize_dynamic_symtab,
4471218822Sdim    _bfd_nodynamic_get_synthetic_symtab,
4472104834Sobrien    _bfd_xcoff_get_dynamic_reloc_upper_bound,
4473104834Sobrien    _bfd_xcoff_canonicalize_dynamic_reloc,
447489857Sobrien
4475130561Sobrien    /* Opposite endian version, none exists */
4476130561Sobrien    NULL,
447789857Sobrien
4478130561Sobrien    (void *) &bfd_pmac_xcoff_backend_data,
4479130561Sobrien  };
4480