aoutx.h revision 104834
133965Sjdp/* BFD semi-generic back-end for a.out binaries.
278828Sobrien   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
394536Sobrien   2001, 2002
438889Sjdp   Free Software Foundation, Inc.
533965Sjdp   Written by Cygnus Support.
633965Sjdp
733965SjdpThis file is part of BFD, the Binary File Descriptor library.
833965Sjdp
933965SjdpThis program is free software; you can redistribute it and/or modify
1033965Sjdpit under the terms of the GNU General Public License as published by
1133965Sjdpthe Free Software Foundation; either version 2 of the License, or
1233965Sjdp(at your option) any later version.
1333965Sjdp
1433965SjdpThis program is distributed in the hope that it will be useful,
1533965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1633965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1733965SjdpGNU General Public License for more details.
1833965Sjdp
1933965SjdpYou should have received a copy of the GNU General Public License
2033965Sjdpalong with this program; if not, write to the Free Software
2133965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2233965Sjdp
2333965Sjdp/*
2433965SjdpSECTION
2533965Sjdp	a.out backends
2633965Sjdp
2733965SjdpDESCRIPTION
2833965Sjdp
2933965Sjdp	BFD supports a number of different flavours of a.out format,
3033965Sjdp	though the major differences are only the sizes of the
3133965Sjdp	structures on disk, and the shape of the relocation
3233965Sjdp	information.
3333965Sjdp
3433965Sjdp	The support is split into a basic support file @file{aoutx.h}
3533965Sjdp	and other files which derive functions from the base. One
3633965Sjdp	derivation file is @file{aoutf1.h} (for a.out flavour 1), and
3733965Sjdp	adds to the basic a.out functions support for sun3, sun4, 386
3833965Sjdp	and 29k a.out files, to create a target jump vector for a
3933965Sjdp	specific target.
4033965Sjdp
4133965Sjdp	This information is further split out into more specific files
4233965Sjdp	for each machine, including @file{sunos.c} for sun3 and sun4,
4333965Sjdp	@file{newsos3.c} for the Sony NEWS, and @file{demo64.c} for a
4433965Sjdp	demonstration of a 64 bit a.out format.
4533965Sjdp
4633965Sjdp	The base file @file{aoutx.h} defines general mechanisms for
4733965Sjdp	reading and writing records to and from disk and various
4833965Sjdp	other methods which BFD requires. It is included by
4933965Sjdp	@file{aout32.c} and @file{aout64.c} to form the names
5033965Sjdp	<<aout_32_swap_exec_header_in>>, <<aout_64_swap_exec_header_in>>, etc.
5133965Sjdp
5233965Sjdp	As an example, this is what goes on to make the back end for a
5333965Sjdp	sun4, from @file{aout32.c}:
5433965Sjdp
5533965Sjdp|	#define ARCH_SIZE 32
5633965Sjdp|	#include "aoutx.h"
5733965Sjdp
5833965Sjdp	Which exports names:
5933965Sjdp
6033965Sjdp|	...
6133965Sjdp|	aout_32_canonicalize_reloc
6233965Sjdp|	aout_32_find_nearest_line
6333965Sjdp|	aout_32_get_lineno
6433965Sjdp|	aout_32_get_reloc_upper_bound
6533965Sjdp|	...
6633965Sjdp
6733965Sjdp	from @file{sunos.c}:
6833965Sjdp
6933965Sjdp|	#define TARGET_NAME "a.out-sunos-big"
7033965Sjdp|	#define VECNAME    sunos_big_vec
7133965Sjdp|	#include "aoutf1.h"
7233965Sjdp
7333965Sjdp	requires all the names from @file{aout32.c}, and produces the jump vector
7433965Sjdp
7533965Sjdp|	sunos_big_vec
7633965Sjdp
7733965Sjdp	The file @file{host-aout.c} is a special case.  It is for a large set
7833965Sjdp	of hosts that use ``more or less standard'' a.out files, and
7933965Sjdp	for which cross-debugging is not interesting.  It uses the
8033965Sjdp	standard 32-bit a.out support routines, but determines the
8133965Sjdp	file offsets and addresses of the text, data, and BSS
8233965Sjdp	sections, the machine architecture and machine type, and the
8333965Sjdp	entry point address, in a host-dependent manner.  Once these
8433965Sjdp	values have been determined, generic code is used to handle
8533965Sjdp	the  object file.
8633965Sjdp
8733965Sjdp	When porting it to run on a new system, you must supply:
8833965Sjdp
8933965Sjdp|        HOST_PAGE_SIZE
9033965Sjdp|        HOST_SEGMENT_SIZE
9133965Sjdp|        HOST_MACHINE_ARCH       (optional)
9233965Sjdp|        HOST_MACHINE_MACHINE    (optional)
9333965Sjdp|        HOST_TEXT_START_ADDR
9433965Sjdp|        HOST_STACK_END_ADDR
9533965Sjdp
9633965Sjdp	in the file @file{../include/sys/h-@var{XXX}.h} (for your host).  These
9733965Sjdp	values, plus the structures and macros defined in @file{a.out.h} on
9833965Sjdp	your host system, will produce a BFD target that will access
9933965Sjdp	ordinary a.out files on your host. To configure a new machine
10033965Sjdp	to use @file{host-aout.c}, specify:
10133965Sjdp
10233965Sjdp|	TDEFAULTS = -DDEFAULT_VECTOR=host_aout_big_vec
10333965Sjdp|	TDEPFILES= host-aout.o trad-core.o
10433965Sjdp
10533965Sjdp	in the @file{config/@var{XXX}.mt} file, and modify @file{configure.in}
10633965Sjdp	to use the
10733965Sjdp	@file{@var{XXX}.mt} file (by setting "<<bfd_target=XXX>>") when your
10833965Sjdp	configuration is selected.
10933965Sjdp
11033965Sjdp*/
11133965Sjdp
11233965Sjdp/* Some assumptions:
11333965Sjdp   * Any BFD with D_PAGED set is ZMAGIC, and vice versa.
11433965Sjdp     Doesn't matter what the setting of WP_TEXT is on output, but it'll
11533965Sjdp     get set on input.
11633965Sjdp   * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC.
11733965Sjdp   * Any BFD with both flags clear is OMAGIC.
11833965Sjdp   (Just want to make these explicit, so the conditions tested in this
11933965Sjdp   file make sense if you're more familiar with a.out than with BFD.)  */
12033965Sjdp
12133965Sjdp#define KEEPIT udata.i
12233965Sjdp
12333965Sjdp#include "bfd.h"
12460484Sobrien#include "sysdep.h"
12589857Sobrien#include "safe-ctype.h"
12633965Sjdp#include "bfdlink.h"
12733965Sjdp
12833965Sjdp#include "libaout.h"
12933965Sjdp#include "libbfd.h"
13033965Sjdp#include "aout/aout64.h"
13133965Sjdp#include "aout/stab_gnu.h"
13233965Sjdp#include "aout/ar.h"
13333965Sjdp
13433965Sjdpstatic boolean aout_get_external_symbols PARAMS ((bfd *));
13533965Sjdpstatic boolean translate_from_native_sym_flags
13633965Sjdp  PARAMS ((bfd *, aout_symbol_type *));
13733965Sjdpstatic boolean translate_to_native_sym_flags
13833965Sjdp  PARAMS ((bfd *, asymbol *, struct external_nlist *));
13933965Sjdpstatic void adjust_o_magic PARAMS ((bfd *, struct internal_exec *));
14033965Sjdpstatic void adjust_z_magic PARAMS ((bfd *, struct internal_exec *));
14133965Sjdpstatic void adjust_n_magic PARAMS ((bfd *, struct internal_exec *));
14289857Sobrienreloc_howto_type * NAME(aout,reloc_type_lookup)
14389857Sobrien  PARAMS ((bfd *, bfd_reloc_code_real_type));
14433965Sjdp
14533965Sjdp/*
14633965SjdpSUBSECTION
14733965Sjdp	Relocations
14833965Sjdp
14933965SjdpDESCRIPTION
15033965Sjdp	The file @file{aoutx.h} provides for both the @emph{standard}
15133965Sjdp	and @emph{extended} forms of a.out relocation records.
15233965Sjdp
15333965Sjdp	The standard records contain only an
15433965Sjdp	address, a symbol index, and a type field. The extended records
15533965Sjdp	(used on 29ks and sparcs) also have a full integer for an
15633965Sjdp	addend.
15733965Sjdp
15833965Sjdp*/
15933965Sjdp#ifndef CTOR_TABLE_RELOC_HOWTO
16033965Sjdp#define CTOR_TABLE_RELOC_IDX 2
16189857Sobrien#define CTOR_TABLE_RELOC_HOWTO(BFD)					\
16289857Sobrien  ((obj_reloc_entry_size (BFD) == RELOC_EXT_SIZE			\
16389857Sobrien    ? howto_table_ext : howto_table_std)				\
16489857Sobrien   + CTOR_TABLE_RELOC_IDX)
16533965Sjdp#endif
16633965Sjdp
16733965Sjdp#ifndef MY_swap_std_reloc_in
16833965Sjdp#define MY_swap_std_reloc_in NAME(aout,swap_std_reloc_in)
16933965Sjdp#endif
17033965Sjdp
17177298Sobrien#ifndef MY_swap_ext_reloc_in
17277298Sobrien#define MY_swap_ext_reloc_in NAME(aout,swap_ext_reloc_in)
17377298Sobrien#endif
17477298Sobrien
17533965Sjdp#ifndef MY_swap_std_reloc_out
17633965Sjdp#define MY_swap_std_reloc_out NAME(aout,swap_std_reloc_out)
17733965Sjdp#endif
17833965Sjdp
17977298Sobrien#ifndef MY_swap_ext_reloc_out
18077298Sobrien#define MY_swap_ext_reloc_out NAME(aout,swap_ext_reloc_out)
18177298Sobrien#endif
18277298Sobrien
18333965Sjdp#ifndef MY_final_link_relocate
18433965Sjdp#define MY_final_link_relocate _bfd_final_link_relocate
18533965Sjdp#endif
18633965Sjdp
18733965Sjdp#ifndef MY_relocate_contents
18833965Sjdp#define MY_relocate_contents _bfd_relocate_contents
18933965Sjdp#endif
19033965Sjdp
19133965Sjdp#define howto_table_ext NAME(aout,ext_howto_table)
19233965Sjdp#define howto_table_std NAME(aout,std_howto_table)
19333965Sjdp
19433965Sjdpreloc_howto_type howto_table_ext[] =
19533965Sjdp{
19633965Sjdp  /* type           rs   size bsz  pcrel bitpos ovrf                  sf name          part_inpl readmask setmask pcdone */
19733965Sjdp  HOWTO(RELOC_8,      0,  0,  	8,  false, 0, complain_overflow_bitfield,0,"8",        false, 0,0x000000ff, false),
19833965Sjdp  HOWTO(RELOC_16,     0,  1, 	16, false, 0, complain_overflow_bitfield,0,"16",       false, 0,0x0000ffff, false),
19933965Sjdp  HOWTO(RELOC_32,     0,  2, 	32, false, 0, complain_overflow_bitfield,0,"32",       false, 0,0xffffffff, false),
20033965Sjdp  HOWTO(RELOC_DISP8,  0,  0, 	8,  true,  0, complain_overflow_signed,0,"DISP8", 	false, 0,0x000000ff, false),
20133965Sjdp  HOWTO(RELOC_DISP16, 0,  1, 	16, true,  0, complain_overflow_signed,0,"DISP16", 	false, 0,0x0000ffff, false),
20233965Sjdp  HOWTO(RELOC_DISP32, 0,  2, 	32, true,  0, complain_overflow_signed,0,"DISP32", 	false, 0,0xffffffff, false),
20333965Sjdp  HOWTO(RELOC_WDISP30,2,  2, 	30, true,  0, complain_overflow_signed,0,"WDISP30", 	false, 0,0x3fffffff, false),
20433965Sjdp  HOWTO(RELOC_WDISP22,2,  2, 	22, true,  0, complain_overflow_signed,0,"WDISP22", 	false, 0,0x003fffff, false),
20533965Sjdp  HOWTO(RELOC_HI22,   10, 2, 	22, false, 0, complain_overflow_bitfield,0,"HI22",	false, 0,0x003fffff, false),
20633965Sjdp  HOWTO(RELOC_22,     0,  2, 	22, false, 0, complain_overflow_bitfield,0,"22",       false, 0,0x003fffff, false),
20733965Sjdp  HOWTO(RELOC_13,     0,  2, 	13, false, 0, complain_overflow_bitfield,0,"13",       false, 0,0x00001fff, false),
20833965Sjdp  HOWTO(RELOC_LO10,   0,  2, 	10, false, 0, complain_overflow_dont,0,"LO10",     false, 0,0x000003ff, false),
20933965Sjdp  HOWTO(RELOC_SFA_BASE,0, 2, 	32, false, 0, complain_overflow_bitfield,0,"SFA_BASE", false, 0,0xffffffff, false),
21033965Sjdp  HOWTO(RELOC_SFA_OFF13,0,2, 	32, false, 0, complain_overflow_bitfield,0,"SFA_OFF13",false, 0,0xffffffff, false),
21133965Sjdp  HOWTO(RELOC_BASE10, 0,  2, 	10, false, 0, complain_overflow_dont,0,"BASE10",   false, 0,0x000003ff, false),
21260484Sobrien  HOWTO(RELOC_BASE13, 0,  2,	13, false, 0, complain_overflow_signed,0,"BASE13",   false, 0,0x00001fff, false),
21333965Sjdp  HOWTO(RELOC_BASE22, 10, 2,	22, false, 0, complain_overflow_bitfield,0,"BASE22",   false, 0,0x003fffff, false),
21433965Sjdp  HOWTO(RELOC_PC10,   0,  2,	10, true,  0, complain_overflow_dont,0,"PC10",	false, 0,0x000003ff, true),
21533965Sjdp  HOWTO(RELOC_PC22,   10,  2,	22, true,  0, complain_overflow_signed,0,"PC22", false, 0,0x003fffff, true),
21633965Sjdp  HOWTO(RELOC_JMP_TBL,2,  2, 	30, true,  0, complain_overflow_signed,0,"JMP_TBL", 	false, 0,0x3fffffff, false),
21733965Sjdp  HOWTO(RELOC_SEGOFF16,0, 2,	0,  false, 0, complain_overflow_bitfield,0,"SEGOFF16",	false, 0,0x00000000, false),
21833965Sjdp  HOWTO(RELOC_GLOB_DAT,0, 2,	0,  false, 0, complain_overflow_bitfield,0,"GLOB_DAT",	false, 0,0x00000000, false),
21933965Sjdp  HOWTO(RELOC_JMP_SLOT,0, 2,	0,  false, 0, complain_overflow_bitfield,0,"JMP_SLOT",	false, 0,0x00000000, false),
22033965Sjdp  HOWTO(RELOC_RELATIVE,0, 2,	0,  false, 0, complain_overflow_bitfield,0,"RELATIVE",	false, 0,0x00000000, false),
22160484Sobrien  HOWTO(0,  0, 0,    0,  false, 0, complain_overflow_dont, 0, "R_SPARC_NONE",    false,0,0x00000000,true),
22260484Sobrien  HOWTO(0,  0, 0,    0,  false, 0, complain_overflow_dont, 0, "R_SPARC_NONE",    false,0,0x00000000,true),
22360484Sobrien#define RELOC_SPARC_REV32 RELOC_WDISP19
22460484Sobrien  HOWTO(RELOC_SPARC_REV32,    0,  2, 	32, false, 0, complain_overflow_dont,0,"R_SPARC_REV32",       false, 0,0xffffffff, false),
22533965Sjdp};
22633965Sjdp
22733965Sjdp/* Convert standard reloc records to "arelent" format (incl byte swap).  */
22833965Sjdp
22933965Sjdpreloc_howto_type howto_table_std[] = {
23033965Sjdp  /* type              rs size bsz  pcrel bitpos ovrf                     sf name     part_inpl readmask  setmask    pcdone */
23189857SobrienHOWTO ( 0,	       0,  0,  	8,  false, 0, complain_overflow_bitfield,0,"8",		true, 0x000000ff,0x000000ff, false),
23289857SobrienHOWTO ( 1,	       0,  1, 	16, false, 0, complain_overflow_bitfield,0,"16",	true, 0x0000ffff,0x0000ffff, false),
23389857SobrienHOWTO ( 2,	       0,  2, 	32, false, 0, complain_overflow_bitfield,0,"32",	true, 0xffffffff,0xffffffff, false),
23489857SobrienHOWTO ( 3,	       0,  4, 	64, false, 0, complain_overflow_bitfield,0,"64",	true, 0xdeaddead,0xdeaddead, false),
23589857SobrienHOWTO ( 4,	       0,  0, 	8,  true,  0, complain_overflow_signed,  0,"DISP8",	true, 0x000000ff,0x000000ff, false),
23689857SobrienHOWTO ( 5,	       0,  1, 	16, true,  0, complain_overflow_signed,  0,"DISP16",	true, 0x0000ffff,0x0000ffff, false),
23789857SobrienHOWTO ( 6,	       0,  2, 	32, true,  0, complain_overflow_signed,  0,"DISP32",	true, 0xffffffff,0xffffffff, false),
23889857SobrienHOWTO ( 7,	       0,  4, 	64, true,  0, complain_overflow_signed,  0,"DISP64",	true, 0xfeedface,0xfeedface, false),
23989857SobrienHOWTO ( 8,	       0,  2,    0, false, 0, complain_overflow_bitfield,0,"GOT_REL",	false,         0,0x00000000, false),
24089857SobrienHOWTO ( 9,	       0,  1,   16, false, 0, complain_overflow_bitfield,0,"BASE16",	false,0xffffffff,0xffffffff, false),
24189857SobrienHOWTO (10,	       0,  2,   32, false, 0, complain_overflow_bitfield,0,"BASE32",	false,0xffffffff,0xffffffff, false),
24260484SobrienEMPTY_HOWTO (-1),
24360484SobrienEMPTY_HOWTO (-1),
24460484SobrienEMPTY_HOWTO (-1),
24560484SobrienEMPTY_HOWTO (-1),
24660484SobrienEMPTY_HOWTO (-1),
24789857Sobrien  HOWTO (16,	       0,  2,	 0, false, 0, complain_overflow_bitfield,0,"JMP_TABLE", false,         0,0x00000000, false),
24860484SobrienEMPTY_HOWTO (-1),
24960484SobrienEMPTY_HOWTO (-1),
25060484SobrienEMPTY_HOWTO (-1),
25160484SobrienEMPTY_HOWTO (-1),
25260484SobrienEMPTY_HOWTO (-1),
25360484SobrienEMPTY_HOWTO (-1),
25460484SobrienEMPTY_HOWTO (-1),
25560484SobrienEMPTY_HOWTO (-1),
25660484SobrienEMPTY_HOWTO (-1),
25760484SobrienEMPTY_HOWTO (-1),
25860484SobrienEMPTY_HOWTO (-1),
25960484SobrienEMPTY_HOWTO (-1),
26060484SobrienEMPTY_HOWTO (-1),
26160484SobrienEMPTY_HOWTO (-1),
26260484SobrienEMPTY_HOWTO (-1),
26389857Sobrien  HOWTO (32,	       0,  2,	 0, false, 0, complain_overflow_bitfield,0,"RELATIVE",  false,         0,0x00000000, false),
26460484SobrienEMPTY_HOWTO (-1),
26560484SobrienEMPTY_HOWTO (-1),
26660484SobrienEMPTY_HOWTO (-1),
26760484SobrienEMPTY_HOWTO (-1),
26860484SobrienEMPTY_HOWTO (-1),
26960484SobrienEMPTY_HOWTO (-1),
27060484SobrienEMPTY_HOWTO (-1),
27189857Sobrien  HOWTO (40,	       0,  2,	 0, false, 0, complain_overflow_bitfield,0,"BASEREL",   false,         0,0x00000000, false),
27233965Sjdp};
27333965Sjdp
27489857Sobrien#define TABLE_SIZE(TABLE)	(sizeof (TABLE) / sizeof (TABLE[0]))
27533965Sjdp
27633965Sjdpreloc_howto_type *
27733965SjdpNAME(aout,reloc_type_lookup) (abfd,code)
27833965Sjdp     bfd *abfd;
27933965Sjdp     bfd_reloc_code_real_type code;
28033965Sjdp{
28189857Sobrien#define EXT(i, j)	case i: return &howto_table_ext[j]
28289857Sobrien#define STD(i, j)	case i: return &howto_table_std[j]
28333965Sjdp  int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
28433965Sjdp  if (code == BFD_RELOC_CTOR)
28533965Sjdp    switch (bfd_get_arch_info (abfd)->bits_per_address)
28633965Sjdp      {
28733965Sjdp      case 32:
28833965Sjdp	code = BFD_RELOC_32;
28933965Sjdp	break;
29033965Sjdp      case 64:
29133965Sjdp	code = BFD_RELOC_64;
29233965Sjdp	break;
29333965Sjdp      }
29433965Sjdp  if (ext)
29533965Sjdp    switch (code)
29633965Sjdp      {
29777298Sobrien	EXT (BFD_RELOC_8, 0);
29877298Sobrien	EXT (BFD_RELOC_16, 1);
29933965Sjdp	EXT (BFD_RELOC_32, 2);
30033965Sjdp	EXT (BFD_RELOC_HI22, 8);
30133965Sjdp	EXT (BFD_RELOC_LO10, 11);
30233965Sjdp	EXT (BFD_RELOC_32_PCREL_S2, 6);
30333965Sjdp	EXT (BFD_RELOC_SPARC_WDISP22, 7);
30433965Sjdp	EXT (BFD_RELOC_SPARC13, 10);
30533965Sjdp	EXT (BFD_RELOC_SPARC_GOT10, 14);
30633965Sjdp	EXT (BFD_RELOC_SPARC_BASE13, 15);
30733965Sjdp	EXT (BFD_RELOC_SPARC_GOT13, 15);
30833965Sjdp	EXT (BFD_RELOC_SPARC_GOT22, 16);
30933965Sjdp	EXT (BFD_RELOC_SPARC_PC10, 17);
31033965Sjdp	EXT (BFD_RELOC_SPARC_PC22, 18);
31133965Sjdp	EXT (BFD_RELOC_SPARC_WPLT30, 19);
31260484Sobrien	EXT (BFD_RELOC_SPARC_REV32, 26);
31333965Sjdp      default: return (reloc_howto_type *) NULL;
31433965Sjdp      }
31533965Sjdp  else
31633965Sjdp    /* std relocs */
31733965Sjdp    switch (code)
31833965Sjdp      {
31933965Sjdp	STD (BFD_RELOC_16, 1);
32033965Sjdp	STD (BFD_RELOC_32, 2);
32133965Sjdp	STD (BFD_RELOC_8_PCREL, 4);
32233965Sjdp	STD (BFD_RELOC_16_PCREL, 5);
32333965Sjdp	STD (BFD_RELOC_32_PCREL, 6);
32433965Sjdp	STD (BFD_RELOC_16_BASEREL, 9);
32533965Sjdp	STD (BFD_RELOC_32_BASEREL, 10);
32633965Sjdp      default: return (reloc_howto_type *) NULL;
32733965Sjdp      }
32833965Sjdp}
32933965Sjdp
33033965Sjdp/*
33133965SjdpSUBSECTION
33233965Sjdp	Internal entry points
33333965Sjdp
33433965SjdpDESCRIPTION
33533965Sjdp	@file{aoutx.h} exports several routines for accessing the
33633965Sjdp	contents of an a.out file, which are gathered and exported in
33733965Sjdp	turn by various format specific files (eg sunos.c).
33833965Sjdp
33933965Sjdp*/
34033965Sjdp
34133965Sjdp/*
34233965SjdpFUNCTION
34333965Sjdp	 aout_@var{size}_swap_exec_header_in
34433965Sjdp
34533965SjdpSYNOPSIS
34633965Sjdp	void aout_@var{size}_swap_exec_header_in,
34733965Sjdp           (bfd *abfd,
34833965Sjdp            struct external_exec *raw_bytes,
34933965Sjdp            struct internal_exec *execp);
35033965Sjdp
35133965SjdpDESCRIPTION
35233965Sjdp	Swap the information in an executable header @var{raw_bytes} taken
35333965Sjdp	from a raw byte stream memory image into the internal exec header
35433965Sjdp	structure @var{execp}.
35533965Sjdp*/
35633965Sjdp
35733965Sjdp#ifndef NAME_swap_exec_header_in
35833965Sjdpvoid
35933965SjdpNAME(aout,swap_exec_header_in) (abfd, raw_bytes, execp)
36033965Sjdp     bfd *abfd;
36133965Sjdp     struct external_exec *raw_bytes;
36233965Sjdp     struct internal_exec *execp;
36333965Sjdp{
36433965Sjdp  struct external_exec *bytes = (struct external_exec *)raw_bytes;
36533965Sjdp
36633965Sjdp  /* The internal_exec structure has some fields that are unused in this
36733965Sjdp     configuration (IE for i960), so ensure that all such uninitialized
36833965Sjdp     fields are zero'd out.  There are places where two of these structs
36977298Sobrien     are memcmp'd, and thus the contents do matter.  */
37033965Sjdp  memset ((PTR) execp, 0, sizeof (struct internal_exec));
37133965Sjdp  /* Now fill in fields in the execp, from the bytes in the raw data.  */
37289857Sobrien  execp->a_info   = H_GET_32 (abfd, bytes->e_info);
37333965Sjdp  execp->a_text   = GET_WORD (abfd, bytes->e_text);
37433965Sjdp  execp->a_data   = GET_WORD (abfd, bytes->e_data);
37533965Sjdp  execp->a_bss    = GET_WORD (abfd, bytes->e_bss);
37633965Sjdp  execp->a_syms   = GET_WORD (abfd, bytes->e_syms);
37733965Sjdp  execp->a_entry  = GET_WORD (abfd, bytes->e_entry);
37833965Sjdp  execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
37933965Sjdp  execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
38033965Sjdp}
38133965Sjdp#define NAME_swap_exec_header_in NAME(aout,swap_exec_header_in)
38233965Sjdp#endif
38333965Sjdp
38433965Sjdp/*
38533965SjdpFUNCTION
38633965Sjdp	aout_@var{size}_swap_exec_header_out
38733965Sjdp
38833965SjdpSYNOPSIS
38933965Sjdp	void aout_@var{size}_swap_exec_header_out
39033965Sjdp	  (bfd *abfd,
39133965Sjdp	   struct internal_exec *execp,
39233965Sjdp	   struct external_exec *raw_bytes);
39333965Sjdp
39433965SjdpDESCRIPTION
39533965Sjdp	Swap the information in an internal exec header structure
39633965Sjdp	@var{execp} into the buffer @var{raw_bytes} ready for writing to disk.
39733965Sjdp*/
39833965Sjdpvoid
39933965SjdpNAME(aout,swap_exec_header_out) (abfd, execp, raw_bytes)
40033965Sjdp     bfd *abfd;
40133965Sjdp     struct internal_exec *execp;
40233965Sjdp     struct external_exec *raw_bytes;
40333965Sjdp{
40433965Sjdp  struct external_exec *bytes = (struct external_exec *)raw_bytes;
40533965Sjdp
40677298Sobrien  /* Now fill in fields in the raw data, from the fields in the exec struct.  */
40789857Sobrien  H_PUT_32 (abfd, execp->a_info  , bytes->e_info);
40833965Sjdp  PUT_WORD (abfd, execp->a_text  , bytes->e_text);
40933965Sjdp  PUT_WORD (abfd, execp->a_data  , bytes->e_data);
41033965Sjdp  PUT_WORD (abfd, execp->a_bss   , bytes->e_bss);
41133965Sjdp  PUT_WORD (abfd, execp->a_syms  , bytes->e_syms);
41233965Sjdp  PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
41333965Sjdp  PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
41433965Sjdp  PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
41533965Sjdp}
41633965Sjdp
41733965Sjdp/* Make all the section for an a.out file.  */
41833965Sjdp
41933965Sjdpboolean
42033965SjdpNAME(aout,make_sections) (abfd)
42133965Sjdp     bfd *abfd;
42233965Sjdp{
42333965Sjdp  if (obj_textsec (abfd) == (asection *) NULL
42433965Sjdp      && bfd_make_section (abfd, ".text") == (asection *) NULL)
42533965Sjdp    return false;
42633965Sjdp  if (obj_datasec (abfd) == (asection *) NULL
42733965Sjdp      && bfd_make_section (abfd, ".data") == (asection *) NULL)
42833965Sjdp    return false;
42933965Sjdp  if (obj_bsssec (abfd) == (asection *) NULL
43033965Sjdp      && bfd_make_section (abfd, ".bss") == (asection *) NULL)
43133965Sjdp    return false;
43233965Sjdp  return true;
43333965Sjdp}
43433965Sjdp
43533965Sjdp/*
43633965SjdpFUNCTION
43733965Sjdp	aout_@var{size}_some_aout_object_p
43833965Sjdp
43933965SjdpSYNOPSIS
44033965Sjdp	const bfd_target *aout_@var{size}_some_aout_object_p
44133965Sjdp	 (bfd *abfd,
44277298Sobrien	  const bfd_target *(*callback_to_real_object_p) ());
44333965Sjdp
44433965SjdpDESCRIPTION
44533965Sjdp	Some a.out variant thinks that the file open in @var{abfd}
44633965Sjdp	checking is an a.out file.  Do some more checking, and set up
44733965Sjdp	for access if it really is.  Call back to the calling
44833965Sjdp	environment's "finish up" function just before returning, to
44933965Sjdp	handle any last-minute setup.
45033965Sjdp*/
45133965Sjdp
45233965Sjdpconst bfd_target *
45333965SjdpNAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p)
45433965Sjdp     bfd *abfd;
45533965Sjdp     struct internal_exec *execp;
45633965Sjdp     const bfd_target *(*callback_to_real_object_p) PARAMS ((bfd *));
45733965Sjdp{
45833965Sjdp  struct aout_data_struct *rawptr, *oldrawptr;
45933965Sjdp  const bfd_target *result;
46089857Sobrien  bfd_size_type amt = sizeof (struct aout_data_struct);
46133965Sjdp
46289857Sobrien  rawptr = (struct aout_data_struct  *) bfd_zalloc (abfd, amt);
46333965Sjdp  if (rawptr == NULL)
46433965Sjdp    return 0;
46533965Sjdp
46633965Sjdp  oldrawptr = abfd->tdata.aout_data;
46733965Sjdp  abfd->tdata.aout_data = rawptr;
46833965Sjdp
46933965Sjdp  /* Copy the contents of the old tdata struct.
47033965Sjdp     In particular, we want the subformat, since for hpux it was set in
47133965Sjdp     hp300hpux.c:swap_exec_header_in and will be used in
47233965Sjdp     hp300hpux.c:callback.  */
47333965Sjdp  if (oldrawptr != NULL)
47433965Sjdp    *abfd->tdata.aout_data = *oldrawptr;
47533965Sjdp
47633965Sjdp  abfd->tdata.aout_data->a.hdr = &rawptr->e;
47733965Sjdp  *(abfd->tdata.aout_data->a.hdr) = *execp;	/* Copy in the internal_exec struct */
47833965Sjdp  execp = abfd->tdata.aout_data->a.hdr;
47933965Sjdp
48033965Sjdp  /* Set the file flags */
48133965Sjdp  abfd->flags = BFD_NO_FLAGS;
48233965Sjdp  if (execp->a_drsize || execp->a_trsize)
48333965Sjdp    abfd->flags |= HAS_RELOC;
48433965Sjdp  /* Setting of EXEC_P has been deferred to the bottom of this function */
48533965Sjdp  if (execp->a_syms)
48633965Sjdp    abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
48789857Sobrien  if (N_DYNAMIC (*execp))
48833965Sjdp    abfd->flags |= DYNAMIC;
48933965Sjdp
49033965Sjdp  if (N_MAGIC (*execp) == ZMAGIC)
49133965Sjdp    {
49233965Sjdp      abfd->flags |= D_PAGED | WP_TEXT;
49333965Sjdp      adata (abfd).magic = z_magic;
49433965Sjdp    }
49533965Sjdp  else if (N_MAGIC (*execp) == QMAGIC)
49633965Sjdp    {
49733965Sjdp      abfd->flags |= D_PAGED | WP_TEXT;
49833965Sjdp      adata (abfd).magic = z_magic;
49933965Sjdp      adata (abfd).subformat = q_magic_format;
50033965Sjdp    }
50133965Sjdp  else if (N_MAGIC (*execp) == NMAGIC)
50233965Sjdp    {
50333965Sjdp      abfd->flags |= WP_TEXT;
50433965Sjdp      adata (abfd).magic = n_magic;
50533965Sjdp    }
50633965Sjdp  else if (N_MAGIC (*execp) == OMAGIC
50733965Sjdp	   || N_MAGIC (*execp) == BMAGIC)
50833965Sjdp    adata (abfd).magic = o_magic;
50933965Sjdp  else
51033965Sjdp    {
51133965Sjdp      /* Should have been checked with N_BADMAG before this routine
51233965Sjdp	 was called.  */
51333965Sjdp      abort ();
51433965Sjdp    }
51533965Sjdp
51633965Sjdp  bfd_get_start_address (abfd) = execp->a_entry;
51733965Sjdp
51833965Sjdp  obj_aout_symbols (abfd) = (aout_symbol_type *)NULL;
51933965Sjdp  bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
52033965Sjdp
52133965Sjdp  /* The default relocation entry size is that of traditional V7 Unix.  */
52233965Sjdp  obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
52333965Sjdp
52477298Sobrien  /* The default symbol entry size is that of traditional Unix.  */
52533965Sjdp  obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
52633965Sjdp
52733965Sjdp#ifdef USE_MMAP
52833965Sjdp  bfd_init_window (&obj_aout_sym_window (abfd));
52933965Sjdp  bfd_init_window (&obj_aout_string_window (abfd));
53033965Sjdp#endif
53133965Sjdp  obj_aout_external_syms (abfd) = NULL;
53233965Sjdp  obj_aout_external_strings (abfd) = NULL;
53333965Sjdp  obj_aout_sym_hashes (abfd) = NULL;
53433965Sjdp
53533965Sjdp  if (! NAME(aout,make_sections) (abfd))
536104834Sobrien    goto error_ret;
53733965Sjdp
53833965Sjdp  obj_datasec (abfd)->_raw_size = execp->a_data;
53933965Sjdp  obj_bsssec (abfd)->_raw_size = execp->a_bss;
54033965Sjdp
54133965Sjdp  obj_textsec (abfd)->flags =
54233965Sjdp    (execp->a_trsize != 0
54333965Sjdp     ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
54433965Sjdp     : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
54533965Sjdp  obj_datasec (abfd)->flags =
54633965Sjdp    (execp->a_drsize != 0
54733965Sjdp     ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
54833965Sjdp     : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
54933965Sjdp  obj_bsssec (abfd)->flags = SEC_ALLOC;
55033965Sjdp
55133965Sjdp#ifdef THIS_IS_ONLY_DOCUMENTATION
55233965Sjdp  /* The common code can't fill in these things because they depend
55333965Sjdp     on either the start address of the text segment, the rounding
55433965Sjdp     up of virtual addresses between segments, or the starting file
55533965Sjdp     position of the text segment -- all of which varies among different
55633965Sjdp     versions of a.out.  */
55733965Sjdp
55833965Sjdp  /* Call back to the format-dependent code to fill in the rest of the
55933965Sjdp     fields and do any further cleanup.  Things that should be filled
56033965Sjdp     in by the callback:  */
56133965Sjdp
56233965Sjdp  struct exec *execp = exec_hdr (abfd);
56333965Sjdp
56489857Sobrien  obj_textsec (abfd)->size = N_TXTSIZE (*execp);
56589857Sobrien  obj_textsec (abfd)->raw_size = N_TXTSIZE (*execp);
56633965Sjdp  /* data and bss are already filled in since they're so standard */
56733965Sjdp
56833965Sjdp  /* The virtual memory addresses of the sections */
56989857Sobrien  obj_textsec (abfd)->vma = N_TXTADDR (*execp);
57089857Sobrien  obj_datasec (abfd)->vma = N_DATADDR (*execp);
57189857Sobrien  obj_bsssec  (abfd)->vma = N_BSSADDR (*execp);
57233965Sjdp
57333965Sjdp  /* The file offsets of the sections */
57489857Sobrien  obj_textsec (abfd)->filepos = N_TXTOFF (*execp);
57589857Sobrien  obj_datasec (abfd)->filepos = N_DATOFF (*execp);
57633965Sjdp
57733965Sjdp  /* The file offsets of the relocation info */
57889857Sobrien  obj_textsec (abfd)->rel_filepos = N_TRELOFF (*execp);
57989857Sobrien  obj_datasec (abfd)->rel_filepos = N_DRELOFF (*execp);
58033965Sjdp
58133965Sjdp  /* The file offsets of the string table and symbol table.  */
58233965Sjdp  obj_str_filepos (abfd) = N_STROFF (*execp);
58333965Sjdp  obj_sym_filepos (abfd) = N_SYMOFF (*execp);
58433965Sjdp
58533965Sjdp  /* Determine the architecture and machine type of the object file.  */
58689857Sobrien  switch (N_MACHTYPE (*exec_hdr (abfd)))
58789857Sobrien    {
58889857Sobrien    default:
58989857Sobrien      abfd->obj_arch = bfd_arch_obscure;
59089857Sobrien      break;
59189857Sobrien    }
59233965Sjdp
59389857Sobrien  adata (abfd)->page_size = TARGET_PAGE_SIZE;
59489857Sobrien  adata (abfd)->segment_size = SEGMENT_SIZE;
59589857Sobrien  adata (abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
59633965Sjdp
59733965Sjdp  return abfd->xvec;
59833965Sjdp
59933965Sjdp  /* The architecture is encoded in various ways in various a.out variants,
60033965Sjdp     or is not encoded at all in some of them.  The relocation size depends
60133965Sjdp     on the architecture and the a.out variant.  Finally, the return value
60233965Sjdp     is the bfd_target vector in use.  If an error occurs, return zero and
60333965Sjdp     set bfd_error to the appropriate error code.
60433965Sjdp
60533965Sjdp     Formats such as b.out, which have additional fields in the a.out
60633965Sjdp     header, should cope with them in this callback as well.  */
60733965Sjdp#endif				/* DOCUMENTATION */
60833965Sjdp
60977298Sobrien  result = (*callback_to_real_object_p) (abfd);
61033965Sjdp
61133965Sjdp  /* Now that the segment addresses have been worked out, take a better
61233965Sjdp     guess at whether the file is executable.  If the entry point
61333965Sjdp     is within the text segment, assume it is.  (This makes files
61433965Sjdp     executable even if their entry point address is 0, as long as
61533965Sjdp     their text starts at zero.).
61633965Sjdp
61733965Sjdp     This test had to be changed to deal with systems where the text segment
61833965Sjdp     runs at a different location than the default.  The problem is that the
61933965Sjdp     entry address can appear to be outside the text segment, thus causing an
62033965Sjdp     erroneous conclusion that the file isn't executable.
62133965Sjdp
62233965Sjdp     To fix this, we now accept any non-zero entry point as an indication of
62333965Sjdp     executability.  This will work most of the time, since only the linker
62477298Sobrien     sets the entry point, and that is likely to be non-zero for most systems.  */
62533965Sjdp
62633965Sjdp  if (execp->a_entry != 0
62789857Sobrien      || (execp->a_entry >= obj_textsec (abfd)->vma
62889857Sobrien	  && execp->a_entry < (obj_textsec (abfd)->vma
62989857Sobrien			       + obj_textsec (abfd)->_raw_size)))
63033965Sjdp    abfd->flags |= EXEC_P;
63133965Sjdp#ifdef STAT_FOR_EXEC
63233965Sjdp  else
63333965Sjdp    {
63433965Sjdp      struct stat stat_buf;
63533965Sjdp
63633965Sjdp      /* The original heuristic doesn't work in some important cases.
63733965Sjdp        The a.out file has no information about the text start
63833965Sjdp        address.  For files (like kernels) linked to non-standard
63933965Sjdp        addresses (ld -Ttext nnn) the entry point may not be between
64033965Sjdp        the default text start (obj_textsec(abfd)->vma) and
64133965Sjdp        (obj_textsec(abfd)->vma) + text size.  This is not just a mach
64233965Sjdp        issue.  Many kernels are loaded at non standard addresses.  */
64333965Sjdp      if (abfd->iostream != NULL
64433965Sjdp	  && (abfd->flags & BFD_IN_MEMORY) == 0
64589857Sobrien	  && (fstat (fileno ((FILE *) (abfd->iostream)), &stat_buf) == 0)
64633965Sjdp	  && ((stat_buf.st_mode & 0111) != 0))
64733965Sjdp	abfd->flags |= EXEC_P;
64833965Sjdp    }
64933965Sjdp#endif /* STAT_FOR_EXEC */
65033965Sjdp
65133965Sjdp  if (result)
65233965Sjdp    {
65333965Sjdp#if 0 /* These should be set correctly anyways.  */
65433965Sjdp      abfd->sections = obj_textsec (abfd);
65533965Sjdp      obj_textsec (abfd)->next = obj_datasec (abfd);
65633965Sjdp      obj_datasec (abfd)->next = obj_bsssec (abfd);
65733965Sjdp#endif
658104834Sobrien      return result;
65933965Sjdp    }
660104834Sobrien
661104834Sobrien error_ret:
662104834Sobrien  bfd_release (abfd, rawptr);
663104834Sobrien  abfd->tdata.aout_data = oldrawptr;
664104834Sobrien  return NULL;
66533965Sjdp}
66633965Sjdp
66733965Sjdp/*
66833965SjdpFUNCTION
66933965Sjdp	aout_@var{size}_mkobject
67033965Sjdp
67133965SjdpSYNOPSIS
67233965Sjdp	boolean aout_@var{size}_mkobject, (bfd *abfd);
67333965Sjdp
67433965SjdpDESCRIPTION
67533965Sjdp	Initialize BFD @var{abfd} for use with a.out files.
67633965Sjdp*/
67733965Sjdp
67833965Sjdpboolean
67933965SjdpNAME(aout,mkobject) (abfd)
68033965Sjdp     bfd *abfd;
68133965Sjdp{
68289857Sobrien  struct aout_data_struct *rawptr;
68389857Sobrien  bfd_size_type amt = sizeof (struct aout_data_struct);
68433965Sjdp
68533965Sjdp  bfd_set_error (bfd_error_system_call);
68633965Sjdp
68789857Sobrien  rawptr = (struct aout_data_struct *) bfd_zalloc (abfd, amt);
68833965Sjdp  if (rawptr == NULL)
68933965Sjdp    return false;
69033965Sjdp
69133965Sjdp  abfd->tdata.aout_data = rawptr;
69233965Sjdp  exec_hdr (abfd) = &(rawptr->e);
69333965Sjdp
69489857Sobrien  obj_textsec (abfd) = (asection *) NULL;
69589857Sobrien  obj_datasec (abfd) = (asection *) NULL;
69689857Sobrien  obj_bsssec (abfd) = (asection *) NULL;
69733965Sjdp
69833965Sjdp  return true;
69933965Sjdp}
70033965Sjdp
70133965Sjdp/*
70233965SjdpFUNCTION
70333965Sjdp	aout_@var{size}_machine_type
70433965Sjdp
70533965SjdpSYNOPSIS
70633965Sjdp	enum machine_type  aout_@var{size}_machine_type
70733965Sjdp	 (enum bfd_architecture arch,
70833965Sjdp	  unsigned long machine));
70933965Sjdp
71033965SjdpDESCRIPTION
71133965Sjdp	Keep track of machine architecture and machine type for
71233965Sjdp	a.out's. Return the <<machine_type>> for a particular
71333965Sjdp	architecture and machine, or <<M_UNKNOWN>> if that exact architecture
71433965Sjdp	and machine can't be represented in a.out format.
71533965Sjdp
71633965Sjdp	If the architecture is understood, machine type 0 (default)
71733965Sjdp	is always understood.
71833965Sjdp*/
71933965Sjdp
72033965Sjdpenum machine_type
72133965SjdpNAME(aout,machine_type) (arch, machine, unknown)
72233965Sjdp     enum bfd_architecture arch;
72333965Sjdp     unsigned long machine;
72433965Sjdp     boolean *unknown;
72533965Sjdp{
72633965Sjdp  enum machine_type arch_flags;
72733965Sjdp
72833965Sjdp  arch_flags = M_UNKNOWN;
72933965Sjdp  *unknown = true;
73033965Sjdp
73189857Sobrien  switch (arch)
73289857Sobrien    {
73389857Sobrien    case bfd_arch_sparc:
73489857Sobrien      if (machine == 0
73589857Sobrien	  || machine == bfd_mach_sparc
73689857Sobrien	  || machine == bfd_mach_sparc_sparclite
73789857Sobrien	  || machine == bfd_mach_sparc_sparclite_le
73889857Sobrien	  || machine == bfd_mach_sparc_v9)
73989857Sobrien	arch_flags = M_SPARC;
74089857Sobrien      else if (machine == bfd_mach_sparc_sparclet)
74189857Sobrien	arch_flags = M_SPARCLET;
74289857Sobrien      break;
74333965Sjdp
74489857Sobrien    case bfd_arch_m68k:
74589857Sobrien      switch (machine)
74689857Sobrien	{
74789857Sobrien	case 0:		      arch_flags = M_68010; break;
74889857Sobrien	case bfd_mach_m68000: arch_flags = M_UNKNOWN; *unknown = false; break;
74989857Sobrien	case bfd_mach_m68010: arch_flags = M_68010; break;
75089857Sobrien	case bfd_mach_m68020: arch_flags = M_68020; break;
75189857Sobrien	default:	      arch_flags = M_UNKNOWN; break;
75289857Sobrien	}
75389857Sobrien      break;
75433965Sjdp
75589857Sobrien    case bfd_arch_i386:
75689857Sobrien      if (machine == 0)
75789857Sobrien	arch_flags = M_386;
75889857Sobrien      break;
75933965Sjdp
76089857Sobrien    case bfd_arch_a29k:
76189857Sobrien      if (machine == 0)
76289857Sobrien	arch_flags = M_29K;
76389857Sobrien      break;
76433965Sjdp
76589857Sobrien    case bfd_arch_arm:
76689857Sobrien      if (machine == 0)
76789857Sobrien	arch_flags = M_ARM;
76889857Sobrien      break;
76977298Sobrien
77089857Sobrien    case bfd_arch_mips:
77189857Sobrien      switch (machine)
77289857Sobrien	{
77389857Sobrien	case 0:
77489857Sobrien	case bfd_mach_mips3000:
77589857Sobrien	case bfd_mach_mips3900:
77689857Sobrien	  arch_flags = M_MIPS1;
77789857Sobrien	  break;
77889857Sobrien	case bfd_mach_mips6000:
77989857Sobrien	  arch_flags = M_MIPS2;
78089857Sobrien	  break;
78189857Sobrien	case bfd_mach_mips4000:
78289857Sobrien	case bfd_mach_mips4010:
78389857Sobrien	case bfd_mach_mips4100:
78489857Sobrien	case bfd_mach_mips4300:
78589857Sobrien	case bfd_mach_mips4400:
78689857Sobrien	case bfd_mach_mips4600:
78789857Sobrien	case bfd_mach_mips4650:
78889857Sobrien	case bfd_mach_mips8000:
78989857Sobrien	case bfd_mach_mips10000:
79089857Sobrien	case bfd_mach_mips12000:
79189857Sobrien	case bfd_mach_mips16:
79289857Sobrien	case bfd_mach_mipsisa32:
79389857Sobrien	case bfd_mach_mips5:
79489857Sobrien	case bfd_mach_mipsisa64:
79589857Sobrien	case bfd_mach_mips_sb1:
79689857Sobrien	  /* FIXME: These should be MIPS3, MIPS4, MIPS16, MIPS32, etc.  */
79789857Sobrien	  arch_flags = M_MIPS2;
79889857Sobrien	  break;
79989857Sobrien	default:
80089857Sobrien	  arch_flags = M_UNKNOWN;
80189857Sobrien	  break;
80289857Sobrien	}
80360484Sobrien      break;
80489857Sobrien
80589857Sobrien    case bfd_arch_ns32k:
80689857Sobrien      switch (machine)
80789857Sobrien	{
80889857Sobrien	case 0:    	arch_flags = M_NS32532; break;
80989857Sobrien	case 32032:	arch_flags = M_NS32032; break;
81089857Sobrien	case 32532:	arch_flags = M_NS32532; break;
81189857Sobrien	default:	arch_flags = M_UNKNOWN; break;
81289857Sobrien	}
81360484Sobrien      break;
81489857Sobrien
81589857Sobrien    case bfd_arch_vax:
81689857Sobrien      *unknown = false;
81760484Sobrien      break;
81889857Sobrien
81989857Sobrien    case bfd_arch_cris:
82089857Sobrien      if (machine == 0 || machine == 255)
82189857Sobrien	arch_flags = M_CRIS;
82289857Sobrien      break;
82389857Sobrien
82460484Sobrien    default:
82560484Sobrien      arch_flags = M_UNKNOWN;
82633965Sjdp    }
82733965Sjdp
82833965Sjdp  if (arch_flags != M_UNKNOWN)
82933965Sjdp    *unknown = false;
83033965Sjdp
83133965Sjdp  return arch_flags;
83233965Sjdp}
83333965Sjdp
83433965Sjdp/*
83533965SjdpFUNCTION
83633965Sjdp	aout_@var{size}_set_arch_mach
83733965Sjdp
83833965SjdpSYNOPSIS
83933965Sjdp	boolean aout_@var{size}_set_arch_mach,
84033965Sjdp	 (bfd *,
84133965Sjdp	  enum bfd_architecture arch,
84233965Sjdp	  unsigned long machine));
84333965Sjdp
84433965SjdpDESCRIPTION
84533965Sjdp	Set the architecture and the machine of the BFD @var{abfd} to the
84633965Sjdp	values @var{arch} and @var{machine}.  Verify that @var{abfd}'s format
84733965Sjdp	can support the architecture required.
84833965Sjdp*/
84933965Sjdp
85033965Sjdpboolean
85133965SjdpNAME(aout,set_arch_mach) (abfd, arch, machine)
85233965Sjdp     bfd *abfd;
85333965Sjdp     enum bfd_architecture arch;
85433965Sjdp     unsigned long machine;
85533965Sjdp{
85633965Sjdp  if (! bfd_default_set_arch_mach (abfd, arch, machine))
85733965Sjdp    return false;
85833965Sjdp
85933965Sjdp  if (arch != bfd_arch_unknown)
86033965Sjdp    {
86133965Sjdp      boolean unknown;
86233965Sjdp
86333965Sjdp      NAME(aout,machine_type) (arch, machine, &unknown);
86433965Sjdp      if (unknown)
86533965Sjdp	return false;
86633965Sjdp    }
86733965Sjdp
86833965Sjdp  /* Determine the size of a relocation entry */
86989857Sobrien  switch (arch)
87089857Sobrien    {
87189857Sobrien    case bfd_arch_sparc:
87289857Sobrien    case bfd_arch_a29k:
87389857Sobrien    case bfd_arch_mips:
87489857Sobrien      obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
87589857Sobrien      break;
87689857Sobrien    default:
87789857Sobrien      obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
87889857Sobrien      break;
87989857Sobrien    }
88033965Sjdp
88189857Sobrien  return (*aout_backend_info (abfd)->set_sizes) (abfd);
88233965Sjdp}
88333965Sjdp
88433965Sjdpstatic void
88533965Sjdpadjust_o_magic (abfd, execp)
88633965Sjdp     bfd *abfd;
88733965Sjdp     struct internal_exec *execp;
88833965Sjdp{
88933965Sjdp  file_ptr pos = adata (abfd).exec_bytes_size;
89033965Sjdp  bfd_vma vma = 0;
89133965Sjdp  int pad = 0;
89233965Sjdp
89333965Sjdp  /* Text.  */
89489857Sobrien  obj_textsec (abfd)->filepos = pos;
89589857Sobrien  if (!obj_textsec (abfd)->user_set_vma)
89689857Sobrien    obj_textsec (abfd)->vma = vma;
89733965Sjdp  else
89889857Sobrien    vma = obj_textsec (abfd)->vma;
89933965Sjdp
90089857Sobrien  pos += obj_textsec (abfd)->_raw_size;
90189857Sobrien  vma += obj_textsec (abfd)->_raw_size;
90233965Sjdp
90333965Sjdp  /* Data.  */
90489857Sobrien  if (!obj_datasec (abfd)->user_set_vma)
90533965Sjdp    {
90633965Sjdp#if 0	    /* ?? Does alignment in the file image really matter? */
90789857Sobrien      pad = align_power (vma, obj_datasec (abfd)->alignment_power) - vma;
90833965Sjdp#endif
90989857Sobrien      obj_textsec (abfd)->_raw_size += pad;
91033965Sjdp      pos += pad;
91133965Sjdp      vma += pad;
91289857Sobrien      obj_datasec (abfd)->vma = vma;
91333965Sjdp    }
91433965Sjdp  else
91589857Sobrien    vma = obj_datasec (abfd)->vma;
91689857Sobrien  obj_datasec (abfd)->filepos = pos;
91789857Sobrien  pos += obj_datasec (abfd)->_raw_size;
91889857Sobrien  vma += obj_datasec (abfd)->_raw_size;
91933965Sjdp
92033965Sjdp  /* BSS.  */
92189857Sobrien  if (!obj_bsssec (abfd)->user_set_vma)
92233965Sjdp    {
92333965Sjdp#if 0
92489857Sobrien      pad = align_power (vma, obj_bsssec (abfd)->alignment_power) - vma;
92533965Sjdp#endif
92689857Sobrien      obj_datasec (abfd)->_raw_size += pad;
92733965Sjdp      pos += pad;
92833965Sjdp      vma += pad;
92989857Sobrien      obj_bsssec (abfd)->vma = vma;
93033965Sjdp    }
93133965Sjdp  else
93233965Sjdp    {
93389857Sobrien      /* The VMA of the .bss section is set by the VMA of the
93433965Sjdp         .data section plus the size of the .data section.  We may
93533965Sjdp         need to add padding bytes to make this true.  */
93633965Sjdp      pad = obj_bsssec (abfd)->vma - vma;
93733965Sjdp      if (pad > 0)
93833965Sjdp	{
93933965Sjdp	  obj_datasec (abfd)->_raw_size += pad;
94033965Sjdp	  pos += pad;
94133965Sjdp	}
94233965Sjdp    }
94389857Sobrien  obj_bsssec (abfd)->filepos = pos;
94433965Sjdp
94533965Sjdp  /* Fix up the exec header.  */
94689857Sobrien  execp->a_text = obj_textsec (abfd)->_raw_size;
94789857Sobrien  execp->a_data = obj_datasec (abfd)->_raw_size;
94889857Sobrien  execp->a_bss = obj_bsssec (abfd)->_raw_size;
94933965Sjdp  N_SET_MAGIC (*execp, OMAGIC);
95033965Sjdp}
95133965Sjdp
95233965Sjdpstatic void
95333965Sjdpadjust_z_magic (abfd, execp)
95433965Sjdp     bfd *abfd;
95533965Sjdp     struct internal_exec *execp;
95633965Sjdp{
95733965Sjdp  bfd_size_type data_pad, text_pad;
95833965Sjdp  file_ptr text_end;
95989857Sobrien  const struct aout_backend_data *abdp;
96033965Sjdp  int ztih;			/* Nonzero if text includes exec header.  */
96177298Sobrien
96233965Sjdp  abdp = aout_backend_info (abfd);
96333965Sjdp
96433965Sjdp  /* Text.  */
96533965Sjdp  ztih = (abdp != NULL
96633965Sjdp	  && (abdp->text_includes_header
96733965Sjdp	      || obj_aout_subformat (abfd) == q_magic_format));
96889857Sobrien  obj_textsec (abfd)->filepos = (ztih
96989857Sobrien				 ? adata (abfd).exec_bytes_size
97089857Sobrien				 : adata (abfd).zmagic_disk_block_size);
97189857Sobrien  if (! obj_textsec (abfd)->user_set_vma)
97233965Sjdp    {
97333965Sjdp      /* ?? Do we really need to check for relocs here?  */
97489857Sobrien      obj_textsec (abfd)->vma = ((abfd->flags & HAS_RELOC)
97589857Sobrien				 ? 0
97689857Sobrien				 : (ztih
97789857Sobrien				    ? (abdp->default_text_vma
97889857Sobrien				       + adata (abfd).exec_bytes_size)
97989857Sobrien				    : abdp->default_text_vma));
98033965Sjdp      text_pad = 0;
98133965Sjdp    }
98233965Sjdp  else
98333965Sjdp    {
98433965Sjdp      /* The .text section is being loaded at an unusual address.  We
98533965Sjdp         may need to pad it such that the .data section starts at a page
98633965Sjdp         boundary.  */
98733965Sjdp      if (ztih)
98833965Sjdp	text_pad = ((obj_textsec (abfd)->filepos - obj_textsec (abfd)->vma)
98933965Sjdp		    & (adata (abfd).page_size - 1));
99033965Sjdp      else
99133965Sjdp	text_pad = ((- obj_textsec (abfd)->vma)
99233965Sjdp		    & (adata (abfd).page_size - 1));
99333965Sjdp    }
99433965Sjdp
99533965Sjdp  /* Find start of data.  */
99633965Sjdp  if (ztih)
99733965Sjdp    {
99833965Sjdp      text_end = obj_textsec (abfd)->filepos + obj_textsec (abfd)->_raw_size;
99933965Sjdp      text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
100033965Sjdp    }
100133965Sjdp  else
100233965Sjdp    {
100333965Sjdp      /* Note that if page_size == zmagic_disk_block_size, then
100433965Sjdp	 filepos == page_size, and this case is the same as the ztih
100533965Sjdp	 case.  */
100633965Sjdp      text_end = obj_textsec (abfd)->_raw_size;
100733965Sjdp      text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
100833965Sjdp      text_end += obj_textsec (abfd)->filepos;
100933965Sjdp    }
101089857Sobrien  obj_textsec (abfd)->_raw_size += text_pad;
101133965Sjdp  text_end += text_pad;
101233965Sjdp
101333965Sjdp  /* Data.  */
101489857Sobrien  if (!obj_datasec (abfd)->user_set_vma)
101533965Sjdp    {
101633965Sjdp      bfd_vma vma;
101789857Sobrien      vma = obj_textsec (abfd)->vma + obj_textsec (abfd)->_raw_size;
101889857Sobrien      obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size);
101933965Sjdp    }
102033965Sjdp  if (abdp && abdp->zmagic_mapped_contiguous)
102133965Sjdp    {
102289857Sobrien      asection * text = obj_textsec (abfd);
102389857Sobrien      asection * data = obj_datasec (abfd);
102489857Sobrien
102589857Sobrien      text_pad = data->vma - (text->vma + text->_raw_size);
102689857Sobrien      /* Only pad the text section if the data
102789857Sobrien	 section is going to be placed after it.  */
102889857Sobrien      if (text_pad > 0)
102989857Sobrien	text->_raw_size += text_pad;
103033965Sjdp    }
103189857Sobrien  obj_datasec (abfd)->filepos = (obj_textsec (abfd)->filepos
103289857Sobrien				 + obj_textsec (abfd)->_raw_size);
103377298Sobrien
103433965Sjdp  /* Fix up exec header while we're at it.  */
103589857Sobrien  execp->a_text = obj_textsec (abfd)->_raw_size;
103633965Sjdp  if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
103789857Sobrien    execp->a_text += adata (abfd).exec_bytes_size;
103833965Sjdp  if (obj_aout_subformat (abfd) == q_magic_format)
103933965Sjdp    N_SET_MAGIC (*execp, QMAGIC);
104033965Sjdp  else
104133965Sjdp    N_SET_MAGIC (*execp, ZMAGIC);
104233965Sjdp
104333965Sjdp  /* Spec says data section should be rounded up to page boundary.  */
104489857Sobrien  obj_datasec (abfd)->_raw_size
104589857Sobrien    = align_power (obj_datasec (abfd)->_raw_size,
104689857Sobrien		   obj_bsssec (abfd)->alignment_power);
104789857Sobrien  execp->a_data = BFD_ALIGN (obj_datasec (abfd)->_raw_size,
104889857Sobrien			     adata (abfd).page_size);
104989857Sobrien  data_pad = execp->a_data - obj_datasec (abfd)->_raw_size;
105033965Sjdp
105133965Sjdp  /* BSS.  */
105289857Sobrien  if (!obj_bsssec (abfd)->user_set_vma)
105389857Sobrien    obj_bsssec (abfd)->vma = (obj_datasec (abfd)->vma
105489857Sobrien			      + obj_datasec (abfd)->_raw_size);
105533965Sjdp  /* If the BSS immediately follows the data section and extra space
105633965Sjdp     in the page is left after the data section, fudge data
105733965Sjdp     in the header so that the bss section looks smaller by that
105833965Sjdp     amount.  We'll start the bss section there, and lie to the OS.
105933965Sjdp     (Note that a linker script, as well as the above assignment,
106033965Sjdp     could have explicitly set the BSS vma to immediately follow
106133965Sjdp     the data section.)  */
106289857Sobrien  if (align_power (obj_bsssec (abfd)->vma, obj_bsssec (abfd)->alignment_power)
106389857Sobrien      == obj_datasec (abfd)->vma + obj_datasec (abfd)->_raw_size)
106489857Sobrien    execp->a_bss = (data_pad > obj_bsssec (abfd)->_raw_size
106589857Sobrien		    ? 0 : obj_bsssec (abfd)->_raw_size - data_pad);
106633965Sjdp  else
106789857Sobrien    execp->a_bss = obj_bsssec (abfd)->_raw_size;
106833965Sjdp}
106933965Sjdp
107033965Sjdpstatic void
107133965Sjdpadjust_n_magic (abfd, execp)
107233965Sjdp     bfd *abfd;
107333965Sjdp     struct internal_exec *execp;
107433965Sjdp{
107589857Sobrien  file_ptr pos = adata (abfd).exec_bytes_size;
107633965Sjdp  bfd_vma vma = 0;
107733965Sjdp  int pad;
107877298Sobrien
107933965Sjdp  /* Text.  */
108089857Sobrien  obj_textsec (abfd)->filepos = pos;
108189857Sobrien  if (!obj_textsec (abfd)->user_set_vma)
108289857Sobrien    obj_textsec (abfd)->vma = vma;
108333965Sjdp  else
108489857Sobrien    vma = obj_textsec (abfd)->vma;
108589857Sobrien  pos += obj_textsec (abfd)->_raw_size;
108689857Sobrien  vma += obj_textsec (abfd)->_raw_size;
108733965Sjdp
108833965Sjdp  /* Data.  */
108989857Sobrien  obj_datasec (abfd)->filepos = pos;
109089857Sobrien  if (!obj_datasec (abfd)->user_set_vma)
109189857Sobrien    obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size);
109289857Sobrien  vma = obj_datasec (abfd)->vma;
109377298Sobrien
109433965Sjdp  /* Since BSS follows data immediately, see if it needs alignment.  */
109589857Sobrien  vma += obj_datasec (abfd)->_raw_size;
109689857Sobrien  pad = align_power (vma, obj_bsssec (abfd)->alignment_power) - vma;
109789857Sobrien  obj_datasec (abfd)->_raw_size += pad;
109889857Sobrien  pos += obj_datasec (abfd)->_raw_size;
109933965Sjdp
110033965Sjdp  /* BSS.  */
110189857Sobrien  if (!obj_bsssec (abfd)->user_set_vma)
110289857Sobrien    obj_bsssec (abfd)->vma = vma;
110333965Sjdp  else
110489857Sobrien    vma = obj_bsssec (abfd)->vma;
110533965Sjdp
110633965Sjdp  /* Fix up exec header.  */
110789857Sobrien  execp->a_text = obj_textsec (abfd)->_raw_size;
110889857Sobrien  execp->a_data = obj_datasec (abfd)->_raw_size;
110989857Sobrien  execp->a_bss = obj_bsssec (abfd)->_raw_size;
111033965Sjdp  N_SET_MAGIC (*execp, NMAGIC);
111133965Sjdp}
111233965Sjdp
111333965Sjdpboolean
111433965SjdpNAME(aout,adjust_sizes_and_vmas) (abfd, text_size, text_end)
111533965Sjdp     bfd *abfd;
111633965Sjdp     bfd_size_type *text_size;
111760484Sobrien     file_ptr *text_end ATTRIBUTE_UNUSED;
111833965Sjdp{
111933965Sjdp  struct internal_exec *execp = exec_hdr (abfd);
112033965Sjdp
112133965Sjdp  if (! NAME(aout,make_sections) (abfd))
112233965Sjdp    return false;
112333965Sjdp
112489857Sobrien  if (adata (abfd).magic != undecided_magic)
112533965Sjdp    return true;
112633965Sjdp
112789857Sobrien  obj_textsec (abfd)->_raw_size =
112889857Sobrien    align_power (obj_textsec (abfd)->_raw_size,
112989857Sobrien		 obj_textsec (abfd)->alignment_power);
113033965Sjdp
113133965Sjdp  *text_size = obj_textsec (abfd)->_raw_size;
113233965Sjdp  /* Rule (heuristic) for when to pad to a new page.  Note that there
113333965Sjdp     are (at least) two ways demand-paged (ZMAGIC) files have been
113433965Sjdp     handled.  Most Berkeley-based systems start the text segment at
113533965Sjdp     (TARGET_PAGE_SIZE).  However, newer versions of SUNOS start the text
113633965Sjdp     segment right after the exec header; the latter is counted in the
113733965Sjdp     text segment size, and is paged in by the kernel with the rest of
113877298Sobrien     the text.  */
113933965Sjdp
114033965Sjdp  /* This perhaps isn't the right way to do this, but made it simpler for me
114133965Sjdp     to understand enough to implement it.  Better would probably be to go
114233965Sjdp     right from BFD flags to alignment/positioning characteristics.  But the
114333965Sjdp     old code was sloppy enough about handling the flags, and had enough
114433965Sjdp     other magic, that it was a little hard for me to understand.  I think
114533965Sjdp     I understand it better now, but I haven't time to do the cleanup this
114633965Sjdp     minute.  */
114733965Sjdp
114833965Sjdp  if (abfd->flags & D_PAGED)
114933965Sjdp    /* Whether or not WP_TEXT is set -- let D_PAGED override.  */
115089857Sobrien    adata (abfd).magic = z_magic;
115133965Sjdp  else if (abfd->flags & WP_TEXT)
115289857Sobrien    adata (abfd).magic = n_magic;
115333965Sjdp  else
115489857Sobrien    adata (abfd).magic = o_magic;
115533965Sjdp
115633965Sjdp#ifdef BFD_AOUT_DEBUG /* requires gcc2 */
115733965Sjdp#if __GNUC__ >= 2
115833965Sjdp  fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n",
115933965Sjdp	   ({ char *str;
116089857Sobrien	      switch (adata (abfd).magic)
116189857Sobrien		{
116289857Sobrien		case n_magic: str = "NMAGIC"; break;
116389857Sobrien		case o_magic: str = "OMAGIC"; break;
116489857Sobrien		case z_magic: str = "ZMAGIC"; break;
116589857Sobrien		default: abort ();
116689857Sobrien		}
116733965Sjdp	      str;
116833965Sjdp	    }),
116989857Sobrien	   obj_textsec (abfd)->vma, obj_textsec (abfd)->_raw_size,
117089857Sobrien	   	obj_textsec (abfd)->alignment_power,
117189857Sobrien	   obj_datasec (abfd)->vma, obj_datasec (abfd)->_raw_size,
117289857Sobrien	   	obj_datasec (abfd)->alignment_power,
117389857Sobrien	   obj_bsssec (abfd)->vma, obj_bsssec (abfd)->_raw_size,
117489857Sobrien	   	obj_bsssec (abfd)->alignment_power);
117533965Sjdp#endif
117633965Sjdp#endif
117733965Sjdp
117889857Sobrien  switch (adata (abfd).magic)
117933965Sjdp    {
118033965Sjdp    case o_magic:
118133965Sjdp      adjust_o_magic (abfd, execp);
118233965Sjdp      break;
118333965Sjdp    case z_magic:
118433965Sjdp      adjust_z_magic (abfd, execp);
118533965Sjdp      break;
118633965Sjdp    case n_magic:
118733965Sjdp      adjust_n_magic (abfd, execp);
118833965Sjdp      break;
118933965Sjdp    default:
119033965Sjdp      abort ();
119133965Sjdp    }
119233965Sjdp
119333965Sjdp#ifdef BFD_AOUT_DEBUG
119433965Sjdp  fprintf (stderr, "       text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n",
119589857Sobrien	   obj_textsec (abfd)->vma, obj_textsec (abfd)->_raw_size,
119689857Sobrien	   	obj_textsec (abfd)->filepos,
119789857Sobrien	   obj_datasec (abfd)->vma, obj_datasec (abfd)->_raw_size,
119889857Sobrien	   	obj_datasec (abfd)->filepos,
119989857Sobrien	   obj_bsssec (abfd)->vma, obj_bsssec (abfd)->_raw_size);
120033965Sjdp#endif
120133965Sjdp
120233965Sjdp  return true;
120333965Sjdp}
120433965Sjdp
120533965Sjdp/*
120633965SjdpFUNCTION
120733965Sjdp	aout_@var{size}_new_section_hook
120833965Sjdp
120933965SjdpSYNOPSIS
121033965Sjdp        boolean aout_@var{size}_new_section_hook,
121133965Sjdp	   (bfd *abfd,
121233965Sjdp	    asection *newsect));
121333965Sjdp
121433965SjdpDESCRIPTION
121533965Sjdp	Called by the BFD in response to a @code{bfd_make_section}
121633965Sjdp	request.
121733965Sjdp*/
121833965Sjdpboolean
121933965SjdpNAME(aout,new_section_hook) (abfd, newsect)
122033965Sjdp     bfd *abfd;
122133965Sjdp     asection *newsect;
122233965Sjdp{
122333965Sjdp  /* align to double at least */
122489857Sobrien  newsect->alignment_power = bfd_get_arch_info (abfd)->section_align_power;
122533965Sjdp
122633965Sjdp  if (bfd_get_format (abfd) == bfd_object)
122733965Sjdp  {
122889857Sobrien    if (obj_textsec (abfd) == NULL && !strcmp (newsect->name, ".text"))
122989857Sobrien      {
123089857Sobrien	obj_textsec (abfd)= newsect;
123133965Sjdp	newsect->target_index = N_TEXT;
123233965Sjdp	return true;
123333965Sjdp      }
123433965Sjdp
123589857Sobrien    if (obj_datasec (abfd) == NULL && !strcmp (newsect->name, ".data"))
123689857Sobrien      {
123789857Sobrien	obj_datasec (abfd) = newsect;
123833965Sjdp	newsect->target_index = N_DATA;
123933965Sjdp	return true;
124033965Sjdp      }
124133965Sjdp
124289857Sobrien    if (obj_bsssec (abfd) == NULL && !strcmp (newsect->name, ".bss"))
124389857Sobrien      {
124489857Sobrien	obj_bsssec (abfd) = newsect;
124533965Sjdp	newsect->target_index = N_BSS;
124633965Sjdp	return true;
124733965Sjdp      }
124833965Sjdp
124933965Sjdp  }
125033965Sjdp
125133965Sjdp  /* We allow more than three sections internally */
125233965Sjdp  return true;
125333965Sjdp}
125433965Sjdp
125533965Sjdpboolean
125633965SjdpNAME(aout,set_section_contents) (abfd, section, location, offset, count)
125733965Sjdp     bfd *abfd;
125833965Sjdp     sec_ptr section;
125933965Sjdp     PTR location;
126033965Sjdp     file_ptr offset;
126133965Sjdp     bfd_size_type count;
126233965Sjdp{
126333965Sjdp  file_ptr text_end;
126433965Sjdp  bfd_size_type text_size;
126533965Sjdp
126633965Sjdp  if (! abfd->output_has_begun)
126733965Sjdp    {
126833965Sjdp      if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
126933965Sjdp	return false;
127033965Sjdp    }
127133965Sjdp
127233965Sjdp  if (section == obj_bsssec (abfd))
127333965Sjdp    {
127433965Sjdp      bfd_set_error (bfd_error_no_contents);
127533965Sjdp      return false;
127633965Sjdp    }
127733965Sjdp
127833965Sjdp  if (section != obj_textsec (abfd)
127933965Sjdp      && section != obj_datasec (abfd))
128033965Sjdp    {
128133965Sjdp      (*_bfd_error_handler)
128260484Sobrien	(_("%s: can not represent section `%s' in a.out object file format"),
128333965Sjdp	 bfd_get_filename (abfd), bfd_get_section_name (abfd, section));
128433965Sjdp      bfd_set_error (bfd_error_nonrepresentable_section);
128533965Sjdp      return false;
128633965Sjdp    }
128733965Sjdp
128833965Sjdp  if (count != 0)
128933965Sjdp    {
129033965Sjdp      if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
129189857Sobrien	  || bfd_bwrite (location, count, abfd) != count)
129233965Sjdp	return false;
129333965Sjdp    }
129433965Sjdp
129533965Sjdp  return true;
129633965Sjdp}
129733965Sjdp
129833965Sjdp/* Read the external symbols from an a.out file.  */
129933965Sjdp
130033965Sjdpstatic boolean
130133965Sjdpaout_get_external_symbols (abfd)
130233965Sjdp     bfd *abfd;
130333965Sjdp{
130433965Sjdp  if (obj_aout_external_syms (abfd) == (struct external_nlist *) NULL)
130533965Sjdp    {
130633965Sjdp      bfd_size_type count;
130733965Sjdp      struct external_nlist *syms;
130889857Sobrien      bfd_size_type amt;
130933965Sjdp
131033965Sjdp      count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
131133965Sjdp
131233965Sjdp#ifdef USE_MMAP
1313104834Sobrien      if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd),
1314104834Sobrien				 exec_hdr (abfd)->a_syms,
1315104834Sobrien				 &obj_aout_sym_window (abfd), true))
131633965Sjdp	return false;
131733965Sjdp      syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
131833965Sjdp#else
131933965Sjdp      /* We allocate using malloc to make the values easy to free
132033965Sjdp	 later on.  If we put them on the objalloc it might not be
132133965Sjdp	 possible to free them.  */
132233965Sjdp      syms = ((struct external_nlist *)
132389857Sobrien	      bfd_malloc (count * EXTERNAL_NLIST_SIZE));
132433965Sjdp      if (syms == (struct external_nlist *) NULL && count != 0)
132533965Sjdp	return false;
132633965Sjdp
132789857Sobrien      amt = exec_hdr (abfd)->a_syms;
132833965Sjdp      if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
132989857Sobrien	  || bfd_bread (syms, amt, abfd) != amt)
133033965Sjdp	{
133133965Sjdp	  free (syms);
133233965Sjdp	  return false;
133333965Sjdp	}
133433965Sjdp#endif
133533965Sjdp
133633965Sjdp      obj_aout_external_syms (abfd) = syms;
133733965Sjdp      obj_aout_external_sym_count (abfd) = count;
133833965Sjdp    }
133977298Sobrien
134033965Sjdp  if (obj_aout_external_strings (abfd) == NULL
134133965Sjdp      && exec_hdr (abfd)->a_syms != 0)
134233965Sjdp    {
134333965Sjdp      unsigned char string_chars[BYTES_IN_WORD];
134433965Sjdp      bfd_size_type stringsize;
134533965Sjdp      char *strings;
134689857Sobrien      bfd_size_type amt = BYTES_IN_WORD;
134733965Sjdp
134833965Sjdp      /* Get the size of the strings.  */
134933965Sjdp      if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
135089857Sobrien	  || bfd_bread ((PTR) string_chars, amt, abfd) != amt)
135133965Sjdp	return false;
135233965Sjdp      stringsize = GET_WORD (abfd, string_chars);
135333965Sjdp
135433965Sjdp#ifdef USE_MMAP
1355104834Sobrien      if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize,
1356104834Sobrien				 &obj_aout_string_window (abfd), true))
135733965Sjdp	return false;
135833965Sjdp      strings = (char *) obj_aout_string_window (abfd).data;
135933965Sjdp#else
136089857Sobrien      strings = (char *) bfd_malloc (stringsize + 1);
136133965Sjdp      if (strings == NULL)
136233965Sjdp	return false;
136333965Sjdp
136433965Sjdp      /* Skip space for the string count in the buffer for convenience
136533965Sjdp	 when using indexes.  */
136689857Sobrien      amt = stringsize - BYTES_IN_WORD;
136789857Sobrien      if (bfd_bread (strings + BYTES_IN_WORD, amt, abfd) != amt)
136833965Sjdp	{
136933965Sjdp	  free (strings);
137033965Sjdp	  return false;
137133965Sjdp	}
137233965Sjdp#endif
137333965Sjdp
137433965Sjdp      /* Ensure that a zero index yields an empty string.  */
137533965Sjdp      strings[0] = '\0';
137633965Sjdp
137733965Sjdp      strings[stringsize - 1] = 0;
137833965Sjdp
137933965Sjdp      obj_aout_external_strings (abfd) = strings;
138033965Sjdp      obj_aout_external_string_size (abfd) = stringsize;
138133965Sjdp    }
138233965Sjdp
138333965Sjdp  return true;
138433965Sjdp}
138533965Sjdp
138633965Sjdp/* Translate an a.out symbol into a BFD symbol.  The desc, other, type
138733965Sjdp   and symbol->value fields of CACHE_PTR will be set from the a.out
138833965Sjdp   nlist structure.  This function is responsible for setting
138933965Sjdp   symbol->flags and symbol->section, and adjusting symbol->value.  */
139033965Sjdp
139133965Sjdpstatic boolean
139233965Sjdptranslate_from_native_sym_flags (abfd, cache_ptr)
139333965Sjdp     bfd *abfd;
139433965Sjdp     aout_symbol_type *cache_ptr;
139533965Sjdp{
139633965Sjdp  flagword visible;
139733965Sjdp
139833965Sjdp  if ((cache_ptr->type & N_STAB) != 0
139933965Sjdp      || cache_ptr->type == N_FN)
140033965Sjdp    {
140133965Sjdp      asection *sec;
140233965Sjdp
140333965Sjdp      /* This is a debugging symbol.  */
140433965Sjdp
140533965Sjdp      cache_ptr->symbol.flags = BSF_DEBUGGING;
140633965Sjdp
140733965Sjdp      /* Work out the symbol section.  */
140833965Sjdp      switch (cache_ptr->type & N_TYPE)
140933965Sjdp	{
141033965Sjdp	case N_TEXT:
141133965Sjdp	case N_FN:
141233965Sjdp	  sec = obj_textsec (abfd);
141333965Sjdp	  break;
141433965Sjdp	case N_DATA:
141533965Sjdp	  sec = obj_datasec (abfd);
141633965Sjdp	  break;
141733965Sjdp	case N_BSS:
141833965Sjdp	  sec = obj_bsssec (abfd);
141933965Sjdp	  break;
142033965Sjdp	default:
142133965Sjdp	case N_ABS:
142233965Sjdp	  sec = bfd_abs_section_ptr;
142333965Sjdp	  break;
142433965Sjdp	}
142533965Sjdp
142633965Sjdp      cache_ptr->symbol.section = sec;
142733965Sjdp      cache_ptr->symbol.value -= sec->vma;
142833965Sjdp
142933965Sjdp      return true;
143033965Sjdp    }
143133965Sjdp
143233965Sjdp  /* Get the default visibility.  This does not apply to all types, so
143333965Sjdp     we just hold it in a local variable to use if wanted.  */
143433965Sjdp  if ((cache_ptr->type & N_EXT) == 0)
143533965Sjdp    visible = BSF_LOCAL;
143633965Sjdp  else
143733965Sjdp    visible = BSF_GLOBAL;
143833965Sjdp
143933965Sjdp  switch (cache_ptr->type)
144033965Sjdp    {
144133965Sjdp    default:
144233965Sjdp    case N_ABS: case N_ABS | N_EXT:
144333965Sjdp      cache_ptr->symbol.section = bfd_abs_section_ptr;
144433965Sjdp      cache_ptr->symbol.flags = visible;
144533965Sjdp      break;
144633965Sjdp
144733965Sjdp    case N_UNDF | N_EXT:
144833965Sjdp      if (cache_ptr->symbol.value != 0)
144933965Sjdp	{
145033965Sjdp	  /* This is a common symbol.  */
145133965Sjdp	  cache_ptr->symbol.flags = BSF_GLOBAL;
145233965Sjdp	  cache_ptr->symbol.section = bfd_com_section_ptr;
145333965Sjdp	}
145433965Sjdp      else
145533965Sjdp	{
145633965Sjdp	  cache_ptr->symbol.flags = 0;
145733965Sjdp	  cache_ptr->symbol.section = bfd_und_section_ptr;
145833965Sjdp	}
145933965Sjdp      break;
146033965Sjdp
146133965Sjdp    case N_TEXT: case N_TEXT | N_EXT:
146233965Sjdp      cache_ptr->symbol.section = obj_textsec (abfd);
146333965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
146433965Sjdp      cache_ptr->symbol.flags = visible;
146533965Sjdp      break;
146633965Sjdp
146733965Sjdp      /* N_SETV symbols used to represent set vectors placed in the
146833965Sjdp	 data section.  They are no longer generated.  Theoretically,
146933965Sjdp	 it was possible to extract the entries and combine them with
147033965Sjdp	 new ones, although I don't know if that was ever actually
147133965Sjdp	 done.  Unless that feature is restored, treat them as data
147233965Sjdp	 symbols.  */
147333965Sjdp    case N_SETV: case N_SETV | N_EXT:
147433965Sjdp    case N_DATA: case N_DATA | N_EXT:
147533965Sjdp      cache_ptr->symbol.section = obj_datasec (abfd);
147633965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
147733965Sjdp      cache_ptr->symbol.flags = visible;
147833965Sjdp      break;
147933965Sjdp
148033965Sjdp    case N_BSS: case N_BSS | N_EXT:
148133965Sjdp      cache_ptr->symbol.section = obj_bsssec (abfd);
148233965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
148333965Sjdp      cache_ptr->symbol.flags = visible;
148433965Sjdp      break;
148533965Sjdp
148633965Sjdp    case N_SETA: case N_SETA | N_EXT:
148733965Sjdp    case N_SETT: case N_SETT | N_EXT:
148833965Sjdp    case N_SETD: case N_SETD | N_EXT:
148933965Sjdp    case N_SETB: case N_SETB | N_EXT:
149033965Sjdp      {
149133965Sjdp	/* This code is no longer needed.  It used to be used to make
149233965Sjdp           the linker handle set symbols, but they are now handled in
149333965Sjdp           the add_symbols routine instead.  */
149433965Sjdp#if 0
149533965Sjdp	asection *section;
149633965Sjdp	arelent_chain *reloc;
149733965Sjdp	asection *into_section;
149889857Sobrien	bfd_size_type amt;
149933965Sjdp
150033965Sjdp	/* This is a set symbol.  The name of the symbol is the name
150133965Sjdp	   of the set (e.g., __CTOR_LIST__).  The value of the symbol
150233965Sjdp	   is the value to add to the set.  We create a section with
150333965Sjdp	   the same name as the symbol, and add a reloc to insert the
150433965Sjdp	   appropriate value into the section.
150533965Sjdp
150633965Sjdp	   This action is actually obsolete; it used to make the
150733965Sjdp	   linker do the right thing, but the linker no longer uses
150833965Sjdp	   this function.  */
150933965Sjdp
151033965Sjdp	section = bfd_get_section_by_name (abfd, cache_ptr->symbol.name);
151133965Sjdp	if (section == NULL)
151233965Sjdp	  {
151333965Sjdp	    char *copy;
151433965Sjdp
151589857Sobrien	    amt = strlen (cache_ptr->symbol.name) + 1;
151689857Sobrien	    copy = bfd_alloc (abfd, amt);
151733965Sjdp	    if (copy == NULL)
151833965Sjdp	      return false;
151933965Sjdp
152033965Sjdp	    strcpy (copy, cache_ptr->symbol.name);
152133965Sjdp	    section = bfd_make_section (abfd, copy);
152233965Sjdp	    if (section == NULL)
152333965Sjdp	      return false;
152433965Sjdp	  }
152533965Sjdp
152689857Sobrien	amt = sizeof (arelent_chain);
152789857Sobrien	reloc = (arelent_chain *) bfd_alloc (abfd, amt);
152833965Sjdp	if (reloc == NULL)
152933965Sjdp	  return false;
153033965Sjdp
153133965Sjdp	/* Build a relocation entry for the constructor.  */
153233965Sjdp	switch (cache_ptr->type & N_TYPE)
153333965Sjdp	  {
153433965Sjdp	  case N_SETA:
153533965Sjdp	    into_section = bfd_abs_section_ptr;
153633965Sjdp	    cache_ptr->type = N_ABS;
153733965Sjdp	    break;
153833965Sjdp	  case N_SETT:
153933965Sjdp	    into_section = obj_textsec (abfd);
154033965Sjdp	    cache_ptr->type = N_TEXT;
154133965Sjdp	    break;
154233965Sjdp	  case N_SETD:
154333965Sjdp	    into_section = obj_datasec (abfd);
154433965Sjdp	    cache_ptr->type = N_DATA;
154533965Sjdp	    break;
154633965Sjdp	  case N_SETB:
154733965Sjdp	    into_section = obj_bsssec (abfd);
154833965Sjdp	    cache_ptr->type = N_BSS;
154933965Sjdp	    break;
155033965Sjdp	  }
155133965Sjdp
155233965Sjdp	/* Build a relocation pointing into the constructor section
155333965Sjdp	   pointing at the symbol in the set vector specified.  */
155433965Sjdp	reloc->relent.addend = cache_ptr->symbol.value;
155533965Sjdp	cache_ptr->symbol.section = into_section;
155633965Sjdp	reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr;
155733965Sjdp
155833965Sjdp	/* We modify the symbol to belong to a section depending upon
155933965Sjdp	   the name of the symbol, and add to the size of the section
156033965Sjdp	   to contain a pointer to the symbol. Build a reloc entry to
156133965Sjdp	   relocate to this symbol attached to this section.  */
156233965Sjdp	section->flags = SEC_CONSTRUCTOR | SEC_RELOC;
156333965Sjdp
156433965Sjdp	section->reloc_count++;
156533965Sjdp	section->alignment_power = 2;
156633965Sjdp
156733965Sjdp	reloc->next = section->constructor_chain;
156833965Sjdp	section->constructor_chain = reloc;
156933965Sjdp	reloc->relent.address = section->_raw_size;
157033965Sjdp	section->_raw_size += BYTES_IN_WORD;
157133965Sjdp
157289857Sobrien	reloc->relent.howto = CTOR_TABLE_RELOC_HOWTO (abfd);
157333965Sjdp
157433965Sjdp#endif /* 0 */
157533965Sjdp
157633965Sjdp	switch (cache_ptr->type & N_TYPE)
157733965Sjdp	  {
157833965Sjdp	  case N_SETA:
157933965Sjdp	    cache_ptr->symbol.section = bfd_abs_section_ptr;
158033965Sjdp	    break;
158133965Sjdp	  case N_SETT:
158233965Sjdp	    cache_ptr->symbol.section = obj_textsec (abfd);
158333965Sjdp	    break;
158433965Sjdp	  case N_SETD:
158533965Sjdp	    cache_ptr->symbol.section = obj_datasec (abfd);
158633965Sjdp	    break;
158733965Sjdp	  case N_SETB:
158833965Sjdp	    cache_ptr->symbol.section = obj_bsssec (abfd);
158933965Sjdp	    break;
159033965Sjdp	  }
159133965Sjdp
159233965Sjdp	cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
159333965Sjdp      }
159433965Sjdp      break;
159533965Sjdp
159633965Sjdp    case N_WARNING:
159733965Sjdp      /* This symbol is the text of a warning message.  The next
159833965Sjdp	 symbol is the symbol to associate the warning with.  If a
159933965Sjdp	 reference is made to that symbol, a warning is issued.  */
160033965Sjdp      cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
160133965Sjdp      cache_ptr->symbol.section = bfd_abs_section_ptr;
160233965Sjdp      break;
160333965Sjdp
160433965Sjdp    case N_INDR: case N_INDR | N_EXT:
160533965Sjdp      /* An indirect symbol.  This consists of two symbols in a row.
160633965Sjdp	 The first symbol is the name of the indirection.  The second
160733965Sjdp	 symbol is the name of the target.  A reference to the first
160833965Sjdp	 symbol becomes a reference to the second.  */
160933965Sjdp      cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible;
161033965Sjdp      cache_ptr->symbol.section = bfd_ind_section_ptr;
161133965Sjdp      break;
161233965Sjdp
161333965Sjdp    case N_WEAKU:
161433965Sjdp      cache_ptr->symbol.section = bfd_und_section_ptr;
161533965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
161633965Sjdp      break;
161733965Sjdp
161833965Sjdp    case N_WEAKA:
161933965Sjdp      cache_ptr->symbol.section = bfd_abs_section_ptr;
162033965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
162133965Sjdp      break;
162233965Sjdp
162333965Sjdp    case N_WEAKT:
162433965Sjdp      cache_ptr->symbol.section = obj_textsec (abfd);
162533965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
162633965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
162733965Sjdp      break;
162833965Sjdp
162933965Sjdp    case N_WEAKD:
163033965Sjdp      cache_ptr->symbol.section = obj_datasec (abfd);
163133965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
163233965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
163333965Sjdp      break;
163433965Sjdp
163533965Sjdp    case N_WEAKB:
163633965Sjdp      cache_ptr->symbol.section = obj_bsssec (abfd);
163733965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
163833965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
163933965Sjdp      break;
164033965Sjdp    }
164133965Sjdp
164233965Sjdp  return true;
164333965Sjdp}
164433965Sjdp
164533965Sjdp/* Set the fields of SYM_POINTER according to CACHE_PTR.  */
164633965Sjdp
164733965Sjdpstatic boolean
164833965Sjdptranslate_to_native_sym_flags (abfd, cache_ptr, sym_pointer)
164933965Sjdp     bfd *abfd;
165033965Sjdp     asymbol *cache_ptr;
165133965Sjdp     struct external_nlist *sym_pointer;
165233965Sjdp{
165333965Sjdp  bfd_vma value = cache_ptr->value;
165433965Sjdp  asection *sec;
165533965Sjdp  bfd_vma off;
165633965Sjdp
165733965Sjdp  /* Mask out any existing type bits in case copying from one section
165833965Sjdp     to another.  */
165933965Sjdp  sym_pointer->e_type[0] &= ~N_TYPE;
166033965Sjdp
166133965Sjdp  sec = bfd_get_section (cache_ptr);
166233965Sjdp  off = 0;
166333965Sjdp
166433965Sjdp  if (sec == NULL)
166533965Sjdp    {
166633965Sjdp      /* This case occurs, e.g., for the *DEBUG* section of a COFF
166733965Sjdp	 file.  */
166833965Sjdp      (*_bfd_error_handler)
166960484Sobrien	(_("%s: can not represent section for symbol `%s' in a.out object file format"),
167077298Sobrien	 bfd_get_filename (abfd),
167160484Sobrien	 cache_ptr->name != NULL ? cache_ptr->name : _("*unknown*"));
167233965Sjdp      bfd_set_error (bfd_error_nonrepresentable_section);
167333965Sjdp      return false;
167433965Sjdp    }
167533965Sjdp
167633965Sjdp  if (sec->output_section != NULL)
167733965Sjdp    {
167833965Sjdp      off = sec->output_offset;
167933965Sjdp      sec = sec->output_section;
168033965Sjdp    }
168133965Sjdp
168233965Sjdp  if (bfd_is_abs_section (sec))
168333965Sjdp    sym_pointer->e_type[0] |= N_ABS;
168433965Sjdp  else if (sec == obj_textsec (abfd))
168533965Sjdp    sym_pointer->e_type[0] |= N_TEXT;
168633965Sjdp  else if (sec == obj_datasec (abfd))
168733965Sjdp    sym_pointer->e_type[0] |= N_DATA;
168833965Sjdp  else if (sec == obj_bsssec (abfd))
168933965Sjdp    sym_pointer->e_type[0] |= N_BSS;
169033965Sjdp  else if (bfd_is_und_section (sec))
169133965Sjdp    sym_pointer->e_type[0] = N_UNDF | N_EXT;
169233965Sjdp  else if (bfd_is_ind_section (sec))
169333965Sjdp    sym_pointer->e_type[0] = N_INDR;
169433965Sjdp  else if (bfd_is_com_section (sec))
169533965Sjdp    sym_pointer->e_type[0] = N_UNDF | N_EXT;
169633965Sjdp  else
169733965Sjdp    {
169833965Sjdp      (*_bfd_error_handler)
169960484Sobrien	(_("%s: can not represent section `%s' in a.out object file format"),
170033965Sjdp	 bfd_get_filename (abfd), bfd_get_section_name (abfd, sec));
170133965Sjdp      bfd_set_error (bfd_error_nonrepresentable_section);
170233965Sjdp      return false;
170333965Sjdp    }
170433965Sjdp
170533965Sjdp  /* Turn the symbol from section relative to absolute again */
170633965Sjdp  value += sec->vma + off;
170733965Sjdp
170833965Sjdp  if ((cache_ptr->flags & BSF_WARNING) != 0)
170933965Sjdp    sym_pointer->e_type[0] = N_WARNING;
171033965Sjdp
171133965Sjdp  if ((cache_ptr->flags & BSF_DEBUGGING) != 0)
171233965Sjdp    sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type;
171333965Sjdp  else if ((cache_ptr->flags & BSF_GLOBAL) != 0)
171433965Sjdp    sym_pointer->e_type[0] |= N_EXT;
171577298Sobrien  else if ((cache_ptr->flags & BSF_LOCAL) != 0)
171677298Sobrien    sym_pointer->e_type[0] &= ~N_EXT;
171733965Sjdp
171833965Sjdp  if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0)
171933965Sjdp    {
172033965Sjdp      int type = ((aout_symbol_type *) cache_ptr)->type;
172133965Sjdp      switch (type)
172233965Sjdp	{
172333965Sjdp	case N_ABS:	type = N_SETA; break;
172433965Sjdp	case N_TEXT:	type = N_SETT; break;
172533965Sjdp	case N_DATA:	type = N_SETD; break;
172633965Sjdp	case N_BSS:	type = N_SETB; break;
172733965Sjdp	}
172833965Sjdp      sym_pointer->e_type[0] = type;
172933965Sjdp    }
173033965Sjdp
173133965Sjdp  if ((cache_ptr->flags & BSF_WEAK) != 0)
173233965Sjdp    {
173333965Sjdp      int type;
173433965Sjdp
173533965Sjdp      switch (sym_pointer->e_type[0] & N_TYPE)
173633965Sjdp	{
173733965Sjdp	default:
173833965Sjdp	case N_ABS:	type = N_WEAKA; break;
173933965Sjdp	case N_TEXT:	type = N_WEAKT; break;
174033965Sjdp	case N_DATA:	type = N_WEAKD; break;
174133965Sjdp	case N_BSS:	type = N_WEAKB; break;
174233965Sjdp	case N_UNDF:	type = N_WEAKU; break;
174333965Sjdp	}
174433965Sjdp      sym_pointer->e_type[0] = type;
174533965Sjdp    }
174633965Sjdp
174789857Sobrien  PUT_WORD (abfd, value, sym_pointer->e_value);
174833965Sjdp
174933965Sjdp  return true;
175033965Sjdp}
175133965Sjdp
175277298Sobrien/* Native-level interface to symbols.  */
175333965Sjdp
175433965Sjdpasymbol *
175533965SjdpNAME(aout,make_empty_symbol) (abfd)
175633965Sjdp     bfd *abfd;
175733965Sjdp{
175889857Sobrien  bfd_size_type amt = sizeof (aout_symbol_type);
175989857Sobrien  aout_symbol_type *new = (aout_symbol_type *) bfd_zalloc (abfd, amt);
176033965Sjdp  if (!new)
176133965Sjdp    return NULL;
176233965Sjdp  new->symbol.the_bfd = abfd;
176333965Sjdp
176433965Sjdp  return &new->symbol;
176533965Sjdp}
176633965Sjdp
176733965Sjdp/* Translate a set of internal symbols into external symbols.  */
176833965Sjdp
176933965Sjdpboolean
177033965SjdpNAME(aout,translate_symbol_table) (abfd, in, ext, count, str, strsize, dynamic)
177133965Sjdp     bfd *abfd;
177233965Sjdp     aout_symbol_type *in;
177333965Sjdp     struct external_nlist *ext;
177433965Sjdp     bfd_size_type count;
177533965Sjdp     char *str;
177633965Sjdp     bfd_size_type strsize;
177733965Sjdp     boolean dynamic;
177833965Sjdp{
177933965Sjdp  struct external_nlist *ext_end;
178033965Sjdp
178133965Sjdp  ext_end = ext + count;
178233965Sjdp  for (; ext < ext_end; ext++, in++)
178333965Sjdp    {
178433965Sjdp      bfd_vma x;
178533965Sjdp
178633965Sjdp      x = GET_WORD (abfd, ext->e_strx);
178733965Sjdp      in->symbol.the_bfd = abfd;
178833965Sjdp
178933965Sjdp      /* For the normal symbols, the zero index points at the number
179033965Sjdp	 of bytes in the string table but is to be interpreted as the
179133965Sjdp	 null string.  For the dynamic symbols, the number of bytes in
179233965Sjdp	 the string table is stored in the __DYNAMIC structure and the
179333965Sjdp	 zero index points at an actual string.  */
179433965Sjdp      if (x == 0 && ! dynamic)
179533965Sjdp	in->symbol.name = "";
179633965Sjdp      else if (x < strsize)
179733965Sjdp	in->symbol.name = str + x;
179833965Sjdp      else
179933965Sjdp	return false;
180033965Sjdp
180133965Sjdp      in->symbol.value = GET_SWORD (abfd,  ext->e_value);
180289857Sobrien      in->desc = H_GET_16 (abfd, ext->e_desc);
180389857Sobrien      in->other = H_GET_8 (abfd, ext->e_other);
180489857Sobrien      in->type = H_GET_8 (abfd,  ext->e_type);
180533965Sjdp      in->symbol.udata.p = NULL;
180633965Sjdp
180733965Sjdp      if (! translate_from_native_sym_flags (abfd, in))
180833965Sjdp	return false;
180933965Sjdp
181033965Sjdp      if (dynamic)
181133965Sjdp	in->symbol.flags |= BSF_DYNAMIC;
181233965Sjdp    }
181333965Sjdp
181433965Sjdp  return true;
181533965Sjdp}
181633965Sjdp
181733965Sjdp/* We read the symbols into a buffer, which is discarded when this
181833965Sjdp   function exits.  We read the strings into a buffer large enough to
181977298Sobrien   hold them all plus all the cached symbol entries.  */
182033965Sjdp
182133965Sjdpboolean
182233965SjdpNAME(aout,slurp_symbol_table) (abfd)
182333965Sjdp     bfd *abfd;
182433965Sjdp{
182533965Sjdp  struct external_nlist *old_external_syms;
182633965Sjdp  aout_symbol_type *cached;
182789857Sobrien  bfd_size_type cached_size;
182833965Sjdp
182933965Sjdp  /* If there's no work to be done, don't do any */
183033965Sjdp  if (obj_aout_symbols (abfd) != (aout_symbol_type *) NULL)
183133965Sjdp    return true;
183233965Sjdp
183333965Sjdp  old_external_syms = obj_aout_external_syms (abfd);
183433965Sjdp
183533965Sjdp  if (! aout_get_external_symbols (abfd))
183633965Sjdp    return false;
183733965Sjdp
183889857Sobrien  cached_size = obj_aout_external_sym_count (abfd);
183989857Sobrien  cached_size *= sizeof (aout_symbol_type);
1840104834Sobrien  cached = (aout_symbol_type *) bfd_zmalloc (cached_size);
184133965Sjdp  if (cached == NULL && cached_size != 0)
184233965Sjdp    return false;
184333965Sjdp
184433965Sjdp  /* Convert from external symbol information to internal.  */
184533965Sjdp  if (! (NAME(aout,translate_symbol_table)
184633965Sjdp	 (abfd, cached,
184733965Sjdp	  obj_aout_external_syms (abfd),
184833965Sjdp	  obj_aout_external_sym_count (abfd),
184933965Sjdp	  obj_aout_external_strings (abfd),
185033965Sjdp	  obj_aout_external_string_size (abfd),
185133965Sjdp	  false)))
185233965Sjdp    {
185333965Sjdp      free (cached);
185433965Sjdp      return false;
185533965Sjdp    }
185633965Sjdp
185733965Sjdp  bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd);
185833965Sjdp
185933965Sjdp  obj_aout_symbols (abfd) = cached;
186033965Sjdp
186133965Sjdp  /* It is very likely that anybody who calls this function will not
186233965Sjdp     want the external symbol information, so if it was allocated
186333965Sjdp     because of our call to aout_get_external_symbols, we free it up
186433965Sjdp     right away to save space.  */
186533965Sjdp  if (old_external_syms == (struct external_nlist *) NULL
186633965Sjdp      && obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
186733965Sjdp    {
186833965Sjdp#ifdef USE_MMAP
186933965Sjdp      bfd_free_window (&obj_aout_sym_window (abfd));
187033965Sjdp#else
187133965Sjdp      free (obj_aout_external_syms (abfd));
187233965Sjdp#endif
187333965Sjdp      obj_aout_external_syms (abfd) = NULL;
187433965Sjdp    }
187533965Sjdp
187633965Sjdp  return true;
187733965Sjdp}
187833965Sjdp
187933965Sjdp/* We use a hash table when writing out symbols so that we only write
188033965Sjdp   out a particular string once.  This helps particularly when the
188133965Sjdp   linker writes out stabs debugging entries, because each different
188233965Sjdp   contributing object file tends to have many duplicate stabs
188333965Sjdp   strings.
188433965Sjdp
188533965Sjdp   This hash table code breaks dbx on SunOS 4.1.3, so we don't do it
188633965Sjdp   if BFD_TRADITIONAL_FORMAT is set.  */
188733965Sjdp
188833965Sjdpstatic bfd_size_type add_to_stringtab
188933965Sjdp  PARAMS ((bfd *, struct bfd_strtab_hash *, const char *, boolean));
189033965Sjdpstatic boolean emit_stringtab PARAMS ((bfd *, struct bfd_strtab_hash *));
189133965Sjdp
189233965Sjdp/* Get the index of a string in a strtab, adding it if it is not
189333965Sjdp   already present.  */
189433965Sjdp
189533965Sjdpstatic INLINE bfd_size_type
189633965Sjdpadd_to_stringtab (abfd, tab, str, copy)
189733965Sjdp     bfd *abfd;
189833965Sjdp     struct bfd_strtab_hash *tab;
189933965Sjdp     const char *str;
190033965Sjdp     boolean copy;
190133965Sjdp{
190233965Sjdp  boolean hash;
190333965Sjdp  bfd_size_type index;
190433965Sjdp
190533965Sjdp  /* An index of 0 always means the empty string.  */
190633965Sjdp  if (str == 0 || *str == '\0')
190733965Sjdp    return 0;
190833965Sjdp
190933965Sjdp  /* Don't hash if BFD_TRADITIONAL_FORMAT is set, because SunOS dbx
191033965Sjdp     doesn't understand a hashed string table.  */
191133965Sjdp  hash = true;
191233965Sjdp  if ((abfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
191333965Sjdp    hash = false;
191433965Sjdp
191533965Sjdp  index = _bfd_stringtab_add (tab, str, hash, copy);
191633965Sjdp
191733965Sjdp  if (index != (bfd_size_type) -1)
191833965Sjdp    {
191933965Sjdp      /* Add BYTES_IN_WORD to the return value to account for the
192033965Sjdp	 space taken up by the string table size.  */
192133965Sjdp      index += BYTES_IN_WORD;
192233965Sjdp    }
192333965Sjdp
192433965Sjdp  return index;
192533965Sjdp}
192633965Sjdp
192733965Sjdp/* Write out a strtab.  ABFD is already at the right location in the
192833965Sjdp   file.  */
192933965Sjdp
193033965Sjdpstatic boolean
193133965Sjdpemit_stringtab (abfd, tab)
193233965Sjdp     register bfd *abfd;
193333965Sjdp     struct bfd_strtab_hash *tab;
193433965Sjdp{
193533965Sjdp  bfd_byte buffer[BYTES_IN_WORD];
193689857Sobrien  bfd_size_type amt = BYTES_IN_WORD;
193733965Sjdp
193833965Sjdp  /* The string table starts with the size.  */
193933965Sjdp  PUT_WORD (abfd, _bfd_stringtab_size (tab) + BYTES_IN_WORD, buffer);
194089857Sobrien  if (bfd_bwrite ((PTR) buffer, amt, abfd) != amt)
194133965Sjdp    return false;
194233965Sjdp
194333965Sjdp  return _bfd_stringtab_emit (abfd, tab);
194433965Sjdp}
194533965Sjdp
194633965Sjdpboolean
194733965SjdpNAME(aout,write_syms) (abfd)
194833965Sjdp     bfd *abfd;
194933965Sjdp{
195033965Sjdp  unsigned int count ;
195133965Sjdp  asymbol **generic = bfd_get_outsymbols (abfd);
195233965Sjdp  struct bfd_strtab_hash *strtab;
195333965Sjdp
195433965Sjdp  strtab = _bfd_stringtab_init ();
195533965Sjdp  if (strtab == NULL)
195633965Sjdp    return false;
195733965Sjdp
195833965Sjdp  for (count = 0; count < bfd_get_symcount (abfd); count++)
195933965Sjdp    {
196033965Sjdp      asymbol *g = generic[count];
196133965Sjdp      bfd_size_type indx;
196233965Sjdp      struct external_nlist nsp;
196389857Sobrien      bfd_size_type amt;
196433965Sjdp
196533965Sjdp      indx = add_to_stringtab (abfd, strtab, g->name, false);
196633965Sjdp      if (indx == (bfd_size_type) -1)
196733965Sjdp	goto error_return;
196833965Sjdp      PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx);
196933965Sjdp
197089857Sobrien      if (bfd_asymbol_flavour (g) == abfd->xvec->flavour)
197133965Sjdp	{
197289857Sobrien	  H_PUT_16 (abfd, aout_symbol (g)->desc,  nsp.e_desc);
197389857Sobrien	  H_PUT_8  (abfd, aout_symbol (g)->other, nsp.e_other);
197489857Sobrien	  H_PUT_8  (abfd, aout_symbol (g)->type,  nsp.e_type);
197533965Sjdp	}
197633965Sjdp      else
197733965Sjdp	{
197889857Sobrien	  H_PUT_16 (abfd, 0, nsp.e_desc);
197989857Sobrien	  H_PUT_8  (abfd, 0, nsp.e_other);
198089857Sobrien	  H_PUT_8  (abfd, 0, nsp.e_type);
198133965Sjdp	}
198233965Sjdp
198333965Sjdp      if (! translate_to_native_sym_flags (abfd, g, &nsp))
198433965Sjdp	goto error_return;
198533965Sjdp
198689857Sobrien      amt = EXTERNAL_NLIST_SIZE;
198789857Sobrien      if (bfd_bwrite ((PTR) &nsp, amt, abfd) != amt)
198833965Sjdp	goto error_return;
198933965Sjdp
199033965Sjdp      /* NB: `KEEPIT' currently overlays `udata.p', so set this only
199133965Sjdp	 here, at the end.  */
199233965Sjdp      g->KEEPIT = count;
199333965Sjdp    }
199433965Sjdp
199533965Sjdp  if (! emit_stringtab (abfd, strtab))
199633965Sjdp    goto error_return;
199733965Sjdp
199833965Sjdp  _bfd_stringtab_free (strtab);
199933965Sjdp
200033965Sjdp  return true;
200133965Sjdp
200233965Sjdperror_return:
200333965Sjdp  _bfd_stringtab_free (strtab);
200433965Sjdp  return false;
200533965Sjdp}
200633965Sjdp
200733965Sjdplong
200833965SjdpNAME(aout,get_symtab) (abfd, location)
200933965Sjdp     bfd *abfd;
201033965Sjdp     asymbol **location;
201133965Sjdp{
201233965Sjdp    unsigned int counter = 0;
201333965Sjdp    aout_symbol_type *symbase;
201433965Sjdp
201577298Sobrien    if (!NAME(aout,slurp_symbol_table) (abfd))
201633965Sjdp      return -1;
201733965Sjdp
201889857Sobrien    for (symbase = obj_aout_symbols (abfd);
201989857Sobrien	 counter++ < bfd_get_symcount (abfd);
202089857Sobrien	 )
202189857Sobrien      *(location++) = (asymbol *) (symbase++);
202233965Sjdp    *location++ =0;
202333965Sjdp    return bfd_get_symcount (abfd);
202433965Sjdp}
202533965Sjdp
202633965Sjdp/* Standard reloc stuff */
202777298Sobrien/* Output standard relocation information to a file in target byte order.  */
202833965Sjdp
202933965Sjdpextern void  NAME(aout,swap_std_reloc_out)
203033965Sjdp  PARAMS ((bfd *, arelent *, struct reloc_std_external *));
203133965Sjdp
203233965Sjdpvoid
203333965SjdpNAME(aout,swap_std_reloc_out) (abfd, g, natptr)
203433965Sjdp     bfd *abfd;
203533965Sjdp     arelent *g;
203633965Sjdp     struct reloc_std_external *natptr;
203733965Sjdp{
203833965Sjdp  int r_index;
203933965Sjdp  asymbol *sym = *(g->sym_ptr_ptr);
204033965Sjdp  int r_extern;
204133965Sjdp  unsigned int r_length;
204233965Sjdp  int r_pcrel;
204333965Sjdp  int r_baserel, r_jmptable, r_relative;
204433965Sjdp  asection *output_section = sym->section->output_section;
204533965Sjdp
204689857Sobrien  PUT_WORD (abfd, g->address, natptr->r_address);
204733965Sjdp
204833965Sjdp  r_length = g->howto->size ;	/* Size as a power of two */
204933965Sjdp  r_pcrel  = (int) g->howto->pc_relative; /* Relative to PC? */
205033965Sjdp  /* XXX This relies on relocs coming from a.out files.  */
205133965Sjdp  r_baserel = (g->howto->type & 8) != 0;
205233965Sjdp  r_jmptable = (g->howto->type & 16) != 0;
205333965Sjdp  r_relative = (g->howto->type & 32) != 0;
205433965Sjdp
205533965Sjdp#if 0
205633965Sjdp  /* For a standard reloc, the addend is in the object file.  */
205733965Sjdp  r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma;
205833965Sjdp#endif
205933965Sjdp
206033965Sjdp  /* name was clobbered by aout_write_syms to be symbol index */
206133965Sjdp
206233965Sjdp  /* If this relocation is relative to a symbol then set the
206333965Sjdp     r_index to the symbols index, and the r_extern bit.
206433965Sjdp
206533965Sjdp     Absolute symbols can come in in two ways, either as an offset
206633965Sjdp     from the abs section, or as a symbol which has an abs value.
206733965Sjdp     check for that here
206833965Sjdp     */
206933965Sjdp
207033965Sjdp  if (bfd_is_com_section (output_section)
207133965Sjdp      || bfd_is_abs_section (output_section)
207233965Sjdp      || bfd_is_und_section (output_section))
207333965Sjdp    {
207433965Sjdp      if (bfd_abs_section_ptr->symbol == sym)
207533965Sjdp      {
207633965Sjdp	/* Whoops, looked like an abs symbol, but is really an offset
207733965Sjdp	   from the abs section */
207833965Sjdp	r_index = N_ABS;
207933965Sjdp	r_extern = 0;
208033965Sjdp       }
208133965Sjdp      else
208233965Sjdp      {
208333965Sjdp	/* Fill in symbol */
208433965Sjdp	r_extern = 1;
208533965Sjdp	r_index = (*(g->sym_ptr_ptr))->KEEPIT;
208633965Sjdp
208733965Sjdp      }
208833965Sjdp    }
208933965Sjdp  else
209033965Sjdp    {
209133965Sjdp      /* Just an ordinary section */
209233965Sjdp      r_extern = 0;
209333965Sjdp      r_index  = output_section->target_index;
209433965Sjdp    }
209533965Sjdp
209633965Sjdp  /* now the fun stuff */
209789857Sobrien  if (bfd_header_big_endian (abfd))
209889857Sobrien    {
209933965Sjdp      natptr->r_index[0] = r_index >> 16;
210033965Sjdp      natptr->r_index[1] = r_index >> 8;
210133965Sjdp      natptr->r_index[2] = r_index;
210289857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
210389857Sobrien			   | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
210489857Sobrien			   | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
210589857Sobrien			   | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
210689857Sobrien			   | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
210789857Sobrien			   | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG));
210889857Sobrien    }
210989857Sobrien  else
211089857Sobrien    {
211189857Sobrien      natptr->r_index[2] = r_index >> 16;
211289857Sobrien      natptr->r_index[1] = r_index >> 8;
211389857Sobrien      natptr->r_index[0] = r_index;
211489857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
211589857Sobrien			   | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
211689857Sobrien			   | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
211789857Sobrien			   | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
211889857Sobrien			   | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
211989857Sobrien			   | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE));
212089857Sobrien    }
212133965Sjdp}
212233965Sjdp
212333965Sjdp/* Extended stuff */
212477298Sobrien/* Output extended relocation information to a file in target byte order.  */
212533965Sjdp
212633965Sjdpextern void NAME(aout,swap_ext_reloc_out)
212733965Sjdp  PARAMS ((bfd *, arelent *, struct reloc_ext_external *));
212833965Sjdp
212933965Sjdpvoid
213033965SjdpNAME(aout,swap_ext_reloc_out) (abfd, g, natptr)
213133965Sjdp     bfd *abfd;
213233965Sjdp     arelent *g;
213333965Sjdp     register struct reloc_ext_external *natptr;
213433965Sjdp{
213533965Sjdp  int r_index;
213633965Sjdp  int r_extern;
213733965Sjdp  unsigned int r_type;
213889857Sobrien  bfd_vma r_addend;
213933965Sjdp  asymbol *sym = *(g->sym_ptr_ptr);
214033965Sjdp  asection *output_section = sym->section->output_section;
214133965Sjdp
214233965Sjdp  PUT_WORD (abfd, g->address, natptr->r_address);
214333965Sjdp
214433965Sjdp  r_type = (unsigned int) g->howto->type;
214533965Sjdp
214633965Sjdp  r_addend = g->addend;
214733965Sjdp  if ((sym->flags & BSF_SECTION_SYM) != 0)
214833965Sjdp    r_addend += (*(g->sym_ptr_ptr))->section->output_section->vma;
214933965Sjdp
215033965Sjdp  /* If this relocation is relative to a symbol then set the
215133965Sjdp     r_index to the symbols index, and the r_extern bit.
215233965Sjdp
215333965Sjdp     Absolute symbols can come in in two ways, either as an offset
215433965Sjdp     from the abs section, or as a symbol which has an abs value.
215533965Sjdp     check for that here.  */
215633965Sjdp
215733965Sjdp  if (bfd_is_abs_section (bfd_get_section (sym)))
215833965Sjdp    {
215933965Sjdp      r_extern = 0;
216033965Sjdp      r_index = N_ABS;
216133965Sjdp    }
216233965Sjdp  else if ((sym->flags & BSF_SECTION_SYM) == 0)
216333965Sjdp    {
216433965Sjdp      if (bfd_is_und_section (bfd_get_section (sym))
216533965Sjdp	  || (sym->flags & BSF_GLOBAL) != 0)
216633965Sjdp	r_extern = 1;
216733965Sjdp      else
216833965Sjdp	r_extern = 0;
216933965Sjdp      r_index = (*(g->sym_ptr_ptr))->KEEPIT;
217033965Sjdp    }
217133965Sjdp  else
217233965Sjdp    {
217333965Sjdp      /* Just an ordinary section */
217433965Sjdp      r_extern = 0;
217533965Sjdp      r_index = output_section->target_index;
217633965Sjdp    }
217733965Sjdp
217833965Sjdp  /* now the fun stuff */
217989857Sobrien  if (bfd_header_big_endian (abfd))
218089857Sobrien    {
218189857Sobrien      natptr->r_index[0] = r_index >> 16;
218289857Sobrien      natptr->r_index[1] = r_index >> 8;
218389857Sobrien      natptr->r_index[2] = r_index;
218489857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
218589857Sobrien			   | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG));
218689857Sobrien    }
218789857Sobrien  else
218889857Sobrien    {
218989857Sobrien      natptr->r_index[2] = r_index >> 16;
219089857Sobrien      natptr->r_index[1] = r_index >> 8;
219189857Sobrien      natptr->r_index[0] = r_index;
219289857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
219389857Sobrien			   | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE));
219489857Sobrien    }
219533965Sjdp
219633965Sjdp  PUT_WORD (abfd, r_addend, natptr->r_addend);
219733965Sjdp}
219833965Sjdp
219933965Sjdp/* BFD deals internally with all things based from the section they're
220033965Sjdp   in. so, something in 10 bytes into a text section  with a base of
220133965Sjdp   50 would have a symbol (.text+10) and know .text vma was 50.
220233965Sjdp
220333965Sjdp   Aout keeps all it's symbols based from zero, so the symbol would
220433965Sjdp   contain 60. This macro subs the base of each section from the value
220589857Sobrien   to give the true offset from the section.  */
220633965Sjdp
220789857Sobrien#define MOVE_ADDRESS(ad)						\
220889857Sobrien  if (r_extern)								\
220989857Sobrien    {									\
221089857Sobrien      /* Undefined symbol.  */						\
221189857Sobrien      cache_ptr->sym_ptr_ptr = symbols + r_index;			\
221233965Sjdp      cache_ptr->addend = ad;						\
221333965Sjdp    }									\
221489857Sobrien   else									\
221589857Sobrien    {									\
221689857Sobrien      /* Defined, section relative.  Replace symbol with pointer to	\
221789857Sobrien	 symbol which points to section.  */				\
221889857Sobrien      switch (r_index)							\
221989857Sobrien	{								\
222089857Sobrien	case N_TEXT:							\
222189857Sobrien	case N_TEXT | N_EXT:						\
222289857Sobrien	  cache_ptr->sym_ptr_ptr = obj_textsec (abfd)->symbol_ptr_ptr;	\
222389857Sobrien	  cache_ptr->addend = ad - su->textsec->vma;			\
222489857Sobrien	  break;							\
222589857Sobrien	case N_DATA:							\
222689857Sobrien	case N_DATA | N_EXT:						\
222789857Sobrien	  cache_ptr->sym_ptr_ptr = obj_datasec (abfd)->symbol_ptr_ptr;	\
222889857Sobrien	  cache_ptr->addend = ad - su->datasec->vma;			\
222989857Sobrien	  break;							\
223089857Sobrien	case N_BSS:							\
223189857Sobrien	case N_BSS | N_EXT:						\
223289857Sobrien	  cache_ptr->sym_ptr_ptr = obj_bsssec (abfd)->symbol_ptr_ptr;	\
223389857Sobrien	  cache_ptr->addend = ad - su->bsssec->vma;			\
223489857Sobrien	  break;							\
223589857Sobrien	default:							\
223689857Sobrien	case N_ABS:							\
223789857Sobrien	case N_ABS | N_EXT:						\
223889857Sobrien	  cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\
223989857Sobrien	  cache_ptr->addend = ad;					\
224089857Sobrien	  break;							\
224189857Sobrien	}								\
224289857Sobrien    }
224333965Sjdp
224433965Sjdpvoid
224533965SjdpNAME(aout,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
224633965Sjdp     bfd *abfd;
224733965Sjdp     struct reloc_ext_external *bytes;
224833965Sjdp     arelent *cache_ptr;
224933965Sjdp     asymbol **symbols;
225033965Sjdp     bfd_size_type symcount;
225133965Sjdp{
225233965Sjdp  unsigned int r_index;
225333965Sjdp  int r_extern;
225433965Sjdp  unsigned int r_type;
225533965Sjdp  struct aoutdata *su = &(abfd->tdata.aout_data->a);
225633965Sjdp
225733965Sjdp  cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
225833965Sjdp
225933965Sjdp  /* now the fun stuff */
226089857Sobrien  if (bfd_header_big_endian (abfd))
226189857Sobrien    {
226289857Sobrien      r_index = ((bytes->r_index[0] << 16)
226389857Sobrien		 | (bytes->r_index[1] << 8)
226489857Sobrien		 | bytes->r_index[2]);
226589857Sobrien      r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
226689857Sobrien      r_type = ((bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
226789857Sobrien		>> RELOC_EXT_BITS_TYPE_SH_BIG);
226889857Sobrien    }
226989857Sobrien  else
227089857Sobrien    {
227189857Sobrien      r_index =  ((bytes->r_index[2] << 16)
227289857Sobrien		  | (bytes->r_index[1] << 8)
227389857Sobrien		  | bytes->r_index[0]);
227489857Sobrien      r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
227589857Sobrien      r_type = ((bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
227689857Sobrien		>> RELOC_EXT_BITS_TYPE_SH_LITTLE);
227789857Sobrien    }
227833965Sjdp
227933965Sjdp  cache_ptr->howto =  howto_table_ext + r_type;
228033965Sjdp
228133965Sjdp  /* Base relative relocs are always against the symbol table,
228233965Sjdp     regardless of the setting of r_extern.  r_extern just reflects
228333965Sjdp     whether the symbol the reloc is against is local or global.  */
228433965Sjdp  if (r_type == RELOC_BASE10
228533965Sjdp      || r_type == RELOC_BASE13
228633965Sjdp      || r_type == RELOC_BASE22)
228733965Sjdp    r_extern = 1;
228833965Sjdp
228933965Sjdp  if (r_extern && r_index > symcount)
229033965Sjdp    {
229133965Sjdp      /* We could arrange to return an error, but it might be useful
229233965Sjdp         to see the file even if it is bad.  */
229333965Sjdp      r_extern = 0;
229433965Sjdp      r_index = N_ABS;
229533965Sjdp    }
229633965Sjdp
229789857Sobrien  MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
229833965Sjdp}
229933965Sjdp
230033965Sjdpvoid
230133965SjdpNAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
230233965Sjdp     bfd *abfd;
230333965Sjdp     struct reloc_std_external *bytes;
230433965Sjdp     arelent *cache_ptr;
230533965Sjdp     asymbol **symbols;
230633965Sjdp     bfd_size_type symcount;
230733965Sjdp{
230833965Sjdp  unsigned int r_index;
230933965Sjdp  int r_extern;
231033965Sjdp  unsigned int r_length;
231133965Sjdp  int r_pcrel;
231233965Sjdp  int r_baserel, r_jmptable, r_relative;
231333965Sjdp  struct aoutdata  *su = &(abfd->tdata.aout_data->a);
231433965Sjdp  unsigned int howto_idx;
231533965Sjdp
231689857Sobrien  cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
231733965Sjdp
231833965Sjdp  /* now the fun stuff */
231989857Sobrien  if (bfd_header_big_endian (abfd))
232089857Sobrien    {
232189857Sobrien      r_index = ((bytes->r_index[0] << 16)
232289857Sobrien		 | (bytes->r_index[1] << 8)
232389857Sobrien		 | bytes->r_index[2]);
232489857Sobrien      r_extern  = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
232589857Sobrien      r_pcrel   = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
232689857Sobrien      r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
232789857Sobrien      r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
232889857Sobrien      r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
232989857Sobrien      r_length  = ((bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
233089857Sobrien		   >> RELOC_STD_BITS_LENGTH_SH_BIG);
233189857Sobrien    }
233289857Sobrien  else
233389857Sobrien    {
233489857Sobrien      r_index = ((bytes->r_index[2] << 16)
233589857Sobrien		 | (bytes->r_index[1] << 8)
233689857Sobrien		 | bytes->r_index[0]);
233789857Sobrien      r_extern  = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
233889857Sobrien      r_pcrel   = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
233989857Sobrien      r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
234089857Sobrien      r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
234189857Sobrien      r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
234289857Sobrien      r_length  = ((bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
234389857Sobrien		   >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
234489857Sobrien    }
234533965Sjdp
234689857Sobrien  howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
234789857Sobrien	       + 16 * r_jmptable + 32 * r_relative);
234833965Sjdp  BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
234933965Sjdp  cache_ptr->howto =  howto_table_std + howto_idx;
235033965Sjdp  BFD_ASSERT (cache_ptr->howto->type != (unsigned int) -1);
235133965Sjdp
235233965Sjdp  /* Base relative relocs are always against the symbol table,
235333965Sjdp     regardless of the setting of r_extern.  r_extern just reflects
235433965Sjdp     whether the symbol the reloc is against is local or global.  */
235533965Sjdp  if (r_baserel)
235633965Sjdp    r_extern = 1;
235733965Sjdp
235833965Sjdp  if (r_extern && r_index > symcount)
235933965Sjdp    {
236033965Sjdp      /* We could arrange to return an error, but it might be useful
236133965Sjdp         to see the file even if it is bad.  */
236233965Sjdp      r_extern = 0;
236333965Sjdp      r_index = N_ABS;
236433965Sjdp    }
236533965Sjdp
236689857Sobrien  MOVE_ADDRESS (0);
236733965Sjdp}
236833965Sjdp
236933965Sjdp/* Read and swap the relocs for a section.  */
237033965Sjdp
237133965Sjdpboolean
237233965SjdpNAME(aout,slurp_reloc_table) (abfd, asect, symbols)
237333965Sjdp     bfd *abfd;
237433965Sjdp     sec_ptr asect;
237533965Sjdp     asymbol **symbols;
237633965Sjdp{
237789857Sobrien  bfd_size_type count;
237833965Sjdp  bfd_size_type reloc_size;
237933965Sjdp  PTR relocs;
238033965Sjdp  arelent *reloc_cache;
238133965Sjdp  size_t each_size;
238233965Sjdp  unsigned int counter = 0;
238333965Sjdp  arelent *cache_ptr;
238489857Sobrien  bfd_size_type amt;
238533965Sjdp
238633965Sjdp  if (asect->relocation)
238733965Sjdp    return true;
238833965Sjdp
238933965Sjdp  if (asect->flags & SEC_CONSTRUCTOR)
239033965Sjdp    return true;
239133965Sjdp
239233965Sjdp  if (asect == obj_datasec (abfd))
239389857Sobrien    reloc_size = exec_hdr (abfd)->a_drsize;
239433965Sjdp  else if (asect == obj_textsec (abfd))
239589857Sobrien    reloc_size = exec_hdr (abfd)->a_trsize;
239633965Sjdp  else if (asect == obj_bsssec (abfd))
239733965Sjdp    reloc_size = 0;
239833965Sjdp  else
239933965Sjdp    {
240033965Sjdp      bfd_set_error (bfd_error_invalid_operation);
240133965Sjdp      return false;
240233965Sjdp    }
240333965Sjdp
240433965Sjdp  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
240533965Sjdp    return false;
240633965Sjdp
240733965Sjdp  each_size = obj_reloc_entry_size (abfd);
240833965Sjdp
240933965Sjdp  count = reloc_size / each_size;
241033965Sjdp
241189857Sobrien  amt = count * sizeof (arelent);
2412104834Sobrien  reloc_cache = (arelent *) bfd_zmalloc (amt);
241333965Sjdp  if (reloc_cache == NULL && count != 0)
241433965Sjdp    return false;
241533965Sjdp
241689857Sobrien  relocs = bfd_malloc (reloc_size);
241733965Sjdp  if (relocs == NULL && reloc_size != 0)
241833965Sjdp    {
241933965Sjdp      free (reloc_cache);
242033965Sjdp      return false;
242133965Sjdp    }
242233965Sjdp
242389857Sobrien  if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
242433965Sjdp    {
242533965Sjdp      free (relocs);
242633965Sjdp      free (reloc_cache);
242733965Sjdp      return false;
242833965Sjdp    }
242933965Sjdp
243033965Sjdp  cache_ptr = reloc_cache;
243133965Sjdp  if (each_size == RELOC_EXT_SIZE)
243233965Sjdp    {
243389857Sobrien      struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
243433965Sjdp
243533965Sjdp      for (; counter < count; counter++, rptr++, cache_ptr++)
243677298Sobrien	MY_swap_ext_reloc_in (abfd, rptr, cache_ptr, symbols,
243789857Sobrien			      (bfd_size_type) bfd_get_symcount (abfd));
243833965Sjdp    }
243933965Sjdp  else
244033965Sjdp    {
244189857Sobrien      struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
244233965Sjdp
244333965Sjdp      for (; counter < count; counter++, rptr++, cache_ptr++)
244433965Sjdp	MY_swap_std_reloc_in (abfd, rptr, cache_ptr, symbols,
244589857Sobrien			      (bfd_size_type) bfd_get_symcount (abfd));
244633965Sjdp    }
244733965Sjdp
244833965Sjdp  free (relocs);
244933965Sjdp
245033965Sjdp  asect->relocation = reloc_cache;
245133965Sjdp  asect->reloc_count = cache_ptr - reloc_cache;
245233965Sjdp
245333965Sjdp  return true;
245433965Sjdp}
245533965Sjdp
245633965Sjdp/* Write out a relocation section into an object file.  */
245733965Sjdp
245833965Sjdpboolean
245933965SjdpNAME(aout,squirt_out_relocs) (abfd, section)
246033965Sjdp     bfd *abfd;
246133965Sjdp     asection *section;
246233965Sjdp{
246333965Sjdp  arelent **generic;
246433965Sjdp  unsigned char *native, *natptr;
246533965Sjdp  size_t each_size;
246633965Sjdp
246733965Sjdp  unsigned int count = section->reloc_count;
246889857Sobrien  bfd_size_type natsize;
246933965Sjdp
247033965Sjdp  if (count == 0 || section->orelocation == NULL)
247133965Sjdp    return true;
247233965Sjdp
247333965Sjdp  each_size = obj_reloc_entry_size (abfd);
247489857Sobrien  natsize = (bfd_size_type) each_size * count;
247533965Sjdp  native = (unsigned char *) bfd_zalloc (abfd, natsize);
247633965Sjdp  if (!native)
247733965Sjdp    return false;
247833965Sjdp
247933965Sjdp  generic = section->orelocation;
248033965Sjdp
248133965Sjdp  if (each_size == RELOC_EXT_SIZE)
248233965Sjdp    {
248333965Sjdp      for (natptr = native;
248433965Sjdp	   count != 0;
248533965Sjdp	   --count, natptr += each_size, ++generic)
248677298Sobrien	MY_swap_ext_reloc_out (abfd, *generic,
248777298Sobrien			       (struct reloc_ext_external *) natptr);
248833965Sjdp    }
248933965Sjdp  else
249033965Sjdp    {
249133965Sjdp      for (natptr = native;
249233965Sjdp	   count != 0;
249333965Sjdp	   --count, natptr += each_size, ++generic)
249489857Sobrien	MY_swap_std_reloc_out (abfd, *generic,
249589857Sobrien			       (struct reloc_std_external *) natptr);
249633965Sjdp    }
249733965Sjdp
249889857Sobrien  if (bfd_bwrite ((PTR) native, natsize, abfd) != natsize)
249989857Sobrien    {
250089857Sobrien      bfd_release (abfd, native);
250189857Sobrien      return false;
250289857Sobrien    }
250333965Sjdp  bfd_release (abfd, native);
250433965Sjdp
250533965Sjdp  return true;
250633965Sjdp}
250733965Sjdp
250833965Sjdp/* This is stupid.  This function should be a boolean predicate */
250933965Sjdplong
251033965SjdpNAME(aout,canonicalize_reloc) (abfd, section, relptr, symbols)
251133965Sjdp     bfd *abfd;
251233965Sjdp     sec_ptr section;
251333965Sjdp     arelent **relptr;
251433965Sjdp     asymbol **symbols;
251533965Sjdp{
251633965Sjdp  arelent *tblptr = section->relocation;
251733965Sjdp  unsigned int count;
251833965Sjdp
251933965Sjdp  if (section == obj_bsssec (abfd))
252033965Sjdp    {
252133965Sjdp      *relptr = NULL;
252233965Sjdp      return 0;
252333965Sjdp    }
252433965Sjdp
252577298Sobrien  if (!(tblptr || NAME(aout,slurp_reloc_table) (abfd, section, symbols)))
252633965Sjdp    return -1;
252733965Sjdp
252889857Sobrien  if (section->flags & SEC_CONSTRUCTOR)
252989857Sobrien    {
253089857Sobrien      arelent_chain *chain = section->constructor_chain;
253189857Sobrien      for (count = 0; count < section->reloc_count; count ++)
253289857Sobrien	{
253389857Sobrien	  *relptr ++ = &chain->relent;
253489857Sobrien	  chain = chain->next;
253589857Sobrien	}
253633965Sjdp    }
253789857Sobrien  else
253889857Sobrien    {
253989857Sobrien      tblptr = section->relocation;
254033965Sjdp
254189857Sobrien      for (count = 0; count++ < section->reloc_count; )
254289857Sobrien	{
254389857Sobrien	  *relptr++ = tblptr++;
254489857Sobrien	}
254589857Sobrien    }
254633965Sjdp  *relptr = 0;
254733965Sjdp
254833965Sjdp  return section->reloc_count;
254933965Sjdp}
255033965Sjdp
255133965Sjdplong
255233965SjdpNAME(aout,get_reloc_upper_bound) (abfd, asect)
255333965Sjdp     bfd *abfd;
255433965Sjdp     sec_ptr asect;
255533965Sjdp{
255689857Sobrien  if (bfd_get_format (abfd) != bfd_object)
255789857Sobrien    {
255889857Sobrien      bfd_set_error (bfd_error_invalid_operation);
255989857Sobrien      return -1;
256089857Sobrien    }
256189857Sobrien  if (asect->flags & SEC_CONSTRUCTOR)
256289857Sobrien    {
256389857Sobrien      return (sizeof (arelent *) * (asect->reloc_count+1));
256489857Sobrien    }
256533965Sjdp
256633965Sjdp  if (asect == obj_datasec (abfd))
256733965Sjdp    return (sizeof (arelent *)
256889857Sobrien	    * ((exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd))
256933965Sjdp	       + 1));
257033965Sjdp
257133965Sjdp  if (asect == obj_textsec (abfd))
257233965Sjdp    return (sizeof (arelent *)
257389857Sobrien	    * ((exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd))
257433965Sjdp	       + 1));
257533965Sjdp
257633965Sjdp  if (asect == obj_bsssec (abfd))
257733965Sjdp    return sizeof (arelent *);
257833965Sjdp
257933965Sjdp  if (asect == obj_bsssec (abfd))
258033965Sjdp    return 0;
258133965Sjdp
258233965Sjdp  bfd_set_error (bfd_error_invalid_operation);
258333965Sjdp  return -1;
258433965Sjdp}
258533965Sjdp
258633965Sjdplong
258733965SjdpNAME(aout,get_symtab_upper_bound) (abfd)
258833965Sjdp     bfd *abfd;
258933965Sjdp{
259077298Sobrien  if (!NAME(aout,slurp_symbol_table) (abfd))
259133965Sjdp    return -1;
259233965Sjdp
259333965Sjdp  return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
259433965Sjdp}
259533965Sjdp
259689857Sobrienalent *
259733965SjdpNAME(aout,get_lineno) (ignore_abfd, ignore_symbol)
259860484Sobrien     bfd *ignore_abfd ATTRIBUTE_UNUSED;
259960484Sobrien     asymbol *ignore_symbol ATTRIBUTE_UNUSED;
260033965Sjdp{
260160484Sobrien  return (alent *)NULL;
260233965Sjdp}
260333965Sjdp
260433965Sjdpvoid
260533965SjdpNAME(aout,get_symbol_info) (ignore_abfd, symbol, ret)
260660484Sobrien     bfd *ignore_abfd ATTRIBUTE_UNUSED;
260733965Sjdp     asymbol *symbol;
260833965Sjdp     symbol_info *ret;
260933965Sjdp{
261033965Sjdp  bfd_symbol_info (symbol, ret);
261133965Sjdp
261233965Sjdp  if (ret->type == '?')
261333965Sjdp    {
261489857Sobrien      int type_code = aout_symbol (symbol)->type & 0xff;
261533965Sjdp      const char *stab_name = bfd_get_stab_name (type_code);
261633965Sjdp      static char buf[10];
261733965Sjdp
261833965Sjdp      if (stab_name == NULL)
261933965Sjdp	{
262077298Sobrien	  sprintf (buf, "(%d)", type_code);
262133965Sjdp	  stab_name = buf;
262233965Sjdp	}
262333965Sjdp      ret->type = '-';
262433965Sjdp      ret->stab_type = type_code;
262589857Sobrien      ret->stab_other = (unsigned) (aout_symbol (symbol)->other & 0xff);
262689857Sobrien      ret->stab_desc = (unsigned) (aout_symbol (symbol)->desc & 0xffff);
262733965Sjdp      ret->stab_name = stab_name;
262833965Sjdp    }
262933965Sjdp}
263033965Sjdp
263133965Sjdpvoid
263289857SobrienNAME(aout,print_symbol) (abfd, afile, symbol, how)
263389857Sobrien     bfd *abfd;
263433965Sjdp     PTR afile;
263533965Sjdp     asymbol *symbol;
263633965Sjdp     bfd_print_symbol_type how;
263733965Sjdp{
263833965Sjdp  FILE *file = (FILE *)afile;
263933965Sjdp
264089857Sobrien  switch (how)
264133965Sjdp    {
264289857Sobrien    case bfd_print_symbol_name:
264389857Sobrien      if (symbol->name)
264489857Sobrien	fprintf (file,"%s", symbol->name);
264589857Sobrien      break;
264689857Sobrien    case bfd_print_symbol_more:
264789857Sobrien      fprintf (file,"%4x %2x %2x",
264889857Sobrien	       (unsigned) (aout_symbol (symbol)->desc & 0xffff),
264989857Sobrien	       (unsigned) (aout_symbol (symbol)->other & 0xff),
265089857Sobrien	       (unsigned) (aout_symbol (symbol)->type));
265189857Sobrien      break;
265289857Sobrien    case bfd_print_symbol_all:
265389857Sobrien      {
265489857Sobrien	const char *section_name = symbol->section->name;
265533965Sjdp
265689857Sobrien	bfd_print_symbol_vandf (abfd, (PTR)file, symbol);
265733965Sjdp
265889857Sobrien	fprintf (file," %-5s %04x %02x %02x",
265989857Sobrien		 section_name,
266089857Sobrien		 (unsigned) (aout_symbol (symbol)->desc & 0xffff),
266189857Sobrien		 (unsigned) (aout_symbol (symbol)->other & 0xff),
266289857Sobrien		 (unsigned) (aout_symbol (symbol)->type & 0xff));
266389857Sobrien	if (symbol->name)
266489857Sobrien	  fprintf (file," %s", symbol->name);
266589857Sobrien      }
266689857Sobrien      break;
266733965Sjdp    }
266833965Sjdp}
266933965Sjdp
267033965Sjdp/* If we don't have to allocate more than 1MB to hold the generic
267133965Sjdp   symbols, we use the generic minisymbol methord: it's faster, since
267233965Sjdp   it only translates the symbols once, not multiple times.  */
267333965Sjdp#define MINISYM_THRESHOLD (1000000 / sizeof (asymbol))
267433965Sjdp
267533965Sjdp/* Read minisymbols.  For minisymbols, we use the unmodified a.out
267633965Sjdp   symbols.  The minisymbol_to_symbol function translates these into
267733965Sjdp   BFD asymbol structures.  */
267833965Sjdp
267933965Sjdplong
268033965SjdpNAME(aout,read_minisymbols) (abfd, dynamic, minisymsp, sizep)
268133965Sjdp     bfd *abfd;
268233965Sjdp     boolean dynamic;
268333965Sjdp     PTR *minisymsp;
268433965Sjdp     unsigned int *sizep;
268533965Sjdp{
268633965Sjdp  if (dynamic)
268733965Sjdp    {
268833965Sjdp      /* We could handle the dynamic symbols here as well, but it's
268933965Sjdp         easier to hand them off.  */
269033965Sjdp      return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
269133965Sjdp    }
269233965Sjdp
269333965Sjdp  if (! aout_get_external_symbols (abfd))
269433965Sjdp    return -1;
269533965Sjdp
269633965Sjdp  if (obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
269733965Sjdp    return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
269833965Sjdp
269933965Sjdp  *minisymsp = (PTR) obj_aout_external_syms (abfd);
270033965Sjdp
270133965Sjdp  /* By passing the external symbols back from this routine, we are
270233965Sjdp     giving up control over the memory block.  Clear
270333965Sjdp     obj_aout_external_syms, so that we do not try to free it
270433965Sjdp     ourselves.  */
270533965Sjdp  obj_aout_external_syms (abfd) = NULL;
270633965Sjdp
270733965Sjdp  *sizep = EXTERNAL_NLIST_SIZE;
270833965Sjdp  return obj_aout_external_sym_count (abfd);
270933965Sjdp}
271033965Sjdp
271133965Sjdp/* Convert a minisymbol to a BFD asymbol.  A minisymbol is just an
271233965Sjdp   unmodified a.out symbol.  The SYM argument is a structure returned
271333965Sjdp   by bfd_make_empty_symbol, which we fill in here.  */
271433965Sjdp
271533965Sjdpasymbol *
271633965SjdpNAME(aout,minisymbol_to_symbol) (abfd, dynamic, minisym, sym)
271733965Sjdp     bfd *abfd;
271833965Sjdp     boolean dynamic;
271933965Sjdp     const PTR minisym;
272033965Sjdp     asymbol *sym;
272133965Sjdp{
272233965Sjdp  if (dynamic
272333965Sjdp      || obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
272433965Sjdp    return _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym);
272533965Sjdp
272633965Sjdp  memset (sym, 0, sizeof (aout_symbol_type));
272733965Sjdp
272833965Sjdp  /* We call translate_symbol_table to translate a single symbol.  */
272933965Sjdp  if (! (NAME(aout,translate_symbol_table)
273033965Sjdp	 (abfd,
273133965Sjdp	  (aout_symbol_type *) sym,
273233965Sjdp	  (struct external_nlist *) minisym,
273333965Sjdp	  (bfd_size_type) 1,
273433965Sjdp	  obj_aout_external_strings (abfd),
273533965Sjdp	  obj_aout_external_string_size (abfd),
273633965Sjdp	  false)))
273733965Sjdp    return NULL;
273833965Sjdp
273933965Sjdp  return sym;
274033965Sjdp}
274133965Sjdp
274233965Sjdp/*
274333965Sjdp provided a BFD, a section and an offset into the section, calculate
274433965Sjdp and return the name of the source file and the line nearest to the
274533965Sjdp wanted location.
274633965Sjdp*/
274733965Sjdp
274833965Sjdpboolean
274933965SjdpNAME(aout,find_nearest_line)
275033965Sjdp     (abfd, section, symbols, offset, filename_ptr, functionname_ptr, line_ptr)
275133965Sjdp     bfd *abfd;
275233965Sjdp     asection *section;
275333965Sjdp     asymbol **symbols;
275433965Sjdp     bfd_vma offset;
275589857Sobrien     const char **filename_ptr;
275689857Sobrien     const char **functionname_ptr;
275733965Sjdp     unsigned int *line_ptr;
275833965Sjdp{
275933965Sjdp  /* Run down the file looking for the filename, function and linenumber */
276033965Sjdp  asymbol **p;
276189857Sobrien  const char *directory_name = NULL;
276289857Sobrien  const char *main_file_name = NULL;
276389857Sobrien  const char *current_file_name = NULL;
276489857Sobrien  const char *line_file_name = NULL; /* Value of current_file_name at line number.  */
276589857Sobrien  const char *line_directory_name = NULL; /* Value of directory_name at line number.  */
276633965Sjdp  bfd_vma low_line_vma = 0;
276733965Sjdp  bfd_vma low_func_vma = 0;
276833965Sjdp  asymbol *func = 0;
276989857Sobrien  bfd_size_type filelen, funclen;
277033965Sjdp  char *buf;
277133965Sjdp
277233965Sjdp  *filename_ptr = abfd->filename;
277333965Sjdp  *functionname_ptr = 0;
277433965Sjdp  *line_ptr = 0;
277589857Sobrien  if (symbols != (asymbol **)NULL)
277689857Sobrien    {
277789857Sobrien      for (p = symbols; *p; p++)
277889857Sobrien	{
277989857Sobrien	  aout_symbol_type  *q = (aout_symbol_type *) (*p);
278089857Sobrien	next:
278189857Sobrien	  switch (q->type)
278289857Sobrien	    {
278389857Sobrien	    case N_TEXT:
278489857Sobrien	      /* If this looks like a file name symbol, and it comes after
278589857Sobrien		 the line number we have found so far, but before the
278689857Sobrien		 offset, then we have probably not found the right line
278789857Sobrien		 number.  */
278889857Sobrien	      if (q->symbol.value <= offset
278989857Sobrien		  && ((q->symbol.value > low_line_vma
279089857Sobrien		       && (line_file_name != NULL
279189857Sobrien			   || *line_ptr != 0))
279289857Sobrien		      || (q->symbol.value > low_func_vma
279389857Sobrien			  && func != NULL)))
279489857Sobrien		{
279589857Sobrien		  const char *symname;
279633965Sjdp
279789857Sobrien		  symname = q->symbol.name;
279889857Sobrien		  if (strcmp (symname + strlen (symname) - 2, ".o") == 0)
279989857Sobrien		    {
280089857Sobrien		      if (q->symbol.value > low_line_vma)
280189857Sobrien			{
280289857Sobrien			  *line_ptr = 0;
280389857Sobrien			  line_file_name = NULL;
280489857Sobrien			}
280589857Sobrien		      if (q->symbol.value > low_func_vma)
280689857Sobrien			func = NULL;
280789857Sobrien		    }
280889857Sobrien		}
280989857Sobrien	      break;
281033965Sjdp
281189857Sobrien	    case N_SO:
281289857Sobrien	      /* If this symbol is less than the offset, but greater than
281389857Sobrien		 the line number we have found so far, then we have not
281489857Sobrien		 found the right line number.  */
281589857Sobrien	      if (q->symbol.value <= offset)
281689857Sobrien		{
281789857Sobrien		  if (q->symbol.value > low_line_vma)
281889857Sobrien		    {
281989857Sobrien		      *line_ptr = 0;
282089857Sobrien		      line_file_name = NULL;
282189857Sobrien		    }
282289857Sobrien		  if (q->symbol.value > low_func_vma)
282389857Sobrien		    func = NULL;
282489857Sobrien		}
282533965Sjdp
282689857Sobrien	      main_file_name = current_file_name = q->symbol.name;
282789857Sobrien	      /* Look ahead to next symbol to check if that too is an N_SO.  */
282889857Sobrien	      p++;
282989857Sobrien	      if (*p == NULL)
283089857Sobrien		break;
283189857Sobrien	      q = (aout_symbol_type *) (*p);
283289857Sobrien	      if (q->type != (int)N_SO)
283389857Sobrien		goto next;
283433965Sjdp
283589857Sobrien	      /* Found a second N_SO  First is directory; second is filename.  */
283689857Sobrien	      directory_name = current_file_name;
283789857Sobrien	      main_file_name = current_file_name = q->symbol.name;
283889857Sobrien	      if (obj_textsec (abfd) != section)
283989857Sobrien		goto done;
284089857Sobrien	      break;
284189857Sobrien	    case N_SOL:
284289857Sobrien	      current_file_name = q->symbol.name;
284389857Sobrien	      break;
284433965Sjdp
284589857Sobrien	    case N_SLINE:
284633965Sjdp
284789857Sobrien	    case N_DSLINE:
284889857Sobrien	    case N_BSLINE:
284989857Sobrien	      /* We'll keep this if it resolves nearer than the one we have
285089857Sobrien		 already.  */
285189857Sobrien	      if (q->symbol.value >= low_line_vma
285289857Sobrien		  && q->symbol.value <= offset)
285389857Sobrien		{
285489857Sobrien		  *line_ptr = q->desc;
285589857Sobrien		  low_line_vma = q->symbol.value;
285689857Sobrien		  line_file_name = current_file_name;
285789857Sobrien		  line_directory_name = directory_name;
285889857Sobrien		}
285989857Sobrien	      break;
286089857Sobrien	    case N_FUN:
286189857Sobrien	      {
286289857Sobrien		/* We'll keep this if it is nearer than the one we have already */
286389857Sobrien		if (q->symbol.value >= low_func_vma &&
286489857Sobrien		    q->symbol.value <= offset) {
286589857Sobrien		  low_func_vma = q->symbol.value;
286689857Sobrien		  func = (asymbol *)q;
286789857Sobrien		}
286889857Sobrien		else if (q->symbol.value > offset)
286989857Sobrien		  goto done;
287089857Sobrien	      }
287189857Sobrien	      break;
287289857Sobrien	    }
287333965Sjdp	}
287433965Sjdp    }
287533965Sjdp
287633965Sjdp done:
287733965Sjdp  if (*line_ptr != 0)
287860484Sobrien    {
287960484Sobrien      main_file_name = line_file_name;
288060484Sobrien      directory_name = line_directory_name;
288160484Sobrien    }
288233965Sjdp
288333965Sjdp  if (main_file_name == NULL
288461843Sobrien      || IS_ABSOLUTE_PATH (main_file_name)
288533965Sjdp      || directory_name == NULL)
288633965Sjdp    filelen = 0;
288733965Sjdp  else
288833965Sjdp    filelen = strlen (directory_name) + strlen (main_file_name);
288933965Sjdp  if (func == NULL)
289033965Sjdp    funclen = 0;
289133965Sjdp  else
289233965Sjdp    funclen = strlen (bfd_asymbol_name (func));
289333965Sjdp
289433965Sjdp  if (adata (abfd).line_buf != NULL)
289533965Sjdp    free (adata (abfd).line_buf);
289633965Sjdp  if (filelen + funclen == 0)
289733965Sjdp    adata (abfd).line_buf = buf = NULL;
289833965Sjdp  else
289933965Sjdp    {
290033965Sjdp      buf = (char *) bfd_malloc (filelen + funclen + 3);
290133965Sjdp      adata (abfd).line_buf = buf;
290233965Sjdp      if (buf == NULL)
290333965Sjdp	return false;
290433965Sjdp    }
290533965Sjdp
290633965Sjdp  if (main_file_name != NULL)
290733965Sjdp    {
290861843Sobrien      if (IS_ABSOLUTE_PATH (main_file_name) || directory_name == NULL)
290933965Sjdp	*filename_ptr = main_file_name;
291033965Sjdp      else
291133965Sjdp	{
291233965Sjdp	  sprintf (buf, "%s%s", directory_name, main_file_name);
291333965Sjdp	  *filename_ptr = buf;
291433965Sjdp	  buf += filelen + 1;
291533965Sjdp	}
291633965Sjdp    }
291733965Sjdp
291833965Sjdp  if (func)
291933965Sjdp    {
292033965Sjdp      const char *function = func->name;
292189857Sobrien      char *colon;
292233965Sjdp
292333965Sjdp      /* The caller expects a symbol name.  We actually have a
292433965Sjdp	 function name, without the leading underscore.  Put the
292533965Sjdp	 underscore back in, so that the caller gets a symbol name.  */
292633965Sjdp      if (bfd_get_symbol_leading_char (abfd) == '\0')
292733965Sjdp	strcpy (buf, function);
292833965Sjdp      else
292933965Sjdp	{
293033965Sjdp	  buf[0] = bfd_get_symbol_leading_char (abfd);
293133965Sjdp	  strcpy (buf + 1, function);
293233965Sjdp	}
293333965Sjdp      /* Have to remove : stuff */
293489857Sobrien      colon = strchr (buf, ':');
293589857Sobrien      if (colon != NULL)
293689857Sobrien	*colon = '\0';
293733965Sjdp      *functionname_ptr = buf;
293833965Sjdp    }
293933965Sjdp
294033965Sjdp  return true;
294133965Sjdp}
294233965Sjdp
294333965Sjdpint
294433965SjdpNAME(aout,sizeof_headers) (abfd, execable)
294533965Sjdp     bfd *abfd;
294660484Sobrien     boolean execable ATTRIBUTE_UNUSED;
294733965Sjdp{
294889857Sobrien  return adata (abfd).exec_bytes_size;
294933965Sjdp}
295033965Sjdp
295133965Sjdp/* Free all information we have cached for this BFD.  We can always
295233965Sjdp   read it again later if we need it.  */
295333965Sjdp
295433965Sjdpboolean
295533965SjdpNAME(aout,bfd_free_cached_info) (abfd)
295633965Sjdp     bfd *abfd;
295733965Sjdp{
295833965Sjdp  asection *o;
295933965Sjdp
296078828Sobrien  if (bfd_get_format (abfd) != bfd_object
296178828Sobrien      || abfd->tdata.aout_data == NULL)
296233965Sjdp    return true;
296333965Sjdp
296433965Sjdp#define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; }
296533965Sjdp  BFCI_FREE (obj_aout_symbols (abfd));
296633965Sjdp#ifdef USE_MMAP
296733965Sjdp  obj_aout_external_syms (abfd) = 0;
296833965Sjdp  bfd_free_window (&obj_aout_sym_window (abfd));
296933965Sjdp  bfd_free_window (&obj_aout_string_window (abfd));
297033965Sjdp  obj_aout_external_strings (abfd) = 0;
297133965Sjdp#else
297233965Sjdp  BFCI_FREE (obj_aout_external_syms (abfd));
297333965Sjdp  BFCI_FREE (obj_aout_external_strings (abfd));
297433965Sjdp#endif
297533965Sjdp  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
297633965Sjdp    BFCI_FREE (o->relocation);
297733965Sjdp#undef BFCI_FREE
297833965Sjdp
297933965Sjdp  return true;
298033965Sjdp}
298133965Sjdp
298233965Sjdp/* a.out link code.  */
298333965Sjdp
298433965Sjdpstatic boolean aout_link_add_object_symbols
298533965Sjdp  PARAMS ((bfd *, struct bfd_link_info *));
298633965Sjdpstatic boolean aout_link_check_archive_element
298733965Sjdp  PARAMS ((bfd *, struct bfd_link_info *, boolean *));
298833965Sjdpstatic boolean aout_link_free_symbols PARAMS ((bfd *));
298933965Sjdpstatic boolean aout_link_check_ar_symbols
299033965Sjdp  PARAMS ((bfd *, struct bfd_link_info *, boolean *pneeded));
299133965Sjdpstatic boolean aout_link_add_symbols
299233965Sjdp  PARAMS ((bfd *, struct bfd_link_info *));
299333965Sjdp
299433965Sjdp/* Routine to create an entry in an a.out link hash table.  */
299533965Sjdp
299633965Sjdpstruct bfd_hash_entry *
299733965SjdpNAME(aout,link_hash_newfunc) (entry, table, string)
299833965Sjdp     struct bfd_hash_entry *entry;
299933965Sjdp     struct bfd_hash_table *table;
300033965Sjdp     const char *string;
300133965Sjdp{
300233965Sjdp  struct aout_link_hash_entry *ret = (struct aout_link_hash_entry *) entry;
300333965Sjdp
300433965Sjdp  /* Allocate the structure if it has not already been allocated by a
300533965Sjdp     subclass.  */
300633965Sjdp  if (ret == (struct aout_link_hash_entry *) NULL)
300733965Sjdp    ret = ((struct aout_link_hash_entry *)
300833965Sjdp	   bfd_hash_allocate (table, sizeof (struct aout_link_hash_entry)));
300933965Sjdp  if (ret == (struct aout_link_hash_entry *) NULL)
301033965Sjdp    return (struct bfd_hash_entry *) ret;
301133965Sjdp
301233965Sjdp  /* Call the allocation method of the superclass.  */
301333965Sjdp  ret = ((struct aout_link_hash_entry *)
301433965Sjdp	 _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
301533965Sjdp				 table, string));
301633965Sjdp  if (ret)
301733965Sjdp    {
301833965Sjdp      /* Set local fields.  */
301933965Sjdp      ret->written = false;
302033965Sjdp      ret->indx = -1;
302133965Sjdp    }
302233965Sjdp
302333965Sjdp  return (struct bfd_hash_entry *) ret;
302433965Sjdp}
302533965Sjdp
302633965Sjdp/* Initialize an a.out link hash table.  */
302733965Sjdp
302833965Sjdpboolean
302933965SjdpNAME(aout,link_hash_table_init) (table, abfd, newfunc)
303033965Sjdp     struct aout_link_hash_table *table;
303133965Sjdp     bfd *abfd;
303233965Sjdp     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
303333965Sjdp						struct bfd_hash_table *,
303433965Sjdp						const char *));
303533965Sjdp{
303633965Sjdp  return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
303733965Sjdp}
303833965Sjdp
303933965Sjdp/* Create an a.out link hash table.  */
304033965Sjdp
304133965Sjdpstruct bfd_link_hash_table *
304233965SjdpNAME(aout,link_hash_table_create) (abfd)
304333965Sjdp     bfd *abfd;
304433965Sjdp{
304533965Sjdp  struct aout_link_hash_table *ret;
304689857Sobrien  bfd_size_type amt = sizeof (struct aout_link_hash_table);
304733965Sjdp
304889857Sobrien  ret = (struct aout_link_hash_table *) bfd_alloc (abfd, amt);
304933965Sjdp  if (ret == NULL)
305033965Sjdp    return (struct bfd_link_hash_table *) NULL;
305133965Sjdp  if (! NAME(aout,link_hash_table_init) (ret, abfd,
305233965Sjdp					 NAME(aout,link_hash_newfunc)))
305333965Sjdp    {
305433965Sjdp      free (ret);
305533965Sjdp      return (struct bfd_link_hash_table *) NULL;
305633965Sjdp    }
305733965Sjdp  return &ret->root;
305833965Sjdp}
305933965Sjdp
306033965Sjdp/* Given an a.out BFD, add symbols to the global hash table as
306133965Sjdp   appropriate.  */
306233965Sjdp
306333965Sjdpboolean
306433965SjdpNAME(aout,link_add_symbols) (abfd, info)
306533965Sjdp     bfd *abfd;
306633965Sjdp     struct bfd_link_info *info;
306733965Sjdp{
306833965Sjdp  switch (bfd_get_format (abfd))
306933965Sjdp    {
307033965Sjdp    case bfd_object:
307133965Sjdp      return aout_link_add_object_symbols (abfd, info);
307233965Sjdp    case bfd_archive:
307333965Sjdp      return _bfd_generic_link_add_archive_symbols
307433965Sjdp	(abfd, info, aout_link_check_archive_element);
307533965Sjdp    default:
307633965Sjdp      bfd_set_error (bfd_error_wrong_format);
307733965Sjdp      return false;
307833965Sjdp    }
307933965Sjdp}
308033965Sjdp
308133965Sjdp/* Add symbols from an a.out object file.  */
308233965Sjdp
308333965Sjdpstatic boolean
308433965Sjdpaout_link_add_object_symbols (abfd, info)
308533965Sjdp     bfd *abfd;
308633965Sjdp     struct bfd_link_info *info;
308733965Sjdp{
308833965Sjdp  if (! aout_get_external_symbols (abfd))
308933965Sjdp    return false;
309033965Sjdp  if (! aout_link_add_symbols (abfd, info))
309133965Sjdp    return false;
309233965Sjdp  if (! info->keep_memory)
309333965Sjdp    {
309433965Sjdp      if (! aout_link_free_symbols (abfd))
309533965Sjdp	return false;
309633965Sjdp    }
309733965Sjdp  return true;
309833965Sjdp}
309933965Sjdp
310033965Sjdp/* Check a single archive element to see if we need to include it in
310133965Sjdp   the link.  *PNEEDED is set according to whether this element is
310233965Sjdp   needed in the link or not.  This is called from
310333965Sjdp   _bfd_generic_link_add_archive_symbols.  */
310433965Sjdp
310533965Sjdpstatic boolean
310633965Sjdpaout_link_check_archive_element (abfd, info, pneeded)
310733965Sjdp     bfd *abfd;
310833965Sjdp     struct bfd_link_info *info;
310933965Sjdp     boolean *pneeded;
311033965Sjdp{
311133965Sjdp  if (! aout_get_external_symbols (abfd))
311233965Sjdp    return false;
311333965Sjdp
311433965Sjdp  if (! aout_link_check_ar_symbols (abfd, info, pneeded))
311533965Sjdp    return false;
311633965Sjdp
311733965Sjdp  if (*pneeded)
311833965Sjdp    {
311933965Sjdp      if (! aout_link_add_symbols (abfd, info))
312033965Sjdp	return false;
312133965Sjdp    }
312233965Sjdp
312333965Sjdp  if (! info->keep_memory || ! *pneeded)
312433965Sjdp    {
312533965Sjdp      if (! aout_link_free_symbols (abfd))
312633965Sjdp	return false;
312733965Sjdp    }
312833965Sjdp
312933965Sjdp  return true;
313033965Sjdp}
313133965Sjdp
313233965Sjdp/* Free up the internal symbols read from an a.out file.  */
313333965Sjdp
313433965Sjdpstatic boolean
313533965Sjdpaout_link_free_symbols (abfd)
313633965Sjdp     bfd *abfd;
313733965Sjdp{
313833965Sjdp  if (obj_aout_external_syms (abfd) != (struct external_nlist *) NULL)
313933965Sjdp    {
314033965Sjdp#ifdef USE_MMAP
314133965Sjdp      bfd_free_window (&obj_aout_sym_window (abfd));
314233965Sjdp#else
314333965Sjdp      free ((PTR) obj_aout_external_syms (abfd));
314433965Sjdp#endif
314533965Sjdp      obj_aout_external_syms (abfd) = (struct external_nlist *) NULL;
314633965Sjdp    }
314733965Sjdp  if (obj_aout_external_strings (abfd) != (char *) NULL)
314833965Sjdp    {
314933965Sjdp#ifdef USE_MMAP
315033965Sjdp      bfd_free_window (&obj_aout_string_window (abfd));
315133965Sjdp#else
315233965Sjdp      free ((PTR) obj_aout_external_strings (abfd));
315333965Sjdp#endif
315433965Sjdp      obj_aout_external_strings (abfd) = (char *) NULL;
315533965Sjdp    }
315633965Sjdp  return true;
315733965Sjdp}
315833965Sjdp
315933965Sjdp/* Look through the internal symbols to see if this object file should
316033965Sjdp   be included in the link.  We should include this object file if it
316133965Sjdp   defines any symbols which are currently undefined.  If this object
316233965Sjdp   file defines a common symbol, then we may adjust the size of the
316333965Sjdp   known symbol but we do not include the object file in the link
316433965Sjdp   (unless there is some other reason to include it).  */
316533965Sjdp
316633965Sjdpstatic boolean
316733965Sjdpaout_link_check_ar_symbols (abfd, info, pneeded)
316833965Sjdp     bfd *abfd;
316933965Sjdp     struct bfd_link_info *info;
317033965Sjdp     boolean *pneeded;
317133965Sjdp{
317233965Sjdp  register struct external_nlist *p;
317333965Sjdp  struct external_nlist *pend;
317433965Sjdp  char *strings;
317533965Sjdp
317633965Sjdp  *pneeded = false;
317733965Sjdp
317833965Sjdp  /* Look through all the symbols.  */
317933965Sjdp  p = obj_aout_external_syms (abfd);
318033965Sjdp  pend = p + obj_aout_external_sym_count (abfd);
318133965Sjdp  strings = obj_aout_external_strings (abfd);
318233965Sjdp  for (; p < pend; p++)
318333965Sjdp    {
318489857Sobrien      int type = H_GET_8 (abfd, p->e_type);
318533965Sjdp      const char *name;
318633965Sjdp      struct bfd_link_hash_entry *h;
318733965Sjdp
318833965Sjdp      /* Ignore symbols that are not externally visible.  This is an
318933965Sjdp	 optimization only, as we check the type more thoroughly
319033965Sjdp	 below.  */
319133965Sjdp      if (((type & N_EXT) == 0
319233965Sjdp	   || (type & N_STAB) != 0
319333965Sjdp	   || type == N_FN)
319433965Sjdp	  && type != N_WEAKA
319533965Sjdp	  && type != N_WEAKT
319633965Sjdp	  && type != N_WEAKD
319733965Sjdp	  && type != N_WEAKB)
319833965Sjdp	{
319933965Sjdp	  if (type == N_WARNING
320033965Sjdp	      || type == N_INDR)
320133965Sjdp	    ++p;
320233965Sjdp	  continue;
320333965Sjdp	}
320433965Sjdp
320533965Sjdp      name = strings + GET_WORD (abfd, p->e_strx);
320633965Sjdp      h = bfd_link_hash_lookup (info->hash, name, false, false, true);
320733965Sjdp
320833965Sjdp      /* We are only interested in symbols that are currently
320933965Sjdp	 undefined or common.  */
321033965Sjdp      if (h == (struct bfd_link_hash_entry *) NULL
321133965Sjdp	  || (h->type != bfd_link_hash_undefined
321233965Sjdp	      && h->type != bfd_link_hash_common))
321333965Sjdp	{
321433965Sjdp	  if (type == (N_INDR | N_EXT))
321533965Sjdp	    ++p;
321633965Sjdp	  continue;
321733965Sjdp	}
321833965Sjdp
321933965Sjdp      if (type == (N_TEXT | N_EXT)
322033965Sjdp	  || type == (N_DATA | N_EXT)
322133965Sjdp	  || type == (N_BSS | N_EXT)
322233965Sjdp	  || type == (N_ABS | N_EXT)
322333965Sjdp	  || type == (N_INDR | N_EXT))
322433965Sjdp	{
322533965Sjdp	  /* This object file defines this symbol.  We must link it
322633965Sjdp	     in.  This is true regardless of whether the current
322733965Sjdp	     definition of the symbol is undefined or common.  If the
322833965Sjdp	     current definition is common, we have a case in which we
322933965Sjdp	     have already seen an object file including
323033965Sjdp	         int a;
323133965Sjdp	     and this object file from the archive includes
323233965Sjdp	         int a = 5;
323333965Sjdp	     In such a case we must include this object file.
323433965Sjdp
323533965Sjdp	     FIXME: The SunOS 4.1.3 linker will pull in the archive
323633965Sjdp	     element if the symbol is defined in the .data section,
323733965Sjdp	     but not if it is defined in the .text section.  That
323833965Sjdp	     seems a bit crazy to me, and I haven't implemented it.
323933965Sjdp	     However, it might be correct.  */
324033965Sjdp	  if (! (*info->callbacks->add_archive_element) (info, abfd, name))
324133965Sjdp	    return false;
324233965Sjdp	  *pneeded = true;
324333965Sjdp	  return true;
324433965Sjdp	}
324533965Sjdp
324633965Sjdp      if (type == (N_UNDF | N_EXT))
324733965Sjdp	{
324833965Sjdp	  bfd_vma value;
324933965Sjdp
325033965Sjdp	  value = GET_WORD (abfd, p->e_value);
325133965Sjdp	  if (value != 0)
325233965Sjdp	    {
325333965Sjdp	      /* This symbol is common in the object from the archive
325433965Sjdp		 file.  */
325533965Sjdp	      if (h->type == bfd_link_hash_undefined)
325633965Sjdp		{
325733965Sjdp		  bfd *symbfd;
325833965Sjdp		  unsigned int power;
325933965Sjdp
326033965Sjdp		  symbfd = h->u.undef.abfd;
326133965Sjdp		  if (symbfd == (bfd *) NULL)
326233965Sjdp		    {
326333965Sjdp		      /* This symbol was created as undefined from
326433965Sjdp			 outside BFD.  We assume that we should link
326533965Sjdp			 in the object file.  This is done for the -u
326633965Sjdp			 option in the linker.  */
326733965Sjdp		      if (! (*info->callbacks->add_archive_element) (info,
326833965Sjdp								     abfd,
326933965Sjdp								     name))
327033965Sjdp			return false;
327133965Sjdp		      *pneeded = true;
327233965Sjdp		      return true;
327333965Sjdp		    }
327433965Sjdp		  /* Turn the current link symbol into a common
327533965Sjdp		     symbol.  It is already on the undefs list.  */
327633965Sjdp		  h->type = bfd_link_hash_common;
327733965Sjdp		  h->u.c.p = ((struct bfd_link_hash_common_entry *)
327833965Sjdp			      bfd_hash_allocate (&info->hash->table,
327933965Sjdp				  sizeof (struct bfd_link_hash_common_entry)));
328033965Sjdp		  if (h->u.c.p == NULL)
328133965Sjdp		    return false;
328233965Sjdp
328333965Sjdp		  h->u.c.size = value;
328433965Sjdp
328533965Sjdp		  /* FIXME: This isn't quite right.  The maximum
328633965Sjdp		     alignment of a common symbol should be set by the
328733965Sjdp		     architecture of the output file, not of the input
328833965Sjdp		     file.  */
328933965Sjdp		  power = bfd_log2 (value);
329033965Sjdp		  if (power > bfd_get_arch_info (abfd)->section_align_power)
329133965Sjdp		    power = bfd_get_arch_info (abfd)->section_align_power;
329233965Sjdp		  h->u.c.p->alignment_power = power;
329333965Sjdp
329433965Sjdp		  h->u.c.p->section = bfd_make_section_old_way (symbfd,
329533965Sjdp								"COMMON");
329633965Sjdp		}
329733965Sjdp	      else
329833965Sjdp		{
329933965Sjdp		  /* Adjust the size of the common symbol if
330033965Sjdp		     necessary.  */
330133965Sjdp		  if (value > h->u.c.size)
330233965Sjdp		    h->u.c.size = value;
330333965Sjdp		}
330433965Sjdp	    }
330533965Sjdp	}
330633965Sjdp
330733965Sjdp      if (type == N_WEAKA
330833965Sjdp	  || type == N_WEAKT
330933965Sjdp	  || type == N_WEAKD
331033965Sjdp	  || type == N_WEAKB)
331133965Sjdp	{
331233965Sjdp	  /* This symbol is weak but defined.  We must pull it in if
331333965Sjdp	     the current link symbol is undefined, but we don't want
331433965Sjdp	     it if the current link symbol is common.  */
331533965Sjdp	  if (h->type == bfd_link_hash_undefined)
331633965Sjdp	    {
331733965Sjdp	      if (! (*info->callbacks->add_archive_element) (info, abfd, name))
331833965Sjdp		return false;
331933965Sjdp	      *pneeded = true;
332033965Sjdp	      return true;
332133965Sjdp	    }
332233965Sjdp	}
332333965Sjdp    }
332433965Sjdp
332533965Sjdp  /* We do not need this object file.  */
332633965Sjdp  return true;
332733965Sjdp}
332833965Sjdp
332933965Sjdp/* Add all symbols from an object file to the hash table.  */
333033965Sjdp
333133965Sjdpstatic boolean
333233965Sjdpaout_link_add_symbols (abfd, info)
333333965Sjdp     bfd *abfd;
333433965Sjdp     struct bfd_link_info *info;
333533965Sjdp{
333633965Sjdp  boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *,
333733965Sjdp				     const char *, flagword, asection *,
333833965Sjdp				     bfd_vma, const char *, boolean,
333933965Sjdp				     boolean,
334033965Sjdp				     struct bfd_link_hash_entry **));
334133965Sjdp  struct external_nlist *syms;
334233965Sjdp  bfd_size_type sym_count;
334333965Sjdp  char *strings;
334433965Sjdp  boolean copy;
334533965Sjdp  struct aout_link_hash_entry **sym_hash;
334633965Sjdp  register struct external_nlist *p;
334733965Sjdp  struct external_nlist *pend;
334889857Sobrien  bfd_size_type amt;
334933965Sjdp
335033965Sjdp  syms = obj_aout_external_syms (abfd);
335133965Sjdp  sym_count = obj_aout_external_sym_count (abfd);
335233965Sjdp  strings = obj_aout_external_strings (abfd);
335333965Sjdp  if (info->keep_memory)
335433965Sjdp    copy = false;
335533965Sjdp  else
335633965Sjdp    copy = true;
335733965Sjdp
335833965Sjdp  if (aout_backend_info (abfd)->add_dynamic_symbols != NULL)
335933965Sjdp    {
336033965Sjdp      if (! ((*aout_backend_info (abfd)->add_dynamic_symbols)
336133965Sjdp	     (abfd, info, &syms, &sym_count, &strings)))
336233965Sjdp	return false;
336333965Sjdp    }
336433965Sjdp
336533965Sjdp  /* We keep a list of the linker hash table entries that correspond
336633965Sjdp     to particular symbols.  We could just look them up in the hash
336733965Sjdp     table, but keeping the list is more efficient.  Perhaps this
336833965Sjdp     should be conditional on info->keep_memory.  */
336989857Sobrien  amt = sym_count * sizeof (struct aout_link_hash_entry *);
337089857Sobrien  sym_hash = (struct aout_link_hash_entry **) bfd_alloc (abfd, amt);
337133965Sjdp  if (sym_hash == NULL && sym_count != 0)
337233965Sjdp    return false;
337333965Sjdp  obj_aout_sym_hashes (abfd) = sym_hash;
337433965Sjdp
337533965Sjdp  add_one_symbol = aout_backend_info (abfd)->add_one_symbol;
337633965Sjdp  if (add_one_symbol == NULL)
337733965Sjdp    add_one_symbol = _bfd_generic_link_add_one_symbol;
337833965Sjdp
337933965Sjdp  p = syms;
338033965Sjdp  pend = p + sym_count;
338133965Sjdp  for (; p < pend; p++, sym_hash++)
338233965Sjdp    {
338333965Sjdp      int type;
338433965Sjdp      const char *name;
338533965Sjdp      bfd_vma value;
338633965Sjdp      asection *section;
338733965Sjdp      flagword flags;
338833965Sjdp      const char *string;
338933965Sjdp
339033965Sjdp      *sym_hash = NULL;
339133965Sjdp
339289857Sobrien      type = H_GET_8 (abfd, p->e_type);
339333965Sjdp
339433965Sjdp      /* Ignore debugging symbols.  */
339533965Sjdp      if ((type & N_STAB) != 0)
339633965Sjdp	continue;
339733965Sjdp
339833965Sjdp      name = strings + GET_WORD (abfd, p->e_strx);
339933965Sjdp      value = GET_WORD (abfd, p->e_value);
340033965Sjdp      flags = BSF_GLOBAL;
340133965Sjdp      string = NULL;
340233965Sjdp      switch (type)
340333965Sjdp	{
340433965Sjdp	default:
340533965Sjdp	  abort ();
340633965Sjdp
340733965Sjdp	case N_UNDF:
340833965Sjdp	case N_ABS:
340933965Sjdp	case N_TEXT:
341033965Sjdp	case N_DATA:
341133965Sjdp	case N_BSS:
341233965Sjdp	case N_FN_SEQ:
341333965Sjdp	case N_COMM:
341433965Sjdp	case N_SETV:
341533965Sjdp	case N_FN:
341633965Sjdp	  /* Ignore symbols that are not externally visible.  */
341733965Sjdp	  continue;
341833965Sjdp	case N_INDR:
341933965Sjdp	  /* Ignore local indirect symbol.  */
342033965Sjdp	  ++p;
342133965Sjdp	  ++sym_hash;
342233965Sjdp	  continue;
342333965Sjdp
342433965Sjdp	case N_UNDF | N_EXT:
342533965Sjdp	  if (value == 0)
342633965Sjdp	    {
342733965Sjdp	      section = bfd_und_section_ptr;
342833965Sjdp	      flags = 0;
342933965Sjdp	    }
343033965Sjdp	  else
343133965Sjdp	    section = bfd_com_section_ptr;
343233965Sjdp	  break;
343333965Sjdp	case N_ABS | N_EXT:
343433965Sjdp	  section = bfd_abs_section_ptr;
343533965Sjdp	  break;
343633965Sjdp	case N_TEXT | N_EXT:
343733965Sjdp	  section = obj_textsec (abfd);
343833965Sjdp	  value -= bfd_get_section_vma (abfd, section);
343933965Sjdp	  break;
344033965Sjdp	case N_DATA | N_EXT:
344133965Sjdp	case N_SETV | N_EXT:
344233965Sjdp	  /* Treat N_SETV symbols as N_DATA symbol; see comment in
344333965Sjdp	     translate_from_native_sym_flags.  */
344433965Sjdp	  section = obj_datasec (abfd);
344533965Sjdp	  value -= bfd_get_section_vma (abfd, section);
344633965Sjdp	  break;
344733965Sjdp	case N_BSS | N_EXT:
344833965Sjdp	  section = obj_bsssec (abfd);
344933965Sjdp	  value -= bfd_get_section_vma (abfd, section);
345033965Sjdp	  break;
345133965Sjdp	case N_INDR | N_EXT:
345233965Sjdp	  /* An indirect symbol.  The next symbol is the symbol
345333965Sjdp	     which this one really is.  */
345433965Sjdp	  BFD_ASSERT (p + 1 < pend);
345533965Sjdp	  ++p;
345633965Sjdp	  string = strings + GET_WORD (abfd, p->e_strx);
345733965Sjdp	  section = bfd_ind_section_ptr;
345833965Sjdp	  flags |= BSF_INDIRECT;
345933965Sjdp	  break;
346033965Sjdp	case N_COMM | N_EXT:
346133965Sjdp	  section = bfd_com_section_ptr;
346233965Sjdp	  break;
346333965Sjdp	case N_SETA: case N_SETA | N_EXT:
346433965Sjdp	  section = bfd_abs_section_ptr;
346533965Sjdp	  flags |= BSF_CONSTRUCTOR;
346633965Sjdp	  break;
346733965Sjdp	case N_SETT: case N_SETT | N_EXT:
346833965Sjdp	  section = obj_textsec (abfd);
346933965Sjdp	  flags |= BSF_CONSTRUCTOR;
347033965Sjdp	  value -= bfd_get_section_vma (abfd, section);
347133965Sjdp	  break;
347233965Sjdp	case N_SETD: case N_SETD | N_EXT:
347333965Sjdp	  section = obj_datasec (abfd);
347433965Sjdp	  flags |= BSF_CONSTRUCTOR;
347533965Sjdp	  value -= bfd_get_section_vma (abfd, section);
347633965Sjdp	  break;
347733965Sjdp	case N_SETB: case N_SETB | N_EXT:
347833965Sjdp	  section = obj_bsssec (abfd);
347933965Sjdp	  flags |= BSF_CONSTRUCTOR;
348033965Sjdp	  value -= bfd_get_section_vma (abfd, section);
348133965Sjdp	  break;
348233965Sjdp	case N_WARNING:
348333965Sjdp	  /* A warning symbol.  The next symbol is the one to warn
348433965Sjdp	     about.  */
348533965Sjdp	  BFD_ASSERT (p + 1 < pend);
348633965Sjdp	  ++p;
348733965Sjdp	  string = name;
348833965Sjdp	  name = strings + GET_WORD (abfd, p->e_strx);
348933965Sjdp	  section = bfd_und_section_ptr;
349033965Sjdp	  flags |= BSF_WARNING;
349133965Sjdp	  break;
349233965Sjdp	case N_WEAKU:
349333965Sjdp	  section = bfd_und_section_ptr;
349433965Sjdp	  flags = BSF_WEAK;
349533965Sjdp	  break;
349633965Sjdp	case N_WEAKA:
349733965Sjdp	  section = bfd_abs_section_ptr;
349833965Sjdp	  flags = BSF_WEAK;
349933965Sjdp	  break;
350033965Sjdp	case N_WEAKT:
350133965Sjdp	  section = obj_textsec (abfd);
350233965Sjdp	  value -= bfd_get_section_vma (abfd, section);
350333965Sjdp	  flags = BSF_WEAK;
350433965Sjdp	  break;
350533965Sjdp	case N_WEAKD:
350633965Sjdp	  section = obj_datasec (abfd);
350733965Sjdp	  value -= bfd_get_section_vma (abfd, section);
350833965Sjdp	  flags = BSF_WEAK;
350933965Sjdp	  break;
351033965Sjdp	case N_WEAKB:
351133965Sjdp	  section = obj_bsssec (abfd);
351233965Sjdp	  value -= bfd_get_section_vma (abfd, section);
351333965Sjdp	  flags = BSF_WEAK;
351433965Sjdp	  break;
351533965Sjdp	}
351633965Sjdp
351733965Sjdp      if (! ((*add_one_symbol)
351833965Sjdp	     (info, abfd, name, flags, section, value, string, copy, false,
351933965Sjdp	      (struct bfd_link_hash_entry **) sym_hash)))
352033965Sjdp	return false;
352133965Sjdp
352233965Sjdp      /* Restrict the maximum alignment of a common symbol based on
352333965Sjdp	 the architecture, since a.out has no way to represent
352433965Sjdp	 alignment requirements of a section in a .o file.  FIXME:
352533965Sjdp	 This isn't quite right: it should use the architecture of the
352633965Sjdp	 output file, not the input files.  */
352733965Sjdp      if ((*sym_hash)->root.type == bfd_link_hash_common
352833965Sjdp	  && ((*sym_hash)->root.u.c.p->alignment_power >
352933965Sjdp	      bfd_get_arch_info (abfd)->section_align_power))
353033965Sjdp	(*sym_hash)->root.u.c.p->alignment_power =
353133965Sjdp	  bfd_get_arch_info (abfd)->section_align_power;
353233965Sjdp
353333965Sjdp      /* If this is a set symbol, and we are not building sets, then
353433965Sjdp	 it is possible for the hash entry to not have been set.  In
353533965Sjdp	 such a case, treat the symbol as not globally defined.  */
353633965Sjdp      if ((*sym_hash)->root.type == bfd_link_hash_new)
353733965Sjdp	{
353833965Sjdp	  BFD_ASSERT ((flags & BSF_CONSTRUCTOR) != 0);
353933965Sjdp	  *sym_hash = NULL;
354033965Sjdp	}
354133965Sjdp
354233965Sjdp      if (type == (N_INDR | N_EXT) || type == N_WARNING)
354333965Sjdp	++sym_hash;
354433965Sjdp    }
354533965Sjdp
354633965Sjdp  return true;
354733965Sjdp}
354833965Sjdp
354933965Sjdp/* A hash table used for header files with N_BINCL entries.  */
355033965Sjdp
355133965Sjdpstruct aout_link_includes_table
355233965Sjdp{
355333965Sjdp  struct bfd_hash_table root;
355433965Sjdp};
355533965Sjdp
355633965Sjdp/* A linked list of totals that we have found for a particular header
355733965Sjdp   file.  */
355833965Sjdp
355933965Sjdpstruct aout_link_includes_totals
356033965Sjdp{
356133965Sjdp  struct aout_link_includes_totals *next;
356233965Sjdp  bfd_vma total;
356333965Sjdp};
356433965Sjdp
356533965Sjdp/* An entry in the header file hash table.  */
356633965Sjdp
356733965Sjdpstruct aout_link_includes_entry
356833965Sjdp{
356933965Sjdp  struct bfd_hash_entry root;
357033965Sjdp  /* List of totals we have found for this file.  */
357133965Sjdp  struct aout_link_includes_totals *totals;
357233965Sjdp};
357333965Sjdp
357433965Sjdp/* Look up an entry in an the header file hash table.  */
357533965Sjdp
357689857Sobrien#define aout_link_includes_lookup(table, string, create, copy)		\
357789857Sobrien  ((struct aout_link_includes_entry *)					\
357833965Sjdp   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
357933965Sjdp
358033965Sjdp/* During the final link step we need to pass around a bunch of
358133965Sjdp   information, so we do it in an instance of this structure.  */
358233965Sjdp
358333965Sjdpstruct aout_final_link_info
358433965Sjdp{
358533965Sjdp  /* General link information.  */
358633965Sjdp  struct bfd_link_info *info;
358733965Sjdp  /* Output bfd.  */
358833965Sjdp  bfd *output_bfd;
358933965Sjdp  /* Reloc file positions.  */
359033965Sjdp  file_ptr treloff, dreloff;
359133965Sjdp  /* File position of symbols.  */
359233965Sjdp  file_ptr symoff;
359333965Sjdp  /* String table.  */
359433965Sjdp  struct bfd_strtab_hash *strtab;
359533965Sjdp  /* Header file hash table.  */
359633965Sjdp  struct aout_link_includes_table includes;
359733965Sjdp  /* A buffer large enough to hold the contents of any section.  */
359833965Sjdp  bfd_byte *contents;
359933965Sjdp  /* A buffer large enough to hold the relocs of any section.  */
360033965Sjdp  PTR relocs;
360133965Sjdp  /* A buffer large enough to hold the symbol map of any input BFD.  */
360233965Sjdp  int *symbol_map;
360333965Sjdp  /* A buffer large enough to hold output symbols of any input BFD.  */
360433965Sjdp  struct external_nlist *output_syms;
360533965Sjdp};
360633965Sjdp
360733965Sjdpstatic struct bfd_hash_entry *aout_link_includes_newfunc
360833965Sjdp  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
360933965Sjdpstatic boolean aout_link_input_bfd
361033965Sjdp  PARAMS ((struct aout_final_link_info *, bfd *input_bfd));
361133965Sjdpstatic boolean aout_link_write_symbols
361233965Sjdp  PARAMS ((struct aout_final_link_info *, bfd *input_bfd));
361333965Sjdpstatic boolean aout_link_write_other_symbol
361433965Sjdp  PARAMS ((struct aout_link_hash_entry *, PTR));
361533965Sjdpstatic boolean aout_link_input_section
361633965Sjdp  PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
361733965Sjdp	   asection *input_section, file_ptr *reloff_ptr,
361833965Sjdp	   bfd_size_type rel_size));
361933965Sjdpstatic boolean aout_link_input_section_std
362033965Sjdp  PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
362133965Sjdp	   asection *input_section, struct reloc_std_external *,
362233965Sjdp	   bfd_size_type rel_size, bfd_byte *contents));
362333965Sjdpstatic boolean aout_link_input_section_ext
362433965Sjdp  PARAMS ((struct aout_final_link_info *, bfd *input_bfd,
362533965Sjdp	   asection *input_section, struct reloc_ext_external *,
362633965Sjdp	   bfd_size_type rel_size, bfd_byte *contents));
362733965Sjdpstatic INLINE asection *aout_reloc_index_to_section
362833965Sjdp  PARAMS ((bfd *, int));
362933965Sjdpstatic boolean aout_link_reloc_link_order
363033965Sjdp  PARAMS ((struct aout_final_link_info *, asection *,
363133965Sjdp	   struct bfd_link_order *));
363233965Sjdp
363333965Sjdp/* The function to create a new entry in the header file hash table.  */
363433965Sjdp
363533965Sjdpstatic struct bfd_hash_entry *
363633965Sjdpaout_link_includes_newfunc (entry, table, string)
363733965Sjdp     struct bfd_hash_entry *entry;
363833965Sjdp     struct bfd_hash_table *table;
363933965Sjdp     const char *string;
364033965Sjdp{
364133965Sjdp  struct aout_link_includes_entry *ret =
364233965Sjdp    (struct aout_link_includes_entry *) entry;
364333965Sjdp
364433965Sjdp  /* Allocate the structure if it has not already been allocated by a
364533965Sjdp     subclass.  */
364633965Sjdp  if (ret == (struct aout_link_includes_entry *) NULL)
364733965Sjdp    ret = ((struct aout_link_includes_entry *)
364833965Sjdp	   bfd_hash_allocate (table,
364933965Sjdp			      sizeof (struct aout_link_includes_entry)));
365033965Sjdp  if (ret == (struct aout_link_includes_entry *) NULL)
365133965Sjdp    return (struct bfd_hash_entry *) ret;
365233965Sjdp
365333965Sjdp  /* Call the allocation method of the superclass.  */
365433965Sjdp  ret = ((struct aout_link_includes_entry *)
365533965Sjdp	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
365633965Sjdp  if (ret)
365733965Sjdp    {
365833965Sjdp      /* Set local fields.  */
365933965Sjdp      ret->totals = NULL;
366033965Sjdp    }
366133965Sjdp
366233965Sjdp  return (struct bfd_hash_entry *) ret;
366333965Sjdp}
366433965Sjdp
366533965Sjdp/* Do the final link step.  This is called on the output BFD.  The
366633965Sjdp   INFO structure should point to a list of BFDs linked through the
366733965Sjdp   link_next field which can be used to find each BFD which takes part
366833965Sjdp   in the output.  Also, each section in ABFD should point to a list
366933965Sjdp   of bfd_link_order structures which list all the input sections for
367033965Sjdp   the output section.  */
367133965Sjdp
367233965Sjdpboolean
367333965SjdpNAME(aout,final_link) (abfd, info, callback)
367433965Sjdp     bfd *abfd;
367533965Sjdp     struct bfd_link_info *info;
367633965Sjdp     void (*callback) PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
367733965Sjdp{
367833965Sjdp  struct aout_final_link_info aout_info;
367933965Sjdp  boolean includes_hash_initialized = false;
368033965Sjdp  register bfd *sub;
368133965Sjdp  bfd_size_type trsize, drsize;
368289857Sobrien  bfd_size_type max_contents_size;
368389857Sobrien  bfd_size_type max_relocs_size;
368489857Sobrien  bfd_size_type max_sym_count;
368533965Sjdp  bfd_size_type text_size;
368633965Sjdp  file_ptr text_end;
368733965Sjdp  register struct bfd_link_order *p;
368833965Sjdp  asection *o;
368933965Sjdp  boolean have_link_order_relocs;
369033965Sjdp
369133965Sjdp  if (info->shared)
369233965Sjdp    abfd->flags |= DYNAMIC;
369333965Sjdp
369433965Sjdp  aout_info.info = info;
369533965Sjdp  aout_info.output_bfd = abfd;
369633965Sjdp  aout_info.contents = NULL;
369733965Sjdp  aout_info.relocs = NULL;
369833965Sjdp  aout_info.symbol_map = NULL;
369933965Sjdp  aout_info.output_syms = NULL;
370033965Sjdp
370133965Sjdp  if (! bfd_hash_table_init_n (&aout_info.includes.root,
370233965Sjdp			       aout_link_includes_newfunc,
370333965Sjdp			       251))
370433965Sjdp    goto error_return;
370533965Sjdp  includes_hash_initialized = true;
370633965Sjdp
370733965Sjdp  /* Figure out the largest section size.  Also, if generating
370833965Sjdp     relocateable output, count the relocs.  */
370933965Sjdp  trsize = 0;
371033965Sjdp  drsize = 0;
371133965Sjdp  max_contents_size = 0;
371233965Sjdp  max_relocs_size = 0;
371333965Sjdp  max_sym_count = 0;
371433965Sjdp  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
371533965Sjdp    {
371689857Sobrien      bfd_size_type sz;
371733965Sjdp
371833965Sjdp      if (info->relocateable)
371933965Sjdp	{
372033965Sjdp	  if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
372133965Sjdp	    {
372233965Sjdp	      trsize += exec_hdr (sub)->a_trsize;
372333965Sjdp	      drsize += exec_hdr (sub)->a_drsize;
372433965Sjdp	    }
372533965Sjdp	  else
372633965Sjdp	    {
372733965Sjdp	      /* FIXME: We need to identify the .text and .data sections
372833965Sjdp		 and call get_reloc_upper_bound and canonicalize_reloc to
372933965Sjdp		 work out the number of relocs needed, and then multiply
373033965Sjdp		 by the reloc size.  */
373133965Sjdp	      (*_bfd_error_handler)
373260484Sobrien		(_("%s: relocateable link from %s to %s not supported"),
373333965Sjdp		 bfd_get_filename (abfd),
373433965Sjdp		 sub->xvec->name, abfd->xvec->name);
373533965Sjdp	      bfd_set_error (bfd_error_invalid_operation);
373633965Sjdp	      goto error_return;
373733965Sjdp	    }
373833965Sjdp	}
373933965Sjdp
374033965Sjdp      if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
374133965Sjdp	{
374233965Sjdp	  sz = bfd_section_size (sub, obj_textsec (sub));
374333965Sjdp	  if (sz > max_contents_size)
374433965Sjdp	    max_contents_size = sz;
374533965Sjdp	  sz = bfd_section_size (sub, obj_datasec (sub));
374633965Sjdp	  if (sz > max_contents_size)
374733965Sjdp	    max_contents_size = sz;
374833965Sjdp
374933965Sjdp	  sz = exec_hdr (sub)->a_trsize;
375033965Sjdp	  if (sz > max_relocs_size)
375133965Sjdp	    max_relocs_size = sz;
375233965Sjdp	  sz = exec_hdr (sub)->a_drsize;
375333965Sjdp	  if (sz > max_relocs_size)
375433965Sjdp	    max_relocs_size = sz;
375533965Sjdp
375633965Sjdp	  sz = obj_aout_external_sym_count (sub);
375733965Sjdp	  if (sz > max_sym_count)
375833965Sjdp	    max_sym_count = sz;
375933965Sjdp	}
376033965Sjdp    }
376133965Sjdp
376233965Sjdp  if (info->relocateable)
376333965Sjdp    {
376433965Sjdp      if (obj_textsec (abfd) != (asection *) NULL)
376533965Sjdp	trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd)
376633965Sjdp						 ->link_order_head)
376733965Sjdp		   * obj_reloc_entry_size (abfd));
376833965Sjdp      if (obj_datasec (abfd) != (asection *) NULL)
376933965Sjdp	drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd)
377033965Sjdp						 ->link_order_head)
377133965Sjdp		   * obj_reloc_entry_size (abfd));
377233965Sjdp    }
377333965Sjdp
377433965Sjdp  exec_hdr (abfd)->a_trsize = trsize;
377533965Sjdp  exec_hdr (abfd)->a_drsize = drsize;
377633965Sjdp
377733965Sjdp  exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
377833965Sjdp
377933965Sjdp  /* Adjust the section sizes and vmas according to the magic number.
378033965Sjdp     This sets a_text, a_data and a_bss in the exec_hdr and sets the
378133965Sjdp     filepos for each section.  */
378233965Sjdp  if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
378333965Sjdp    goto error_return;
378433965Sjdp
378533965Sjdp  /* The relocation and symbol file positions differ among a.out
378633965Sjdp     targets.  We are passed a callback routine from the backend
378733965Sjdp     specific code to handle this.
378833965Sjdp     FIXME: At this point we do not know how much space the symbol
378933965Sjdp     table will require.  This will not work for any (nonstandard)
379033965Sjdp     a.out target that needs to know the symbol table size before it
379133965Sjdp     can compute the relocation file positions.  This may or may not
379233965Sjdp     be the case for the hp300hpux target, for example.  */
379333965Sjdp  (*callback) (abfd, &aout_info.treloff, &aout_info.dreloff,
379433965Sjdp	       &aout_info.symoff);
379533965Sjdp  obj_textsec (abfd)->rel_filepos = aout_info.treloff;
379633965Sjdp  obj_datasec (abfd)->rel_filepos = aout_info.dreloff;
379733965Sjdp  obj_sym_filepos (abfd) = aout_info.symoff;
379833965Sjdp
379933965Sjdp  /* We keep a count of the symbols as we output them.  */
380033965Sjdp  obj_aout_external_sym_count (abfd) = 0;
380133965Sjdp
380233965Sjdp  /* We accumulate the string table as we write out the symbols.  */
380333965Sjdp  aout_info.strtab = _bfd_stringtab_init ();
380433965Sjdp  if (aout_info.strtab == NULL)
380533965Sjdp    goto error_return;
380633965Sjdp
380733965Sjdp  /* Allocate buffers to hold section contents and relocs.  */
380833965Sjdp  aout_info.contents = (bfd_byte *) bfd_malloc (max_contents_size);
380933965Sjdp  aout_info.relocs = (PTR) bfd_malloc (max_relocs_size);
381033965Sjdp  aout_info.symbol_map = (int *) bfd_malloc (max_sym_count * sizeof (int *));
381133965Sjdp  aout_info.output_syms = ((struct external_nlist *)
381233965Sjdp			   bfd_malloc ((max_sym_count + 1)
381333965Sjdp				       * sizeof (struct external_nlist)));
381433965Sjdp  if ((aout_info.contents == NULL && max_contents_size != 0)
381533965Sjdp      || (aout_info.relocs == NULL && max_relocs_size != 0)
381633965Sjdp      || (aout_info.symbol_map == NULL && max_sym_count != 0)
381733965Sjdp      || aout_info.output_syms == NULL)
381833965Sjdp    goto error_return;
381933965Sjdp
382033965Sjdp  /* If we have a symbol named __DYNAMIC, force it out now.  This is
382133965Sjdp     required by SunOS.  Doing this here rather than in sunos.c is a
382233965Sjdp     hack, but it's easier than exporting everything which would be
382333965Sjdp     needed.  */
382433965Sjdp  {
382533965Sjdp    struct aout_link_hash_entry *h;
382633965Sjdp
382733965Sjdp    h = aout_link_hash_lookup (aout_hash_table (info), "__DYNAMIC",
382833965Sjdp			       false, false, false);
382933965Sjdp    if (h != NULL)
383033965Sjdp      aout_link_write_other_symbol (h, &aout_info);
383133965Sjdp  }
383233965Sjdp
383333965Sjdp  /* The most time efficient way to do the link would be to read all
383433965Sjdp     the input object files into memory and then sort out the
383533965Sjdp     information into the output file.  Unfortunately, that will
383633965Sjdp     probably use too much memory.  Another method would be to step
383733965Sjdp     through everything that composes the text section and write it
383833965Sjdp     out, and then everything that composes the data section and write
383933965Sjdp     it out, and then write out the relocs, and then write out the
384033965Sjdp     symbols.  Unfortunately, that requires reading stuff from each
384133965Sjdp     input file several times, and we will not be able to keep all the
384233965Sjdp     input files open simultaneously, and reopening them will be slow.
384333965Sjdp
384433965Sjdp     What we do is basically process one input file at a time.  We do
384533965Sjdp     everything we need to do with an input file once--copy over the
384633965Sjdp     section contents, handle the relocation information, and write
384733965Sjdp     out the symbols--and then we throw away the information we read
384833965Sjdp     from it.  This approach requires a lot of lseeks of the output
384933965Sjdp     file, which is unfortunate but still faster than reopening a lot
385033965Sjdp     of files.
385133965Sjdp
385233965Sjdp     We use the output_has_begun field of the input BFDs to see
385333965Sjdp     whether we have already handled it.  */
385433965Sjdp  for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
385533965Sjdp    sub->output_has_begun = false;
385633965Sjdp
385733965Sjdp  /* Mark all sections which are to be included in the link.  This
385833965Sjdp     will normally be every section.  We need to do this so that we
385933965Sjdp     can identify any sections which the linker has decided to not
386033965Sjdp     include.  */
386133965Sjdp  for (o = abfd->sections; o != NULL; o = o->next)
386233965Sjdp    {
386333965Sjdp      for (p = o->link_order_head; p != NULL; p = p->next)
386433965Sjdp	{
386533965Sjdp	  if (p->type == bfd_indirect_link_order)
386633965Sjdp	    p->u.indirect.section->linker_mark = true;
386733965Sjdp	}
386833965Sjdp    }
386933965Sjdp
387033965Sjdp  have_link_order_relocs = false;
387133965Sjdp  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
387233965Sjdp    {
387333965Sjdp      for (p = o->link_order_head;
387433965Sjdp	   p != (struct bfd_link_order *) NULL;
387533965Sjdp	   p = p->next)
387633965Sjdp	{
387733965Sjdp	  if (p->type == bfd_indirect_link_order
387833965Sjdp	      && (bfd_get_flavour (p->u.indirect.section->owner)
387933965Sjdp		  == bfd_target_aout_flavour))
388033965Sjdp	    {
388133965Sjdp	      bfd *input_bfd;
388233965Sjdp
388333965Sjdp	      input_bfd = p->u.indirect.section->owner;
388433965Sjdp	      if (! input_bfd->output_has_begun)
388533965Sjdp		{
388633965Sjdp		  if (! aout_link_input_bfd (&aout_info, input_bfd))
388733965Sjdp		    goto error_return;
388833965Sjdp		  input_bfd->output_has_begun = true;
388933965Sjdp		}
389033965Sjdp	    }
389133965Sjdp	  else if (p->type == bfd_section_reloc_link_order
389233965Sjdp		   || p->type == bfd_symbol_reloc_link_order)
389333965Sjdp	    {
389433965Sjdp	      /* These are handled below.  */
389533965Sjdp	      have_link_order_relocs = true;
389633965Sjdp	    }
389733965Sjdp	  else
389833965Sjdp	    {
389933965Sjdp	      if (! _bfd_default_link_order (abfd, info, o, p))
390033965Sjdp		goto error_return;
390133965Sjdp	    }
390233965Sjdp	}
390333965Sjdp    }
390433965Sjdp
390533965Sjdp  /* Write out any symbols that we have not already written out.  */
390633965Sjdp  aout_link_hash_traverse (aout_hash_table (info),
390733965Sjdp			   aout_link_write_other_symbol,
390833965Sjdp			   (PTR) &aout_info);
390933965Sjdp
391033965Sjdp  /* Now handle any relocs we were asked to create by the linker.
391133965Sjdp     These did not come from any input file.  We must do these after
391233965Sjdp     we have written out all the symbols, so that we know the symbol
391333965Sjdp     indices to use.  */
391433965Sjdp  if (have_link_order_relocs)
391533965Sjdp    {
391633965Sjdp      for (o = abfd->sections; o != (asection *) NULL; o = o->next)
391733965Sjdp	{
391833965Sjdp	  for (p = o->link_order_head;
391933965Sjdp	       p != (struct bfd_link_order *) NULL;
392033965Sjdp	       p = p->next)
392133965Sjdp	    {
392233965Sjdp	      if (p->type == bfd_section_reloc_link_order
392333965Sjdp		  || p->type == bfd_symbol_reloc_link_order)
392433965Sjdp		{
392533965Sjdp		  if (! aout_link_reloc_link_order (&aout_info, o, p))
392633965Sjdp		    goto error_return;
392733965Sjdp		}
392833965Sjdp	    }
392933965Sjdp	}
393033965Sjdp    }
393133965Sjdp
393233965Sjdp  if (aout_info.contents != NULL)
393333965Sjdp    {
393433965Sjdp      free (aout_info.contents);
393533965Sjdp      aout_info.contents = NULL;
393633965Sjdp    }
393733965Sjdp  if (aout_info.relocs != NULL)
393833965Sjdp    {
393933965Sjdp      free (aout_info.relocs);
394033965Sjdp      aout_info.relocs = NULL;
394133965Sjdp    }
394233965Sjdp  if (aout_info.symbol_map != NULL)
394333965Sjdp    {
394433965Sjdp      free (aout_info.symbol_map);
394533965Sjdp      aout_info.symbol_map = NULL;
394633965Sjdp    }
394733965Sjdp  if (aout_info.output_syms != NULL)
394833965Sjdp    {
394933965Sjdp      free (aout_info.output_syms);
395033965Sjdp      aout_info.output_syms = NULL;
395133965Sjdp    }
395233965Sjdp  if (includes_hash_initialized)
395333965Sjdp    {
395433965Sjdp      bfd_hash_table_free (&aout_info.includes.root);
395533965Sjdp      includes_hash_initialized = false;
395633965Sjdp    }
395733965Sjdp
395833965Sjdp  /* Finish up any dynamic linking we may be doing.  */
395933965Sjdp  if (aout_backend_info (abfd)->finish_dynamic_link != NULL)
396033965Sjdp    {
396133965Sjdp      if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info))
396233965Sjdp	goto error_return;
396333965Sjdp    }
396433965Sjdp
396533965Sjdp  /* Update the header information.  */
396633965Sjdp  abfd->symcount = obj_aout_external_sym_count (abfd);
396733965Sjdp  exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE;
396833965Sjdp  obj_str_filepos (abfd) = obj_sym_filepos (abfd) + exec_hdr (abfd)->a_syms;
396933965Sjdp  obj_textsec (abfd)->reloc_count =
397033965Sjdp    exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd);
397133965Sjdp  obj_datasec (abfd)->reloc_count =
397233965Sjdp    exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd);
397333965Sjdp
397438889Sjdp  /* Write out the string table, unless there are no symbols.  */
397538889Sjdp  if (abfd->symcount > 0)
397638889Sjdp    {
397738889Sjdp      if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
397838889Sjdp	  || ! emit_stringtab (abfd, aout_info.strtab))
397938889Sjdp	goto error_return;
398038889Sjdp    }
398138889Sjdp  else if (obj_textsec (abfd)->reloc_count == 0
398238889Sjdp	   && obj_datasec (abfd)->reloc_count == 0)
398338889Sjdp    {
398438889Sjdp      bfd_byte b;
398589857Sobrien      file_ptr pos;
398633965Sjdp
398738889Sjdp      b = 0;
398889857Sobrien      pos = obj_datasec (abfd)->filepos + exec_hdr (abfd)->a_data - 1;
398989857Sobrien      if (bfd_seek (abfd, pos, SEEK_SET) != 0
399089857Sobrien	  || bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
399138889Sjdp	goto error_return;
399238889Sjdp    }
399338889Sjdp
399438889Sjdp  return true;
399538889Sjdp
399633965Sjdp error_return:
399733965Sjdp  if (aout_info.contents != NULL)
399833965Sjdp    free (aout_info.contents);
399933965Sjdp  if (aout_info.relocs != NULL)
400033965Sjdp    free (aout_info.relocs);
400133965Sjdp  if (aout_info.symbol_map != NULL)
400233965Sjdp    free (aout_info.symbol_map);
400333965Sjdp  if (aout_info.output_syms != NULL)
400433965Sjdp    free (aout_info.output_syms);
400533965Sjdp  if (includes_hash_initialized)
400633965Sjdp    bfd_hash_table_free (&aout_info.includes.root);
400733965Sjdp  return false;
400833965Sjdp}
400933965Sjdp
401033965Sjdp/* Link an a.out input BFD into the output file.  */
401133965Sjdp
401233965Sjdpstatic boolean
401333965Sjdpaout_link_input_bfd (finfo, input_bfd)
401433965Sjdp     struct aout_final_link_info *finfo;
401533965Sjdp     bfd *input_bfd;
401633965Sjdp{
401733965Sjdp  bfd_size_type sym_count;
401833965Sjdp
401933965Sjdp  BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object);
402033965Sjdp
402133965Sjdp  /* If this is a dynamic object, it may need special handling.  */
402233965Sjdp  if ((input_bfd->flags & DYNAMIC) != 0
402333965Sjdp      && aout_backend_info (input_bfd)->link_dynamic_object != NULL)
402433965Sjdp    {
402533965Sjdp      return ((*aout_backend_info (input_bfd)->link_dynamic_object)
402633965Sjdp	      (finfo->info, input_bfd));
402733965Sjdp    }
402833965Sjdp
402933965Sjdp  /* Get the symbols.  We probably have them already, unless
403033965Sjdp     finfo->info->keep_memory is false.  */
403133965Sjdp  if (! aout_get_external_symbols (input_bfd))
403233965Sjdp    return false;
403333965Sjdp
403433965Sjdp  sym_count = obj_aout_external_sym_count (input_bfd);
403533965Sjdp
403633965Sjdp  /* Write out the symbols and get a map of the new indices.  The map
403733965Sjdp     is placed into finfo->symbol_map.  */
403833965Sjdp  if (! aout_link_write_symbols (finfo, input_bfd))
403933965Sjdp    return false;
404033965Sjdp
404133965Sjdp  /* Relocate and write out the sections.  These functions use the
404233965Sjdp     symbol map created by aout_link_write_symbols.  The linker_mark
404333965Sjdp     field will be set if these sections are to be included in the
404433965Sjdp     link, which will normally be the case.  */
404533965Sjdp  if (obj_textsec (input_bfd)->linker_mark)
404633965Sjdp    {
404733965Sjdp      if (! aout_link_input_section (finfo, input_bfd,
404833965Sjdp				     obj_textsec (input_bfd),
404933965Sjdp				     &finfo->treloff,
405033965Sjdp				     exec_hdr (input_bfd)->a_trsize))
405133965Sjdp	return false;
405233965Sjdp    }
405333965Sjdp  if (obj_datasec (input_bfd)->linker_mark)
405433965Sjdp    {
405533965Sjdp      if (! aout_link_input_section (finfo, input_bfd,
405633965Sjdp				     obj_datasec (input_bfd),
405733965Sjdp				     &finfo->dreloff,
405833965Sjdp				     exec_hdr (input_bfd)->a_drsize))
405933965Sjdp	return false;
406033965Sjdp    }
406133965Sjdp
406233965Sjdp  /* If we are not keeping memory, we don't need the symbols any
406333965Sjdp     longer.  We still need them if we are keeping memory, because the
406433965Sjdp     strings in the hash table point into them.  */
406533965Sjdp  if (! finfo->info->keep_memory)
406633965Sjdp    {
406733965Sjdp      if (! aout_link_free_symbols (input_bfd))
406833965Sjdp	return false;
406933965Sjdp    }
407033965Sjdp
407133965Sjdp  return true;
407233965Sjdp}
407333965Sjdp
407433965Sjdp/* Adjust and write out the symbols for an a.out file.  Set the new
407533965Sjdp   symbol indices into a symbol_map.  */
407633965Sjdp
407733965Sjdpstatic boolean
407833965Sjdpaout_link_write_symbols (finfo, input_bfd)
407933965Sjdp     struct aout_final_link_info *finfo;
408033965Sjdp     bfd *input_bfd;
408133965Sjdp{
408233965Sjdp  bfd *output_bfd;
408333965Sjdp  bfd_size_type sym_count;
408433965Sjdp  char *strings;
408533965Sjdp  enum bfd_link_strip strip;
408633965Sjdp  enum bfd_link_discard discard;
408733965Sjdp  struct external_nlist *outsym;
408833965Sjdp  bfd_size_type strtab_index;
408933965Sjdp  register struct external_nlist *sym;
409033965Sjdp  struct external_nlist *sym_end;
409133965Sjdp  struct aout_link_hash_entry **sym_hash;
409233965Sjdp  int *symbol_map;
409333965Sjdp  boolean pass;
409433965Sjdp  boolean skip_next;
409533965Sjdp
409633965Sjdp  output_bfd = finfo->output_bfd;
409733965Sjdp  sym_count = obj_aout_external_sym_count (input_bfd);
409833965Sjdp  strings = obj_aout_external_strings (input_bfd);
409933965Sjdp  strip = finfo->info->strip;
410033965Sjdp  discard = finfo->info->discard;
410133965Sjdp  outsym = finfo->output_syms;
410233965Sjdp
410333965Sjdp  /* First write out a symbol for this object file, unless we are
410433965Sjdp     discarding such symbols.  */
410533965Sjdp  if (strip != strip_all
410633965Sjdp      && (strip != strip_some
410733965Sjdp	  || bfd_hash_lookup (finfo->info->keep_hash, input_bfd->filename,
410833965Sjdp			      false, false) != NULL)
410933965Sjdp      && discard != discard_all)
411033965Sjdp    {
411189857Sobrien      H_PUT_8 (output_bfd, N_TEXT, outsym->e_type);
411289857Sobrien      H_PUT_8 (output_bfd, 0, outsym->e_other);
411389857Sobrien      H_PUT_16 (output_bfd, 0, outsym->e_desc);
411433965Sjdp      strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
411533965Sjdp				       input_bfd->filename, false);
411633965Sjdp      if (strtab_index == (bfd_size_type) -1)
411733965Sjdp	return false;
411833965Sjdp      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
411933965Sjdp      PUT_WORD (output_bfd,
412033965Sjdp		(bfd_get_section_vma (output_bfd,
412133965Sjdp				      obj_textsec (input_bfd)->output_section)
412233965Sjdp		 + obj_textsec (input_bfd)->output_offset),
412333965Sjdp		outsym->e_value);
412433965Sjdp      ++obj_aout_external_sym_count (output_bfd);
412533965Sjdp      ++outsym;
412633965Sjdp    }
412733965Sjdp
412833965Sjdp  pass = false;
412933965Sjdp  skip_next = false;
413033965Sjdp  sym = obj_aout_external_syms (input_bfd);
413133965Sjdp  sym_end = sym + sym_count;
413233965Sjdp  sym_hash = obj_aout_sym_hashes (input_bfd);
413333965Sjdp  symbol_map = finfo->symbol_map;
413489857Sobrien  memset (symbol_map, 0, (size_t) sym_count * sizeof *symbol_map);
413533965Sjdp  for (; sym < sym_end; sym++, sym_hash++, symbol_map++)
413633965Sjdp    {
413733965Sjdp      const char *name;
413833965Sjdp      int type;
413933965Sjdp      struct aout_link_hash_entry *h;
414033965Sjdp      boolean skip;
414133965Sjdp      asection *symsec;
414233965Sjdp      bfd_vma val = 0;
414333965Sjdp      boolean copy;
414433965Sjdp
414533965Sjdp      /* We set *symbol_map to 0 above for all symbols.  If it has
414633965Sjdp         already been set to -1 for this symbol, it means that we are
414733965Sjdp         discarding it because it appears in a duplicate header file.
414833965Sjdp         See the N_BINCL code below.  */
414933965Sjdp      if (*symbol_map == -1)
415033965Sjdp	continue;
415133965Sjdp
415233965Sjdp      /* Initialize *symbol_map to -1, which means that the symbol was
415333965Sjdp         not copied into the output file.  We will change it later if
415433965Sjdp         we do copy the symbol over.  */
415533965Sjdp      *symbol_map = -1;
415633965Sjdp
415789857Sobrien      type = H_GET_8 (input_bfd, sym->e_type);
415833965Sjdp      name = strings + GET_WORD (input_bfd, sym->e_strx);
415933965Sjdp
416033965Sjdp      h = NULL;
416133965Sjdp
416233965Sjdp      if (pass)
416333965Sjdp	{
416433965Sjdp	  /* Pass this symbol through.  It is the target of an
416533965Sjdp	     indirect or warning symbol.  */
416633965Sjdp	  val = GET_WORD (input_bfd, sym->e_value);
416733965Sjdp	  pass = false;
416833965Sjdp	}
416933965Sjdp      else if (skip_next)
417033965Sjdp	{
417133965Sjdp	  /* Skip this symbol, which is the target of an indirect
417233965Sjdp	     symbol that we have changed to no longer be an indirect
417333965Sjdp	     symbol.  */
417433965Sjdp	  skip_next = false;
417533965Sjdp	  continue;
417633965Sjdp	}
417733965Sjdp      else
417833965Sjdp	{
417933965Sjdp	  struct aout_link_hash_entry *hresolve;
418033965Sjdp
418133965Sjdp	  /* We have saved the hash table entry for this symbol, if
418233965Sjdp	     there is one.  Note that we could just look it up again
418333965Sjdp	     in the hash table, provided we first check that it is an
418477298Sobrien	     external symbol.  */
418533965Sjdp	  h = *sym_hash;
418633965Sjdp
418733965Sjdp	  /* Use the name from the hash table, in case the symbol was
418833965Sjdp             wrapped.  */
4189104834Sobrien	  if (h != NULL
4190104834Sobrien	      && h->root.type != bfd_link_hash_warning)
419133965Sjdp	    name = h->root.root.string;
419233965Sjdp
419333965Sjdp	  /* If this is an indirect or warning symbol, then change
419433965Sjdp	     hresolve to the base symbol.  We also change *sym_hash so
419533965Sjdp	     that the relocation routines relocate against the real
419633965Sjdp	     symbol.  */
419733965Sjdp	  hresolve = h;
419833965Sjdp	  if (h != (struct aout_link_hash_entry *) NULL
419933965Sjdp	      && (h->root.type == bfd_link_hash_indirect
420033965Sjdp		  || h->root.type == bfd_link_hash_warning))
420133965Sjdp	    {
420233965Sjdp	      hresolve = (struct aout_link_hash_entry *) h->root.u.i.link;
420333965Sjdp	      while (hresolve->root.type == bfd_link_hash_indirect
420433965Sjdp		     || hresolve->root.type == bfd_link_hash_warning)
420533965Sjdp		hresolve = ((struct aout_link_hash_entry *)
420633965Sjdp			    hresolve->root.u.i.link);
420733965Sjdp	      *sym_hash = hresolve;
420833965Sjdp	    }
420933965Sjdp
421033965Sjdp	  /* If the symbol has already been written out, skip it.  */
421133965Sjdp	  if (h != (struct aout_link_hash_entry *) NULL
421233965Sjdp	      && h->written)
421333965Sjdp	    {
421433965Sjdp	      if ((type & N_TYPE) == N_INDR
421533965Sjdp		  || type == N_WARNING)
421633965Sjdp		skip_next = true;
421733965Sjdp	      *symbol_map = h->indx;
421833965Sjdp	      continue;
421933965Sjdp	    }
422033965Sjdp
422133965Sjdp	  /* See if we are stripping this symbol.  */
422233965Sjdp	  skip = false;
422333965Sjdp	  switch (strip)
422433965Sjdp	    {
422533965Sjdp	    case strip_none:
422633965Sjdp	      break;
422733965Sjdp	    case strip_debugger:
422833965Sjdp	      if ((type & N_STAB) != 0)
422933965Sjdp		skip = true;
423033965Sjdp	      break;
423133965Sjdp	    case strip_some:
423233965Sjdp	      if (bfd_hash_lookup (finfo->info->keep_hash, name, false, false)
423333965Sjdp		  == NULL)
423433965Sjdp		skip = true;
423533965Sjdp	      break;
423633965Sjdp	    case strip_all:
423733965Sjdp	      skip = true;
423833965Sjdp	      break;
423933965Sjdp	    }
424033965Sjdp	  if (skip)
424133965Sjdp	    {
424233965Sjdp	      if (h != (struct aout_link_hash_entry *) NULL)
424333965Sjdp		h->written = true;
424433965Sjdp	      continue;
424533965Sjdp	    }
424633965Sjdp
424733965Sjdp	  /* Get the value of the symbol.  */
424833965Sjdp	  if ((type & N_TYPE) == N_TEXT
424933965Sjdp	      || type == N_WEAKT)
425033965Sjdp	    symsec = obj_textsec (input_bfd);
425133965Sjdp	  else if ((type & N_TYPE) == N_DATA
425233965Sjdp		   || type == N_WEAKD)
425333965Sjdp	    symsec = obj_datasec (input_bfd);
425433965Sjdp	  else if ((type & N_TYPE) == N_BSS
425533965Sjdp		   || type == N_WEAKB)
425633965Sjdp	    symsec = obj_bsssec (input_bfd);
425733965Sjdp	  else if ((type & N_TYPE) == N_ABS
425833965Sjdp		   || type == N_WEAKA)
425933965Sjdp	    symsec = bfd_abs_section_ptr;
426033965Sjdp	  else if (((type & N_TYPE) == N_INDR
426133965Sjdp		    && (hresolve == (struct aout_link_hash_entry *) NULL
426233965Sjdp			|| (hresolve->root.type != bfd_link_hash_defined
426333965Sjdp			    && hresolve->root.type != bfd_link_hash_defweak
426433965Sjdp			    && hresolve->root.type != bfd_link_hash_common)))
426533965Sjdp		   || type == N_WARNING)
426633965Sjdp	    {
426733965Sjdp	      /* Pass the next symbol through unchanged.  The
426833965Sjdp		 condition above for indirect symbols is so that if
426933965Sjdp		 the indirect symbol was defined, we output it with
427033965Sjdp		 the correct definition so the debugger will
427133965Sjdp		 understand it.  */
427233965Sjdp	      pass = true;
427333965Sjdp	      val = GET_WORD (input_bfd, sym->e_value);
427433965Sjdp	      symsec = NULL;
427533965Sjdp	    }
427633965Sjdp	  else if ((type & N_STAB) != 0)
427733965Sjdp	    {
427833965Sjdp	      val = GET_WORD (input_bfd, sym->e_value);
427933965Sjdp	      symsec = NULL;
428033965Sjdp	    }
428133965Sjdp	  else
428233965Sjdp	    {
428333965Sjdp	      /* If we get here with an indirect symbol, it means that
428433965Sjdp		 we are outputting it with a real definition.  In such
428533965Sjdp		 a case we do not want to output the next symbol,
428633965Sjdp		 which is the target of the indirection.  */
428733965Sjdp	      if ((type & N_TYPE) == N_INDR)
428833965Sjdp		skip_next = true;
428933965Sjdp
429033965Sjdp	      symsec = NULL;
429133965Sjdp
429233965Sjdp	      /* We need to get the value from the hash table.  We use
429333965Sjdp		 hresolve so that if we have defined an indirect
429433965Sjdp		 symbol we output the final definition.  */
429533965Sjdp	      if (h == (struct aout_link_hash_entry *) NULL)
429633965Sjdp		{
429733965Sjdp		  switch (type & N_TYPE)
429833965Sjdp		    {
429933965Sjdp		    case N_SETT:
430033965Sjdp		      symsec = obj_textsec (input_bfd);
430133965Sjdp		      break;
430233965Sjdp		    case N_SETD:
430333965Sjdp		      symsec = obj_datasec (input_bfd);
430433965Sjdp		      break;
430533965Sjdp		    case N_SETB:
430633965Sjdp		      symsec = obj_bsssec (input_bfd);
430733965Sjdp		      break;
430833965Sjdp		    case N_SETA:
430933965Sjdp		      symsec = bfd_abs_section_ptr;
431033965Sjdp		      break;
431133965Sjdp		    default:
431233965Sjdp		      val = 0;
431333965Sjdp		      break;
431433965Sjdp		    }
431533965Sjdp		}
431633965Sjdp	      else if (hresolve->root.type == bfd_link_hash_defined
431733965Sjdp		       || hresolve->root.type == bfd_link_hash_defweak)
431833965Sjdp		{
431933965Sjdp		  asection *input_section;
432033965Sjdp		  asection *output_section;
432133965Sjdp
432233965Sjdp		  /* This case usually means a common symbol which was
432333965Sjdp		     turned into a defined symbol.  */
432433965Sjdp		  input_section = hresolve->root.u.def.section;
432533965Sjdp		  output_section = input_section->output_section;
432633965Sjdp		  BFD_ASSERT (bfd_is_abs_section (output_section)
432733965Sjdp			      || output_section->owner == output_bfd);
432833965Sjdp		  val = (hresolve->root.u.def.value
432933965Sjdp			 + bfd_get_section_vma (output_bfd, output_section)
433033965Sjdp			 + input_section->output_offset);
433133965Sjdp
433233965Sjdp		  /* Get the correct type based on the section.  If
433333965Sjdp		     this is a constructed set, force it to be
433433965Sjdp		     globally visible.  */
433533965Sjdp		  if (type == N_SETT
433633965Sjdp		      || type == N_SETD
433733965Sjdp		      || type == N_SETB
433833965Sjdp		      || type == N_SETA)
433933965Sjdp		    type |= N_EXT;
434033965Sjdp
434133965Sjdp		  type &=~ N_TYPE;
434233965Sjdp
434333965Sjdp		  if (output_section == obj_textsec (output_bfd))
434433965Sjdp		    type |= (hresolve->root.type == bfd_link_hash_defined
434533965Sjdp			     ? N_TEXT
434633965Sjdp			     : N_WEAKT);
434733965Sjdp		  else if (output_section == obj_datasec (output_bfd))
434833965Sjdp		    type |= (hresolve->root.type == bfd_link_hash_defined
434933965Sjdp			     ? N_DATA
435033965Sjdp			     : N_WEAKD);
435133965Sjdp		  else if (output_section == obj_bsssec (output_bfd))
435233965Sjdp		    type |= (hresolve->root.type == bfd_link_hash_defined
435333965Sjdp			     ? N_BSS
435433965Sjdp			     : N_WEAKB);
435533965Sjdp		  else
435633965Sjdp		    type |= (hresolve->root.type == bfd_link_hash_defined
435733965Sjdp			     ? N_ABS
435833965Sjdp			     : N_WEAKA);
435933965Sjdp		}
436033965Sjdp	      else if (hresolve->root.type == bfd_link_hash_common)
436133965Sjdp		val = hresolve->root.u.c.size;
436233965Sjdp	      else if (hresolve->root.type == bfd_link_hash_undefweak)
436333965Sjdp		{
436433965Sjdp		  val = 0;
436533965Sjdp		  type = N_WEAKU;
436633965Sjdp		}
436733965Sjdp	      else
436833965Sjdp		val = 0;
436933965Sjdp	    }
437033965Sjdp	  if (symsec != (asection *) NULL)
437133965Sjdp	    val = (symsec->output_section->vma
437233965Sjdp		   + symsec->output_offset
437333965Sjdp		   + (GET_WORD (input_bfd, sym->e_value)
437433965Sjdp		      - symsec->vma));
437533965Sjdp
437633965Sjdp	  /* If this is a global symbol set the written flag, and if
437733965Sjdp	     it is a local symbol see if we should discard it.  */
437833965Sjdp	  if (h != (struct aout_link_hash_entry *) NULL)
437933965Sjdp	    {
438033965Sjdp	      h->written = true;
438133965Sjdp	      h->indx = obj_aout_external_sym_count (output_bfd);
438233965Sjdp	    }
438333965Sjdp	  else if ((type & N_TYPE) != N_SETT
438433965Sjdp		   && (type & N_TYPE) != N_SETD
438533965Sjdp		   && (type & N_TYPE) != N_SETB
438633965Sjdp		   && (type & N_TYPE) != N_SETA)
438733965Sjdp	    {
438833965Sjdp	      switch (discard)
438933965Sjdp		{
439033965Sjdp		case discard_none:
439189857Sobrien		case discard_sec_merge:
439233965Sjdp		  break;
439333965Sjdp		case discard_l:
439433965Sjdp		  if ((type & N_STAB) == 0
439533965Sjdp		      && bfd_is_local_label_name (input_bfd, name))
439633965Sjdp		    skip = true;
439733965Sjdp		  break;
439833965Sjdp		case discard_all:
439933965Sjdp		  skip = true;
440033965Sjdp		  break;
440133965Sjdp		}
440233965Sjdp	      if (skip)
440333965Sjdp		{
440433965Sjdp		  pass = false;
440533965Sjdp		  continue;
440633965Sjdp		}
440733965Sjdp	    }
440833965Sjdp
440933965Sjdp	  /* An N_BINCL symbol indicates the start of the stabs
441033965Sjdp	     entries for a header file.  We need to scan ahead to the
441133965Sjdp	     next N_EINCL symbol, ignoring nesting, adding up all the
441233965Sjdp	     characters in the symbol names, not including the file
441333965Sjdp	     numbers in types (the first number after an open
441433965Sjdp	     parenthesis).  */
441533965Sjdp	  if (type == N_BINCL)
441633965Sjdp	    {
441733965Sjdp	      struct external_nlist *incl_sym;
441833965Sjdp	      int nest;
441933965Sjdp	      struct aout_link_includes_entry *incl_entry;
442033965Sjdp	      struct aout_link_includes_totals *t;
442133965Sjdp
442233965Sjdp	      val = 0;
442333965Sjdp	      nest = 0;
442433965Sjdp	      for (incl_sym = sym + 1; incl_sym < sym_end; incl_sym++)
442533965Sjdp		{
442633965Sjdp		  int incl_type;
442733965Sjdp
442889857Sobrien		  incl_type = H_GET_8 (input_bfd, incl_sym->e_type);
442933965Sjdp		  if (incl_type == N_EINCL)
443033965Sjdp		    {
443133965Sjdp		      if (nest == 0)
443233965Sjdp			break;
443333965Sjdp		      --nest;
443433965Sjdp		    }
443533965Sjdp		  else if (incl_type == N_BINCL)
443633965Sjdp		    ++nest;
443733965Sjdp		  else if (nest == 0)
443833965Sjdp		    {
443933965Sjdp		      const char *s;
444033965Sjdp
444133965Sjdp		      s = strings + GET_WORD (input_bfd, incl_sym->e_strx);
444233965Sjdp		      for (; *s != '\0'; s++)
444333965Sjdp			{
444433965Sjdp			  val += *s;
444533965Sjdp			  if (*s == '(')
444633965Sjdp			    {
444733965Sjdp			      /* Skip the file number.  */
444833965Sjdp			      ++s;
444989857Sobrien			      while (ISDIGIT (*s))
445033965Sjdp				++s;
445133965Sjdp			      --s;
445233965Sjdp			    }
445333965Sjdp			}
445433965Sjdp		    }
445533965Sjdp		}
445633965Sjdp
445733965Sjdp	      /* If we have already included a header file with the
445833965Sjdp                 same value, then replace this one with an N_EXCL
445933965Sjdp                 symbol.  */
446033965Sjdp	      copy = ! finfo->info->keep_memory;
446133965Sjdp	      incl_entry = aout_link_includes_lookup (&finfo->includes,
446233965Sjdp						      name, true, copy);
446333965Sjdp	      if (incl_entry == NULL)
446433965Sjdp		return false;
446533965Sjdp	      for (t = incl_entry->totals; t != NULL; t = t->next)
446633965Sjdp		if (t->total == val)
446733965Sjdp		  break;
446833965Sjdp	      if (t == NULL)
446933965Sjdp		{
447033965Sjdp		  /* This is the first time we have seen this header
447133965Sjdp                     file with this set of stabs strings.  */
447233965Sjdp		  t = ((struct aout_link_includes_totals *)
447333965Sjdp		       bfd_hash_allocate (&finfo->includes.root,
447433965Sjdp					  sizeof *t));
447533965Sjdp		  if (t == NULL)
447633965Sjdp		    return false;
447733965Sjdp		  t->total = val;
447833965Sjdp		  t->next = incl_entry->totals;
447933965Sjdp		  incl_entry->totals = t;
448033965Sjdp		}
448133965Sjdp	      else
448233965Sjdp		{
448333965Sjdp		  int *incl_map;
448433965Sjdp
448533965Sjdp		  /* This is a duplicate header file.  We must change
448633965Sjdp                     it to be an N_EXCL entry, and mark all the
448733965Sjdp                     included symbols to prevent outputting them.  */
448833965Sjdp		  type = N_EXCL;
448933965Sjdp
449033965Sjdp		  nest = 0;
449133965Sjdp		  for (incl_sym = sym + 1, incl_map = symbol_map + 1;
449233965Sjdp		       incl_sym < sym_end;
449333965Sjdp		       incl_sym++, incl_map++)
449433965Sjdp		    {
449533965Sjdp		      int incl_type;
449633965Sjdp
449789857Sobrien		      incl_type = H_GET_8 (input_bfd, incl_sym->e_type);
449833965Sjdp		      if (incl_type == N_EINCL)
449933965Sjdp			{
450033965Sjdp			  if (nest == 0)
450133965Sjdp			    {
450233965Sjdp			      *incl_map = -1;
450333965Sjdp			      break;
450433965Sjdp			    }
450533965Sjdp			  --nest;
450633965Sjdp			}
450733965Sjdp		      else if (incl_type == N_BINCL)
450833965Sjdp			++nest;
450933965Sjdp		      else if (nest == 0)
451033965Sjdp			*incl_map = -1;
451133965Sjdp		    }
451233965Sjdp		}
451333965Sjdp	    }
451433965Sjdp	}
451533965Sjdp
451633965Sjdp      /* Copy this symbol into the list of symbols we are going to
451733965Sjdp	 write out.  */
451889857Sobrien      H_PUT_8 (output_bfd, type, outsym->e_type);
451989857Sobrien      H_PUT_8 (output_bfd, H_GET_8 (input_bfd, sym->e_other), outsym->e_other);
452089857Sobrien      H_PUT_16 (output_bfd, H_GET_16 (input_bfd, sym->e_desc), outsym->e_desc);
452133965Sjdp      copy = false;
452233965Sjdp      if (! finfo->info->keep_memory)
452333965Sjdp	{
452433965Sjdp	  /* name points into a string table which we are going to
452533965Sjdp	     free.  If there is a hash table entry, use that string.
452633965Sjdp	     Otherwise, copy name into memory.  */
452733965Sjdp	  if (h != (struct aout_link_hash_entry *) NULL)
452833965Sjdp	    name = h->root.root.string;
452933965Sjdp	  else
453033965Sjdp	    copy = true;
453133965Sjdp	}
453233965Sjdp      strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
453333965Sjdp				       name, copy);
453433965Sjdp      if (strtab_index == (bfd_size_type) -1)
453533965Sjdp	return false;
453633965Sjdp      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
453733965Sjdp      PUT_WORD (output_bfd, val, outsym->e_value);
453833965Sjdp      *symbol_map = obj_aout_external_sym_count (output_bfd);
453933965Sjdp      ++obj_aout_external_sym_count (output_bfd);
454033965Sjdp      ++outsym;
454133965Sjdp    }
454233965Sjdp
454333965Sjdp  /* Write out the output symbols we have just constructed.  */
454433965Sjdp  if (outsym > finfo->output_syms)
454533965Sjdp    {
454689857Sobrien      bfd_size_type outsym_size;
454733965Sjdp
454833965Sjdp      if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0)
454933965Sjdp	return false;
455089857Sobrien      outsym_size = outsym - finfo->output_syms;
455189857Sobrien      outsym_size *= EXTERNAL_NLIST_SIZE;
455289857Sobrien      if (bfd_bwrite ((PTR) finfo->output_syms, outsym_size, output_bfd)
455389857Sobrien	  != outsym_size)
455433965Sjdp	return false;
455589857Sobrien      finfo->symoff += outsym_size;
455633965Sjdp    }
455733965Sjdp
455833965Sjdp  return true;
455933965Sjdp}
456033965Sjdp
456133965Sjdp/* Write out a symbol that was not associated with an a.out input
456233965Sjdp   object.  */
456333965Sjdp
456433965Sjdpstatic boolean
456533965Sjdpaout_link_write_other_symbol (h, data)
456633965Sjdp     struct aout_link_hash_entry *h;
456733965Sjdp     PTR data;
456833965Sjdp{
456933965Sjdp  struct aout_final_link_info *finfo = (struct aout_final_link_info *) data;
457033965Sjdp  bfd *output_bfd;
457133965Sjdp  int type;
457233965Sjdp  bfd_vma val;
457333965Sjdp  struct external_nlist outsym;
457433965Sjdp  bfd_size_type indx;
457589857Sobrien  bfd_size_type amt;
457633965Sjdp
457794536Sobrien  if (h->root.type == bfd_link_hash_warning)
457894536Sobrien    {
457994536Sobrien      h = (struct aout_link_hash_entry *) h->root.u.i.link;
458094536Sobrien      if (h->root.type == bfd_link_hash_new)
458194536Sobrien	return true;
458294536Sobrien    }
458394536Sobrien
458433965Sjdp  output_bfd = finfo->output_bfd;
458533965Sjdp
458633965Sjdp  if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL)
458733965Sjdp    {
458833965Sjdp      if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol)
458933965Sjdp	     (output_bfd, finfo->info, h)))
459033965Sjdp	{
459133965Sjdp	  /* FIXME: No way to handle errors.  */
459233965Sjdp	  abort ();
459333965Sjdp	}
459433965Sjdp    }
459533965Sjdp
459633965Sjdp  if (h->written)
459733965Sjdp    return true;
459833965Sjdp
459933965Sjdp  h->written = true;
460033965Sjdp
460133965Sjdp  /* An indx of -2 means the symbol must be written.  */
460233965Sjdp  if (h->indx != -2
460333965Sjdp      && (finfo->info->strip == strip_all
460433965Sjdp	  || (finfo->info->strip == strip_some
460533965Sjdp	      && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
460633965Sjdp				  false, false) == NULL)))
460733965Sjdp    return true;
460833965Sjdp
460933965Sjdp  switch (h->root.type)
461033965Sjdp    {
461133965Sjdp    default:
461294536Sobrien    case bfd_link_hash_warning:
461333965Sjdp      abort ();
461433965Sjdp      /* Avoid variable not initialized warnings.  */
461533965Sjdp      return true;
461633965Sjdp    case bfd_link_hash_new:
461733965Sjdp      /* This can happen for set symbols when sets are not being
461833965Sjdp         built.  */
461933965Sjdp      return true;
462033965Sjdp    case bfd_link_hash_undefined:
462133965Sjdp      type = N_UNDF | N_EXT;
462233965Sjdp      val = 0;
462333965Sjdp      break;
462433965Sjdp    case bfd_link_hash_defined:
462533965Sjdp    case bfd_link_hash_defweak:
462633965Sjdp      {
462733965Sjdp	asection *sec;
462833965Sjdp
462933965Sjdp	sec = h->root.u.def.section->output_section;
463033965Sjdp	BFD_ASSERT (bfd_is_abs_section (sec)
463133965Sjdp		    || sec->owner == output_bfd);
463233965Sjdp	if (sec == obj_textsec (output_bfd))
463333965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT;
463433965Sjdp	else if (sec == obj_datasec (output_bfd))
463533965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD;
463633965Sjdp	else if (sec == obj_bsssec (output_bfd))
463733965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB;
463833965Sjdp	else
463933965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA;
464033965Sjdp	type |= N_EXT;
464133965Sjdp	val = (h->root.u.def.value
464233965Sjdp	       + sec->vma
464333965Sjdp	       + h->root.u.def.section->output_offset);
464433965Sjdp      }
464533965Sjdp      break;
464633965Sjdp    case bfd_link_hash_common:
464733965Sjdp      type = N_UNDF | N_EXT;
464833965Sjdp      val = h->root.u.c.size;
464933965Sjdp      break;
465033965Sjdp    case bfd_link_hash_undefweak:
465133965Sjdp      type = N_WEAKU;
465233965Sjdp      val = 0;
465333965Sjdp    case bfd_link_hash_indirect:
465494536Sobrien      /* We ignore these symbols, since the indirected symbol is
465594536Sobrien	 already in the hash table.  */
465633965Sjdp      return true;
465733965Sjdp    }
465833965Sjdp
465989857Sobrien  H_PUT_8 (output_bfd, type, outsym.e_type);
466089857Sobrien  H_PUT_8 (output_bfd, 0, outsym.e_other);
466189857Sobrien  H_PUT_16 (output_bfd, 0, outsym.e_desc);
466233965Sjdp  indx = add_to_stringtab (output_bfd, finfo->strtab, h->root.root.string,
466333965Sjdp			   false);
466489857Sobrien  if (indx == - (bfd_size_type) 1)
466533965Sjdp    {
466633965Sjdp      /* FIXME: No way to handle errors.  */
466733965Sjdp      abort ();
466833965Sjdp    }
466933965Sjdp  PUT_WORD (output_bfd, indx, outsym.e_strx);
467033965Sjdp  PUT_WORD (output_bfd, val, outsym.e_value);
467133965Sjdp
467289857Sobrien  amt = EXTERNAL_NLIST_SIZE;
467333965Sjdp  if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0
467489857Sobrien      || bfd_bwrite ((PTR) &outsym, amt, output_bfd) != amt)
467533965Sjdp    {
467633965Sjdp      /* FIXME: No way to handle errors.  */
467733965Sjdp      abort ();
467833965Sjdp    }
467933965Sjdp
468033965Sjdp  finfo->symoff += EXTERNAL_NLIST_SIZE;
468133965Sjdp  h->indx = obj_aout_external_sym_count (output_bfd);
468233965Sjdp  ++obj_aout_external_sym_count (output_bfd);
468333965Sjdp
468433965Sjdp  return true;
468533965Sjdp}
468633965Sjdp
468733965Sjdp/* Link an a.out section into the output file.  */
468833965Sjdp
468933965Sjdpstatic boolean
469033965Sjdpaout_link_input_section (finfo, input_bfd, input_section, reloff_ptr,
469133965Sjdp			 rel_size)
469233965Sjdp     struct aout_final_link_info *finfo;
469333965Sjdp     bfd *input_bfd;
469433965Sjdp     asection *input_section;
469533965Sjdp     file_ptr *reloff_ptr;
469633965Sjdp     bfd_size_type rel_size;
469733965Sjdp{
469833965Sjdp  bfd_size_type input_size;
469933965Sjdp  PTR relocs;
470033965Sjdp
470133965Sjdp  /* Get the section contents.  */
470233965Sjdp  input_size = bfd_section_size (input_bfd, input_section);
470333965Sjdp  if (! bfd_get_section_contents (input_bfd, input_section,
470433965Sjdp				  (PTR) finfo->contents,
470533965Sjdp				  (file_ptr) 0, input_size))
470633965Sjdp    return false;
470733965Sjdp
470833965Sjdp  /* Read in the relocs if we haven't already done it.  */
470933965Sjdp  if (aout_section_data (input_section) != NULL
471033965Sjdp      && aout_section_data (input_section)->relocs != NULL)
471133965Sjdp    relocs = aout_section_data (input_section)->relocs;
471233965Sjdp  else
471333965Sjdp    {
471433965Sjdp      relocs = finfo->relocs;
471533965Sjdp      if (rel_size > 0)
471633965Sjdp	{
471733965Sjdp	  if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
471889857Sobrien	      || bfd_bread (relocs, rel_size, input_bfd) != rel_size)
471933965Sjdp	    return false;
472033965Sjdp	}
472133965Sjdp    }
472233965Sjdp
472333965Sjdp  /* Relocate the section contents.  */
472433965Sjdp  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
472533965Sjdp    {
472633965Sjdp      if (! aout_link_input_section_std (finfo, input_bfd, input_section,
472733965Sjdp					 (struct reloc_std_external *) relocs,
472833965Sjdp					 rel_size, finfo->contents))
472933965Sjdp	return false;
473033965Sjdp    }
473133965Sjdp  else
473233965Sjdp    {
473333965Sjdp      if (! aout_link_input_section_ext (finfo, input_bfd, input_section,
473433965Sjdp					 (struct reloc_ext_external *) relocs,
473533965Sjdp					 rel_size, finfo->contents))
473633965Sjdp	return false;
473733965Sjdp    }
473833965Sjdp
473933965Sjdp  /* Write out the section contents.  */
474033965Sjdp  if (! bfd_set_section_contents (finfo->output_bfd,
474133965Sjdp				  input_section->output_section,
474233965Sjdp				  (PTR) finfo->contents,
474389857Sobrien				  (file_ptr) input_section->output_offset,
474433965Sjdp				  input_size))
474533965Sjdp    return false;
474633965Sjdp
474733965Sjdp  /* If we are producing relocateable output, the relocs were
474833965Sjdp     modified, and we now write them out.  */
474933965Sjdp  if (finfo->info->relocateable && rel_size > 0)
475033965Sjdp    {
475133965Sjdp      if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
475233965Sjdp	return false;
475389857Sobrien      if (bfd_bwrite (relocs, rel_size, finfo->output_bfd) != rel_size)
475433965Sjdp	return false;
475533965Sjdp      *reloff_ptr += rel_size;
475633965Sjdp
475733965Sjdp      /* Assert that the relocs have not run into the symbols, and
475833965Sjdp	 that if these are the text relocs they have not run into the
475933965Sjdp	 data relocs.  */
476033965Sjdp      BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
476133965Sjdp		  && (reloff_ptr != &finfo->treloff
476233965Sjdp		      || (*reloff_ptr
476333965Sjdp			  <= obj_datasec (finfo->output_bfd)->rel_filepos)));
476433965Sjdp    }
476533965Sjdp
476633965Sjdp  return true;
476733965Sjdp}
476833965Sjdp
476933965Sjdp/* Get the section corresponding to a reloc index.  */
477033965Sjdp
477133965Sjdpstatic INLINE asection *
477233965Sjdpaout_reloc_index_to_section (abfd, indx)
477333965Sjdp     bfd *abfd;
477433965Sjdp     int indx;
477533965Sjdp{
477633965Sjdp  switch (indx & N_TYPE)
477733965Sjdp    {
477833965Sjdp    case N_TEXT:
477933965Sjdp      return obj_textsec (abfd);
478033965Sjdp    case N_DATA:
478133965Sjdp      return obj_datasec (abfd);
478233965Sjdp    case N_BSS:
478333965Sjdp      return obj_bsssec (abfd);
478433965Sjdp    case N_ABS:
478533965Sjdp    case N_UNDF:
478633965Sjdp      return bfd_abs_section_ptr;
478733965Sjdp    default:
478833965Sjdp      abort ();
478933965Sjdp    }
479060484Sobrien  /*NOTREACHED*/
479160484Sobrien  return NULL;
479233965Sjdp}
479333965Sjdp
479433965Sjdp/* Relocate an a.out section using standard a.out relocs.  */
479533965Sjdp
479633965Sjdpstatic boolean
479733965Sjdpaout_link_input_section_std (finfo, input_bfd, input_section, relocs,
479833965Sjdp			     rel_size, contents)
479933965Sjdp     struct aout_final_link_info *finfo;
480033965Sjdp     bfd *input_bfd;
480133965Sjdp     asection *input_section;
480233965Sjdp     struct reloc_std_external *relocs;
480333965Sjdp     bfd_size_type rel_size;
480433965Sjdp     bfd_byte *contents;
480533965Sjdp{
480633965Sjdp  boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
480733965Sjdp					  bfd *, asection *,
480833965Sjdp					  struct aout_link_hash_entry *,
480933965Sjdp					  PTR, bfd_byte *, boolean *,
481033965Sjdp					  bfd_vma *));
481133965Sjdp  bfd *output_bfd;
481233965Sjdp  boolean relocateable;
481333965Sjdp  struct external_nlist *syms;
481433965Sjdp  char *strings;
481533965Sjdp  struct aout_link_hash_entry **sym_hashes;
481633965Sjdp  int *symbol_map;
481733965Sjdp  bfd_size_type reloc_count;
481833965Sjdp  register struct reloc_std_external *rel;
481933965Sjdp  struct reloc_std_external *rel_end;
482033965Sjdp
482133965Sjdp  output_bfd = finfo->output_bfd;
482233965Sjdp  check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
482333965Sjdp
482433965Sjdp  BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE);
482533965Sjdp  BFD_ASSERT (input_bfd->xvec->header_byteorder
482633965Sjdp	      == output_bfd->xvec->header_byteorder);
482733965Sjdp
482833965Sjdp  relocateable = finfo->info->relocateable;
482933965Sjdp  syms = obj_aout_external_syms (input_bfd);
483033965Sjdp  strings = obj_aout_external_strings (input_bfd);
483133965Sjdp  sym_hashes = obj_aout_sym_hashes (input_bfd);
483233965Sjdp  symbol_map = finfo->symbol_map;
483333965Sjdp
483433965Sjdp  reloc_count = rel_size / RELOC_STD_SIZE;
483533965Sjdp  rel = relocs;
483633965Sjdp  rel_end = rel + reloc_count;
483733965Sjdp  for (; rel < rel_end; rel++)
483833965Sjdp    {
483933965Sjdp      bfd_vma r_addr;
484033965Sjdp      int r_index;
484133965Sjdp      int r_extern;
484233965Sjdp      int r_pcrel;
484333965Sjdp      int r_baserel = 0;
484433965Sjdp      reloc_howto_type *howto;
484533965Sjdp      struct aout_link_hash_entry *h = NULL;
484633965Sjdp      bfd_vma relocation;
484733965Sjdp      bfd_reloc_status_type r;
484833965Sjdp
484933965Sjdp      r_addr = GET_SWORD (input_bfd, rel->r_address);
485033965Sjdp
485133965Sjdp#ifdef MY_reloc_howto
485289857Sobrien      howto = MY_reloc_howto (input_bfd, rel, r_index, r_extern, r_pcrel);
485377298Sobrien#else
485433965Sjdp      {
485533965Sjdp	int r_jmptable;
485633965Sjdp	int r_relative;
485733965Sjdp	int r_length;
485833965Sjdp	unsigned int howto_idx;
485933965Sjdp
486033965Sjdp	if (bfd_header_big_endian (input_bfd))
486133965Sjdp	  {
486233965Sjdp	    r_index   =  ((rel->r_index[0] << 16)
486333965Sjdp			  | (rel->r_index[1] << 8)
486433965Sjdp			  | rel->r_index[2]);
486533965Sjdp	    r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
486633965Sjdp	    r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
486733965Sjdp	    r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
486833965Sjdp	    r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
486933965Sjdp	    r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
487033965Sjdp	    r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
487133965Sjdp			 >> RELOC_STD_BITS_LENGTH_SH_BIG);
487233965Sjdp	  }
487333965Sjdp	else
487433965Sjdp	  {
487533965Sjdp	    r_index   = ((rel->r_index[2] << 16)
487633965Sjdp			 | (rel->r_index[1] << 8)
487733965Sjdp			 | rel->r_index[0]);
487833965Sjdp	    r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
487933965Sjdp	    r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
488033965Sjdp	    r_baserel = (0 != (rel->r_type[0]
488133965Sjdp			       & RELOC_STD_BITS_BASEREL_LITTLE));
488233965Sjdp	    r_jmptable= (0 != (rel->r_type[0]
488333965Sjdp			       & RELOC_STD_BITS_JMPTABLE_LITTLE));
488433965Sjdp	    r_relative= (0 != (rel->r_type[0]
488533965Sjdp			       & RELOC_STD_BITS_RELATIVE_LITTLE));
488633965Sjdp	    r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
488733965Sjdp			 >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
488833965Sjdp	  }
488933965Sjdp
489033965Sjdp	howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
489133965Sjdp		     + 16 * r_jmptable + 32 * r_relative);
489233965Sjdp	BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
489333965Sjdp	howto = howto_table_std + howto_idx;
489433965Sjdp      }
489533965Sjdp#endif
489633965Sjdp
489733965Sjdp      if (relocateable)
489833965Sjdp	{
489933965Sjdp	  /* We are generating a relocateable output file, and must
490033965Sjdp	     modify the reloc accordingly.  */
490133965Sjdp	  if (r_extern)
490233965Sjdp	    {
490333965Sjdp	      /* If we know the symbol this relocation is against,
490433965Sjdp		 convert it into a relocation against a section.  This
490533965Sjdp		 is what the native linker does.  */
490633965Sjdp	      h = sym_hashes[r_index];
490733965Sjdp	      if (h != (struct aout_link_hash_entry *) NULL
490833965Sjdp		  && (h->root.type == bfd_link_hash_defined
490933965Sjdp		      || h->root.type == bfd_link_hash_defweak))
491033965Sjdp		{
491133965Sjdp		  asection *output_section;
491233965Sjdp
491333965Sjdp		  /* Change the r_extern value.  */
491433965Sjdp		  if (bfd_header_big_endian (output_bfd))
491533965Sjdp		    rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_BIG;
491633965Sjdp		  else
491733965Sjdp		    rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_LITTLE;
491833965Sjdp
491933965Sjdp		  /* Compute a new r_index.  */
492033965Sjdp		  output_section = h->root.u.def.section->output_section;
492133965Sjdp		  if (output_section == obj_textsec (output_bfd))
492233965Sjdp		    r_index = N_TEXT;
492333965Sjdp		  else if (output_section == obj_datasec (output_bfd))
492433965Sjdp		    r_index = N_DATA;
492533965Sjdp		  else if (output_section == obj_bsssec (output_bfd))
492633965Sjdp		    r_index = N_BSS;
492733965Sjdp		  else
492833965Sjdp		    r_index = N_ABS;
492933965Sjdp
493033965Sjdp		  /* Add the symbol value and the section VMA to the
493133965Sjdp		     addend stored in the contents.  */
493233965Sjdp		  relocation = (h->root.u.def.value
493333965Sjdp				+ output_section->vma
493433965Sjdp				+ h->root.u.def.section->output_offset);
493533965Sjdp		}
493633965Sjdp	      else
493733965Sjdp		{
493833965Sjdp		  /* We must change r_index according to the symbol
493933965Sjdp		     map.  */
494033965Sjdp		  r_index = symbol_map[r_index];
494133965Sjdp
494233965Sjdp		  if (r_index == -1)
494333965Sjdp		    {
494433965Sjdp		      if (h != NULL)
494533965Sjdp			{
494633965Sjdp			  /* We decided to strip this symbol, but it
494733965Sjdp                             turns out that we can't.  Note that we
494833965Sjdp                             lose the other and desc information here.
494933965Sjdp                             I don't think that will ever matter for a
495033965Sjdp                             global symbol.  */
495133965Sjdp			  if (h->indx < 0)
495233965Sjdp			    {
495333965Sjdp			      h->indx = -2;
495433965Sjdp			      h->written = false;
495533965Sjdp			      if (! aout_link_write_other_symbol (h,
495633965Sjdp								  (PTR) finfo))
495733965Sjdp				return false;
495833965Sjdp			    }
495933965Sjdp			  r_index = h->indx;
496033965Sjdp			}
496133965Sjdp		      else
496233965Sjdp			{
496333965Sjdp			  const char *name;
496433965Sjdp
496533965Sjdp			  name = strings + GET_WORD (input_bfd,
496633965Sjdp						     syms[r_index].e_strx);
496733965Sjdp			  if (! ((*finfo->info->callbacks->unattached_reloc)
496833965Sjdp				 (finfo->info, name, input_bfd, input_section,
496933965Sjdp				  r_addr)))
497033965Sjdp			    return false;
497133965Sjdp			  r_index = 0;
497233965Sjdp			}
497333965Sjdp		    }
497433965Sjdp
497533965Sjdp		  relocation = 0;
497633965Sjdp		}
497733965Sjdp
497833965Sjdp	      /* Write out the new r_index value.  */
497933965Sjdp	      if (bfd_header_big_endian (output_bfd))
498033965Sjdp		{
498133965Sjdp		  rel->r_index[0] = r_index >> 16;
498233965Sjdp		  rel->r_index[1] = r_index >> 8;
498333965Sjdp		  rel->r_index[2] = r_index;
498433965Sjdp		}
498533965Sjdp	      else
498633965Sjdp		{
498733965Sjdp		  rel->r_index[2] = r_index >> 16;
498833965Sjdp		  rel->r_index[1] = r_index >> 8;
498933965Sjdp		  rel->r_index[0] = r_index;
499033965Sjdp		}
499133965Sjdp	    }
499233965Sjdp	  else
499333965Sjdp	    {
499433965Sjdp	      asection *section;
499533965Sjdp
499633965Sjdp	      /* This is a relocation against a section.  We must
499733965Sjdp		 adjust by the amount that the section moved.  */
499833965Sjdp	      section = aout_reloc_index_to_section (input_bfd, r_index);
499933965Sjdp	      relocation = (section->output_section->vma
500033965Sjdp			    + section->output_offset
500133965Sjdp			    - section->vma);
500233965Sjdp	    }
500333965Sjdp
500433965Sjdp	  /* Change the address of the relocation.  */
500533965Sjdp	  PUT_WORD (output_bfd,
500633965Sjdp		    r_addr + input_section->output_offset,
500733965Sjdp		    rel->r_address);
500833965Sjdp
500933965Sjdp	  /* Adjust a PC relative relocation by removing the reference
501033965Sjdp	     to the original address in the section and including the
501133965Sjdp	     reference to the new address.  */
501233965Sjdp	  if (r_pcrel)
501333965Sjdp	    relocation -= (input_section->output_section->vma
501433965Sjdp			   + input_section->output_offset
501533965Sjdp			   - input_section->vma);
501633965Sjdp
501733965Sjdp#ifdef MY_relocatable_reloc
501833965Sjdp	  MY_relocatable_reloc (howto, output_bfd, rel, relocation, r_addr);
501933965Sjdp#endif
502033965Sjdp
502133965Sjdp	  if (relocation == 0)
502233965Sjdp	    r = bfd_reloc_ok;
502333965Sjdp	  else
502433965Sjdp	    r = MY_relocate_contents (howto,
502533965Sjdp					input_bfd, relocation,
502633965Sjdp					contents + r_addr);
502733965Sjdp	}
502833965Sjdp      else
502933965Sjdp	{
503033965Sjdp	  boolean hundef;
503133965Sjdp
503233965Sjdp	  /* We are generating an executable, and must do a full
503333965Sjdp	     relocation.  */
503433965Sjdp	  hundef = false;
503560484Sobrien
503633965Sjdp	  if (r_extern)
503733965Sjdp	    {
503833965Sjdp	      h = sym_hashes[r_index];
503933965Sjdp
504033965Sjdp	      if (h != (struct aout_link_hash_entry *) NULL
504133965Sjdp		  && (h->root.type == bfd_link_hash_defined
504233965Sjdp		      || h->root.type == bfd_link_hash_defweak))
504333965Sjdp		{
504433965Sjdp		  relocation = (h->root.u.def.value
504533965Sjdp				+ h->root.u.def.section->output_section->vma
504633965Sjdp				+ h->root.u.def.section->output_offset);
504733965Sjdp		}
504833965Sjdp	      else if (h != (struct aout_link_hash_entry *) NULL
504933965Sjdp		       && h->root.type == bfd_link_hash_undefweak)
505033965Sjdp		relocation = 0;
505133965Sjdp	      else
505233965Sjdp		{
505333965Sjdp		  hundef = true;
505433965Sjdp		  relocation = 0;
505533965Sjdp		}
505633965Sjdp	    }
505733965Sjdp	  else
505833965Sjdp	    {
505933965Sjdp	      asection *section;
506033965Sjdp
506133965Sjdp	      section = aout_reloc_index_to_section (input_bfd, r_index);
506233965Sjdp	      relocation = (section->output_section->vma
506333965Sjdp			    + section->output_offset
506433965Sjdp			    - section->vma);
506533965Sjdp	      if (r_pcrel)
506633965Sjdp		relocation += input_section->vma;
506733965Sjdp	    }
506833965Sjdp
506933965Sjdp	  if (check_dynamic_reloc != NULL)
507033965Sjdp	    {
507133965Sjdp	      boolean skip;
507233965Sjdp
507333965Sjdp	      if (! ((*check_dynamic_reloc)
507433965Sjdp		     (finfo->info, input_bfd, input_section, h,
507533965Sjdp		      (PTR) rel, contents, &skip, &relocation)))
507633965Sjdp		return false;
507733965Sjdp	      if (skip)
507833965Sjdp		continue;
507933965Sjdp	    }
508033965Sjdp
508133965Sjdp	  /* Now warn if a global symbol is undefined.  We could not
508233965Sjdp             do this earlier, because check_dynamic_reloc might want
508333965Sjdp             to skip this reloc.  */
508433965Sjdp	  if (hundef && ! finfo->info->shared && ! r_baserel)
508533965Sjdp	    {
508633965Sjdp	      const char *name;
508733965Sjdp
508833965Sjdp	      if (h != NULL)
508933965Sjdp		name = h->root.root.string;
509033965Sjdp	      else
509133965Sjdp		name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
509233965Sjdp	      if (! ((*finfo->info->callbacks->undefined_symbol)
509360484Sobrien		     (finfo->info, name, input_bfd, input_section,
509460484Sobrien		     r_addr, true)))
509533965Sjdp		return false;
509633965Sjdp	    }
509733965Sjdp
509833965Sjdp	  r = MY_final_link_relocate (howto,
509933965Sjdp				      input_bfd, input_section,
510033965Sjdp				      contents, r_addr, relocation,
510133965Sjdp				      (bfd_vma) 0);
510233965Sjdp	}
510333965Sjdp
510433965Sjdp      if (r != bfd_reloc_ok)
510533965Sjdp	{
510633965Sjdp	  switch (r)
510733965Sjdp	    {
510833965Sjdp	    default:
510933965Sjdp	    case bfd_reloc_outofrange:
511033965Sjdp	      abort ();
511133965Sjdp	    case bfd_reloc_overflow:
511233965Sjdp	      {
511333965Sjdp		const char *name;
511433965Sjdp
511533965Sjdp		if (h != NULL)
511633965Sjdp		  name = h->root.root.string;
511733965Sjdp		else if (r_extern)
511833965Sjdp		  name = strings + GET_WORD (input_bfd,
511933965Sjdp					     syms[r_index].e_strx);
512033965Sjdp		else
512133965Sjdp		  {
512233965Sjdp		    asection *s;
512333965Sjdp
512433965Sjdp		    s = aout_reloc_index_to_section (input_bfd, r_index);
512533965Sjdp		    name = bfd_section_name (input_bfd, s);
512633965Sjdp		  }
512733965Sjdp		if (! ((*finfo->info->callbacks->reloc_overflow)
512833965Sjdp		       (finfo->info, name, howto->name,
512933965Sjdp			(bfd_vma) 0, input_bfd, input_section, r_addr)))
513033965Sjdp		  return false;
513133965Sjdp	      }
513233965Sjdp	      break;
513333965Sjdp	    }
513433965Sjdp	}
513533965Sjdp    }
513633965Sjdp
513733965Sjdp  return true;
513833965Sjdp}
513933965Sjdp
514033965Sjdp/* Relocate an a.out section using extended a.out relocs.  */
514133965Sjdp
514233965Sjdpstatic boolean
514333965Sjdpaout_link_input_section_ext (finfo, input_bfd, input_section, relocs,
514433965Sjdp			     rel_size, contents)
514533965Sjdp     struct aout_final_link_info *finfo;
514633965Sjdp     bfd *input_bfd;
514733965Sjdp     asection *input_section;
514833965Sjdp     struct reloc_ext_external *relocs;
514933965Sjdp     bfd_size_type rel_size;
515033965Sjdp     bfd_byte *contents;
515133965Sjdp{
515233965Sjdp  boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *,
515333965Sjdp					  bfd *, asection *,
515433965Sjdp					  struct aout_link_hash_entry *,
515533965Sjdp					  PTR, bfd_byte *, boolean *,
515633965Sjdp					  bfd_vma *));
515733965Sjdp  bfd *output_bfd;
515833965Sjdp  boolean relocateable;
515933965Sjdp  struct external_nlist *syms;
516033965Sjdp  char *strings;
516133965Sjdp  struct aout_link_hash_entry **sym_hashes;
516233965Sjdp  int *symbol_map;
516333965Sjdp  bfd_size_type reloc_count;
516433965Sjdp  register struct reloc_ext_external *rel;
516533965Sjdp  struct reloc_ext_external *rel_end;
516633965Sjdp
516733965Sjdp  output_bfd = finfo->output_bfd;
516833965Sjdp  check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
516933965Sjdp
517033965Sjdp  BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE);
517133965Sjdp  BFD_ASSERT (input_bfd->xvec->header_byteorder
517233965Sjdp	      == output_bfd->xvec->header_byteorder);
517333965Sjdp
517433965Sjdp  relocateable = finfo->info->relocateable;
517533965Sjdp  syms = obj_aout_external_syms (input_bfd);
517633965Sjdp  strings = obj_aout_external_strings (input_bfd);
517733965Sjdp  sym_hashes = obj_aout_sym_hashes (input_bfd);
517833965Sjdp  symbol_map = finfo->symbol_map;
517933965Sjdp
518033965Sjdp  reloc_count = rel_size / RELOC_EXT_SIZE;
518133965Sjdp  rel = relocs;
518233965Sjdp  rel_end = rel + reloc_count;
518333965Sjdp  for (; rel < rel_end; rel++)
518433965Sjdp    {
518533965Sjdp      bfd_vma r_addr;
518633965Sjdp      int r_index;
518733965Sjdp      int r_extern;
518833965Sjdp      unsigned int r_type;
518933965Sjdp      bfd_vma r_addend;
519033965Sjdp      struct aout_link_hash_entry *h = NULL;
519133965Sjdp      asection *r_section = NULL;
519233965Sjdp      bfd_vma relocation;
519333965Sjdp
519433965Sjdp      r_addr = GET_SWORD (input_bfd, rel->r_address);
519533965Sjdp
519633965Sjdp      if (bfd_header_big_endian (input_bfd))
519733965Sjdp	{
519833965Sjdp	  r_index  = ((rel->r_index[0] << 16)
519933965Sjdp		      | (rel->r_index[1] << 8)
520033965Sjdp		      | rel->r_index[2]);
520133965Sjdp	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
520233965Sjdp	  r_type   = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
520333965Sjdp		      >> RELOC_EXT_BITS_TYPE_SH_BIG);
520433965Sjdp	}
520533965Sjdp      else
520633965Sjdp	{
520733965Sjdp	  r_index  = ((rel->r_index[2] << 16)
520833965Sjdp		      | (rel->r_index[1] << 8)
520933965Sjdp		      | rel->r_index[0]);
521033965Sjdp	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
521133965Sjdp	  r_type   = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
521233965Sjdp		      >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
521333965Sjdp	}
521433965Sjdp
521533965Sjdp      r_addend = GET_SWORD (input_bfd, rel->r_addend);
521633965Sjdp
521733965Sjdp      BFD_ASSERT (r_type < TABLE_SIZE (howto_table_ext));
521833965Sjdp
521933965Sjdp      if (relocateable)
522033965Sjdp	{
522133965Sjdp	  /* We are generating a relocateable output file, and must
522233965Sjdp	     modify the reloc accordingly.  */
522333965Sjdp	  if (r_extern
522433965Sjdp	      || r_type == RELOC_BASE10
522533965Sjdp	      || r_type == RELOC_BASE13
522633965Sjdp	      || r_type == RELOC_BASE22)
522733965Sjdp	    {
522833965Sjdp	      /* If we know the symbol this relocation is against,
522933965Sjdp		 convert it into a relocation against a section.  This
523033965Sjdp		 is what the native linker does.  */
523133965Sjdp	      if (r_type == RELOC_BASE10
523233965Sjdp		  || r_type == RELOC_BASE13
523333965Sjdp		  || r_type == RELOC_BASE22)
523433965Sjdp		h = NULL;
523533965Sjdp	      else
523633965Sjdp		h = sym_hashes[r_index];
523733965Sjdp	      if (h != (struct aout_link_hash_entry *) NULL
523833965Sjdp		  && (h->root.type == bfd_link_hash_defined
523933965Sjdp		      || h->root.type == bfd_link_hash_defweak))
524033965Sjdp		{
524133965Sjdp		  asection *output_section;
524233965Sjdp
524333965Sjdp		  /* Change the r_extern value.  */
524433965Sjdp		  if (bfd_header_big_endian (output_bfd))
524533965Sjdp		    rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_BIG;
524633965Sjdp		  else
524733965Sjdp		    rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_LITTLE;
524833965Sjdp
524933965Sjdp		  /* Compute a new r_index.  */
525033965Sjdp		  output_section = h->root.u.def.section->output_section;
525133965Sjdp		  if (output_section == obj_textsec (output_bfd))
525233965Sjdp		    r_index = N_TEXT;
525333965Sjdp		  else if (output_section == obj_datasec (output_bfd))
525433965Sjdp		    r_index = N_DATA;
525533965Sjdp		  else if (output_section == obj_bsssec (output_bfd))
525633965Sjdp		    r_index = N_BSS;
525733965Sjdp		  else
525833965Sjdp		    r_index = N_ABS;
525933965Sjdp
526033965Sjdp		  /* Add the symbol value and the section VMA to the
526133965Sjdp		     addend.  */
526233965Sjdp		  relocation = (h->root.u.def.value
526333965Sjdp				+ output_section->vma
526433965Sjdp				+ h->root.u.def.section->output_offset);
526533965Sjdp
526633965Sjdp		  /* Now RELOCATION is the VMA of the final
526733965Sjdp		     destination.  If this is a PC relative reloc,
526833965Sjdp		     then ADDEND is the negative of the source VMA.
526933965Sjdp		     We want to set ADDEND to the difference between
527033965Sjdp		     the destination VMA and the source VMA, which
527133965Sjdp		     means we must adjust RELOCATION by the change in
527233965Sjdp		     the source VMA.  This is done below.  */
527333965Sjdp		}
527433965Sjdp	      else
527533965Sjdp		{
527633965Sjdp		  /* We must change r_index according to the symbol
527733965Sjdp		     map.  */
527833965Sjdp		  r_index = symbol_map[r_index];
527933965Sjdp
528033965Sjdp		  if (r_index == -1)
528133965Sjdp		    {
528233965Sjdp		      if (h != NULL)
528333965Sjdp			{
528433965Sjdp			  /* We decided to strip this symbol, but it
528533965Sjdp                             turns out that we can't.  Note that we
528633965Sjdp                             lose the other and desc information here.
528733965Sjdp                             I don't think that will ever matter for a
528833965Sjdp                             global symbol.  */
528933965Sjdp			  if (h->indx < 0)
529033965Sjdp			    {
529133965Sjdp			      h->indx = -2;
529233965Sjdp			      h->written = false;
529333965Sjdp			      if (! aout_link_write_other_symbol (h,
529433965Sjdp								  (PTR) finfo))
529533965Sjdp				return false;
529633965Sjdp			    }
529733965Sjdp			  r_index = h->indx;
529833965Sjdp			}
529933965Sjdp		      else
530033965Sjdp			{
530133965Sjdp			  const char *name;
530233965Sjdp
530333965Sjdp			  name = strings + GET_WORD (input_bfd,
530433965Sjdp						     syms[r_index].e_strx);
530533965Sjdp			  if (! ((*finfo->info->callbacks->unattached_reloc)
530633965Sjdp				 (finfo->info, name, input_bfd, input_section,
530733965Sjdp				  r_addr)))
530833965Sjdp			    return false;
530933965Sjdp			  r_index = 0;
531033965Sjdp			}
531133965Sjdp		    }
531233965Sjdp
531333965Sjdp		  relocation = 0;
531433965Sjdp
531533965Sjdp		  /* If this is a PC relative reloc, then the addend
531633965Sjdp		     is the negative of the source VMA.  We must
531733965Sjdp		     adjust it by the change in the source VMA.  This
531833965Sjdp		     is done below.  */
531933965Sjdp		}
532033965Sjdp
532133965Sjdp	      /* Write out the new r_index value.  */
532233965Sjdp	      if (bfd_header_big_endian (output_bfd))
532333965Sjdp		{
532433965Sjdp		  rel->r_index[0] = r_index >> 16;
532533965Sjdp		  rel->r_index[1] = r_index >> 8;
532633965Sjdp		  rel->r_index[2] = r_index;
532733965Sjdp		}
532833965Sjdp	      else
532933965Sjdp		{
533033965Sjdp		  rel->r_index[2] = r_index >> 16;
533133965Sjdp		  rel->r_index[1] = r_index >> 8;
533233965Sjdp		  rel->r_index[0] = r_index;
533333965Sjdp		}
533433965Sjdp	    }
533533965Sjdp	  else
533633965Sjdp	    {
533733965Sjdp	      /* This is a relocation against a section.  We must
533833965Sjdp		 adjust by the amount that the section moved.  */
533933965Sjdp	      r_section = aout_reloc_index_to_section (input_bfd, r_index);
534033965Sjdp	      relocation = (r_section->output_section->vma
534133965Sjdp			    + r_section->output_offset
534233965Sjdp			    - r_section->vma);
534333965Sjdp
534433965Sjdp	      /* If this is a PC relative reloc, then the addend is
534533965Sjdp		 the difference in VMA between the destination and the
534633965Sjdp		 source.  We have just adjusted for the change in VMA
534733965Sjdp		 of the destination, so we must also adjust by the
534833965Sjdp		 change in VMA of the source.  This is done below.  */
534933965Sjdp	    }
535033965Sjdp
535133965Sjdp	  /* As described above, we must always adjust a PC relative
535233965Sjdp	     reloc by the change in VMA of the source.  However, if
535333965Sjdp	     pcrel_offset is set, then the addend does not include the
535433965Sjdp	     location within the section, in which case we don't need
535533965Sjdp	     to adjust anything.  */
535633965Sjdp	  if (howto_table_ext[r_type].pc_relative
535733965Sjdp	      && ! howto_table_ext[r_type].pcrel_offset)
535833965Sjdp	    relocation -= (input_section->output_section->vma
535933965Sjdp			   + input_section->output_offset
536033965Sjdp			   - input_section->vma);
536133965Sjdp
536233965Sjdp	  /* Change the addend if necessary.  */
536333965Sjdp	  if (relocation != 0)
536433965Sjdp	    PUT_WORD (output_bfd, r_addend + relocation, rel->r_addend);
536533965Sjdp
536633965Sjdp	  /* Change the address of the relocation.  */
536733965Sjdp	  PUT_WORD (output_bfd,
536833965Sjdp		    r_addr + input_section->output_offset,
536933965Sjdp		    rel->r_address);
537033965Sjdp	}
537133965Sjdp      else
537233965Sjdp	{
537333965Sjdp	  boolean hundef;
537433965Sjdp	  bfd_reloc_status_type r;
537533965Sjdp
537633965Sjdp	  /* We are generating an executable, and must do a full
537733965Sjdp	     relocation.  */
537833965Sjdp	  hundef = false;
537960484Sobrien
538033965Sjdp	  if (r_extern)
538133965Sjdp	    {
538233965Sjdp	      h = sym_hashes[r_index];
538333965Sjdp
538433965Sjdp	      if (h != (struct aout_link_hash_entry *) NULL
538533965Sjdp		  && (h->root.type == bfd_link_hash_defined
538633965Sjdp		      || h->root.type == bfd_link_hash_defweak))
538733965Sjdp		{
538833965Sjdp		  relocation = (h->root.u.def.value
538933965Sjdp				+ h->root.u.def.section->output_section->vma
539033965Sjdp				+ h->root.u.def.section->output_offset);
539133965Sjdp		}
539233965Sjdp	      else if (h != (struct aout_link_hash_entry *) NULL
539333965Sjdp		       && h->root.type == bfd_link_hash_undefweak)
539433965Sjdp		relocation = 0;
539533965Sjdp	      else
539633965Sjdp		{
539733965Sjdp		  hundef = true;
539833965Sjdp		  relocation = 0;
539933965Sjdp		}
540033965Sjdp	    }
540133965Sjdp	  else if (r_type == RELOC_BASE10
540233965Sjdp		   || r_type == RELOC_BASE13
540333965Sjdp		   || r_type == RELOC_BASE22)
540433965Sjdp	    {
540533965Sjdp	      struct external_nlist *sym;
540633965Sjdp	      int type;
540733965Sjdp
540833965Sjdp	      /* For base relative relocs, r_index is always an index
540933965Sjdp                 into the symbol table, even if r_extern is 0.  */
541033965Sjdp	      sym = syms + r_index;
541189857Sobrien	      type = H_GET_8 (input_bfd, sym->e_type);
541233965Sjdp	      if ((type & N_TYPE) == N_TEXT
541333965Sjdp		  || type == N_WEAKT)
541433965Sjdp		r_section = obj_textsec (input_bfd);
541533965Sjdp	      else if ((type & N_TYPE) == N_DATA
541633965Sjdp		       || type == N_WEAKD)
541733965Sjdp		r_section = obj_datasec (input_bfd);
541833965Sjdp	      else if ((type & N_TYPE) == N_BSS
541933965Sjdp		       || type == N_WEAKB)
542033965Sjdp		r_section = obj_bsssec (input_bfd);
542133965Sjdp	      else if ((type & N_TYPE) == N_ABS
542233965Sjdp		       || type == N_WEAKA)
542333965Sjdp		r_section = bfd_abs_section_ptr;
542433965Sjdp	      else
542533965Sjdp		abort ();
542633965Sjdp	      relocation = (r_section->output_section->vma
542733965Sjdp			    + r_section->output_offset
542833965Sjdp			    + (GET_WORD (input_bfd, sym->e_value)
542933965Sjdp			       - r_section->vma));
543033965Sjdp	    }
543133965Sjdp	  else
543233965Sjdp	    {
543333965Sjdp	      r_section = aout_reloc_index_to_section (input_bfd, r_index);
543433965Sjdp
543533965Sjdp	      /* If this is a PC relative reloc, then R_ADDEND is the
543633965Sjdp		 difference between the two vmas, or
543733965Sjdp		   old_dest_sec + old_dest_off - (old_src_sec + old_src_off)
543833965Sjdp		 where
543933965Sjdp		   old_dest_sec == section->vma
544033965Sjdp		 and
544133965Sjdp		   old_src_sec == input_section->vma
544233965Sjdp		 and
544333965Sjdp		   old_src_off == r_addr
544433965Sjdp
544533965Sjdp		 _bfd_final_link_relocate expects RELOCATION +
544633965Sjdp		 R_ADDEND to be the VMA of the destination minus
544733965Sjdp		 r_addr (the minus r_addr is because this relocation
544833965Sjdp		 is not pcrel_offset, which is a bit confusing and
544933965Sjdp		 should, perhaps, be changed), or
545033965Sjdp		   new_dest_sec
545133965Sjdp		 where
545233965Sjdp		   new_dest_sec == output_section->vma + output_offset
545333965Sjdp		 We arrange for this to happen by setting RELOCATION to
545433965Sjdp		   new_dest_sec + old_src_sec - old_dest_sec
545533965Sjdp
545633965Sjdp		 If this is not a PC relative reloc, then R_ADDEND is
545733965Sjdp		 simply the VMA of the destination, so we set
545833965Sjdp		 RELOCATION to the change in the destination VMA, or
545933965Sjdp		   new_dest_sec - old_dest_sec
546033965Sjdp		 */
546133965Sjdp	      relocation = (r_section->output_section->vma
546233965Sjdp			    + r_section->output_offset
546333965Sjdp			    - r_section->vma);
546433965Sjdp	      if (howto_table_ext[r_type].pc_relative)
546533965Sjdp		relocation += input_section->vma;
546633965Sjdp	    }
546733965Sjdp
546833965Sjdp	  if (check_dynamic_reloc != NULL)
546933965Sjdp	    {
547033965Sjdp	      boolean skip;
547133965Sjdp
547233965Sjdp	      if (! ((*check_dynamic_reloc)
547333965Sjdp		     (finfo->info, input_bfd, input_section, h,
547433965Sjdp		      (PTR) rel, contents, &skip, &relocation)))
547533965Sjdp		return false;
547633965Sjdp	      if (skip)
547733965Sjdp		continue;
547833965Sjdp	    }
547933965Sjdp
548033965Sjdp	  /* Now warn if a global symbol is undefined.  We could not
548133965Sjdp             do this earlier, because check_dynamic_reloc might want
548233965Sjdp             to skip this reloc.  */
548333965Sjdp	  if (hundef
548433965Sjdp	      && ! finfo->info->shared
548533965Sjdp	      && r_type != RELOC_BASE10
548633965Sjdp	      && r_type != RELOC_BASE13
548733965Sjdp	      && r_type != RELOC_BASE22)
548833965Sjdp	    {
548933965Sjdp	      const char *name;
549033965Sjdp
549133965Sjdp	      if (h != NULL)
549233965Sjdp		name = h->root.root.string;
549333965Sjdp	      else
549433965Sjdp		name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
549533965Sjdp	      if (! ((*finfo->info->callbacks->undefined_symbol)
549660484Sobrien		     (finfo->info, name, input_bfd, input_section,
549760484Sobrien		     r_addr, true)))
549833965Sjdp		return false;
549933965Sjdp	    }
550033965Sjdp
550160484Sobrien	  if (r_type != RELOC_SPARC_REV32)
550260484Sobrien	    r = MY_final_link_relocate (howto_table_ext + r_type,
550360484Sobrien					input_bfd, input_section,
550460484Sobrien					contents, r_addr, relocation,
550560484Sobrien					r_addend);
550660484Sobrien	  else
550760484Sobrien	    {
550860484Sobrien	      bfd_vma x;
550960484Sobrien
551060484Sobrien	      x = bfd_get_32 (input_bfd, contents + r_addr);
551160484Sobrien	      x = x + relocation + r_addend;
551260484Sobrien	      bfd_putl32 (/*input_bfd,*/ x, contents + r_addr);
551360484Sobrien	      r = bfd_reloc_ok;
551460484Sobrien	    }
551560484Sobrien
551633965Sjdp	  if (r != bfd_reloc_ok)
551733965Sjdp	    {
551833965Sjdp	      switch (r)
551933965Sjdp		{
552033965Sjdp		default:
552133965Sjdp		case bfd_reloc_outofrange:
552233965Sjdp		  abort ();
552333965Sjdp		case bfd_reloc_overflow:
552433965Sjdp		  {
552533965Sjdp		    const char *name;
552633965Sjdp
552733965Sjdp		    if (h != NULL)
552833965Sjdp		      name = h->root.root.string;
552933965Sjdp		    else if (r_extern
553033965Sjdp			     || r_type == RELOC_BASE10
553133965Sjdp			     || r_type == RELOC_BASE13
553233965Sjdp			     || r_type == RELOC_BASE22)
553333965Sjdp		      name = strings + GET_WORD (input_bfd,
553433965Sjdp						 syms[r_index].e_strx);
553533965Sjdp		    else
553633965Sjdp		      {
553733965Sjdp			asection *s;
553833965Sjdp
553933965Sjdp			s = aout_reloc_index_to_section (input_bfd, r_index);
554033965Sjdp			name = bfd_section_name (input_bfd, s);
554133965Sjdp		      }
554233965Sjdp		    if (! ((*finfo->info->callbacks->reloc_overflow)
554333965Sjdp			   (finfo->info, name, howto_table_ext[r_type].name,
554433965Sjdp			    r_addend, input_bfd, input_section, r_addr)))
554533965Sjdp		      return false;
554633965Sjdp		  }
554733965Sjdp		  break;
554833965Sjdp		}
554933965Sjdp	    }
555033965Sjdp	}
555133965Sjdp    }
555233965Sjdp
555333965Sjdp  return true;
555433965Sjdp}
555533965Sjdp
555633965Sjdp/* Handle a link order which is supposed to generate a reloc.  */
555733965Sjdp
555833965Sjdpstatic boolean
555933965Sjdpaout_link_reloc_link_order (finfo, o, p)
556033965Sjdp     struct aout_final_link_info *finfo;
556133965Sjdp     asection *o;
556233965Sjdp     struct bfd_link_order *p;
556333965Sjdp{
556433965Sjdp  struct bfd_link_order_reloc *pr;
556533965Sjdp  int r_index;
556633965Sjdp  int r_extern;
556733965Sjdp  reloc_howto_type *howto;
556860484Sobrien  file_ptr *reloff_ptr = NULL;
556933965Sjdp  struct reloc_std_external srel;
557033965Sjdp  struct reloc_ext_external erel;
557133965Sjdp  PTR rel_ptr;
557289857Sobrien  bfd_size_type amt;
557333965Sjdp
557433965Sjdp  pr = p->u.reloc.p;
557533965Sjdp
557633965Sjdp  if (p->type == bfd_section_reloc_link_order)
557733965Sjdp    {
557833965Sjdp      r_extern = 0;
557933965Sjdp      if (bfd_is_abs_section (pr->u.section))
558033965Sjdp	r_index = N_ABS | N_EXT;
558133965Sjdp      else
558233965Sjdp	{
558333965Sjdp	  BFD_ASSERT (pr->u.section->owner == finfo->output_bfd);
558433965Sjdp	  r_index = pr->u.section->target_index;
558533965Sjdp	}
558633965Sjdp    }
558733965Sjdp  else
558833965Sjdp    {
558933965Sjdp      struct aout_link_hash_entry *h;
559033965Sjdp
559133965Sjdp      BFD_ASSERT (p->type == bfd_symbol_reloc_link_order);
559233965Sjdp      r_extern = 1;
559333965Sjdp      h = ((struct aout_link_hash_entry *)
559433965Sjdp	   bfd_wrapped_link_hash_lookup (finfo->output_bfd, finfo->info,
559533965Sjdp					 pr->u.name, false, false, true));
559633965Sjdp      if (h != (struct aout_link_hash_entry *) NULL
559733965Sjdp	  && h->indx >= 0)
559833965Sjdp	r_index = h->indx;
559933965Sjdp      else if (h != NULL)
560033965Sjdp	{
560133965Sjdp	  /* We decided to strip this symbol, but it turns out that we
560233965Sjdp	     can't.  Note that we lose the other and desc information
560333965Sjdp	     here.  I don't think that will ever matter for a global
560433965Sjdp	     symbol.  */
560533965Sjdp	  h->indx = -2;
560633965Sjdp	  h->written = false;
560733965Sjdp	  if (! aout_link_write_other_symbol (h, (PTR) finfo))
560833965Sjdp	    return false;
560933965Sjdp	  r_index = h->indx;
561033965Sjdp	}
561133965Sjdp      else
561233965Sjdp	{
561333965Sjdp	  if (! ((*finfo->info->callbacks->unattached_reloc)
561433965Sjdp		 (finfo->info, pr->u.name, (bfd *) NULL,
561533965Sjdp		  (asection *) NULL, (bfd_vma) 0)))
561633965Sjdp	    return false;
561733965Sjdp	  r_index = 0;
561833965Sjdp	}
561933965Sjdp    }
562033965Sjdp
562133965Sjdp  howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc);
562233965Sjdp  if (howto == 0)
562333965Sjdp    {
562433965Sjdp      bfd_set_error (bfd_error_bad_value);
562533965Sjdp      return false;
562633965Sjdp    }
562733965Sjdp
562833965Sjdp  if (o == obj_textsec (finfo->output_bfd))
562933965Sjdp    reloff_ptr = &finfo->treloff;
563033965Sjdp  else if (o == obj_datasec (finfo->output_bfd))
563133965Sjdp    reloff_ptr = &finfo->dreloff;
563233965Sjdp  else
563333965Sjdp    abort ();
563433965Sjdp
563533965Sjdp  if (obj_reloc_entry_size (finfo->output_bfd) == RELOC_STD_SIZE)
563633965Sjdp    {
563733965Sjdp#ifdef MY_put_reloc
563889857Sobrien      MY_put_reloc (finfo->output_bfd, r_extern, r_index, p->offset, howto,
563989857Sobrien		    &srel);
564033965Sjdp#else
564133965Sjdp      {
564233965Sjdp	int r_pcrel;
564333965Sjdp	int r_baserel;
564433965Sjdp	int r_jmptable;
564533965Sjdp	int r_relative;
564633965Sjdp	int r_length;
564733965Sjdp
564833965Sjdp	r_pcrel = howto->pc_relative;
564933965Sjdp	r_baserel = (howto->type & 8) != 0;
565033965Sjdp	r_jmptable = (howto->type & 16) != 0;
565133965Sjdp	r_relative = (howto->type & 32) != 0;
565233965Sjdp	r_length = howto->size;
565333965Sjdp
565433965Sjdp	PUT_WORD (finfo->output_bfd, p->offset, srel.r_address);
565533965Sjdp	if (bfd_header_big_endian (finfo->output_bfd))
565633965Sjdp	  {
565733965Sjdp	    srel.r_index[0] = r_index >> 16;
565833965Sjdp	    srel.r_index[1] = r_index >> 8;
565933965Sjdp	    srel.r_index[2] = r_index;
566033965Sjdp	    srel.r_type[0] =
566133965Sjdp	      ((r_extern ?     RELOC_STD_BITS_EXTERN_BIG : 0)
566233965Sjdp	       | (r_pcrel ?    RELOC_STD_BITS_PCREL_BIG : 0)
566333965Sjdp	       | (r_baserel ?  RELOC_STD_BITS_BASEREL_BIG : 0)
566433965Sjdp	       | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
566533965Sjdp	       | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
566633965Sjdp	       | (r_length <<  RELOC_STD_BITS_LENGTH_SH_BIG));
566733965Sjdp	  }
566833965Sjdp	else
566933965Sjdp	  {
567033965Sjdp	    srel.r_index[2] = r_index >> 16;
567133965Sjdp	    srel.r_index[1] = r_index >> 8;
567233965Sjdp	    srel.r_index[0] = r_index;
567333965Sjdp	    srel.r_type[0] =
567433965Sjdp	      ((r_extern ?     RELOC_STD_BITS_EXTERN_LITTLE : 0)
567533965Sjdp	       | (r_pcrel ?    RELOC_STD_BITS_PCREL_LITTLE : 0)
567633965Sjdp	       | (r_baserel ?  RELOC_STD_BITS_BASEREL_LITTLE : 0)
567733965Sjdp	       | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
567833965Sjdp	       | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
567933965Sjdp	       | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE));
568033965Sjdp	  }
568133965Sjdp      }
568233965Sjdp#endif
568333965Sjdp      rel_ptr = (PTR) &srel;
568433965Sjdp
568533965Sjdp      /* We have to write the addend into the object file, since
568633965Sjdp	 standard a.out relocs are in place.  It would be more
568733965Sjdp	 reliable if we had the current contents of the file here,
568833965Sjdp	 rather than assuming zeroes, but we can't read the file since
568933965Sjdp	 it was opened using bfd_openw.  */
569033965Sjdp      if (pr->addend != 0)
569133965Sjdp	{
569233965Sjdp	  bfd_size_type size;
569333965Sjdp	  bfd_reloc_status_type r;
569433965Sjdp	  bfd_byte *buf;
569533965Sjdp	  boolean ok;
569633965Sjdp
569733965Sjdp	  size = bfd_get_reloc_size (howto);
569833965Sjdp	  buf = (bfd_byte *) bfd_zmalloc (size);
569933965Sjdp	  if (buf == (bfd_byte *) NULL)
570033965Sjdp	    return false;
570133965Sjdp	  r = MY_relocate_contents (howto, finfo->output_bfd,
570289857Sobrien				    (bfd_vma) pr->addend, buf);
570333965Sjdp	  switch (r)
570433965Sjdp	    {
570533965Sjdp	    case bfd_reloc_ok:
570633965Sjdp	      break;
570733965Sjdp	    default:
570833965Sjdp	    case bfd_reloc_outofrange:
570933965Sjdp	      abort ();
571033965Sjdp	    case bfd_reloc_overflow:
571133965Sjdp	      if (! ((*finfo->info->callbacks->reloc_overflow)
571233965Sjdp		     (finfo->info,
571333965Sjdp		      (p->type == bfd_section_reloc_link_order
571433965Sjdp		       ? bfd_section_name (finfo->output_bfd,
571533965Sjdp					   pr->u.section)
571633965Sjdp		       : pr->u.name),
571733965Sjdp		      howto->name, pr->addend, (bfd *) NULL,
571833965Sjdp		      (asection *) NULL, (bfd_vma) 0)))
571933965Sjdp		{
572033965Sjdp		  free (buf);
572133965Sjdp		  return false;
572233965Sjdp		}
572333965Sjdp	      break;
572433965Sjdp	    }
572589857Sobrien	  ok = bfd_set_section_contents (finfo->output_bfd, o, (PTR) buf,
572689857Sobrien					 (file_ptr) p->offset, size);
572733965Sjdp	  free (buf);
572833965Sjdp	  if (! ok)
572933965Sjdp	    return false;
573033965Sjdp	}
573133965Sjdp    }
573233965Sjdp  else
573333965Sjdp    {
573477298Sobrien#ifdef MY_put_ext_reloc
573577298Sobrien      MY_put_ext_reloc (finfo->output_bfd, r_extern, r_index, p->offset,
573677298Sobrien			howto, &erel, pr->addend);
573777298Sobrien#else
573833965Sjdp      PUT_WORD (finfo->output_bfd, p->offset, erel.r_address);
573933965Sjdp
574033965Sjdp      if (bfd_header_big_endian (finfo->output_bfd))
574133965Sjdp	{
574233965Sjdp	  erel.r_index[0] = r_index >> 16;
574333965Sjdp	  erel.r_index[1] = r_index >> 8;
574433965Sjdp	  erel.r_index[2] = r_index;
574533965Sjdp	  erel.r_type[0] =
574633965Sjdp	    ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
574733965Sjdp	     | (howto->type << RELOC_EXT_BITS_TYPE_SH_BIG));
574833965Sjdp	}
574933965Sjdp      else
575033965Sjdp	{
575133965Sjdp	  erel.r_index[2] = r_index >> 16;
575233965Sjdp	  erel.r_index[1] = r_index >> 8;
575333965Sjdp	  erel.r_index[0] = r_index;
575433965Sjdp	  erel.r_type[0] =
575533965Sjdp	    (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
575633965Sjdp	      | (howto->type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
575733965Sjdp	}
575833965Sjdp
575989857Sobrien      PUT_WORD (finfo->output_bfd, (bfd_vma) pr->addend, erel.r_addend);
576077298Sobrien#endif /* MY_put_ext_reloc */
576133965Sjdp
576233965Sjdp      rel_ptr = (PTR) &erel;
576333965Sjdp    }
576433965Sjdp
576589857Sobrien  amt = obj_reloc_entry_size (finfo->output_bfd);
576633965Sjdp  if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0
576789857Sobrien      || bfd_bwrite (rel_ptr, amt, finfo->output_bfd) != amt)
576833965Sjdp    return false;
576933965Sjdp
577033965Sjdp  *reloff_ptr += obj_reloc_entry_size (finfo->output_bfd);
577133965Sjdp
577233965Sjdp  /* Assert that the relocs have not run into the symbols, and that n
577333965Sjdp     the text relocs have not run into the data relocs.  */
577433965Sjdp  BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
577533965Sjdp	      && (reloff_ptr != &finfo->treloff
577633965Sjdp		  || (*reloff_ptr
577733965Sjdp		      <= obj_datasec (finfo->output_bfd)->rel_filepos)));
577833965Sjdp
577933965Sjdp  return true;
578033965Sjdp}
5781