133965Sjdp/* BFD semi-generic back-end for a.out binaries.
2218822Sdim   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3218822Sdim   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
438889Sjdp   Free Software Foundation, Inc.
533965Sjdp   Written by Cygnus Support.
633965Sjdp
7130561Sobrien   This file is part of BFD, the Binary File Descriptor library.
833965Sjdp
9130561Sobrien   This program is free software; you can redistribute it and/or modify
10130561Sobrien   it under the terms of the GNU General Public License as published by
11130561Sobrien   the Free Software Foundation; either version 2 of the License, or
12130561Sobrien   (at your option) any later version.
1333965Sjdp
14130561Sobrien   This program is distributed in the hope that it will be useful,
15130561Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130561Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130561Sobrien   GNU General Public License for more details.
1833965Sjdp
19130561Sobrien   You should have received a copy of the GNU General Public License
20130561Sobrien   along with this program; if not, write to the Free Software
21218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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
108130561Sobrien	configuration is selected.  */
10933965Sjdp
11033965Sjdp/* Some assumptions:
11133965Sjdp   * Any BFD with D_PAGED set is ZMAGIC, and vice versa.
11233965Sjdp     Doesn't matter what the setting of WP_TEXT is on output, but it'll
11333965Sjdp     get set on input.
11433965Sjdp   * Any BFD with D_PAGED clear and WP_TEXT set is NMAGIC.
11533965Sjdp   * Any BFD with both flags clear is OMAGIC.
11633965Sjdp   (Just want to make these explicit, so the conditions tested in this
11733965Sjdp   file make sense if you're more familiar with a.out than with BFD.)  */
11833965Sjdp
11933965Sjdp#define KEEPIT udata.i
12033965Sjdp
121218822Sdim#include "sysdep.h"
12233965Sjdp#include "bfd.h"
12389857Sobrien#include "safe-ctype.h"
12433965Sjdp#include "bfdlink.h"
12533965Sjdp
12633965Sjdp#include "libaout.h"
12733965Sjdp#include "libbfd.h"
12833965Sjdp#include "aout/aout64.h"
12933965Sjdp#include "aout/stab_gnu.h"
13033965Sjdp#include "aout/ar.h"
13133965Sjdp
13233965Sjdp/*
13333965SjdpSUBSECTION
13433965Sjdp	Relocations
13533965Sjdp
13633965SjdpDESCRIPTION
13733965Sjdp	The file @file{aoutx.h} provides for both the @emph{standard}
13833965Sjdp	and @emph{extended} forms of a.out relocation records.
13933965Sjdp
14033965Sjdp	The standard records contain only an
14133965Sjdp	address, a symbol index, and a type field. The extended records
14233965Sjdp	(used on 29ks and sparcs) also have a full integer for an
143130561Sobrien	addend.  */
14433965Sjdp
14533965Sjdp#ifndef CTOR_TABLE_RELOC_HOWTO
14633965Sjdp#define CTOR_TABLE_RELOC_IDX 2
14789857Sobrien#define CTOR_TABLE_RELOC_HOWTO(BFD)					\
14889857Sobrien  ((obj_reloc_entry_size (BFD) == RELOC_EXT_SIZE			\
14989857Sobrien    ? howto_table_ext : howto_table_std)				\
15089857Sobrien   + CTOR_TABLE_RELOC_IDX)
15133965Sjdp#endif
15233965Sjdp
15333965Sjdp#ifndef MY_swap_std_reloc_in
154218822Sdim#define MY_swap_std_reloc_in NAME (aout, swap_std_reloc_in)
15533965Sjdp#endif
15633965Sjdp
15777298Sobrien#ifndef MY_swap_ext_reloc_in
158218822Sdim#define MY_swap_ext_reloc_in NAME (aout, swap_ext_reloc_in)
15977298Sobrien#endif
16077298Sobrien
16133965Sjdp#ifndef MY_swap_std_reloc_out
162218822Sdim#define MY_swap_std_reloc_out NAME (aout, swap_std_reloc_out)
16333965Sjdp#endif
16433965Sjdp
16577298Sobrien#ifndef MY_swap_ext_reloc_out
166218822Sdim#define MY_swap_ext_reloc_out NAME (aout, swap_ext_reloc_out)
16777298Sobrien#endif
16877298Sobrien
16933965Sjdp#ifndef MY_final_link_relocate
17033965Sjdp#define MY_final_link_relocate _bfd_final_link_relocate
17133965Sjdp#endif
17233965Sjdp
17333965Sjdp#ifndef MY_relocate_contents
17433965Sjdp#define MY_relocate_contents _bfd_relocate_contents
17533965Sjdp#endif
17633965Sjdp
177218822Sdim#define howto_table_ext NAME (aout, ext_howto_table)
178218822Sdim#define howto_table_std NAME (aout, std_howto_table)
17933965Sjdp
18033965Sjdpreloc_howto_type howto_table_ext[] =
18133965Sjdp{
182218822Sdim  /*     Type         rs   size bsz  pcrel bitpos ovrf                  sf name          part_inpl readmask setmask pcdone.  */
183218822Sdim  HOWTO (RELOC_8,       0,  0,  8,  FALSE, 0, complain_overflow_bitfield, 0, "8",           FALSE, 0, 0x000000ff, FALSE),
184218822Sdim  HOWTO (RELOC_16,      0,  1, 	16, FALSE, 0, complain_overflow_bitfield, 0, "16",          FALSE, 0, 0x0000ffff, FALSE),
185218822Sdim  HOWTO (RELOC_32,      0,  2, 	32, FALSE, 0, complain_overflow_bitfield, 0, "32",          FALSE, 0, 0xffffffff, FALSE),
186218822Sdim  HOWTO (RELOC_DISP8,   0,  0, 	8,  TRUE,  0, complain_overflow_signed,   0, "DISP8", 	    FALSE, 0, 0x000000ff, FALSE),
187218822Sdim  HOWTO (RELOC_DISP16,  0,  1, 	16, TRUE,  0, complain_overflow_signed,   0, "DISP16", 	    FALSE, 0, 0x0000ffff, FALSE),
188218822Sdim  HOWTO (RELOC_DISP32,  0,  2, 	32, TRUE,  0, complain_overflow_signed,   0, "DISP32", 	    FALSE, 0, 0xffffffff, FALSE),
189218822Sdim  HOWTO (RELOC_WDISP30, 2,  2, 	30, TRUE,  0, complain_overflow_signed,   0, "WDISP30",     FALSE, 0, 0x3fffffff, FALSE),
190218822Sdim  HOWTO (RELOC_WDISP22, 2,  2, 	22, TRUE,  0, complain_overflow_signed,   0, "WDISP22",     FALSE, 0, 0x003fffff, FALSE),
191218822Sdim  HOWTO (RELOC_HI22,   10,  2, 	22, FALSE, 0, complain_overflow_bitfield, 0, "HI22",	    FALSE, 0, 0x003fffff, FALSE),
192218822Sdim  HOWTO (RELOC_22,      0,  2, 	22, FALSE, 0, complain_overflow_bitfield, 0, "22",          FALSE, 0, 0x003fffff, FALSE),
193218822Sdim  HOWTO (RELOC_13,      0,  2, 	13, FALSE, 0, complain_overflow_bitfield, 0, "13",          FALSE, 0, 0x00001fff, FALSE),
194218822Sdim  HOWTO (RELOC_LO10,    0,  2, 	10, FALSE, 0, complain_overflow_dont,     0, "LO10",        FALSE, 0, 0x000003ff, FALSE),
195218822Sdim  HOWTO (RELOC_SFA_BASE,0,  2, 	32, FALSE, 0, complain_overflow_bitfield, 0, "SFA_BASE",    FALSE, 0, 0xffffffff, FALSE),
196218822Sdim  HOWTO (RELOC_SFA_OFF13,0, 2, 	32, FALSE, 0, complain_overflow_bitfield, 0, "SFA_OFF13",   FALSE, 0, 0xffffffff, FALSE),
197218822Sdim  HOWTO (RELOC_BASE10,  0,  2, 	10, FALSE, 0, complain_overflow_dont,     0, "BASE10",      FALSE, 0, 0x000003ff, FALSE),
198218822Sdim  HOWTO (RELOC_BASE13,  0,  2,	13, FALSE, 0, complain_overflow_signed,   0, "BASE13",      FALSE, 0, 0x00001fff, FALSE),
199218822Sdim  HOWTO (RELOC_BASE22, 10,  2,	22, FALSE, 0, complain_overflow_bitfield, 0, "BASE22",      FALSE, 0, 0x003fffff, FALSE),
200218822Sdim  HOWTO (RELOC_PC10,    0,  2,	10, TRUE,  0, complain_overflow_dont,     0, "PC10",	    FALSE, 0, 0x000003ff, TRUE),
201218822Sdim  HOWTO (RELOC_PC22,   10,  2,	22, TRUE,  0, complain_overflow_signed,   0, "PC22",  	    FALSE, 0, 0x003fffff, TRUE),
202218822Sdim  HOWTO (RELOC_JMP_TBL, 2,  2, 	30, TRUE,  0, complain_overflow_signed,   0, "JMP_TBL",     FALSE, 0, 0x3fffffff, FALSE),
203218822Sdim  HOWTO (RELOC_SEGOFF16,0,  2,	0,  FALSE, 0, complain_overflow_bitfield, 0, "SEGOFF16",    FALSE, 0, 0x00000000, FALSE),
204218822Sdim  HOWTO (RELOC_GLOB_DAT,0,  2,	0,  FALSE, 0, complain_overflow_bitfield, 0, "GLOB_DAT",    FALSE, 0, 0x00000000, FALSE),
205218822Sdim  HOWTO (RELOC_JMP_SLOT,0,  2,	0,  FALSE, 0, complain_overflow_bitfield, 0, "JMP_SLOT",    FALSE, 0, 0x00000000, FALSE),
206218822Sdim  HOWTO (RELOC_RELATIVE,0,  2,	0,  FALSE, 0, complain_overflow_bitfield, 0, "RELATIVE",    FALSE, 0, 0x00000000, FALSE),
207218822Sdim  HOWTO (0,             0,  0,  0,  FALSE, 0, complain_overflow_dont,     0, "R_SPARC_NONE",FALSE, 0, 0x00000000, TRUE),
208218822Sdim  HOWTO (0,             0,  0,  0,  FALSE, 0, complain_overflow_dont,     0, "R_SPARC_NONE",FALSE, 0, 0x00000000, TRUE),
20960484Sobrien#define RELOC_SPARC_REV32 RELOC_WDISP19
210218822Sdim  HOWTO (RELOC_SPARC_REV32, 0, 2, 32, FALSE, 0, complain_overflow_dont,   0,"R_SPARC_REV32",FALSE, 0, 0xffffffff, FALSE),
21133965Sjdp};
21233965Sjdp
21333965Sjdp/* Convert standard reloc records to "arelent" format (incl byte swap).  */
21433965Sjdp
215130561Sobrienreloc_howto_type howto_table_std[] =
216130561Sobrien{
217130561Sobrien  /* type              rs size bsz  pcrel bitpos ovrf                     sf name     part_inpl readmask  setmask    pcdone.  */
218130561SobrienHOWTO ( 0,	       0,  0,  	8,  FALSE, 0, complain_overflow_bitfield,0,"8",		TRUE, 0x000000ff,0x000000ff, FALSE),
219130561SobrienHOWTO ( 1,	       0,  1, 	16, FALSE, 0, complain_overflow_bitfield,0,"16",	TRUE, 0x0000ffff,0x0000ffff, FALSE),
220130561SobrienHOWTO ( 2,	       0,  2, 	32, FALSE, 0, complain_overflow_bitfield,0,"32",	TRUE, 0xffffffff,0xffffffff, FALSE),
221130561SobrienHOWTO ( 3,	       0,  4, 	64, FALSE, 0, complain_overflow_bitfield,0,"64",	TRUE, 0xdeaddead,0xdeaddead, FALSE),
222130561SobrienHOWTO ( 4,	       0,  0, 	8,  TRUE,  0, complain_overflow_signed,  0,"DISP8",	TRUE, 0x000000ff,0x000000ff, FALSE),
223130561SobrienHOWTO ( 5,	       0,  1, 	16, TRUE,  0, complain_overflow_signed,  0,"DISP16",	TRUE, 0x0000ffff,0x0000ffff, FALSE),
224130561SobrienHOWTO ( 6,	       0,  2, 	32, TRUE,  0, complain_overflow_signed,  0,"DISP32",	TRUE, 0xffffffff,0xffffffff, FALSE),
225130561SobrienHOWTO ( 7,	       0,  4, 	64, TRUE,  0, complain_overflow_signed,  0,"DISP64",	TRUE, 0xfeedface,0xfeedface, FALSE),
226130561SobrienHOWTO ( 8,	       0,  2,    0, FALSE, 0, complain_overflow_bitfield,0,"GOT_REL",	FALSE,         0,0x00000000, FALSE),
227130561SobrienHOWTO ( 9,	       0,  1,   16, FALSE, 0, complain_overflow_bitfield,0,"BASE16",	FALSE,0xffffffff,0xffffffff, FALSE),
228130561SobrienHOWTO (10,	       0,  2,   32, FALSE, 0, complain_overflow_bitfield,0,"BASE32",	FALSE,0xffffffff,0xffffffff, FALSE),
22960484SobrienEMPTY_HOWTO (-1),
23060484SobrienEMPTY_HOWTO (-1),
23160484SobrienEMPTY_HOWTO (-1),
23260484SobrienEMPTY_HOWTO (-1),
23360484SobrienEMPTY_HOWTO (-1),
234130561Sobrien  HOWTO (16,	       0,  2,	 0, FALSE, 0, complain_overflow_bitfield,0,"JMP_TABLE", FALSE,         0,0x00000000, FALSE),
23560484SobrienEMPTY_HOWTO (-1),
23660484SobrienEMPTY_HOWTO (-1),
23760484SobrienEMPTY_HOWTO (-1),
23860484SobrienEMPTY_HOWTO (-1),
23960484SobrienEMPTY_HOWTO (-1),
24060484SobrienEMPTY_HOWTO (-1),
24160484SobrienEMPTY_HOWTO (-1),
24260484SobrienEMPTY_HOWTO (-1),
24360484SobrienEMPTY_HOWTO (-1),
24460484SobrienEMPTY_HOWTO (-1),
24560484SobrienEMPTY_HOWTO (-1),
24660484SobrienEMPTY_HOWTO (-1),
24760484SobrienEMPTY_HOWTO (-1),
24860484SobrienEMPTY_HOWTO (-1),
24960484SobrienEMPTY_HOWTO (-1),
250130561Sobrien  HOWTO (32,	       0,  2,	 0, FALSE, 0, complain_overflow_bitfield,0,"RELATIVE",  FALSE,         0,0x00000000, FALSE),
25160484SobrienEMPTY_HOWTO (-1),
25260484SobrienEMPTY_HOWTO (-1),
25360484SobrienEMPTY_HOWTO (-1),
25460484SobrienEMPTY_HOWTO (-1),
25560484SobrienEMPTY_HOWTO (-1),
25660484SobrienEMPTY_HOWTO (-1),
25760484SobrienEMPTY_HOWTO (-1),
258130561Sobrien  HOWTO (40,	       0,  2,	 0, FALSE, 0, complain_overflow_bitfield,0,"BASEREL",   FALSE,         0,0x00000000, FALSE),
25933965Sjdp};
26033965Sjdp
26189857Sobrien#define TABLE_SIZE(TABLE)	(sizeof (TABLE) / sizeof (TABLE[0]))
26233965Sjdp
26333965Sjdpreloc_howto_type *
264218822SdimNAME (aout, reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
26533965Sjdp{
266218822Sdim#define EXT(i, j)	case i: return & howto_table_ext [j]
267218822Sdim#define STD(i, j)	case i: return & howto_table_std [j]
26833965Sjdp  int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
269130561Sobrien
27033965Sjdp  if (code == BFD_RELOC_CTOR)
27133965Sjdp    switch (bfd_get_arch_info (abfd)->bits_per_address)
27233965Sjdp      {
27333965Sjdp      case 32:
27433965Sjdp	code = BFD_RELOC_32;
27533965Sjdp	break;
27633965Sjdp      case 64:
27733965Sjdp	code = BFD_RELOC_64;
27833965Sjdp	break;
27933965Sjdp      }
280130561Sobrien
28133965Sjdp  if (ext)
28233965Sjdp    switch (code)
28333965Sjdp      {
28477298Sobrien	EXT (BFD_RELOC_8, 0);
28577298Sobrien	EXT (BFD_RELOC_16, 1);
28633965Sjdp	EXT (BFD_RELOC_32, 2);
28733965Sjdp	EXT (BFD_RELOC_HI22, 8);
28833965Sjdp	EXT (BFD_RELOC_LO10, 11);
28933965Sjdp	EXT (BFD_RELOC_32_PCREL_S2, 6);
29033965Sjdp	EXT (BFD_RELOC_SPARC_WDISP22, 7);
29133965Sjdp	EXT (BFD_RELOC_SPARC13, 10);
29233965Sjdp	EXT (BFD_RELOC_SPARC_GOT10, 14);
29333965Sjdp	EXT (BFD_RELOC_SPARC_BASE13, 15);
29433965Sjdp	EXT (BFD_RELOC_SPARC_GOT13, 15);
29533965Sjdp	EXT (BFD_RELOC_SPARC_GOT22, 16);
29633965Sjdp	EXT (BFD_RELOC_SPARC_PC10, 17);
29733965Sjdp	EXT (BFD_RELOC_SPARC_PC22, 18);
29833965Sjdp	EXT (BFD_RELOC_SPARC_WPLT30, 19);
29960484Sobrien	EXT (BFD_RELOC_SPARC_REV32, 26);
300218822Sdim      default:
301218822Sdim	return NULL;
30233965Sjdp      }
30333965Sjdp  else
304130561Sobrien    /* std relocs.  */
30533965Sjdp    switch (code)
30633965Sjdp      {
307130561Sobrien	STD (BFD_RELOC_8, 0);
30833965Sjdp	STD (BFD_RELOC_16, 1);
30933965Sjdp	STD (BFD_RELOC_32, 2);
31033965Sjdp	STD (BFD_RELOC_8_PCREL, 4);
31133965Sjdp	STD (BFD_RELOC_16_PCREL, 5);
31233965Sjdp	STD (BFD_RELOC_32_PCREL, 6);
31333965Sjdp	STD (BFD_RELOC_16_BASEREL, 9);
31433965Sjdp	STD (BFD_RELOC_32_BASEREL, 10);
315218822Sdim      default:
316218822Sdim	return NULL;
31733965Sjdp      }
31833965Sjdp}
31933965Sjdp
320218822Sdimreloc_howto_type *
321218822SdimNAME (aout, reloc_name_lookup) (bfd *abfd, const char *r_name)
322218822Sdim{
323218822Sdim  unsigned int i, size;
324218822Sdim  reloc_howto_type *howto_table;
325218822Sdim
326218822Sdim  if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
327218822Sdim    {
328218822Sdim      howto_table = howto_table_ext;
329218822Sdim      size = sizeof (howto_table_ext) / sizeof (howto_table_ext[0]);
330218822Sdim    }
331218822Sdim  else
332218822Sdim    {
333218822Sdim      howto_table = howto_table_std;
334218822Sdim      size = sizeof (howto_table_std) / sizeof (howto_table_std[0]);
335218822Sdim    }
336218822Sdim
337218822Sdim  for (i = 0; i < size; i++)
338218822Sdim    if (howto_table[i].name != NULL
339218822Sdim	&& strcasecmp (howto_table[i].name, r_name) == 0)
340218822Sdim      return &howto_table[i];
341218822Sdim
342218822Sdim  return NULL;
343218822Sdim}
344218822Sdim
34533965Sjdp/*
34633965SjdpSUBSECTION
34733965Sjdp	Internal entry points
34833965Sjdp
34933965SjdpDESCRIPTION
35033965Sjdp	@file{aoutx.h} exports several routines for accessing the
35133965Sjdp	contents of an a.out file, which are gathered and exported in
35233965Sjdp	turn by various format specific files (eg sunos.c).
35333965Sjdp*/
35433965Sjdp
35533965Sjdp/*
35633965SjdpFUNCTION
35733965Sjdp	 aout_@var{size}_swap_exec_header_in
35833965Sjdp
35933965SjdpSYNOPSIS
36033965Sjdp	void aout_@var{size}_swap_exec_header_in,
36133965Sjdp           (bfd *abfd,
362218822Sdim            struct external_exec *bytes,
36333965Sjdp            struct internal_exec *execp);
36433965Sjdp
36533965SjdpDESCRIPTION
36633965Sjdp	Swap the information in an executable header @var{raw_bytes} taken
36733965Sjdp	from a raw byte stream memory image into the internal exec header
36833965Sjdp	structure @var{execp}.
36933965Sjdp*/
37033965Sjdp
37133965Sjdp#ifndef NAME_swap_exec_header_in
37233965Sjdpvoid
373218822SdimNAME (aout, swap_exec_header_in) (bfd *abfd,
374218822Sdim				  struct external_exec *bytes,
375218822Sdim				  struct internal_exec *execp)
37633965Sjdp{
37733965Sjdp  /* The internal_exec structure has some fields that are unused in this
37833965Sjdp     configuration (IE for i960), so ensure that all such uninitialized
37933965Sjdp     fields are zero'd out.  There are places where two of these structs
38077298Sobrien     are memcmp'd, and thus the contents do matter.  */
381218822Sdim  memset ((void *) execp, 0, sizeof (struct internal_exec));
38233965Sjdp  /* Now fill in fields in the execp, from the bytes in the raw data.  */
38389857Sobrien  execp->a_info   = H_GET_32 (abfd, bytes->e_info);
38433965Sjdp  execp->a_text   = GET_WORD (abfd, bytes->e_text);
38533965Sjdp  execp->a_data   = GET_WORD (abfd, bytes->e_data);
38633965Sjdp  execp->a_bss    = GET_WORD (abfd, bytes->e_bss);
38733965Sjdp  execp->a_syms   = GET_WORD (abfd, bytes->e_syms);
38833965Sjdp  execp->a_entry  = GET_WORD (abfd, bytes->e_entry);
38933965Sjdp  execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
39033965Sjdp  execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
39133965Sjdp}
392218822Sdim#define NAME_swap_exec_header_in NAME (aout, swap_exec_header_in)
39333965Sjdp#endif
39433965Sjdp
39533965Sjdp/*
39633965SjdpFUNCTION
39733965Sjdp	aout_@var{size}_swap_exec_header_out
39833965Sjdp
39933965SjdpSYNOPSIS
40033965Sjdp	void aout_@var{size}_swap_exec_header_out
40133965Sjdp	  (bfd *abfd,
40233965Sjdp	   struct internal_exec *execp,
40333965Sjdp	   struct external_exec *raw_bytes);
40433965Sjdp
40533965SjdpDESCRIPTION
40633965Sjdp	Swap the information in an internal exec header structure
40733965Sjdp	@var{execp} into the buffer @var{raw_bytes} ready for writing to disk.
40833965Sjdp*/
40933965Sjdpvoid
410218822SdimNAME (aout, swap_exec_header_out) (bfd *abfd,
411218822Sdim				   struct internal_exec *execp,
412218822Sdim				   struct external_exec *bytes)
41333965Sjdp{
41477298Sobrien  /* Now fill in fields in the raw data, from the fields in the exec struct.  */
41589857Sobrien  H_PUT_32 (abfd, execp->a_info  , bytes->e_info);
41633965Sjdp  PUT_WORD (abfd, execp->a_text  , bytes->e_text);
41733965Sjdp  PUT_WORD (abfd, execp->a_data  , bytes->e_data);
41833965Sjdp  PUT_WORD (abfd, execp->a_bss   , bytes->e_bss);
41933965Sjdp  PUT_WORD (abfd, execp->a_syms  , bytes->e_syms);
42033965Sjdp  PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
42133965Sjdp  PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
42233965Sjdp  PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
42333965Sjdp}
42433965Sjdp
42533965Sjdp/* Make all the section for an a.out file.  */
42633965Sjdp
427130561Sobrienbfd_boolean
428218822SdimNAME (aout, make_sections) (bfd *abfd)
42933965Sjdp{
430218822Sdim  if (obj_textsec (abfd) == NULL && bfd_make_section (abfd, ".text") == NULL)
431130561Sobrien    return FALSE;
432218822Sdim  if (obj_datasec (abfd) == NULL && bfd_make_section (abfd, ".data") == NULL)
433130561Sobrien    return FALSE;
434218822Sdim  if (obj_bsssec (abfd) == NULL && bfd_make_section (abfd, ".bss") == NULL)
435130561Sobrien    return FALSE;
436130561Sobrien  return TRUE;
43733965Sjdp}
43833965Sjdp
43933965Sjdp/*
44033965SjdpFUNCTION
44133965Sjdp	aout_@var{size}_some_aout_object_p
44233965Sjdp
44333965SjdpSYNOPSIS
44433965Sjdp	const bfd_target *aout_@var{size}_some_aout_object_p
44533965Sjdp	 (bfd *abfd,
446218822Sdim          struct internal_exec *execp,
447218822Sdim	  const bfd_target *(*callback_to_real_object_p) (bfd *));
44833965Sjdp
44933965SjdpDESCRIPTION
45033965Sjdp	Some a.out variant thinks that the file open in @var{abfd}
45133965Sjdp	checking is an a.out file.  Do some more checking, and set up
45233965Sjdp	for access if it really is.  Call back to the calling
45333965Sjdp	environment's "finish up" function just before returning, to
45433965Sjdp	handle any last-minute setup.
45533965Sjdp*/
45633965Sjdp
45733965Sjdpconst bfd_target *
458218822SdimNAME (aout, some_aout_object_p) (bfd *abfd,
459218822Sdim				 struct internal_exec *execp,
460218822Sdim				 const bfd_target *(*callback_to_real_object_p) (bfd *))
46133965Sjdp{
46233965Sjdp  struct aout_data_struct *rawptr, *oldrawptr;
46333965Sjdp  const bfd_target *result;
464218822Sdim  bfd_size_type amt = sizeof (* rawptr);
46533965Sjdp
466218822Sdim  rawptr = bfd_zalloc (abfd, amt);
46733965Sjdp  if (rawptr == NULL)
468218822Sdim    return NULL;
46933965Sjdp
47033965Sjdp  oldrawptr = abfd->tdata.aout_data;
47133965Sjdp  abfd->tdata.aout_data = rawptr;
47233965Sjdp
47333965Sjdp  /* Copy the contents of the old tdata struct.
47433965Sjdp     In particular, we want the subformat, since for hpux it was set in
47533965Sjdp     hp300hpux.c:swap_exec_header_in and will be used in
47633965Sjdp     hp300hpux.c:callback.  */
47733965Sjdp  if (oldrawptr != NULL)
47833965Sjdp    *abfd->tdata.aout_data = *oldrawptr;
47933965Sjdp
48033965Sjdp  abfd->tdata.aout_data->a.hdr = &rawptr->e;
481130561Sobrien  /* Copy in the internal_exec struct.  */
482130561Sobrien  *(abfd->tdata.aout_data->a.hdr) = *execp;
48333965Sjdp  execp = abfd->tdata.aout_data->a.hdr;
48433965Sjdp
485130561Sobrien  /* Set the file flags.  */
48633965Sjdp  abfd->flags = BFD_NO_FLAGS;
48733965Sjdp  if (execp->a_drsize || execp->a_trsize)
48833965Sjdp    abfd->flags |= HAS_RELOC;
489130561Sobrien  /* Setting of EXEC_P has been deferred to the bottom of this function.  */
49033965Sjdp  if (execp->a_syms)
49133965Sjdp    abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
49289857Sobrien  if (N_DYNAMIC (*execp))
49333965Sjdp    abfd->flags |= DYNAMIC;
49433965Sjdp
49533965Sjdp  if (N_MAGIC (*execp) == ZMAGIC)
49633965Sjdp    {
49733965Sjdp      abfd->flags |= D_PAGED | WP_TEXT;
49833965Sjdp      adata (abfd).magic = z_magic;
49933965Sjdp    }
50033965Sjdp  else if (N_MAGIC (*execp) == QMAGIC)
50133965Sjdp    {
50233965Sjdp      abfd->flags |= D_PAGED | WP_TEXT;
50333965Sjdp      adata (abfd).magic = z_magic;
50433965Sjdp      adata (abfd).subformat = q_magic_format;
50533965Sjdp    }
50633965Sjdp  else if (N_MAGIC (*execp) == NMAGIC)
50733965Sjdp    {
50833965Sjdp      abfd->flags |= WP_TEXT;
50933965Sjdp      adata (abfd).magic = n_magic;
51033965Sjdp    }
51133965Sjdp  else if (N_MAGIC (*execp) == OMAGIC
51233965Sjdp	   || N_MAGIC (*execp) == BMAGIC)
51333965Sjdp    adata (abfd).magic = o_magic;
51433965Sjdp  else
515218822Sdim    /* Should have been checked with N_BADMAG before this routine
516218822Sdim       was called.  */
517218822Sdim    abort ();
51833965Sjdp
51933965Sjdp  bfd_get_start_address (abfd) = execp->a_entry;
52033965Sjdp
521218822Sdim  obj_aout_symbols (abfd) = NULL;
52233965Sjdp  bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
52333965Sjdp
52433965Sjdp  /* The default relocation entry size is that of traditional V7 Unix.  */
52533965Sjdp  obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
52633965Sjdp
52777298Sobrien  /* The default symbol entry size is that of traditional Unix.  */
52833965Sjdp  obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
52933965Sjdp
53033965Sjdp#ifdef USE_MMAP
53133965Sjdp  bfd_init_window (&obj_aout_sym_window (abfd));
53233965Sjdp  bfd_init_window (&obj_aout_string_window (abfd));
53333965Sjdp#endif
53433965Sjdp  obj_aout_external_syms (abfd) = NULL;
53533965Sjdp  obj_aout_external_strings (abfd) = NULL;
53633965Sjdp  obj_aout_sym_hashes (abfd) = NULL;
53733965Sjdp
538218822Sdim  if (! NAME (aout, make_sections) (abfd))
539104834Sobrien    goto error_ret;
54033965Sjdp
541218822Sdim  obj_datasec (abfd)->size = execp->a_data;
542218822Sdim  obj_bsssec (abfd)->size = execp->a_bss;
54333965Sjdp
54433965Sjdp  obj_textsec (abfd)->flags =
54533965Sjdp    (execp->a_trsize != 0
54633965Sjdp     ? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
54733965Sjdp     : (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
54833965Sjdp  obj_datasec (abfd)->flags =
54933965Sjdp    (execp->a_drsize != 0
55033965Sjdp     ? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
55133965Sjdp     : (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
55233965Sjdp  obj_bsssec (abfd)->flags = SEC_ALLOC;
55333965Sjdp
55433965Sjdp#ifdef THIS_IS_ONLY_DOCUMENTATION
55533965Sjdp  /* The common code can't fill in these things because they depend
55633965Sjdp     on either the start address of the text segment, the rounding
55733965Sjdp     up of virtual addresses between segments, or the starting file
55833965Sjdp     position of the text segment -- all of which varies among different
55933965Sjdp     versions of a.out.  */
56033965Sjdp
56133965Sjdp  /* Call back to the format-dependent code to fill in the rest of the
56233965Sjdp     fields and do any further cleanup.  Things that should be filled
56333965Sjdp     in by the callback:  */
56433965Sjdp
56533965Sjdp  struct exec *execp = exec_hdr (abfd);
56633965Sjdp
56789857Sobrien  obj_textsec (abfd)->size = N_TXTSIZE (*execp);
568130561Sobrien  /* Data and bss are already filled in since they're so standard.  */
56933965Sjdp
570130561Sobrien  /* The virtual memory addresses of the sections.  */
57189857Sobrien  obj_textsec (abfd)->vma = N_TXTADDR (*execp);
57289857Sobrien  obj_datasec (abfd)->vma = N_DATADDR (*execp);
57389857Sobrien  obj_bsssec  (abfd)->vma = N_BSSADDR (*execp);
57433965Sjdp
575130561Sobrien  /* The file offsets of the sections.  */
57689857Sobrien  obj_textsec (abfd)->filepos = N_TXTOFF (*execp);
57789857Sobrien  obj_datasec (abfd)->filepos = N_DATOFF (*execp);
57833965Sjdp
579130561Sobrien  /* The file offsets of the relocation info.  */
58089857Sobrien  obj_textsec (abfd)->rel_filepos = N_TRELOFF (*execp);
58189857Sobrien  obj_datasec (abfd)->rel_filepos = N_DRELOFF (*execp);
58233965Sjdp
58333965Sjdp  /* The file offsets of the string table and symbol table.  */
58433965Sjdp  obj_str_filepos (abfd) = N_STROFF (*execp);
58533965Sjdp  obj_sym_filepos (abfd) = N_SYMOFF (*execp);
58633965Sjdp
58733965Sjdp  /* Determine the architecture and machine type of the object file.  */
58889857Sobrien  switch (N_MACHTYPE (*exec_hdr (abfd)))
58989857Sobrien    {
59089857Sobrien    default:
59189857Sobrien      abfd->obj_arch = bfd_arch_obscure;
59289857Sobrien      break;
59389857Sobrien    }
59433965Sjdp
59589857Sobrien  adata (abfd)->page_size = TARGET_PAGE_SIZE;
59689857Sobrien  adata (abfd)->segment_size = SEGMENT_SIZE;
59789857Sobrien  adata (abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
59833965Sjdp
59933965Sjdp  return abfd->xvec;
60033965Sjdp
60133965Sjdp  /* The architecture is encoded in various ways in various a.out variants,
60233965Sjdp     or is not encoded at all in some of them.  The relocation size depends
60333965Sjdp     on the architecture and the a.out variant.  Finally, the return value
60433965Sjdp     is the bfd_target vector in use.  If an error occurs, return zero and
60533965Sjdp     set bfd_error to the appropriate error code.
60633965Sjdp
60733965Sjdp     Formats such as b.out, which have additional fields in the a.out
60833965Sjdp     header, should cope with them in this callback as well.  */
60933965Sjdp#endif				/* DOCUMENTATION */
61033965Sjdp
61177298Sobrien  result = (*callback_to_real_object_p) (abfd);
61233965Sjdp
61333965Sjdp  /* Now that the segment addresses have been worked out, take a better
61433965Sjdp     guess at whether the file is executable.  If the entry point
61533965Sjdp     is within the text segment, assume it is.  (This makes files
61633965Sjdp     executable even if their entry point address is 0, as long as
61733965Sjdp     their text starts at zero.).
61833965Sjdp
61933965Sjdp     This test had to be changed to deal with systems where the text segment
62033965Sjdp     runs at a different location than the default.  The problem is that the
62133965Sjdp     entry address can appear to be outside the text segment, thus causing an
62233965Sjdp     erroneous conclusion that the file isn't executable.
62333965Sjdp
62433965Sjdp     To fix this, we now accept any non-zero entry point as an indication of
62533965Sjdp     executability.  This will work most of the time, since only the linker
62677298Sobrien     sets the entry point, and that is likely to be non-zero for most systems.  */
62733965Sjdp
62833965Sjdp  if (execp->a_entry != 0
62989857Sobrien      || (execp->a_entry >= obj_textsec (abfd)->vma
63089857Sobrien	  && execp->a_entry < (obj_textsec (abfd)->vma
631218822Sdim			       + obj_textsec (abfd)->size)))
63233965Sjdp    abfd->flags |= EXEC_P;
63333965Sjdp#ifdef STAT_FOR_EXEC
63433965Sjdp  else
63533965Sjdp    {
63633965Sjdp      struct stat stat_buf;
63733965Sjdp
63833965Sjdp      /* The original heuristic doesn't work in some important cases.
63933965Sjdp        The a.out file has no information about the text start
64033965Sjdp        address.  For files (like kernels) linked to non-standard
64133965Sjdp        addresses (ld -Ttext nnn) the entry point may not be between
64233965Sjdp        the default text start (obj_textsec(abfd)->vma) and
64333965Sjdp        (obj_textsec(abfd)->vma) + text size.  This is not just a mach
64433965Sjdp        issue.  Many kernels are loaded at non standard addresses.  */
64533965Sjdp      if (abfd->iostream != NULL
64633965Sjdp	  && (abfd->flags & BFD_IN_MEMORY) == 0
64789857Sobrien	  && (fstat (fileno ((FILE *) (abfd->iostream)), &stat_buf) == 0)
64833965Sjdp	  && ((stat_buf.st_mode & 0111) != 0))
64933965Sjdp	abfd->flags |= EXEC_P;
65033965Sjdp    }
65133965Sjdp#endif /* STAT_FOR_EXEC */
65233965Sjdp
65333965Sjdp  if (result)
654218822Sdim    return result;
655104834Sobrien
656104834Sobrien error_ret:
657104834Sobrien  bfd_release (abfd, rawptr);
658104834Sobrien  abfd->tdata.aout_data = oldrawptr;
659104834Sobrien  return NULL;
66033965Sjdp}
66133965Sjdp
66233965Sjdp/*
66333965SjdpFUNCTION
66433965Sjdp	aout_@var{size}_mkobject
66533965Sjdp
66633965SjdpSYNOPSIS
667130561Sobrien	bfd_boolean aout_@var{size}_mkobject, (bfd *abfd);
66833965Sjdp
66933965SjdpDESCRIPTION
67033965Sjdp	Initialize BFD @var{abfd} for use with a.out files.
67133965Sjdp*/
67233965Sjdp
673130561Sobrienbfd_boolean
674218822SdimNAME (aout, mkobject) (bfd *abfd)
67533965Sjdp{
67689857Sobrien  struct aout_data_struct *rawptr;
677218822Sdim  bfd_size_type amt = sizeof (* rawptr);
67833965Sjdp
67933965Sjdp  bfd_set_error (bfd_error_system_call);
68033965Sjdp
681218822Sdim  rawptr = bfd_zalloc (abfd, amt);
68233965Sjdp  if (rawptr == NULL)
683130561Sobrien    return FALSE;
68433965Sjdp
68533965Sjdp  abfd->tdata.aout_data = rawptr;
68633965Sjdp  exec_hdr (abfd) = &(rawptr->e);
68733965Sjdp
688218822Sdim  obj_textsec (abfd) = NULL;
689218822Sdim  obj_datasec (abfd) = NULL;
690218822Sdim  obj_bsssec (abfd) = NULL;
69133965Sjdp
692130561Sobrien  return TRUE;
69333965Sjdp}
69433965Sjdp
69533965Sjdp/*
69633965SjdpFUNCTION
69733965Sjdp	aout_@var{size}_machine_type
69833965Sjdp
69933965SjdpSYNOPSIS
70033965Sjdp	enum machine_type  aout_@var{size}_machine_type
70133965Sjdp	 (enum bfd_architecture arch,
702218822Sdim	  unsigned long machine,
703218822Sdim          bfd_boolean *unknown);
70433965Sjdp
70533965SjdpDESCRIPTION
70633965Sjdp	Keep track of machine architecture and machine type for
70733965Sjdp	a.out's. Return the <<machine_type>> for a particular
70833965Sjdp	architecture and machine, or <<M_UNKNOWN>> if that exact architecture
70933965Sjdp	and machine can't be represented in a.out format.
71033965Sjdp
71133965Sjdp	If the architecture is understood, machine type 0 (default)
71233965Sjdp	is always understood.
71333965Sjdp*/
71433965Sjdp
71533965Sjdpenum machine_type
716218822SdimNAME (aout, machine_type) (enum bfd_architecture arch,
717218822Sdim			   unsigned long machine,
718218822Sdim			   bfd_boolean *unknown)
71933965Sjdp{
72033965Sjdp  enum machine_type arch_flags;
72133965Sjdp
72233965Sjdp  arch_flags = M_UNKNOWN;
723130561Sobrien  *unknown = TRUE;
72433965Sjdp
72589857Sobrien  switch (arch)
72689857Sobrien    {
72789857Sobrien    case bfd_arch_sparc:
72889857Sobrien      if (machine == 0
72989857Sobrien	  || machine == bfd_mach_sparc
73089857Sobrien	  || machine == bfd_mach_sparc_sparclite
73189857Sobrien	  || machine == bfd_mach_sparc_sparclite_le
732218822Sdim	  || machine == bfd_mach_sparc_v8plus
733218822Sdim	  || machine == bfd_mach_sparc_v8plusa
734218822Sdim	  || machine == bfd_mach_sparc_v8plusb
735218822Sdim	  || machine == bfd_mach_sparc_v9
736218822Sdim	  || machine == bfd_mach_sparc_v9a
737218822Sdim	  || machine == bfd_mach_sparc_v9b)
73889857Sobrien	arch_flags = M_SPARC;
73989857Sobrien      else if (machine == bfd_mach_sparc_sparclet)
74089857Sobrien	arch_flags = M_SPARCLET;
74189857Sobrien      break;
74233965Sjdp
74389857Sobrien    case bfd_arch_m68k:
74489857Sobrien      switch (machine)
74589857Sobrien	{
74689857Sobrien	case 0:		      arch_flags = M_68010; break;
747130561Sobrien	case bfd_mach_m68000: arch_flags = M_UNKNOWN; *unknown = FALSE; break;
74889857Sobrien	case bfd_mach_m68010: arch_flags = M_68010; break;
74989857Sobrien	case bfd_mach_m68020: arch_flags = M_68020; break;
75089857Sobrien	default:	      arch_flags = M_UNKNOWN; break;
75189857Sobrien	}
75289857Sobrien      break;
75333965Sjdp
75489857Sobrien    case bfd_arch_i386:
755130561Sobrien      if (machine == 0
756130561Sobrien	  || machine == bfd_mach_i386_i386
757130561Sobrien	  || machine == bfd_mach_i386_i386_intel_syntax)
75889857Sobrien	arch_flags = M_386;
75989857Sobrien      break;
76033965Sjdp
76189857Sobrien    case bfd_arch_arm:
76289857Sobrien      if (machine == 0)
76389857Sobrien	arch_flags = M_ARM;
76489857Sobrien      break;
76577298Sobrien
76689857Sobrien    case bfd_arch_mips:
76789857Sobrien      switch (machine)
76889857Sobrien	{
76989857Sobrien	case 0:
77089857Sobrien	case bfd_mach_mips3000:
77189857Sobrien	case bfd_mach_mips3900:
77289857Sobrien	  arch_flags = M_MIPS1;
77389857Sobrien	  break;
77489857Sobrien	case bfd_mach_mips6000:
77589857Sobrien	  arch_flags = M_MIPS2;
77689857Sobrien	  break;
77789857Sobrien	case bfd_mach_mips4000:
77889857Sobrien	case bfd_mach_mips4010:
77989857Sobrien	case bfd_mach_mips4100:
78089857Sobrien	case bfd_mach_mips4300:
78189857Sobrien	case bfd_mach_mips4400:
78289857Sobrien	case bfd_mach_mips4600:
78389857Sobrien	case bfd_mach_mips4650:
78489857Sobrien	case bfd_mach_mips8000:
785218822Sdim	case bfd_mach_mips9000:
78689857Sobrien	case bfd_mach_mips10000:
78789857Sobrien	case bfd_mach_mips12000:
78889857Sobrien	case bfd_mach_mips16:
78989857Sobrien	case bfd_mach_mipsisa32:
790130561Sobrien	case bfd_mach_mipsisa32r2:
79189857Sobrien	case bfd_mach_mips5:
79289857Sobrien	case bfd_mach_mipsisa64:
793130561Sobrien	case bfd_mach_mipsisa64r2:
79489857Sobrien	case bfd_mach_mips_sb1:
79589857Sobrien	  /* FIXME: These should be MIPS3, MIPS4, MIPS16, MIPS32, etc.  */
79689857Sobrien	  arch_flags = M_MIPS2;
79789857Sobrien	  break;
79889857Sobrien	default:
79989857Sobrien	  arch_flags = M_UNKNOWN;
80089857Sobrien	  break;
80189857Sobrien	}
80260484Sobrien      break;
80389857Sobrien
80489857Sobrien    case bfd_arch_ns32k:
80589857Sobrien      switch (machine)
80689857Sobrien	{
80789857Sobrien	case 0:    	arch_flags = M_NS32532; break;
80889857Sobrien	case 32032:	arch_flags = M_NS32032; break;
80989857Sobrien	case 32532:	arch_flags = M_NS32532; break;
81089857Sobrien	default:	arch_flags = M_UNKNOWN; break;
81189857Sobrien	}
81260484Sobrien      break;
81389857Sobrien
81489857Sobrien    case bfd_arch_vax:
815130561Sobrien      *unknown = FALSE;
81660484Sobrien      break;
81789857Sobrien
81889857Sobrien    case bfd_arch_cris:
81989857Sobrien      if (machine == 0 || machine == 255)
82089857Sobrien	arch_flags = M_CRIS;
82189857Sobrien      break;
82289857Sobrien
823218822Sdim    case bfd_arch_m88k:
824218822Sdim      *unknown = FALSE;
825218822Sdim      break;
826218822Sdim
82760484Sobrien    default:
82860484Sobrien      arch_flags = M_UNKNOWN;
82933965Sjdp    }
83033965Sjdp
83133965Sjdp  if (arch_flags != M_UNKNOWN)
832130561Sobrien    *unknown = FALSE;
83333965Sjdp
83433965Sjdp  return arch_flags;
83533965Sjdp}
83633965Sjdp
83733965Sjdp/*
83833965SjdpFUNCTION
83933965Sjdp	aout_@var{size}_set_arch_mach
84033965Sjdp
84133965SjdpSYNOPSIS
842130561Sobrien	bfd_boolean aout_@var{size}_set_arch_mach,
84333965Sjdp	 (bfd *,
84433965Sjdp	  enum bfd_architecture arch,
845218822Sdim	  unsigned long machine);
84633965Sjdp
84733965SjdpDESCRIPTION
84833965Sjdp	Set the architecture and the machine of the BFD @var{abfd} to the
84933965Sjdp	values @var{arch} and @var{machine}.  Verify that @var{abfd}'s format
85033965Sjdp	can support the architecture required.
85133965Sjdp*/
85233965Sjdp
853130561Sobrienbfd_boolean
854218822SdimNAME (aout, set_arch_mach) (bfd *abfd,
855218822Sdim			    enum bfd_architecture arch,
856218822Sdim			    unsigned long machine)
85733965Sjdp{
85833965Sjdp  if (! bfd_default_set_arch_mach (abfd, arch, machine))
859130561Sobrien    return FALSE;
86033965Sjdp
86133965Sjdp  if (arch != bfd_arch_unknown)
86233965Sjdp    {
863130561Sobrien      bfd_boolean unknown;
86433965Sjdp
865218822Sdim      NAME (aout, machine_type) (arch, machine, &unknown);
86633965Sjdp      if (unknown)
867130561Sobrien	return FALSE;
86833965Sjdp    }
86933965Sjdp
870130561Sobrien  /* Determine the size of a relocation entry.  */
87189857Sobrien  switch (arch)
87289857Sobrien    {
87389857Sobrien    case bfd_arch_sparc:
87489857Sobrien    case bfd_arch_mips:
87589857Sobrien      obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
87689857Sobrien      break;
87789857Sobrien    default:
87889857Sobrien      obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
87989857Sobrien      break;
88089857Sobrien    }
88133965Sjdp
88289857Sobrien  return (*aout_backend_info (abfd)->set_sizes) (abfd);
88333965Sjdp}
88433965Sjdp
88533965Sjdpstatic void
886218822Sdimadjust_o_magic (bfd *abfd, struct internal_exec *execp)
88733965Sjdp{
88833965Sjdp  file_ptr pos = adata (abfd).exec_bytes_size;
88933965Sjdp  bfd_vma vma = 0;
89033965Sjdp  int pad = 0;
89133965Sjdp
89233965Sjdp  /* Text.  */
89389857Sobrien  obj_textsec (abfd)->filepos = pos;
89489857Sobrien  if (!obj_textsec (abfd)->user_set_vma)
89589857Sobrien    obj_textsec (abfd)->vma = vma;
89633965Sjdp  else
89789857Sobrien    vma = obj_textsec (abfd)->vma;
89833965Sjdp
899218822Sdim  pos += obj_textsec (abfd)->size;
900218822Sdim  vma += obj_textsec (abfd)->size;
90133965Sjdp
90233965Sjdp  /* Data.  */
90389857Sobrien  if (!obj_datasec (abfd)->user_set_vma)
90433965Sjdp    {
905218822Sdim      obj_textsec (abfd)->size += pad;
90633965Sjdp      pos += pad;
90733965Sjdp      vma += pad;
90889857Sobrien      obj_datasec (abfd)->vma = vma;
90933965Sjdp    }
91033965Sjdp  else
91189857Sobrien    vma = obj_datasec (abfd)->vma;
91289857Sobrien  obj_datasec (abfd)->filepos = pos;
913218822Sdim  pos += obj_datasec (abfd)->size;
914218822Sdim  vma += obj_datasec (abfd)->size;
91533965Sjdp
91633965Sjdp  /* BSS.  */
91789857Sobrien  if (!obj_bsssec (abfd)->user_set_vma)
91833965Sjdp    {
919218822Sdim      obj_datasec (abfd)->size += pad;
92033965Sjdp      pos += pad;
92133965Sjdp      vma += pad;
92289857Sobrien      obj_bsssec (abfd)->vma = vma;
92333965Sjdp    }
92433965Sjdp  else
92533965Sjdp    {
92689857Sobrien      /* The VMA of the .bss section is set by the VMA of the
92733965Sjdp         .data section plus the size of the .data section.  We may
92833965Sjdp         need to add padding bytes to make this true.  */
92933965Sjdp      pad = obj_bsssec (abfd)->vma - vma;
93033965Sjdp      if (pad > 0)
93133965Sjdp	{
932218822Sdim	  obj_datasec (abfd)->size += pad;
93333965Sjdp	  pos += pad;
93433965Sjdp	}
93533965Sjdp    }
93689857Sobrien  obj_bsssec (abfd)->filepos = pos;
93733965Sjdp
93833965Sjdp  /* Fix up the exec header.  */
939218822Sdim  execp->a_text = obj_textsec (abfd)->size;
940218822Sdim  execp->a_data = obj_datasec (abfd)->size;
941218822Sdim  execp->a_bss = obj_bsssec (abfd)->size;
94233965Sjdp  N_SET_MAGIC (*execp, OMAGIC);
94333965Sjdp}
94433965Sjdp
94533965Sjdpstatic void
946218822Sdimadjust_z_magic (bfd *abfd, struct internal_exec *execp)
94733965Sjdp{
94833965Sjdp  bfd_size_type data_pad, text_pad;
94933965Sjdp  file_ptr text_end;
95089857Sobrien  const struct aout_backend_data *abdp;
951218822Sdim  /* TRUE if text includes exec header.  */
952218822Sdim  bfd_boolean ztih;
95377298Sobrien
95433965Sjdp  abdp = aout_backend_info (abfd);
95533965Sjdp
95633965Sjdp  /* Text.  */
95733965Sjdp  ztih = (abdp != NULL
95833965Sjdp	  && (abdp->text_includes_header
95933965Sjdp	      || obj_aout_subformat (abfd) == q_magic_format));
96089857Sobrien  obj_textsec (abfd)->filepos = (ztih
96189857Sobrien				 ? adata (abfd).exec_bytes_size
96289857Sobrien				 : adata (abfd).zmagic_disk_block_size);
96389857Sobrien  if (! obj_textsec (abfd)->user_set_vma)
96433965Sjdp    {
96533965Sjdp      /* ?? Do we really need to check for relocs here?  */
96689857Sobrien      obj_textsec (abfd)->vma = ((abfd->flags & HAS_RELOC)
96789857Sobrien				 ? 0
96889857Sobrien				 : (ztih
96989857Sobrien				    ? (abdp->default_text_vma
97089857Sobrien				       + adata (abfd).exec_bytes_size)
97189857Sobrien				    : abdp->default_text_vma));
97233965Sjdp      text_pad = 0;
97333965Sjdp    }
97433965Sjdp  else
97533965Sjdp    {
97633965Sjdp      /* The .text section is being loaded at an unusual address.  We
97733965Sjdp         may need to pad it such that the .data section starts at a page
97833965Sjdp         boundary.  */
97933965Sjdp      if (ztih)
98033965Sjdp	text_pad = ((obj_textsec (abfd)->filepos - obj_textsec (abfd)->vma)
98133965Sjdp		    & (adata (abfd).page_size - 1));
98233965Sjdp      else
98333965Sjdp	text_pad = ((- obj_textsec (abfd)->vma)
98433965Sjdp		    & (adata (abfd).page_size - 1));
98533965Sjdp    }
98633965Sjdp
98733965Sjdp  /* Find start of data.  */
98833965Sjdp  if (ztih)
98933965Sjdp    {
990218822Sdim      text_end = obj_textsec (abfd)->filepos + obj_textsec (abfd)->size;
99133965Sjdp      text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
99233965Sjdp    }
99333965Sjdp  else
99433965Sjdp    {
99533965Sjdp      /* Note that if page_size == zmagic_disk_block_size, then
99633965Sjdp	 filepos == page_size, and this case is the same as the ztih
99733965Sjdp	 case.  */
998218822Sdim      text_end = obj_textsec (abfd)->size;
99933965Sjdp      text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
100033965Sjdp      text_end += obj_textsec (abfd)->filepos;
100133965Sjdp    }
1002218822Sdim  obj_textsec (abfd)->size += text_pad;
100333965Sjdp  text_end += text_pad;
100433965Sjdp
100533965Sjdp  /* Data.  */
100689857Sobrien  if (!obj_datasec (abfd)->user_set_vma)
100733965Sjdp    {
100833965Sjdp      bfd_vma vma;
1009218822Sdim      vma = obj_textsec (abfd)->vma + obj_textsec (abfd)->size;
101089857Sobrien      obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size);
101133965Sjdp    }
101233965Sjdp  if (abdp && abdp->zmagic_mapped_contiguous)
101333965Sjdp    {
101489857Sobrien      asection * text = obj_textsec (abfd);
101589857Sobrien      asection * data = obj_datasec (abfd);
101689857Sobrien
1017218822Sdim      text_pad = data->vma - (text->vma + text->size);
101889857Sobrien      /* Only pad the text section if the data
101989857Sobrien	 section is going to be placed after it.  */
102089857Sobrien      if (text_pad > 0)
1021218822Sdim	text->size += text_pad;
102233965Sjdp    }
102389857Sobrien  obj_datasec (abfd)->filepos = (obj_textsec (abfd)->filepos
1024218822Sdim				 + obj_textsec (abfd)->size);
102577298Sobrien
102633965Sjdp  /* Fix up exec header while we're at it.  */
1027218822Sdim  execp->a_text = obj_textsec (abfd)->size;
102833965Sjdp  if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
102989857Sobrien    execp->a_text += adata (abfd).exec_bytes_size;
103033965Sjdp  if (obj_aout_subformat (abfd) == q_magic_format)
103133965Sjdp    N_SET_MAGIC (*execp, QMAGIC);
103233965Sjdp  else
103333965Sjdp    N_SET_MAGIC (*execp, ZMAGIC);
103433965Sjdp
103533965Sjdp  /* Spec says data section should be rounded up to page boundary.  */
1036218822Sdim  obj_datasec (abfd)->size
1037218822Sdim    = align_power (obj_datasec (abfd)->size,
103889857Sobrien		   obj_bsssec (abfd)->alignment_power);
1039218822Sdim  execp->a_data = BFD_ALIGN (obj_datasec (abfd)->size,
104089857Sobrien			     adata (abfd).page_size);
1041218822Sdim  data_pad = execp->a_data - obj_datasec (abfd)->size;
104233965Sjdp
104333965Sjdp  /* BSS.  */
104489857Sobrien  if (!obj_bsssec (abfd)->user_set_vma)
104589857Sobrien    obj_bsssec (abfd)->vma = (obj_datasec (abfd)->vma
1046218822Sdim			      + obj_datasec (abfd)->size);
104733965Sjdp  /* If the BSS immediately follows the data section and extra space
104833965Sjdp     in the page is left after the data section, fudge data
104933965Sjdp     in the header so that the bss section looks smaller by that
105033965Sjdp     amount.  We'll start the bss section there, and lie to the OS.
105133965Sjdp     (Note that a linker script, as well as the above assignment,
105233965Sjdp     could have explicitly set the BSS vma to immediately follow
105333965Sjdp     the data section.)  */
105489857Sobrien  if (align_power (obj_bsssec (abfd)->vma, obj_bsssec (abfd)->alignment_power)
1055218822Sdim      == obj_datasec (abfd)->vma + obj_datasec (abfd)->size)
1056218822Sdim    execp->a_bss = (data_pad > obj_bsssec (abfd)->size
1057218822Sdim		    ? 0 : obj_bsssec (abfd)->size - data_pad);
105833965Sjdp  else
1059218822Sdim    execp->a_bss = obj_bsssec (abfd)->size;
106033965Sjdp}
106133965Sjdp
106233965Sjdpstatic void
1063218822Sdimadjust_n_magic (bfd *abfd, struct internal_exec *execp)
106433965Sjdp{
106589857Sobrien  file_ptr pos = adata (abfd).exec_bytes_size;
106633965Sjdp  bfd_vma vma = 0;
106733965Sjdp  int pad;
106877298Sobrien
106933965Sjdp  /* Text.  */
107089857Sobrien  obj_textsec (abfd)->filepos = pos;
107189857Sobrien  if (!obj_textsec (abfd)->user_set_vma)
107289857Sobrien    obj_textsec (abfd)->vma = vma;
107333965Sjdp  else
107489857Sobrien    vma = obj_textsec (abfd)->vma;
1075218822Sdim  pos += obj_textsec (abfd)->size;
1076218822Sdim  vma += obj_textsec (abfd)->size;
107733965Sjdp
107833965Sjdp  /* Data.  */
107989857Sobrien  obj_datasec (abfd)->filepos = pos;
108089857Sobrien  if (!obj_datasec (abfd)->user_set_vma)
108189857Sobrien    obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size);
108289857Sobrien  vma = obj_datasec (abfd)->vma;
108377298Sobrien
108433965Sjdp  /* Since BSS follows data immediately, see if it needs alignment.  */
1085218822Sdim  vma += obj_datasec (abfd)->size;
108689857Sobrien  pad = align_power (vma, obj_bsssec (abfd)->alignment_power) - vma;
1087218822Sdim  obj_datasec (abfd)->size += pad;
1088218822Sdim  pos += obj_datasec (abfd)->size;
108933965Sjdp
109033965Sjdp  /* BSS.  */
109189857Sobrien  if (!obj_bsssec (abfd)->user_set_vma)
109289857Sobrien    obj_bsssec (abfd)->vma = vma;
109333965Sjdp  else
109489857Sobrien    vma = obj_bsssec (abfd)->vma;
109533965Sjdp
109633965Sjdp  /* Fix up exec header.  */
1097218822Sdim  execp->a_text = obj_textsec (abfd)->size;
1098218822Sdim  execp->a_data = obj_datasec (abfd)->size;
1099218822Sdim  execp->a_bss = obj_bsssec (abfd)->size;
110033965Sjdp  N_SET_MAGIC (*execp, NMAGIC);
110133965Sjdp}
110233965Sjdp
1103130561Sobrienbfd_boolean
1104218822SdimNAME (aout, adjust_sizes_and_vmas) (bfd *abfd,
1105218822Sdim				    bfd_size_type *text_size,
1106218822Sdim				    file_ptr *text_end ATTRIBUTE_UNUSED)
110733965Sjdp{
110833965Sjdp  struct internal_exec *execp = exec_hdr (abfd);
110933965Sjdp
1110218822Sdim  if (! NAME (aout, make_sections) (abfd))
1111130561Sobrien    return FALSE;
111233965Sjdp
111389857Sobrien  if (adata (abfd).magic != undecided_magic)
1114130561Sobrien    return TRUE;
111533965Sjdp
1116218822Sdim  obj_textsec (abfd)->size =
1117218822Sdim    align_power (obj_textsec (abfd)->size,
111889857Sobrien		 obj_textsec (abfd)->alignment_power);
111933965Sjdp
1120218822Sdim  *text_size = obj_textsec (abfd)->size;
112133965Sjdp  /* Rule (heuristic) for when to pad to a new page.  Note that there
112233965Sjdp     are (at least) two ways demand-paged (ZMAGIC) files have been
112333965Sjdp     handled.  Most Berkeley-based systems start the text segment at
112433965Sjdp     (TARGET_PAGE_SIZE).  However, newer versions of SUNOS start the text
112533965Sjdp     segment right after the exec header; the latter is counted in the
112633965Sjdp     text segment size, and is paged in by the kernel with the rest of
112777298Sobrien     the text.  */
112833965Sjdp
112933965Sjdp  /* This perhaps isn't the right way to do this, but made it simpler for me
113033965Sjdp     to understand enough to implement it.  Better would probably be to go
113133965Sjdp     right from BFD flags to alignment/positioning characteristics.  But the
113233965Sjdp     old code was sloppy enough about handling the flags, and had enough
113333965Sjdp     other magic, that it was a little hard for me to understand.  I think
113433965Sjdp     I understand it better now, but I haven't time to do the cleanup this
113533965Sjdp     minute.  */
113633965Sjdp
113733965Sjdp  if (abfd->flags & D_PAGED)
113833965Sjdp    /* Whether or not WP_TEXT is set -- let D_PAGED override.  */
113989857Sobrien    adata (abfd).magic = z_magic;
114033965Sjdp  else if (abfd->flags & WP_TEXT)
114189857Sobrien    adata (abfd).magic = n_magic;
114233965Sjdp  else
114389857Sobrien    adata (abfd).magic = o_magic;
114433965Sjdp
114533965Sjdp#ifdef BFD_AOUT_DEBUG /* requires gcc2 */
114633965Sjdp#if __GNUC__ >= 2
114733965Sjdp  fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n",
114833965Sjdp	   ({ char *str;
114989857Sobrien	      switch (adata (abfd).magic)
115089857Sobrien		{
115189857Sobrien		case n_magic: str = "NMAGIC"; break;
115289857Sobrien		case o_magic: str = "OMAGIC"; break;
115389857Sobrien		case z_magic: str = "ZMAGIC"; break;
115489857Sobrien		default: abort ();
115589857Sobrien		}
115633965Sjdp	      str;
115733965Sjdp	    }),
1158218822Sdim	   obj_textsec (abfd)->vma, obj_textsec (abfd)->size,
115989857Sobrien	   	obj_textsec (abfd)->alignment_power,
1160218822Sdim	   obj_datasec (abfd)->vma, obj_datasec (abfd)->size,
116189857Sobrien	   	obj_datasec (abfd)->alignment_power,
1162218822Sdim	   obj_bsssec (abfd)->vma, obj_bsssec (abfd)->size,
116389857Sobrien	   	obj_bsssec (abfd)->alignment_power);
116433965Sjdp#endif
116533965Sjdp#endif
116633965Sjdp
116789857Sobrien  switch (adata (abfd).magic)
116833965Sjdp    {
116933965Sjdp    case o_magic:
117033965Sjdp      adjust_o_magic (abfd, execp);
117133965Sjdp      break;
117233965Sjdp    case z_magic:
117333965Sjdp      adjust_z_magic (abfd, execp);
117433965Sjdp      break;
117533965Sjdp    case n_magic:
117633965Sjdp      adjust_n_magic (abfd, execp);
117733965Sjdp      break;
117833965Sjdp    default:
117933965Sjdp      abort ();
118033965Sjdp    }
118133965Sjdp
118233965Sjdp#ifdef BFD_AOUT_DEBUG
118333965Sjdp  fprintf (stderr, "       text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n",
1184218822Sdim	   obj_textsec (abfd)->vma, obj_textsec (abfd)->size,
118589857Sobrien	   	obj_textsec (abfd)->filepos,
1186218822Sdim	   obj_datasec (abfd)->vma, obj_datasec (abfd)->size,
118789857Sobrien	   	obj_datasec (abfd)->filepos,
1188218822Sdim	   obj_bsssec (abfd)->vma, obj_bsssec (abfd)->size);
118933965Sjdp#endif
119033965Sjdp
1191130561Sobrien  return TRUE;
119233965Sjdp}
119333965Sjdp
119433965Sjdp/*
119533965SjdpFUNCTION
119633965Sjdp	aout_@var{size}_new_section_hook
119733965Sjdp
119833965SjdpSYNOPSIS
1199130561Sobrien        bfd_boolean aout_@var{size}_new_section_hook,
120033965Sjdp	   (bfd *abfd,
1201218822Sdim	    asection *newsect);
120233965Sjdp
120333965SjdpDESCRIPTION
120433965Sjdp	Called by the BFD in response to a @code{bfd_make_section}
120533965Sjdp	request.
120633965Sjdp*/
1207130561Sobrienbfd_boolean
1208218822SdimNAME (aout, new_section_hook) (bfd *abfd, asection *newsect)
120933965Sjdp{
1210130561Sobrien  /* Align to double at least.  */
121189857Sobrien  newsect->alignment_power = bfd_get_arch_info (abfd)->section_align_power;
121233965Sjdp
121333965Sjdp  if (bfd_get_format (abfd) == bfd_object)
1214130561Sobrien    {
1215130561Sobrien      if (obj_textsec (abfd) == NULL && !strcmp (newsect->name, ".text"))
1216130561Sobrien	{
1217130561Sobrien	  obj_textsec (abfd)= newsect;
1218130561Sobrien	  newsect->target_index = N_TEXT;
1219130561Sobrien	}
1220218822Sdim      else if (obj_datasec (abfd) == NULL && !strcmp (newsect->name, ".data"))
1221130561Sobrien	{
1222130561Sobrien	  obj_datasec (abfd) = newsect;
1223130561Sobrien	  newsect->target_index = N_DATA;
1224130561Sobrien	}
1225218822Sdim      else if (obj_bsssec (abfd) == NULL && !strcmp (newsect->name, ".bss"))
1226130561Sobrien	{
1227130561Sobrien	  obj_bsssec (abfd) = newsect;
1228130561Sobrien	  newsect->target_index = N_BSS;
1229130561Sobrien	}
1230130561Sobrien    }
123133965Sjdp
1232130561Sobrien  /* We allow more than three sections internally.  */
1233218822Sdim  return _bfd_generic_new_section_hook (abfd, newsect);
123433965Sjdp}
123533965Sjdp
1236130561Sobrienbfd_boolean
1237218822SdimNAME (aout, set_section_contents) (bfd *abfd,
1238218822Sdim				   sec_ptr section,
1239218822Sdim				   const void * location,
1240218822Sdim				   file_ptr offset,
1241218822Sdim				   bfd_size_type count)
124233965Sjdp{
124333965Sjdp  file_ptr text_end;
124433965Sjdp  bfd_size_type text_size;
124533965Sjdp
124633965Sjdp  if (! abfd->output_has_begun)
124733965Sjdp    {
1248218822Sdim      if (! NAME (aout, adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
1249130561Sobrien	return FALSE;
125033965Sjdp    }
125133965Sjdp
125233965Sjdp  if (section == obj_bsssec (abfd))
125333965Sjdp    {
125433965Sjdp      bfd_set_error (bfd_error_no_contents);
1255130561Sobrien      return FALSE;
125633965Sjdp    }
125733965Sjdp
125833965Sjdp  if (section != obj_textsec (abfd)
125933965Sjdp      && section != obj_datasec (abfd))
126033965Sjdp    {
1261130561Sobrien      if (aout_section_merge_with_text_p (abfd, section))
1262130561Sobrien	section->filepos = obj_textsec (abfd)->filepos +
1263130561Sobrien			   (section->vma - obj_textsec (abfd)->vma);
1264130561Sobrien      else
1265130561Sobrien	{
1266130561Sobrien          (*_bfd_error_handler)
1267130561Sobrien	   (_("%s: can not represent section `%s' in a.out object file format"),
1268130561Sobrien	     bfd_get_filename (abfd), bfd_get_section_name (abfd, section));
1269130561Sobrien          bfd_set_error (bfd_error_nonrepresentable_section);
1270130561Sobrien          return FALSE;
1271130561Sobrien	}
127233965Sjdp    }
127333965Sjdp
127433965Sjdp  if (count != 0)
127533965Sjdp    {
127633965Sjdp      if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
127789857Sobrien	  || bfd_bwrite (location, count, abfd) != count)
1278130561Sobrien	return FALSE;
127933965Sjdp    }
128033965Sjdp
1281130561Sobrien  return TRUE;
128233965Sjdp}
128333965Sjdp
128433965Sjdp/* Read the external symbols from an a.out file.  */
128533965Sjdp
1286130561Sobrienstatic bfd_boolean
1287218822Sdimaout_get_external_symbols (bfd *abfd)
128833965Sjdp{
1289218822Sdim  if (obj_aout_external_syms (abfd) == NULL)
129033965Sjdp    {
129133965Sjdp      bfd_size_type count;
129233965Sjdp      struct external_nlist *syms;
129389857Sobrien      bfd_size_type amt;
129433965Sjdp
129533965Sjdp      count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
129633965Sjdp
129733965Sjdp#ifdef USE_MMAP
1298104834Sobrien      if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd),
1299104834Sobrien				 exec_hdr (abfd)->a_syms,
1300130561Sobrien				 &obj_aout_sym_window (abfd), TRUE))
1301130561Sobrien	return FALSE;
130233965Sjdp      syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
130333965Sjdp#else
130433965Sjdp      /* We allocate using malloc to make the values easy to free
130533965Sjdp	 later on.  If we put them on the objalloc it might not be
130633965Sjdp	 possible to free them.  */
1307218822Sdim      syms = bfd_malloc (count * EXTERNAL_NLIST_SIZE);
1308218822Sdim      if (syms == NULL && count != 0)
1309130561Sobrien	return FALSE;
131033965Sjdp
131189857Sobrien      amt = exec_hdr (abfd)->a_syms;
131233965Sjdp      if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
131389857Sobrien	  || bfd_bread (syms, amt, abfd) != amt)
131433965Sjdp	{
131533965Sjdp	  free (syms);
1316130561Sobrien	  return FALSE;
131733965Sjdp	}
131833965Sjdp#endif
131933965Sjdp
132033965Sjdp      obj_aout_external_syms (abfd) = syms;
132133965Sjdp      obj_aout_external_sym_count (abfd) = count;
132233965Sjdp    }
132377298Sobrien
132433965Sjdp  if (obj_aout_external_strings (abfd) == NULL
132533965Sjdp      && exec_hdr (abfd)->a_syms != 0)
132633965Sjdp    {
132733965Sjdp      unsigned char string_chars[BYTES_IN_WORD];
132833965Sjdp      bfd_size_type stringsize;
132933965Sjdp      char *strings;
133089857Sobrien      bfd_size_type amt = BYTES_IN_WORD;
133133965Sjdp
133233965Sjdp      /* Get the size of the strings.  */
133333965Sjdp      if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
1334218822Sdim	  || bfd_bread ((void *) string_chars, amt, abfd) != amt)
1335130561Sobrien	return FALSE;
133633965Sjdp      stringsize = GET_WORD (abfd, string_chars);
133733965Sjdp
133833965Sjdp#ifdef USE_MMAP
1339104834Sobrien      if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize,
1340130561Sobrien				 &obj_aout_string_window (abfd), TRUE))
1341130561Sobrien	return FALSE;
134233965Sjdp      strings = (char *) obj_aout_string_window (abfd).data;
134333965Sjdp#else
1344218822Sdim      strings = bfd_malloc (stringsize + 1);
134533965Sjdp      if (strings == NULL)
1346130561Sobrien	return FALSE;
134733965Sjdp
134833965Sjdp      /* Skip space for the string count in the buffer for convenience
134933965Sjdp	 when using indexes.  */
135089857Sobrien      amt = stringsize - BYTES_IN_WORD;
135189857Sobrien      if (bfd_bread (strings + BYTES_IN_WORD, amt, abfd) != amt)
135233965Sjdp	{
135333965Sjdp	  free (strings);
1354130561Sobrien	  return FALSE;
135533965Sjdp	}
135633965Sjdp#endif
135733965Sjdp
135833965Sjdp      /* Ensure that a zero index yields an empty string.  */
135933965Sjdp      strings[0] = '\0';
136033965Sjdp
136133965Sjdp      strings[stringsize - 1] = 0;
136233965Sjdp
136333965Sjdp      obj_aout_external_strings (abfd) = strings;
136433965Sjdp      obj_aout_external_string_size (abfd) = stringsize;
136533965Sjdp    }
136633965Sjdp
1367130561Sobrien  return TRUE;
136833965Sjdp}
136933965Sjdp
137033965Sjdp/* Translate an a.out symbol into a BFD symbol.  The desc, other, type
137133965Sjdp   and symbol->value fields of CACHE_PTR will be set from the a.out
137233965Sjdp   nlist structure.  This function is responsible for setting
137333965Sjdp   symbol->flags and symbol->section, and adjusting symbol->value.  */
137433965Sjdp
1375130561Sobrienstatic bfd_boolean
1376218822Sdimtranslate_from_native_sym_flags (bfd *abfd, aout_symbol_type *cache_ptr)
137733965Sjdp{
137833965Sjdp  flagword visible;
137933965Sjdp
138033965Sjdp  if ((cache_ptr->type & N_STAB) != 0
138133965Sjdp      || cache_ptr->type == N_FN)
138233965Sjdp    {
138333965Sjdp      asection *sec;
138433965Sjdp
138533965Sjdp      /* This is a debugging symbol.  */
138633965Sjdp      cache_ptr->symbol.flags = BSF_DEBUGGING;
138733965Sjdp
138833965Sjdp      /* Work out the symbol section.  */
138933965Sjdp      switch (cache_ptr->type & N_TYPE)
139033965Sjdp	{
139133965Sjdp	case N_TEXT:
139233965Sjdp	case N_FN:
139333965Sjdp	  sec = obj_textsec (abfd);
139433965Sjdp	  break;
139533965Sjdp	case N_DATA:
139633965Sjdp	  sec = obj_datasec (abfd);
139733965Sjdp	  break;
139833965Sjdp	case N_BSS:
139933965Sjdp	  sec = obj_bsssec (abfd);
140033965Sjdp	  break;
140133965Sjdp	default:
140233965Sjdp	case N_ABS:
140333965Sjdp	  sec = bfd_abs_section_ptr;
140433965Sjdp	  break;
140533965Sjdp	}
140633965Sjdp
140733965Sjdp      cache_ptr->symbol.section = sec;
140833965Sjdp      cache_ptr->symbol.value -= sec->vma;
140933965Sjdp
1410130561Sobrien      return TRUE;
141133965Sjdp    }
141233965Sjdp
141333965Sjdp  /* Get the default visibility.  This does not apply to all types, so
141433965Sjdp     we just hold it in a local variable to use if wanted.  */
141533965Sjdp  if ((cache_ptr->type & N_EXT) == 0)
141633965Sjdp    visible = BSF_LOCAL;
141733965Sjdp  else
141833965Sjdp    visible = BSF_GLOBAL;
141933965Sjdp
142033965Sjdp  switch (cache_ptr->type)
142133965Sjdp    {
142233965Sjdp    default:
142333965Sjdp    case N_ABS: case N_ABS | N_EXT:
142433965Sjdp      cache_ptr->symbol.section = bfd_abs_section_ptr;
142533965Sjdp      cache_ptr->symbol.flags = visible;
142633965Sjdp      break;
142733965Sjdp
142833965Sjdp    case N_UNDF | N_EXT:
142933965Sjdp      if (cache_ptr->symbol.value != 0)
143033965Sjdp	{
143133965Sjdp	  /* This is a common symbol.  */
143233965Sjdp	  cache_ptr->symbol.flags = BSF_GLOBAL;
143333965Sjdp	  cache_ptr->symbol.section = bfd_com_section_ptr;
143433965Sjdp	}
143533965Sjdp      else
143633965Sjdp	{
143733965Sjdp	  cache_ptr->symbol.flags = 0;
143833965Sjdp	  cache_ptr->symbol.section = bfd_und_section_ptr;
143933965Sjdp	}
144033965Sjdp      break;
144133965Sjdp
144233965Sjdp    case N_TEXT: case N_TEXT | N_EXT:
144333965Sjdp      cache_ptr->symbol.section = obj_textsec (abfd);
144433965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
144533965Sjdp      cache_ptr->symbol.flags = visible;
144633965Sjdp      break;
144733965Sjdp
144833965Sjdp      /* N_SETV symbols used to represent set vectors placed in the
144933965Sjdp	 data section.  They are no longer generated.  Theoretically,
145033965Sjdp	 it was possible to extract the entries and combine them with
145133965Sjdp	 new ones, although I don't know if that was ever actually
145233965Sjdp	 done.  Unless that feature is restored, treat them as data
145333965Sjdp	 symbols.  */
145433965Sjdp    case N_SETV: case N_SETV | N_EXT:
145533965Sjdp    case N_DATA: case N_DATA | N_EXT:
145633965Sjdp      cache_ptr->symbol.section = obj_datasec (abfd);
145733965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
145833965Sjdp      cache_ptr->symbol.flags = visible;
145933965Sjdp      break;
146033965Sjdp
146133965Sjdp    case N_BSS: case N_BSS | N_EXT:
146233965Sjdp      cache_ptr->symbol.section = obj_bsssec (abfd);
146333965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
146433965Sjdp      cache_ptr->symbol.flags = visible;
146533965Sjdp      break;
146633965Sjdp
146733965Sjdp    case N_SETA: case N_SETA | N_EXT:
146833965Sjdp    case N_SETT: case N_SETT | N_EXT:
146933965Sjdp    case N_SETD: case N_SETD | N_EXT:
147033965Sjdp    case N_SETB: case N_SETB | N_EXT:
147133965Sjdp      {
147233965Sjdp	/* This code is no longer needed.  It used to be used to make
147333965Sjdp           the linker handle set symbols, but they are now handled in
147433965Sjdp           the add_symbols routine instead.  */
147533965Sjdp	switch (cache_ptr->type & N_TYPE)
147633965Sjdp	  {
147733965Sjdp	  case N_SETA:
147833965Sjdp	    cache_ptr->symbol.section = bfd_abs_section_ptr;
147933965Sjdp	    break;
148033965Sjdp	  case N_SETT:
148133965Sjdp	    cache_ptr->symbol.section = obj_textsec (abfd);
148233965Sjdp	    break;
148333965Sjdp	  case N_SETD:
148433965Sjdp	    cache_ptr->symbol.section = obj_datasec (abfd);
148533965Sjdp	    break;
148633965Sjdp	  case N_SETB:
148733965Sjdp	    cache_ptr->symbol.section = obj_bsssec (abfd);
148833965Sjdp	    break;
148933965Sjdp	  }
149033965Sjdp
149133965Sjdp	cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
149233965Sjdp      }
149333965Sjdp      break;
149433965Sjdp
149533965Sjdp    case N_WARNING:
149633965Sjdp      /* This symbol is the text of a warning message.  The next
149733965Sjdp	 symbol is the symbol to associate the warning with.  If a
149833965Sjdp	 reference is made to that symbol, a warning is issued.  */
149933965Sjdp      cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
150033965Sjdp      cache_ptr->symbol.section = bfd_abs_section_ptr;
150133965Sjdp      break;
150233965Sjdp
150333965Sjdp    case N_INDR: case N_INDR | N_EXT:
150433965Sjdp      /* An indirect symbol.  This consists of two symbols in a row.
150533965Sjdp	 The first symbol is the name of the indirection.  The second
150633965Sjdp	 symbol is the name of the target.  A reference to the first
150733965Sjdp	 symbol becomes a reference to the second.  */
150833965Sjdp      cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible;
150933965Sjdp      cache_ptr->symbol.section = bfd_ind_section_ptr;
151033965Sjdp      break;
151133965Sjdp
151233965Sjdp    case N_WEAKU:
151333965Sjdp      cache_ptr->symbol.section = bfd_und_section_ptr;
151433965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
151533965Sjdp      break;
151633965Sjdp
151733965Sjdp    case N_WEAKA:
151833965Sjdp      cache_ptr->symbol.section = bfd_abs_section_ptr;
151933965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
152033965Sjdp      break;
152133965Sjdp
152233965Sjdp    case N_WEAKT:
152333965Sjdp      cache_ptr->symbol.section = obj_textsec (abfd);
152433965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
152533965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
152633965Sjdp      break;
152733965Sjdp
152833965Sjdp    case N_WEAKD:
152933965Sjdp      cache_ptr->symbol.section = obj_datasec (abfd);
153033965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
153133965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
153233965Sjdp      break;
153333965Sjdp
153433965Sjdp    case N_WEAKB:
153533965Sjdp      cache_ptr->symbol.section = obj_bsssec (abfd);
153633965Sjdp      cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
153733965Sjdp      cache_ptr->symbol.flags = BSF_WEAK;
153833965Sjdp      break;
153933965Sjdp    }
154033965Sjdp
1541130561Sobrien  return TRUE;
154233965Sjdp}
154333965Sjdp
154433965Sjdp/* Set the fields of SYM_POINTER according to CACHE_PTR.  */
154533965Sjdp
1546130561Sobrienstatic bfd_boolean
1547218822Sdimtranslate_to_native_sym_flags (bfd *abfd,
1548218822Sdim			       asymbol *cache_ptr,
1549218822Sdim			       struct external_nlist *sym_pointer)
155033965Sjdp{
155133965Sjdp  bfd_vma value = cache_ptr->value;
155233965Sjdp  asection *sec;
155333965Sjdp  bfd_vma off;
155433965Sjdp
155533965Sjdp  /* Mask out any existing type bits in case copying from one section
155633965Sjdp     to another.  */
155733965Sjdp  sym_pointer->e_type[0] &= ~N_TYPE;
155833965Sjdp
155933965Sjdp  sec = bfd_get_section (cache_ptr);
156033965Sjdp  off = 0;
156133965Sjdp
156233965Sjdp  if (sec == NULL)
156333965Sjdp    {
156433965Sjdp      /* This case occurs, e.g., for the *DEBUG* section of a COFF
156533965Sjdp	 file.  */
156633965Sjdp      (*_bfd_error_handler)
156760484Sobrien	(_("%s: can not represent section for symbol `%s' in a.out object file format"),
156877298Sobrien	 bfd_get_filename (abfd),
156960484Sobrien	 cache_ptr->name != NULL ? cache_ptr->name : _("*unknown*"));
157033965Sjdp      bfd_set_error (bfd_error_nonrepresentable_section);
1571130561Sobrien      return FALSE;
157233965Sjdp    }
157333965Sjdp
157433965Sjdp  if (sec->output_section != NULL)
157533965Sjdp    {
157633965Sjdp      off = sec->output_offset;
157733965Sjdp      sec = sec->output_section;
157833965Sjdp    }
157933965Sjdp
158033965Sjdp  if (bfd_is_abs_section (sec))
158133965Sjdp    sym_pointer->e_type[0] |= N_ABS;
158233965Sjdp  else if (sec == obj_textsec (abfd))
158333965Sjdp    sym_pointer->e_type[0] |= N_TEXT;
158433965Sjdp  else if (sec == obj_datasec (abfd))
158533965Sjdp    sym_pointer->e_type[0] |= N_DATA;
158633965Sjdp  else if (sec == obj_bsssec (abfd))
158733965Sjdp    sym_pointer->e_type[0] |= N_BSS;
158833965Sjdp  else if (bfd_is_und_section (sec))
158933965Sjdp    sym_pointer->e_type[0] = N_UNDF | N_EXT;
159033965Sjdp  else if (bfd_is_ind_section (sec))
159133965Sjdp    sym_pointer->e_type[0] = N_INDR;
159233965Sjdp  else if (bfd_is_com_section (sec))
159333965Sjdp    sym_pointer->e_type[0] = N_UNDF | N_EXT;
159433965Sjdp  else
159533965Sjdp    {
1596130561Sobrien      if (aout_section_merge_with_text_p (abfd, sec))
1597130561Sobrien	sym_pointer->e_type[0] |= N_TEXT;
1598130561Sobrien      else
1599130561Sobrien	{
1600130561Sobrien          (*_bfd_error_handler)
1601130561Sobrien	   (_("%s: can not represent section `%s' in a.out object file format"),
1602130561Sobrien	     bfd_get_filename (abfd), bfd_get_section_name (abfd, sec));
1603130561Sobrien          bfd_set_error (bfd_error_nonrepresentable_section);
1604130561Sobrien          return FALSE;
1605130561Sobrien	}
160633965Sjdp    }
160733965Sjdp
1608130561Sobrien  /* Turn the symbol from section relative to absolute again.  */
160933965Sjdp  value += sec->vma + off;
161033965Sjdp
161133965Sjdp  if ((cache_ptr->flags & BSF_WARNING) != 0)
161233965Sjdp    sym_pointer->e_type[0] = N_WARNING;
161333965Sjdp
161433965Sjdp  if ((cache_ptr->flags & BSF_DEBUGGING) != 0)
161533965Sjdp    sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type;
161633965Sjdp  else if ((cache_ptr->flags & BSF_GLOBAL) != 0)
161733965Sjdp    sym_pointer->e_type[0] |= N_EXT;
161877298Sobrien  else if ((cache_ptr->flags & BSF_LOCAL) != 0)
161977298Sobrien    sym_pointer->e_type[0] &= ~N_EXT;
162033965Sjdp
162133965Sjdp  if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0)
162233965Sjdp    {
162333965Sjdp      int type = ((aout_symbol_type *) cache_ptr)->type;
1624130561Sobrien
162533965Sjdp      switch (type)
162633965Sjdp	{
162733965Sjdp	case N_ABS:	type = N_SETA; break;
162833965Sjdp	case N_TEXT:	type = N_SETT; break;
162933965Sjdp	case N_DATA:	type = N_SETD; break;
163033965Sjdp	case N_BSS:	type = N_SETB; break;
163133965Sjdp	}
163233965Sjdp      sym_pointer->e_type[0] = type;
163333965Sjdp    }
163433965Sjdp
163533965Sjdp  if ((cache_ptr->flags & BSF_WEAK) != 0)
163633965Sjdp    {
163733965Sjdp      int type;
163833965Sjdp
163933965Sjdp      switch (sym_pointer->e_type[0] & N_TYPE)
164033965Sjdp	{
164133965Sjdp	default:
164233965Sjdp	case N_ABS:	type = N_WEAKA; break;
164333965Sjdp	case N_TEXT:	type = N_WEAKT; break;
164433965Sjdp	case N_DATA:	type = N_WEAKD; break;
164533965Sjdp	case N_BSS:	type = N_WEAKB; break;
164633965Sjdp	case N_UNDF:	type = N_WEAKU; break;
164733965Sjdp	}
164833965Sjdp      sym_pointer->e_type[0] = type;
164933965Sjdp    }
165033965Sjdp
165189857Sobrien  PUT_WORD (abfd, value, sym_pointer->e_value);
165233965Sjdp
1653130561Sobrien  return TRUE;
165433965Sjdp}
165533965Sjdp
165677298Sobrien/* Native-level interface to symbols.  */
165733965Sjdp
165833965Sjdpasymbol *
1659218822SdimNAME (aout, make_empty_symbol) (bfd *abfd)
166033965Sjdp{
166189857Sobrien  bfd_size_type amt = sizeof (aout_symbol_type);
1662218822Sdim
1663218822Sdim  aout_symbol_type *new = bfd_zalloc (abfd, amt);
166433965Sjdp  if (!new)
166533965Sjdp    return NULL;
166633965Sjdp  new->symbol.the_bfd = abfd;
166733965Sjdp
166833965Sjdp  return &new->symbol;
166933965Sjdp}
167033965Sjdp
167133965Sjdp/* Translate a set of internal symbols into external symbols.  */
167233965Sjdp
1673130561Sobrienbfd_boolean
1674218822SdimNAME (aout, translate_symbol_table) (bfd *abfd,
1675218822Sdim				     aout_symbol_type *in,
1676218822Sdim				     struct external_nlist *ext,
1677218822Sdim				     bfd_size_type count,
1678218822Sdim				     char *str,
1679218822Sdim				     bfd_size_type strsize,
1680218822Sdim				     bfd_boolean dynamic)
168133965Sjdp{
168233965Sjdp  struct external_nlist *ext_end;
168333965Sjdp
168433965Sjdp  ext_end = ext + count;
168533965Sjdp  for (; ext < ext_end; ext++, in++)
168633965Sjdp    {
168733965Sjdp      bfd_vma x;
168833965Sjdp
168933965Sjdp      x = GET_WORD (abfd, ext->e_strx);
169033965Sjdp      in->symbol.the_bfd = abfd;
169133965Sjdp
169233965Sjdp      /* For the normal symbols, the zero index points at the number
169333965Sjdp	 of bytes in the string table but is to be interpreted as the
169433965Sjdp	 null string.  For the dynamic symbols, the number of bytes in
169533965Sjdp	 the string table is stored in the __DYNAMIC structure and the
169633965Sjdp	 zero index points at an actual string.  */
169733965Sjdp      if (x == 0 && ! dynamic)
169833965Sjdp	in->symbol.name = "";
169933965Sjdp      else if (x < strsize)
170033965Sjdp	in->symbol.name = str + x;
170133965Sjdp      else
1702130561Sobrien	return FALSE;
170333965Sjdp
170433965Sjdp      in->symbol.value = GET_SWORD (abfd,  ext->e_value);
170589857Sobrien      in->desc = H_GET_16 (abfd, ext->e_desc);
170689857Sobrien      in->other = H_GET_8 (abfd, ext->e_other);
170789857Sobrien      in->type = H_GET_8 (abfd,  ext->e_type);
170833965Sjdp      in->symbol.udata.p = NULL;
170933965Sjdp
171033965Sjdp      if (! translate_from_native_sym_flags (abfd, in))
1711130561Sobrien	return FALSE;
171233965Sjdp
171333965Sjdp      if (dynamic)
171433965Sjdp	in->symbol.flags |= BSF_DYNAMIC;
171533965Sjdp    }
171633965Sjdp
1717130561Sobrien  return TRUE;
171833965Sjdp}
171933965Sjdp
172033965Sjdp/* We read the symbols into a buffer, which is discarded when this
172133965Sjdp   function exits.  We read the strings into a buffer large enough to
172277298Sobrien   hold them all plus all the cached symbol entries.  */
172333965Sjdp
1724130561Sobrienbfd_boolean
1725218822SdimNAME (aout, slurp_symbol_table) (bfd *abfd)
172633965Sjdp{
172733965Sjdp  struct external_nlist *old_external_syms;
172833965Sjdp  aout_symbol_type *cached;
172989857Sobrien  bfd_size_type cached_size;
173033965Sjdp
1731130561Sobrien  /* If there's no work to be done, don't do any.  */
1732218822Sdim  if (obj_aout_symbols (abfd) != NULL)
1733130561Sobrien    return TRUE;
173433965Sjdp
173533965Sjdp  old_external_syms = obj_aout_external_syms (abfd);
173633965Sjdp
173733965Sjdp  if (! aout_get_external_symbols (abfd))
1738130561Sobrien    return FALSE;
173933965Sjdp
174089857Sobrien  cached_size = obj_aout_external_sym_count (abfd);
174189857Sobrien  cached_size *= sizeof (aout_symbol_type);
1742218822Sdim  cached = bfd_zmalloc (cached_size);
174333965Sjdp  if (cached == NULL && cached_size != 0)
1744130561Sobrien    return FALSE;
174533965Sjdp
174633965Sjdp  /* Convert from external symbol information to internal.  */
1747218822Sdim  if (! (NAME (aout, translate_symbol_table)
174833965Sjdp	 (abfd, cached,
174933965Sjdp	  obj_aout_external_syms (abfd),
175033965Sjdp	  obj_aout_external_sym_count (abfd),
175133965Sjdp	  obj_aout_external_strings (abfd),
175233965Sjdp	  obj_aout_external_string_size (abfd),
1753130561Sobrien	  FALSE)))
175433965Sjdp    {
175533965Sjdp      free (cached);
1756130561Sobrien      return FALSE;
175733965Sjdp    }
175833965Sjdp
175933965Sjdp  bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd);
176033965Sjdp
176133965Sjdp  obj_aout_symbols (abfd) = cached;
176233965Sjdp
176333965Sjdp  /* It is very likely that anybody who calls this function will not
176433965Sjdp     want the external symbol information, so if it was allocated
176533965Sjdp     because of our call to aout_get_external_symbols, we free it up
176633965Sjdp     right away to save space.  */
1767218822Sdim  if (old_external_syms == NULL
1768218822Sdim      && obj_aout_external_syms (abfd) != NULL)
176933965Sjdp    {
177033965Sjdp#ifdef USE_MMAP
177133965Sjdp      bfd_free_window (&obj_aout_sym_window (abfd));
177233965Sjdp#else
177333965Sjdp      free (obj_aout_external_syms (abfd));
177433965Sjdp#endif
177533965Sjdp      obj_aout_external_syms (abfd) = NULL;
177633965Sjdp    }
177733965Sjdp
1778130561Sobrien  return TRUE;
177933965Sjdp}
178033965Sjdp
178133965Sjdp/* We use a hash table when writing out symbols so that we only write
178233965Sjdp   out a particular string once.  This helps particularly when the
178333965Sjdp   linker writes out stabs debugging entries, because each different
178433965Sjdp   contributing object file tends to have many duplicate stabs
178533965Sjdp   strings.
178633965Sjdp
178733965Sjdp   This hash table code breaks dbx on SunOS 4.1.3, so we don't do it
178833965Sjdp   if BFD_TRADITIONAL_FORMAT is set.  */
178933965Sjdp
179033965Sjdp/* Get the index of a string in a strtab, adding it if it is not
179133965Sjdp   already present.  */
179233965Sjdp
1793218822Sdimstatic inline bfd_size_type
1794218822Sdimadd_to_stringtab (bfd *abfd,
1795218822Sdim		  struct bfd_strtab_hash *tab,
1796218822Sdim		  const char *str,
1797218822Sdim		  bfd_boolean copy)
179833965Sjdp{
1799130561Sobrien  bfd_boolean hash;
180033965Sjdp  bfd_size_type index;
180133965Sjdp
180233965Sjdp  /* An index of 0 always means the empty string.  */
180333965Sjdp  if (str == 0 || *str == '\0')
180433965Sjdp    return 0;
180533965Sjdp
180633965Sjdp  /* Don't hash if BFD_TRADITIONAL_FORMAT is set, because SunOS dbx
180733965Sjdp     doesn't understand a hashed string table.  */
1808130561Sobrien  hash = TRUE;
180933965Sjdp  if ((abfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
1810130561Sobrien    hash = FALSE;
181133965Sjdp
181233965Sjdp  index = _bfd_stringtab_add (tab, str, hash, copy);
181333965Sjdp
181433965Sjdp  if (index != (bfd_size_type) -1)
1815218822Sdim    /* Add BYTES_IN_WORD to the return value to account for the
1816218822Sdim       space taken up by the string table size.  */
1817218822Sdim    index += BYTES_IN_WORD;
181833965Sjdp
181933965Sjdp  return index;
182033965Sjdp}
182133965Sjdp
182233965Sjdp/* Write out a strtab.  ABFD is already at the right location in the
182333965Sjdp   file.  */
182433965Sjdp
1825130561Sobrienstatic bfd_boolean
1826218822Sdimemit_stringtab (bfd *abfd, struct bfd_strtab_hash *tab)
182733965Sjdp{
182833965Sjdp  bfd_byte buffer[BYTES_IN_WORD];
182989857Sobrien  bfd_size_type amt = BYTES_IN_WORD;
183033965Sjdp
183133965Sjdp  /* The string table starts with the size.  */
183233965Sjdp  PUT_WORD (abfd, _bfd_stringtab_size (tab) + BYTES_IN_WORD, buffer);
1833218822Sdim  if (bfd_bwrite ((void *) buffer, amt, abfd) != amt)
1834130561Sobrien    return FALSE;
183533965Sjdp
183633965Sjdp  return _bfd_stringtab_emit (abfd, tab);
183733965Sjdp}
183833965Sjdp
1839130561Sobrienbfd_boolean
1840218822SdimNAME (aout, write_syms) (bfd *abfd)
184133965Sjdp{
184233965Sjdp  unsigned int count ;
184333965Sjdp  asymbol **generic = bfd_get_outsymbols (abfd);
184433965Sjdp  struct bfd_strtab_hash *strtab;
184533965Sjdp
184633965Sjdp  strtab = _bfd_stringtab_init ();
184733965Sjdp  if (strtab == NULL)
1848130561Sobrien    return FALSE;
184933965Sjdp
185033965Sjdp  for (count = 0; count < bfd_get_symcount (abfd); count++)
185133965Sjdp    {
185233965Sjdp      asymbol *g = generic[count];
185333965Sjdp      bfd_size_type indx;
185433965Sjdp      struct external_nlist nsp;
185589857Sobrien      bfd_size_type amt;
185633965Sjdp
1857130561Sobrien      indx = add_to_stringtab (abfd, strtab, g->name, FALSE);
185833965Sjdp      if (indx == (bfd_size_type) -1)
185933965Sjdp	goto error_return;
186033965Sjdp      PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx);
186133965Sjdp
186289857Sobrien      if (bfd_asymbol_flavour (g) == abfd->xvec->flavour)
186333965Sjdp	{
186489857Sobrien	  H_PUT_16 (abfd, aout_symbol (g)->desc,  nsp.e_desc);
186589857Sobrien	  H_PUT_8  (abfd, aout_symbol (g)->other, nsp.e_other);
186689857Sobrien	  H_PUT_8  (abfd, aout_symbol (g)->type,  nsp.e_type);
186733965Sjdp	}
186833965Sjdp      else
186933965Sjdp	{
187089857Sobrien	  H_PUT_16 (abfd, 0, nsp.e_desc);
187189857Sobrien	  H_PUT_8  (abfd, 0, nsp.e_other);
187289857Sobrien	  H_PUT_8  (abfd, 0, nsp.e_type);
187333965Sjdp	}
187433965Sjdp
187533965Sjdp      if (! translate_to_native_sym_flags (abfd, g, &nsp))
187633965Sjdp	goto error_return;
187733965Sjdp
187889857Sobrien      amt = EXTERNAL_NLIST_SIZE;
1879218822Sdim      if (bfd_bwrite ((void *) &nsp, amt, abfd) != amt)
188033965Sjdp	goto error_return;
188133965Sjdp
188233965Sjdp      /* NB: `KEEPIT' currently overlays `udata.p', so set this only
188333965Sjdp	 here, at the end.  */
188433965Sjdp      g->KEEPIT = count;
188533965Sjdp    }
188633965Sjdp
188733965Sjdp  if (! emit_stringtab (abfd, strtab))
188833965Sjdp    goto error_return;
188933965Sjdp
189033965Sjdp  _bfd_stringtab_free (strtab);
189133965Sjdp
1892130561Sobrien  return TRUE;
189333965Sjdp
189433965Sjdperror_return:
189533965Sjdp  _bfd_stringtab_free (strtab);
1896130561Sobrien  return FALSE;
189733965Sjdp}
189833965Sjdp
189933965Sjdplong
1900218822SdimNAME (aout, canonicalize_symtab) (bfd *abfd, asymbol **location)
190133965Sjdp{
1902218822Sdim  unsigned int counter = 0;
1903218822Sdim  aout_symbol_type *symbase;
190433965Sjdp
1905218822Sdim  if (!NAME (aout, slurp_symbol_table) (abfd))
1906218822Sdim    return -1;
190733965Sjdp
1908218822Sdim  for (symbase = obj_aout_symbols (abfd);
1909218822Sdim       counter++ < bfd_get_symcount (abfd);
1910218822Sdim       )
1911218822Sdim    *(location++) = (asymbol *) (symbase++);
1912218822Sdim  *location++ =0;
1913218822Sdim  return bfd_get_symcount (abfd);
191433965Sjdp}
191533965Sjdp
1916130561Sobrien/* Standard reloc stuff.  */
191777298Sobrien/* Output standard relocation information to a file in target byte order.  */
191833965Sjdp
1919218822Sdimextern void  NAME (aout, swap_std_reloc_out)
1920218822Sdim  (bfd *, arelent *, struct reloc_std_external *);
192133965Sjdp
192233965Sjdpvoid
1923218822SdimNAME (aout, swap_std_reloc_out) (bfd *abfd,
1924218822Sdim				 arelent *g,
1925218822Sdim				 struct reloc_std_external *natptr)
192633965Sjdp{
192733965Sjdp  int r_index;
192833965Sjdp  asymbol *sym = *(g->sym_ptr_ptr);
192933965Sjdp  int r_extern;
193033965Sjdp  unsigned int r_length;
193133965Sjdp  int r_pcrel;
193233965Sjdp  int r_baserel, r_jmptable, r_relative;
193333965Sjdp  asection *output_section = sym->section->output_section;
193433965Sjdp
193589857Sobrien  PUT_WORD (abfd, g->address, natptr->r_address);
193633965Sjdp
1937130561Sobrien  r_length = g->howto->size ;	/* Size as a power of two.  */
1938130561Sobrien  r_pcrel  = (int) g->howto->pc_relative; /* Relative to PC?  */
193933965Sjdp  /* XXX This relies on relocs coming from a.out files.  */
194033965Sjdp  r_baserel = (g->howto->type & 8) != 0;
194133965Sjdp  r_jmptable = (g->howto->type & 16) != 0;
194233965Sjdp  r_relative = (g->howto->type & 32) != 0;
194333965Sjdp
1944130561Sobrien  /* Name was clobbered by aout_write_syms to be symbol index.  */
194533965Sjdp
194633965Sjdp  /* If this relocation is relative to a symbol then set the
194733965Sjdp     r_index to the symbols index, and the r_extern bit.
194833965Sjdp
194933965Sjdp     Absolute symbols can come in in two ways, either as an offset
195033965Sjdp     from the abs section, or as a symbol which has an abs value.
1951130561Sobrien     check for that here.  */
195233965Sjdp
195333965Sjdp  if (bfd_is_com_section (output_section)
195433965Sjdp      || bfd_is_abs_section (output_section)
1955218822Sdim      || bfd_is_und_section (output_section)
1956218822Sdim      /* PR gas/3041  a.out relocs against weak symbols
1957218822Sdim	 must be treated as if they were against externs.  */
1958218822Sdim      || (sym->flags & BSF_WEAK))
195933965Sjdp    {
196033965Sjdp      if (bfd_abs_section_ptr->symbol == sym)
1961130561Sobrien	{
1962130561Sobrien	  /* Whoops, looked like an abs symbol, but is
1963130561Sobrien	     really an offset from the abs section.  */
1964130561Sobrien	  r_index = N_ABS;
1965130561Sobrien	  r_extern = 0;
1966130561Sobrien	}
196733965Sjdp      else
1968130561Sobrien	{
1969130561Sobrien	  /* Fill in symbol.  */
1970130561Sobrien	  r_extern = 1;
1971130561Sobrien	  r_index = (*(g->sym_ptr_ptr))->KEEPIT;
1972130561Sobrien	}
197333965Sjdp    }
197433965Sjdp  else
197533965Sjdp    {
1976130561Sobrien      /* Just an ordinary section.  */
197733965Sjdp      r_extern = 0;
197833965Sjdp      r_index  = output_section->target_index;
197933965Sjdp    }
198033965Sjdp
1981130561Sobrien  /* Now the fun stuff.  */
198289857Sobrien  if (bfd_header_big_endian (abfd))
198389857Sobrien    {
198433965Sjdp      natptr->r_index[0] = r_index >> 16;
198533965Sjdp      natptr->r_index[1] = r_index >> 8;
198633965Sjdp      natptr->r_index[2] = r_index;
198789857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
198889857Sobrien			   | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
198989857Sobrien			   | (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
199089857Sobrien			   | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
199189857Sobrien			   | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
199289857Sobrien			   | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG));
199389857Sobrien    }
199489857Sobrien  else
199589857Sobrien    {
199689857Sobrien      natptr->r_index[2] = r_index >> 16;
199789857Sobrien      natptr->r_index[1] = r_index >> 8;
199889857Sobrien      natptr->r_index[0] = r_index;
199989857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
200089857Sobrien			   | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
200189857Sobrien			   | (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
200289857Sobrien			   | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
200389857Sobrien			   | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
200489857Sobrien			   | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE));
200589857Sobrien    }
200633965Sjdp}
200733965Sjdp
2008130561Sobrien/* Extended stuff.  */
200977298Sobrien/* Output extended relocation information to a file in target byte order.  */
201033965Sjdp
2011218822Sdimextern void NAME (aout, swap_ext_reloc_out)
2012218822Sdim  (bfd *, arelent *, struct reloc_ext_external *);
201333965Sjdp
201433965Sjdpvoid
2015218822SdimNAME (aout, swap_ext_reloc_out) (bfd *abfd,
2016218822Sdim				 arelent *g,
2017218822Sdim				 struct reloc_ext_external *natptr)
201833965Sjdp{
201933965Sjdp  int r_index;
202033965Sjdp  int r_extern;
202133965Sjdp  unsigned int r_type;
202289857Sobrien  bfd_vma r_addend;
202333965Sjdp  asymbol *sym = *(g->sym_ptr_ptr);
202433965Sjdp  asection *output_section = sym->section->output_section;
202533965Sjdp
202633965Sjdp  PUT_WORD (abfd, g->address, natptr->r_address);
202733965Sjdp
202833965Sjdp  r_type = (unsigned int) g->howto->type;
202933965Sjdp
203033965Sjdp  r_addend = g->addend;
203133965Sjdp  if ((sym->flags & BSF_SECTION_SYM) != 0)
203233965Sjdp    r_addend += (*(g->sym_ptr_ptr))->section->output_section->vma;
203333965Sjdp
203433965Sjdp  /* If this relocation is relative to a symbol then set the
203533965Sjdp     r_index to the symbols index, and the r_extern bit.
203633965Sjdp
203733965Sjdp     Absolute symbols can come in in two ways, either as an offset
203833965Sjdp     from the abs section, or as a symbol which has an abs value.
203933965Sjdp     check for that here.  */
204033965Sjdp  if (bfd_is_abs_section (bfd_get_section (sym)))
204133965Sjdp    {
204233965Sjdp      r_extern = 0;
204333965Sjdp      r_index = N_ABS;
204433965Sjdp    }
204533965Sjdp  else if ((sym->flags & BSF_SECTION_SYM) == 0)
204633965Sjdp    {
204733965Sjdp      if (bfd_is_und_section (bfd_get_section (sym))
204833965Sjdp	  || (sym->flags & BSF_GLOBAL) != 0)
204933965Sjdp	r_extern = 1;
205033965Sjdp      else
205133965Sjdp	r_extern = 0;
205233965Sjdp      r_index = (*(g->sym_ptr_ptr))->KEEPIT;
205333965Sjdp    }
205433965Sjdp  else
205533965Sjdp    {
2056130561Sobrien      /* Just an ordinary section.  */
205733965Sjdp      r_extern = 0;
205833965Sjdp      r_index = output_section->target_index;
205933965Sjdp    }
206033965Sjdp
2061130561Sobrien  /* Now the fun stuff.  */
206289857Sobrien  if (bfd_header_big_endian (abfd))
206389857Sobrien    {
206489857Sobrien      natptr->r_index[0] = r_index >> 16;
206589857Sobrien      natptr->r_index[1] = r_index >> 8;
206689857Sobrien      natptr->r_index[2] = r_index;
206789857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
206889857Sobrien			   | (r_type << RELOC_EXT_BITS_TYPE_SH_BIG));
206989857Sobrien    }
207089857Sobrien  else
207189857Sobrien    {
207289857Sobrien      natptr->r_index[2] = r_index >> 16;
207389857Sobrien      natptr->r_index[1] = r_index >> 8;
207489857Sobrien      natptr->r_index[0] = r_index;
207589857Sobrien      natptr->r_type[0] = ((r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
207689857Sobrien			   | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE));
207789857Sobrien    }
207833965Sjdp
207933965Sjdp  PUT_WORD (abfd, r_addend, natptr->r_addend);
208033965Sjdp}
208133965Sjdp
208233965Sjdp/* BFD deals internally with all things based from the section they're
208333965Sjdp   in. so, something in 10 bytes into a text section  with a base of
208433965Sjdp   50 would have a symbol (.text+10) and know .text vma was 50.
208533965Sjdp
208633965Sjdp   Aout keeps all it's symbols based from zero, so the symbol would
208733965Sjdp   contain 60. This macro subs the base of each section from the value
208889857Sobrien   to give the true offset from the section.  */
208933965Sjdp
209089857Sobrien#define MOVE_ADDRESS(ad)						\
209189857Sobrien  if (r_extern)								\
209289857Sobrien    {									\
209389857Sobrien      /* Undefined symbol.  */						\
209489857Sobrien      cache_ptr->sym_ptr_ptr = symbols + r_index;			\
209533965Sjdp      cache_ptr->addend = ad;						\
209633965Sjdp    }									\
209789857Sobrien   else									\
209889857Sobrien    {									\
209989857Sobrien      /* Defined, section relative.  Replace symbol with pointer to	\
210089857Sobrien	 symbol which points to section.  */				\
210189857Sobrien      switch (r_index)							\
210289857Sobrien	{								\
210389857Sobrien	case N_TEXT:							\
210489857Sobrien	case N_TEXT | N_EXT:						\
210589857Sobrien	  cache_ptr->sym_ptr_ptr = obj_textsec (abfd)->symbol_ptr_ptr;	\
210689857Sobrien	  cache_ptr->addend = ad - su->textsec->vma;			\
210789857Sobrien	  break;							\
210889857Sobrien	case N_DATA:							\
210989857Sobrien	case N_DATA | N_EXT:						\
211089857Sobrien	  cache_ptr->sym_ptr_ptr = obj_datasec (abfd)->symbol_ptr_ptr;	\
211189857Sobrien	  cache_ptr->addend = ad - su->datasec->vma;			\
211289857Sobrien	  break;							\
211389857Sobrien	case N_BSS:							\
211489857Sobrien	case N_BSS | N_EXT:						\
211589857Sobrien	  cache_ptr->sym_ptr_ptr = obj_bsssec (abfd)->symbol_ptr_ptr;	\
211689857Sobrien	  cache_ptr->addend = ad - su->bsssec->vma;			\
211789857Sobrien	  break;							\
211889857Sobrien	default:							\
211989857Sobrien	case N_ABS:							\
212089857Sobrien	case N_ABS | N_EXT:						\
212189857Sobrien	  cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;	\
212289857Sobrien	  cache_ptr->addend = ad;					\
212389857Sobrien	  break;							\
212489857Sobrien	}								\
212589857Sobrien    }
212633965Sjdp
212733965Sjdpvoid
2128218822SdimNAME (aout, swap_ext_reloc_in) (bfd *abfd,
2129218822Sdim				struct reloc_ext_external *bytes,
2130218822Sdim				arelent *cache_ptr,
2131218822Sdim				asymbol **symbols,
2132218822Sdim				bfd_size_type symcount)
213333965Sjdp{
213433965Sjdp  unsigned int r_index;
213533965Sjdp  int r_extern;
213633965Sjdp  unsigned int r_type;
213733965Sjdp  struct aoutdata *su = &(abfd->tdata.aout_data->a);
213833965Sjdp
213933965Sjdp  cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
214033965Sjdp
2141130561Sobrien  /* Now the fun stuff.  */
214289857Sobrien  if (bfd_header_big_endian (abfd))
214389857Sobrien    {
2144107492Sobrien      r_index = (((unsigned int) bytes->r_index[0] << 16)
2145107492Sobrien		 | ((unsigned int) bytes->r_index[1] << 8)
214689857Sobrien		 | bytes->r_index[2]);
214789857Sobrien      r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
214889857Sobrien      r_type = ((bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
214989857Sobrien		>> RELOC_EXT_BITS_TYPE_SH_BIG);
215089857Sobrien    }
215189857Sobrien  else
215289857Sobrien    {
2153107492Sobrien      r_index =  (((unsigned int) bytes->r_index[2] << 16)
2154107492Sobrien		  | ((unsigned int) bytes->r_index[1] << 8)
215589857Sobrien		  | bytes->r_index[0]);
215689857Sobrien      r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
215789857Sobrien      r_type = ((bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
215889857Sobrien		>> RELOC_EXT_BITS_TYPE_SH_LITTLE);
215989857Sobrien    }
216033965Sjdp
216133965Sjdp  cache_ptr->howto =  howto_table_ext + r_type;
216233965Sjdp
216333965Sjdp  /* Base relative relocs are always against the symbol table,
216433965Sjdp     regardless of the setting of r_extern.  r_extern just reflects
216533965Sjdp     whether the symbol the reloc is against is local or global.  */
2166107492Sobrien  if (r_type == (unsigned int) RELOC_BASE10
2167107492Sobrien      || r_type == (unsigned int) RELOC_BASE13
2168107492Sobrien      || r_type == (unsigned int) RELOC_BASE22)
216933965Sjdp    r_extern = 1;
217033965Sjdp
217133965Sjdp  if (r_extern && r_index > symcount)
217233965Sjdp    {
217333965Sjdp      /* We could arrange to return an error, but it might be useful
217433965Sjdp         to see the file even if it is bad.  */
217533965Sjdp      r_extern = 0;
217633965Sjdp      r_index = N_ABS;
217733965Sjdp    }
217833965Sjdp
217989857Sobrien  MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
218033965Sjdp}
218133965Sjdp
218233965Sjdpvoid
2183218822SdimNAME (aout, swap_std_reloc_in) (bfd *abfd,
2184218822Sdim				struct reloc_std_external *bytes,
2185218822Sdim				arelent *cache_ptr,
2186218822Sdim				asymbol **symbols,
2187218822Sdim				bfd_size_type symcount)
218833965Sjdp{
218933965Sjdp  unsigned int r_index;
219033965Sjdp  int r_extern;
219133965Sjdp  unsigned int r_length;
219233965Sjdp  int r_pcrel;
219333965Sjdp  int r_baserel, r_jmptable, r_relative;
219433965Sjdp  struct aoutdata  *su = &(abfd->tdata.aout_data->a);
219533965Sjdp  unsigned int howto_idx;
219633965Sjdp
219789857Sobrien  cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
219833965Sjdp
2199130561Sobrien  /* Now the fun stuff.  */
220089857Sobrien  if (bfd_header_big_endian (abfd))
220189857Sobrien    {
2202107492Sobrien      r_index = (((unsigned int) bytes->r_index[0] << 16)
2203107492Sobrien		 | ((unsigned int) bytes->r_index[1] << 8)
220489857Sobrien		 | bytes->r_index[2]);
220589857Sobrien      r_extern  = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
220689857Sobrien      r_pcrel   = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
220789857Sobrien      r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
220889857Sobrien      r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
220989857Sobrien      r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
221089857Sobrien      r_length  = ((bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
221189857Sobrien		   >> RELOC_STD_BITS_LENGTH_SH_BIG);
221289857Sobrien    }
221389857Sobrien  else
221489857Sobrien    {
2215107492Sobrien      r_index = (((unsigned int) bytes->r_index[2] << 16)
2216107492Sobrien		 | ((unsigned int) bytes->r_index[1] << 8)
221789857Sobrien		 | bytes->r_index[0]);
221889857Sobrien      r_extern  = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
221989857Sobrien      r_pcrel   = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
222089857Sobrien      r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
222189857Sobrien      r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
222289857Sobrien      r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
222389857Sobrien      r_length  = ((bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
222489857Sobrien		   >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
222589857Sobrien    }
222633965Sjdp
222789857Sobrien  howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
222889857Sobrien	       + 16 * r_jmptable + 32 * r_relative);
222933965Sjdp  BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
223033965Sjdp  cache_ptr->howto =  howto_table_std + howto_idx;
223133965Sjdp  BFD_ASSERT (cache_ptr->howto->type != (unsigned int) -1);
223233965Sjdp
223333965Sjdp  /* Base relative relocs are always against the symbol table,
223433965Sjdp     regardless of the setting of r_extern.  r_extern just reflects
223533965Sjdp     whether the symbol the reloc is against is local or global.  */
223633965Sjdp  if (r_baserel)
223733965Sjdp    r_extern = 1;
223833965Sjdp
223933965Sjdp  if (r_extern && r_index > symcount)
224033965Sjdp    {
224133965Sjdp      /* We could arrange to return an error, but it might be useful
224233965Sjdp         to see the file even if it is bad.  */
224333965Sjdp      r_extern = 0;
224433965Sjdp      r_index = N_ABS;
224533965Sjdp    }
224633965Sjdp
224789857Sobrien  MOVE_ADDRESS (0);
224833965Sjdp}
224933965Sjdp
225033965Sjdp/* Read and swap the relocs for a section.  */
225133965Sjdp
2252130561Sobrienbfd_boolean
2253218822SdimNAME (aout, slurp_reloc_table) (bfd *abfd, sec_ptr asect, asymbol **symbols)
225433965Sjdp{
225589857Sobrien  bfd_size_type count;
225633965Sjdp  bfd_size_type reloc_size;
2257218822Sdim  void * relocs;
225833965Sjdp  arelent *reloc_cache;
225933965Sjdp  size_t each_size;
226033965Sjdp  unsigned int counter = 0;
226133965Sjdp  arelent *cache_ptr;
226289857Sobrien  bfd_size_type amt;
226333965Sjdp
226433965Sjdp  if (asect->relocation)
2265130561Sobrien    return TRUE;
226633965Sjdp
226733965Sjdp  if (asect->flags & SEC_CONSTRUCTOR)
2268130561Sobrien    return TRUE;
226933965Sjdp
227033965Sjdp  if (asect == obj_datasec (abfd))
227189857Sobrien    reloc_size = exec_hdr (abfd)->a_drsize;
227233965Sjdp  else if (asect == obj_textsec (abfd))
227389857Sobrien    reloc_size = exec_hdr (abfd)->a_trsize;
227433965Sjdp  else if (asect == obj_bsssec (abfd))
227533965Sjdp    reloc_size = 0;
227633965Sjdp  else
227733965Sjdp    {
227833965Sjdp      bfd_set_error (bfd_error_invalid_operation);
2279130561Sobrien      return FALSE;
228033965Sjdp    }
228133965Sjdp
228233965Sjdp  if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
2283130561Sobrien    return FALSE;
228433965Sjdp
228533965Sjdp  each_size = obj_reloc_entry_size (abfd);
228633965Sjdp
228733965Sjdp  count = reloc_size / each_size;
228833965Sjdp
228989857Sobrien  amt = count * sizeof (arelent);
2290218822Sdim  reloc_cache = bfd_zmalloc (amt);
229133965Sjdp  if (reloc_cache == NULL && count != 0)
2292130561Sobrien    return FALSE;
229333965Sjdp
229489857Sobrien  relocs = bfd_malloc (reloc_size);
229533965Sjdp  if (relocs == NULL && reloc_size != 0)
229633965Sjdp    {
229733965Sjdp      free (reloc_cache);
2298130561Sobrien      return FALSE;
229933965Sjdp    }
230033965Sjdp
230189857Sobrien  if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
230233965Sjdp    {
230333965Sjdp      free (relocs);
230433965Sjdp      free (reloc_cache);
2305130561Sobrien      return FALSE;
230633965Sjdp    }
230733965Sjdp
230833965Sjdp  cache_ptr = reloc_cache;
230933965Sjdp  if (each_size == RELOC_EXT_SIZE)
231033965Sjdp    {
231189857Sobrien      struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
231233965Sjdp
231333965Sjdp      for (; counter < count; counter++, rptr++, cache_ptr++)
231477298Sobrien	MY_swap_ext_reloc_in (abfd, rptr, cache_ptr, symbols,
231589857Sobrien			      (bfd_size_type) bfd_get_symcount (abfd));
231633965Sjdp    }
231733965Sjdp  else
231833965Sjdp    {
231989857Sobrien      struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
232033965Sjdp
232133965Sjdp      for (; counter < count; counter++, rptr++, cache_ptr++)
232233965Sjdp	MY_swap_std_reloc_in (abfd, rptr, cache_ptr, symbols,
232389857Sobrien			      (bfd_size_type) bfd_get_symcount (abfd));
232433965Sjdp    }
232533965Sjdp
232633965Sjdp  free (relocs);
232733965Sjdp
232833965Sjdp  asect->relocation = reloc_cache;
232933965Sjdp  asect->reloc_count = cache_ptr - reloc_cache;
233033965Sjdp
2331130561Sobrien  return TRUE;
233233965Sjdp}
233333965Sjdp
233433965Sjdp/* Write out a relocation section into an object file.  */
233533965Sjdp
2336130561Sobrienbfd_boolean
2337218822SdimNAME (aout, squirt_out_relocs) (bfd *abfd, asection *section)
233833965Sjdp{
233933965Sjdp  arelent **generic;
234033965Sjdp  unsigned char *native, *natptr;
234133965Sjdp  size_t each_size;
234233965Sjdp
234333965Sjdp  unsigned int count = section->reloc_count;
234489857Sobrien  bfd_size_type natsize;
234533965Sjdp
234633965Sjdp  if (count == 0 || section->orelocation == NULL)
2347130561Sobrien    return TRUE;
234833965Sjdp
234933965Sjdp  each_size = obj_reloc_entry_size (abfd);
235089857Sobrien  natsize = (bfd_size_type) each_size * count;
2351218822Sdim  native = bfd_zalloc (abfd, natsize);
235233965Sjdp  if (!native)
2353130561Sobrien    return FALSE;
235433965Sjdp
235533965Sjdp  generic = section->orelocation;
235633965Sjdp
235733965Sjdp  if (each_size == RELOC_EXT_SIZE)
235833965Sjdp    {
235933965Sjdp      for (natptr = native;
236033965Sjdp	   count != 0;
236133965Sjdp	   --count, natptr += each_size, ++generic)
236277298Sobrien	MY_swap_ext_reloc_out (abfd, *generic,
236377298Sobrien			       (struct reloc_ext_external *) natptr);
236433965Sjdp    }
236533965Sjdp  else
236633965Sjdp    {
236733965Sjdp      for (natptr = native;
236833965Sjdp	   count != 0;
236933965Sjdp	   --count, natptr += each_size, ++generic)
237089857Sobrien	MY_swap_std_reloc_out (abfd, *generic,
237189857Sobrien			       (struct reloc_std_external *) natptr);
237233965Sjdp    }
237333965Sjdp
2374218822Sdim  if (bfd_bwrite ((void *) native, natsize, abfd) != natsize)
237589857Sobrien    {
237689857Sobrien      bfd_release (abfd, native);
2377130561Sobrien      return FALSE;
237889857Sobrien    }
237933965Sjdp  bfd_release (abfd, native);
238033965Sjdp
2381130561Sobrien  return TRUE;
238233965Sjdp}
238333965Sjdp
2384130561Sobrien/* This is stupid.  This function should be a boolean predicate.  */
2385130561Sobrien
238633965Sjdplong
2387218822SdimNAME (aout, canonicalize_reloc) (bfd *abfd,
2388218822Sdim				 sec_ptr section,
2389218822Sdim				 arelent **relptr,
2390218822Sdim				 asymbol **symbols)
239133965Sjdp{
239233965Sjdp  arelent *tblptr = section->relocation;
239333965Sjdp  unsigned int count;
239433965Sjdp
239533965Sjdp  if (section == obj_bsssec (abfd))
239633965Sjdp    {
239733965Sjdp      *relptr = NULL;
239833965Sjdp      return 0;
239933965Sjdp    }
240033965Sjdp
2401218822Sdim  if (!(tblptr || NAME (aout, slurp_reloc_table) (abfd, section, symbols)))
240233965Sjdp    return -1;
240333965Sjdp
240489857Sobrien  if (section->flags & SEC_CONSTRUCTOR)
240589857Sobrien    {
240689857Sobrien      arelent_chain *chain = section->constructor_chain;
240789857Sobrien      for (count = 0; count < section->reloc_count; count ++)
240889857Sobrien	{
240989857Sobrien	  *relptr ++ = &chain->relent;
241089857Sobrien	  chain = chain->next;
241189857Sobrien	}
241233965Sjdp    }
241389857Sobrien  else
241489857Sobrien    {
241589857Sobrien      tblptr = section->relocation;
241633965Sjdp
241789857Sobrien      for (count = 0; count++ < section->reloc_count; )
241889857Sobrien	{
241989857Sobrien	  *relptr++ = tblptr++;
242089857Sobrien	}
242189857Sobrien    }
242233965Sjdp  *relptr = 0;
242333965Sjdp
242433965Sjdp  return section->reloc_count;
242533965Sjdp}
242633965Sjdp
242733965Sjdplong
2428218822SdimNAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect)
242933965Sjdp{
243089857Sobrien  if (bfd_get_format (abfd) != bfd_object)
243189857Sobrien    {
243289857Sobrien      bfd_set_error (bfd_error_invalid_operation);
243389857Sobrien      return -1;
243489857Sobrien    }
2435130561Sobrien
243689857Sobrien  if (asect->flags & SEC_CONSTRUCTOR)
2437218822Sdim    return sizeof (arelent *) * (asect->reloc_count + 1);
243833965Sjdp
243933965Sjdp  if (asect == obj_datasec (abfd))
2440218822Sdim    return sizeof (arelent *)
2441218822Sdim      * ((exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd))
2442218822Sdim	 + 1);
244333965Sjdp
244433965Sjdp  if (asect == obj_textsec (abfd))
2445218822Sdim    return sizeof (arelent *)
2446218822Sdim      * ((exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd))
2447218822Sdim	 + 1);
244833965Sjdp
244933965Sjdp  if (asect == obj_bsssec (abfd))
245033965Sjdp    return sizeof (arelent *);
245133965Sjdp
245233965Sjdp  if (asect == obj_bsssec (abfd))
245333965Sjdp    return 0;
245433965Sjdp
245533965Sjdp  bfd_set_error (bfd_error_invalid_operation);
245633965Sjdp  return -1;
245733965Sjdp}
245833965Sjdp
245933965Sjdplong
2460218822SdimNAME (aout, get_symtab_upper_bound) (bfd *abfd)
246133965Sjdp{
2462218822Sdim  if (!NAME (aout, slurp_symbol_table) (abfd))
246333965Sjdp    return -1;
246433965Sjdp
246533965Sjdp  return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
246633965Sjdp}
246733965Sjdp
246889857Sobrienalent *
2469218822SdimNAME (aout, get_lineno) (bfd *ignore_abfd ATTRIBUTE_UNUSED,
2470218822Sdim			 asymbol *ignore_symbol ATTRIBUTE_UNUSED)
247133965Sjdp{
2472218822Sdim  return NULL;
247333965Sjdp}
247433965Sjdp
247533965Sjdpvoid
2476218822SdimNAME (aout, get_symbol_info) (bfd *ignore_abfd ATTRIBUTE_UNUSED,
2477218822Sdim			      asymbol *symbol,
2478218822Sdim			      symbol_info *ret)
247933965Sjdp{
248033965Sjdp  bfd_symbol_info (symbol, ret);
248133965Sjdp
248233965Sjdp  if (ret->type == '?')
248333965Sjdp    {
248489857Sobrien      int type_code = aout_symbol (symbol)->type & 0xff;
248533965Sjdp      const char *stab_name = bfd_get_stab_name (type_code);
248633965Sjdp      static char buf[10];
248733965Sjdp
248833965Sjdp      if (stab_name == NULL)
248933965Sjdp	{
249077298Sobrien	  sprintf (buf, "(%d)", type_code);
249133965Sjdp	  stab_name = buf;
249233965Sjdp	}
249333965Sjdp      ret->type = '-';
249433965Sjdp      ret->stab_type = type_code;
249589857Sobrien      ret->stab_other = (unsigned) (aout_symbol (symbol)->other & 0xff);
249689857Sobrien      ret->stab_desc = (unsigned) (aout_symbol (symbol)->desc & 0xffff);
249733965Sjdp      ret->stab_name = stab_name;
249833965Sjdp    }
249933965Sjdp}
250033965Sjdp
250133965Sjdpvoid
2502218822SdimNAME (aout, print_symbol) (bfd *abfd,
2503218822Sdim			   void * afile,
2504218822Sdim			   asymbol *symbol,
2505218822Sdim			   bfd_print_symbol_type how)
250633965Sjdp{
250733965Sjdp  FILE *file = (FILE *)afile;
250833965Sjdp
250989857Sobrien  switch (how)
251033965Sjdp    {
251189857Sobrien    case bfd_print_symbol_name:
251289857Sobrien      if (symbol->name)
251389857Sobrien	fprintf (file,"%s", symbol->name);
251489857Sobrien      break;
251589857Sobrien    case bfd_print_symbol_more:
251689857Sobrien      fprintf (file,"%4x %2x %2x",
251789857Sobrien	       (unsigned) (aout_symbol (symbol)->desc & 0xffff),
251889857Sobrien	       (unsigned) (aout_symbol (symbol)->other & 0xff),
251989857Sobrien	       (unsigned) (aout_symbol (symbol)->type));
252089857Sobrien      break;
252189857Sobrien    case bfd_print_symbol_all:
252289857Sobrien      {
252389857Sobrien	const char *section_name = symbol->section->name;
252433965Sjdp
2525218822Sdim	bfd_print_symbol_vandf (abfd, (void *)file, symbol);
252633965Sjdp
252789857Sobrien	fprintf (file," %-5s %04x %02x %02x",
252889857Sobrien		 section_name,
252989857Sobrien		 (unsigned) (aout_symbol (symbol)->desc & 0xffff),
253089857Sobrien		 (unsigned) (aout_symbol (symbol)->other & 0xff),
253189857Sobrien		 (unsigned) (aout_symbol (symbol)->type & 0xff));
253289857Sobrien	if (symbol->name)
253389857Sobrien	  fprintf (file," %s", symbol->name);
253489857Sobrien      }
253589857Sobrien      break;
253633965Sjdp    }
253733965Sjdp}
253833965Sjdp
253933965Sjdp/* If we don't have to allocate more than 1MB to hold the generic
254033965Sjdp   symbols, we use the generic minisymbol methord: it's faster, since
254133965Sjdp   it only translates the symbols once, not multiple times.  */
254233965Sjdp#define MINISYM_THRESHOLD (1000000 / sizeof (asymbol))
254333965Sjdp
254433965Sjdp/* Read minisymbols.  For minisymbols, we use the unmodified a.out
254533965Sjdp   symbols.  The minisymbol_to_symbol function translates these into
254633965Sjdp   BFD asymbol structures.  */
254733965Sjdp
254833965Sjdplong
2549218822SdimNAME (aout, read_minisymbols) (bfd *abfd,
2550218822Sdim			       bfd_boolean dynamic,
2551218822Sdim			       void * *minisymsp,
2552218822Sdim			       unsigned int *sizep)
255333965Sjdp{
255433965Sjdp  if (dynamic)
2555218822Sdim    /* We could handle the dynamic symbols here as well, but it's
2556218822Sdim       easier to hand them off.  */
2557218822Sdim    return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
255833965Sjdp
255933965Sjdp  if (! aout_get_external_symbols (abfd))
256033965Sjdp    return -1;
256133965Sjdp
256233965Sjdp  if (obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
256333965Sjdp    return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
256433965Sjdp
2565218822Sdim  *minisymsp = (void *) obj_aout_external_syms (abfd);
256633965Sjdp
256733965Sjdp  /* By passing the external symbols back from this routine, we are
256833965Sjdp     giving up control over the memory block.  Clear
256933965Sjdp     obj_aout_external_syms, so that we do not try to free it
257033965Sjdp     ourselves.  */
257133965Sjdp  obj_aout_external_syms (abfd) = NULL;
257233965Sjdp
257333965Sjdp  *sizep = EXTERNAL_NLIST_SIZE;
257433965Sjdp  return obj_aout_external_sym_count (abfd);
257533965Sjdp}
257633965Sjdp
257733965Sjdp/* Convert a minisymbol to a BFD asymbol.  A minisymbol is just an
257833965Sjdp   unmodified a.out symbol.  The SYM argument is a structure returned
257933965Sjdp   by bfd_make_empty_symbol, which we fill in here.  */
258033965Sjdp
258133965Sjdpasymbol *
2582218822SdimNAME (aout, minisymbol_to_symbol) (bfd *abfd,
2583218822Sdim				   bfd_boolean dynamic,
2584218822Sdim				   const void * minisym,
2585218822Sdim				   asymbol *sym)
258633965Sjdp{
258733965Sjdp  if (dynamic
258833965Sjdp      || obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
258933965Sjdp    return _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym);
259033965Sjdp
259133965Sjdp  memset (sym, 0, sizeof (aout_symbol_type));
259233965Sjdp
259333965Sjdp  /* We call translate_symbol_table to translate a single symbol.  */
2594218822Sdim  if (! (NAME (aout, translate_symbol_table)
259533965Sjdp	 (abfd,
259633965Sjdp	  (aout_symbol_type *) sym,
259733965Sjdp	  (struct external_nlist *) minisym,
259833965Sjdp	  (bfd_size_type) 1,
259933965Sjdp	  obj_aout_external_strings (abfd),
260033965Sjdp	  obj_aout_external_string_size (abfd),
2601130561Sobrien	  FALSE)))
260233965Sjdp    return NULL;
260333965Sjdp
260433965Sjdp  return sym;
260533965Sjdp}
260633965Sjdp
2607130561Sobrien/* Provided a BFD, a section and an offset into the section, calculate
2608130561Sobrien   and return the name of the source file and the line nearest to the
2609130561Sobrien   wanted location.  */
261033965Sjdp
2611130561Sobrienbfd_boolean
2612218822SdimNAME (aout, find_nearest_line) (bfd *abfd,
2613218822Sdim				asection *section,
2614218822Sdim				asymbol **symbols,
2615218822Sdim				bfd_vma offset,
2616218822Sdim				const char **filename_ptr,
2617218822Sdim				const char **functionname_ptr,
2618218822Sdim				unsigned int *line_ptr)
261933965Sjdp{
2620130561Sobrien  /* Run down the file looking for the filename, function and linenumber.  */
262133965Sjdp  asymbol **p;
262289857Sobrien  const char *directory_name = NULL;
262389857Sobrien  const char *main_file_name = NULL;
262489857Sobrien  const char *current_file_name = NULL;
2625218822Sdim  const char *line_file_name = NULL;      /* Value of current_file_name at line number.  */
262689857Sobrien  const char *line_directory_name = NULL; /* Value of directory_name at line number.  */
262733965Sjdp  bfd_vma low_line_vma = 0;
262833965Sjdp  bfd_vma low_func_vma = 0;
262933965Sjdp  asymbol *func = 0;
263089857Sobrien  bfd_size_type filelen, funclen;
263133965Sjdp  char *buf;
263233965Sjdp
263333965Sjdp  *filename_ptr = abfd->filename;
263433965Sjdp  *functionname_ptr = 0;
263533965Sjdp  *line_ptr = 0;
2636130561Sobrien
2637218822Sdim  if (symbols != NULL)
263889857Sobrien    {
263989857Sobrien      for (p = symbols; *p; p++)
264089857Sobrien	{
264189857Sobrien	  aout_symbol_type  *q = (aout_symbol_type *) (*p);
264289857Sobrien	next:
264389857Sobrien	  switch (q->type)
264489857Sobrien	    {
264589857Sobrien	    case N_TEXT:
264689857Sobrien	      /* If this looks like a file name symbol, and it comes after
264789857Sobrien		 the line number we have found so far, but before the
264889857Sobrien		 offset, then we have probably not found the right line
264989857Sobrien		 number.  */
265089857Sobrien	      if (q->symbol.value <= offset
265189857Sobrien		  && ((q->symbol.value > low_line_vma
265289857Sobrien		       && (line_file_name != NULL
265389857Sobrien			   || *line_ptr != 0))
265489857Sobrien		      || (q->symbol.value > low_func_vma
265589857Sobrien			  && func != NULL)))
265689857Sobrien		{
265789857Sobrien		  const char *symname;
265833965Sjdp
265989857Sobrien		  symname = q->symbol.name;
266089857Sobrien		  if (strcmp (symname + strlen (symname) - 2, ".o") == 0)
266189857Sobrien		    {
266289857Sobrien		      if (q->symbol.value > low_line_vma)
266389857Sobrien			{
266489857Sobrien			  *line_ptr = 0;
266589857Sobrien			  line_file_name = NULL;
266689857Sobrien			}
266789857Sobrien		      if (q->symbol.value > low_func_vma)
266889857Sobrien			func = NULL;
266989857Sobrien		    }
267089857Sobrien		}
267189857Sobrien	      break;
267233965Sjdp
267389857Sobrien	    case N_SO:
267489857Sobrien	      /* If this symbol is less than the offset, but greater than
267589857Sobrien		 the line number we have found so far, then we have not
267689857Sobrien		 found the right line number.  */
267789857Sobrien	      if (q->symbol.value <= offset)
267889857Sobrien		{
267989857Sobrien		  if (q->symbol.value > low_line_vma)
268089857Sobrien		    {
268189857Sobrien		      *line_ptr = 0;
268289857Sobrien		      line_file_name = NULL;
268389857Sobrien		    }
268489857Sobrien		  if (q->symbol.value > low_func_vma)
268589857Sobrien		    func = NULL;
268689857Sobrien		}
268733965Sjdp
268889857Sobrien	      main_file_name = current_file_name = q->symbol.name;
268989857Sobrien	      /* Look ahead to next symbol to check if that too is an N_SO.  */
269089857Sobrien	      p++;
269189857Sobrien	      if (*p == NULL)
2692218822Sdim		goto done;
269389857Sobrien	      q = (aout_symbol_type *) (*p);
269489857Sobrien	      if (q->type != (int)N_SO)
269589857Sobrien		goto next;
269633965Sjdp
269789857Sobrien	      /* Found a second N_SO  First is directory; second is filename.  */
269889857Sobrien	      directory_name = current_file_name;
269989857Sobrien	      main_file_name = current_file_name = q->symbol.name;
270089857Sobrien	      if (obj_textsec (abfd) != section)
270189857Sobrien		goto done;
270289857Sobrien	      break;
270389857Sobrien	    case N_SOL:
270489857Sobrien	      current_file_name = q->symbol.name;
270589857Sobrien	      break;
270633965Sjdp
270789857Sobrien	    case N_SLINE:
270833965Sjdp
270989857Sobrien	    case N_DSLINE:
271089857Sobrien	    case N_BSLINE:
271189857Sobrien	      /* We'll keep this if it resolves nearer than the one we have
271289857Sobrien		 already.  */
271389857Sobrien	      if (q->symbol.value >= low_line_vma
271489857Sobrien		  && q->symbol.value <= offset)
271589857Sobrien		{
271689857Sobrien		  *line_ptr = q->desc;
271789857Sobrien		  low_line_vma = q->symbol.value;
271889857Sobrien		  line_file_name = current_file_name;
271989857Sobrien		  line_directory_name = directory_name;
272089857Sobrien		}
272189857Sobrien	      break;
272289857Sobrien	    case N_FUN:
272389857Sobrien	      {
2724130561Sobrien		/* We'll keep this if it is nearer than the one we have already.  */
272589857Sobrien		if (q->symbol.value >= low_func_vma &&
2726130561Sobrien		    q->symbol.value <= offset)
2727130561Sobrien		  {
2728130561Sobrien		    low_func_vma = q->symbol.value;
2729130561Sobrien		    func = (asymbol *)q;
2730130561Sobrien		  }
273189857Sobrien		else if (q->symbol.value > offset)
273289857Sobrien		  goto done;
273389857Sobrien	      }
273489857Sobrien	      break;
273589857Sobrien	    }
273633965Sjdp	}
273733965Sjdp    }
273833965Sjdp
273933965Sjdp done:
274033965Sjdp  if (*line_ptr != 0)
274160484Sobrien    {
274260484Sobrien      main_file_name = line_file_name;
274360484Sobrien      directory_name = line_directory_name;
274460484Sobrien    }
274533965Sjdp
274633965Sjdp  if (main_file_name == NULL
274761843Sobrien      || IS_ABSOLUTE_PATH (main_file_name)
274833965Sjdp      || directory_name == NULL)
274933965Sjdp    filelen = 0;
275033965Sjdp  else
275133965Sjdp    filelen = strlen (directory_name) + strlen (main_file_name);
2752130561Sobrien
275333965Sjdp  if (func == NULL)
275433965Sjdp    funclen = 0;
275533965Sjdp  else
275633965Sjdp    funclen = strlen (bfd_asymbol_name (func));
275733965Sjdp
275833965Sjdp  if (adata (abfd).line_buf != NULL)
275933965Sjdp    free (adata (abfd).line_buf);
2760130561Sobrien
276133965Sjdp  if (filelen + funclen == 0)
276233965Sjdp    adata (abfd).line_buf = buf = NULL;
276333965Sjdp  else
276433965Sjdp    {
2765218822Sdim      buf = bfd_malloc (filelen + funclen + 3);
276633965Sjdp      adata (abfd).line_buf = buf;
276733965Sjdp      if (buf == NULL)
2768130561Sobrien	return FALSE;
276933965Sjdp    }
277033965Sjdp
277133965Sjdp  if (main_file_name != NULL)
277233965Sjdp    {
277361843Sobrien      if (IS_ABSOLUTE_PATH (main_file_name) || directory_name == NULL)
277433965Sjdp	*filename_ptr = main_file_name;
277533965Sjdp      else
277633965Sjdp	{
277733965Sjdp	  sprintf (buf, "%s%s", directory_name, main_file_name);
277833965Sjdp	  *filename_ptr = buf;
277933965Sjdp	  buf += filelen + 1;
278033965Sjdp	}
278133965Sjdp    }
278233965Sjdp
278333965Sjdp  if (func)
278433965Sjdp    {
278533965Sjdp      const char *function = func->name;
278689857Sobrien      char *colon;
278733965Sjdp
278833965Sjdp      /* The caller expects a symbol name.  We actually have a
278933965Sjdp	 function name, without the leading underscore.  Put the
279033965Sjdp	 underscore back in, so that the caller gets a symbol name.  */
279133965Sjdp      if (bfd_get_symbol_leading_char (abfd) == '\0')
279233965Sjdp	strcpy (buf, function);
279333965Sjdp      else
279433965Sjdp	{
279533965Sjdp	  buf[0] = bfd_get_symbol_leading_char (abfd);
279633965Sjdp	  strcpy (buf + 1, function);
279733965Sjdp	}
2798130561Sobrien      /* Have to remove : stuff.  */
279989857Sobrien      colon = strchr (buf, ':');
280089857Sobrien      if (colon != NULL)
280189857Sobrien	*colon = '\0';
280233965Sjdp      *functionname_ptr = buf;
280333965Sjdp    }
280433965Sjdp
2805130561Sobrien  return TRUE;
280633965Sjdp}
280733965Sjdp
280833965Sjdpint
2809218822SdimNAME (aout, sizeof_headers) (bfd *abfd,
2810218822Sdim			     struct bfd_link_info *info ATTRIBUTE_UNUSED)
281133965Sjdp{
281289857Sobrien  return adata (abfd).exec_bytes_size;
281333965Sjdp}
281433965Sjdp
281533965Sjdp/* Free all information we have cached for this BFD.  We can always
281633965Sjdp   read it again later if we need it.  */
281733965Sjdp
2818130561Sobrienbfd_boolean
2819218822SdimNAME (aout, bfd_free_cached_info) (bfd *abfd)
282033965Sjdp{
282133965Sjdp  asection *o;
282233965Sjdp
282378828Sobrien  if (bfd_get_format (abfd) != bfd_object
282478828Sobrien      || abfd->tdata.aout_data == NULL)
2825130561Sobrien    return TRUE;
282633965Sjdp
282733965Sjdp#define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; }
282833965Sjdp  BFCI_FREE (obj_aout_symbols (abfd));
282933965Sjdp#ifdef USE_MMAP
283033965Sjdp  obj_aout_external_syms (abfd) = 0;
283133965Sjdp  bfd_free_window (&obj_aout_sym_window (abfd));
283233965Sjdp  bfd_free_window (&obj_aout_string_window (abfd));
283333965Sjdp  obj_aout_external_strings (abfd) = 0;
283433965Sjdp#else
283533965Sjdp  BFCI_FREE (obj_aout_external_syms (abfd));
283633965Sjdp  BFCI_FREE (obj_aout_external_strings (abfd));
283733965Sjdp#endif
2838218822Sdim  for (o = abfd->sections; o != NULL; o = o->next)
283933965Sjdp    BFCI_FREE (o->relocation);
284033965Sjdp#undef BFCI_FREE
284133965Sjdp
2842130561Sobrien  return TRUE;
284333965Sjdp}
284433965Sjdp
284533965Sjdp/* a.out link code.  */
284633965Sjdp
284733965Sjdp/* Routine to create an entry in an a.out link hash table.  */
284833965Sjdp
284933965Sjdpstruct bfd_hash_entry *
2850218822SdimNAME (aout, link_hash_newfunc) (struct bfd_hash_entry *entry,
2851218822Sdim				struct bfd_hash_table *table,
2852218822Sdim				const char *string)
285333965Sjdp{
285433965Sjdp  struct aout_link_hash_entry *ret = (struct aout_link_hash_entry *) entry;
285533965Sjdp
285633965Sjdp  /* Allocate the structure if it has not already been allocated by a
285733965Sjdp     subclass.  */
2858218822Sdim  if (ret == NULL)
2859218822Sdim    ret = bfd_hash_allocate (table, sizeof (* ret));
2860218822Sdim  if (ret == NULL)
2861218822Sdim    return NULL;
286233965Sjdp
286333965Sjdp  /* Call the allocation method of the superclass.  */
286433965Sjdp  ret = ((struct aout_link_hash_entry *)
286533965Sjdp	 _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
286633965Sjdp				 table, string));
286733965Sjdp  if (ret)
286833965Sjdp    {
286933965Sjdp      /* Set local fields.  */
2870130561Sobrien      ret->written = FALSE;
287133965Sjdp      ret->indx = -1;
287233965Sjdp    }
287333965Sjdp
287433965Sjdp  return (struct bfd_hash_entry *) ret;
287533965Sjdp}
287633965Sjdp
287733965Sjdp/* Initialize an a.out link hash table.  */
287833965Sjdp
2879130561Sobrienbfd_boolean
2880218822SdimNAME (aout, link_hash_table_init) (struct aout_link_hash_table *table,
2881218822Sdim				   bfd *abfd,
2882218822Sdim				   struct bfd_hash_entry *(*newfunc)
2883218822Sdim				   (struct bfd_hash_entry *, struct bfd_hash_table *,
2884218822Sdim				    const char *),
2885218822Sdim				   unsigned int entsize)
288633965Sjdp{
2887218822Sdim  return _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
288833965Sjdp}
288933965Sjdp
289033965Sjdp/* Create an a.out link hash table.  */
289133965Sjdp
289233965Sjdpstruct bfd_link_hash_table *
2893218822SdimNAME (aout, link_hash_table_create) (bfd *abfd)
289433965Sjdp{
289533965Sjdp  struct aout_link_hash_table *ret;
2896218822Sdim  bfd_size_type amt = sizeof (* ret);
289733965Sjdp
2898218822Sdim  ret = bfd_malloc (amt);
289933965Sjdp  if (ret == NULL)
2900218822Sdim    return NULL;
2901130561Sobrien
2902218822Sdim  if (!NAME (aout, link_hash_table_init) (ret, abfd,
2903218822Sdim					  NAME (aout, link_hash_newfunc),
2904218822Sdim					  sizeof (struct aout_link_hash_entry)))
290533965Sjdp    {
290633965Sjdp      free (ret);
2907218822Sdim      return NULL;
290833965Sjdp    }
290933965Sjdp  return &ret->root;
291033965Sjdp}
291133965Sjdp
2912218822Sdim/* Add all symbols from an object file to the hash table.  */
291333965Sjdp
2914218822Sdimstatic bfd_boolean
2915218822Sdimaout_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
291633965Sjdp{
2917218822Sdim  bfd_boolean (*add_one_symbol)
2918218822Sdim    (struct bfd_link_info *, bfd *, const char *, flagword, asection *,
2919218822Sdim	     bfd_vma, const char *, bfd_boolean, bfd_boolean,
2920218822Sdim	     struct bfd_link_hash_entry **);
2921218822Sdim  struct external_nlist *syms;
2922218822Sdim  bfd_size_type sym_count;
2923218822Sdim  char *strings;
2924218822Sdim  bfd_boolean copy;
2925218822Sdim  struct aout_link_hash_entry **sym_hash;
2926218822Sdim  struct external_nlist *p;
2927218822Sdim  struct external_nlist *pend;
2928218822Sdim  bfd_size_type amt;
292933965Sjdp
2930218822Sdim  syms = obj_aout_external_syms (abfd);
2931218822Sdim  sym_count = obj_aout_external_sym_count (abfd);
2932218822Sdim  strings = obj_aout_external_strings (abfd);
2933218822Sdim  if (info->keep_memory)
2934218822Sdim    copy = FALSE;
2935218822Sdim  else
2936218822Sdim    copy = TRUE;
293733965Sjdp
2938218822Sdim  if (aout_backend_info (abfd)->add_dynamic_symbols != NULL)
293933965Sjdp    {
2940218822Sdim      if (! ((*aout_backend_info (abfd)->add_dynamic_symbols)
2941218822Sdim	     (abfd, info, &syms, &sym_count, &strings)))
2942130561Sobrien	return FALSE;
294333965Sjdp    }
294433965Sjdp
2945218822Sdim  /* We keep a list of the linker hash table entries that correspond
2946218822Sdim     to particular symbols.  We could just look them up in the hash
2947218822Sdim     table, but keeping the list is more efficient.  Perhaps this
2948218822Sdim     should be conditional on info->keep_memory.  */
2949218822Sdim  amt = sym_count * sizeof (struct aout_link_hash_entry *);
2950218822Sdim  sym_hash = bfd_alloc (abfd, amt);
2951218822Sdim  if (sym_hash == NULL && sym_count != 0)
2952130561Sobrien    return FALSE;
2953218822Sdim  obj_aout_sym_hashes (abfd) = sym_hash;
295433965Sjdp
2955218822Sdim  add_one_symbol = aout_backend_info (abfd)->add_one_symbol;
2956218822Sdim  if (add_one_symbol == NULL)
2957218822Sdim    add_one_symbol = _bfd_generic_link_add_one_symbol;
295833965Sjdp
2959218822Sdim  p = syms;
2960218822Sdim  pend = p + sym_count;
2961218822Sdim  for (; p < pend; p++, sym_hash++)
296233965Sjdp    {
2963218822Sdim      int type;
2964218822Sdim      const char *name;
2965218822Sdim      bfd_vma value;
2966218822Sdim      asection *section;
2967218822Sdim      flagword flags;
2968218822Sdim      const char *string;
2969218822Sdim
2970218822Sdim      *sym_hash = NULL;
2971218822Sdim
2972218822Sdim      type = H_GET_8 (abfd, p->e_type);
2973218822Sdim
2974218822Sdim      /* Ignore debugging symbols.  */
2975218822Sdim      if ((type & N_STAB) != 0)
2976218822Sdim	continue;
2977218822Sdim
2978218822Sdim      name = strings + GET_WORD (abfd, p->e_strx);
2979218822Sdim      value = GET_WORD (abfd, p->e_value);
2980218822Sdim      flags = BSF_GLOBAL;
2981218822Sdim      string = NULL;
2982218822Sdim      switch (type)
2983218822Sdim	{
2984218822Sdim	default:
2985218822Sdim	  abort ();
2986218822Sdim
2987218822Sdim	case N_UNDF:
2988218822Sdim	case N_ABS:
2989218822Sdim	case N_TEXT:
2990218822Sdim	case N_DATA:
2991218822Sdim	case N_BSS:
2992218822Sdim	case N_FN_SEQ:
2993218822Sdim	case N_COMM:
2994218822Sdim	case N_SETV:
2995218822Sdim	case N_FN:
2996218822Sdim	  /* Ignore symbols that are not externally visible.  */
2997218822Sdim	  continue;
2998218822Sdim	case N_INDR:
2999218822Sdim	  /* Ignore local indirect symbol.  */
3000218822Sdim	  ++p;
3001218822Sdim	  ++sym_hash;
3002218822Sdim	  continue;
3003218822Sdim
3004218822Sdim	case N_UNDF | N_EXT:
3005218822Sdim	  if (value == 0)
3006218822Sdim	    {
3007218822Sdim	      section = bfd_und_section_ptr;
3008218822Sdim	      flags = 0;
3009218822Sdim	    }
3010218822Sdim	  else
3011218822Sdim	    section = bfd_com_section_ptr;
3012218822Sdim	  break;
3013218822Sdim	case N_ABS | N_EXT:
3014218822Sdim	  section = bfd_abs_section_ptr;
3015218822Sdim	  break;
3016218822Sdim	case N_TEXT | N_EXT:
3017218822Sdim	  section = obj_textsec (abfd);
3018218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3019218822Sdim	  break;
3020218822Sdim	case N_DATA | N_EXT:
3021218822Sdim	case N_SETV | N_EXT:
3022218822Sdim	  /* Treat N_SETV symbols as N_DATA symbol; see comment in
3023218822Sdim	     translate_from_native_sym_flags.  */
3024218822Sdim	  section = obj_datasec (abfd);
3025218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3026218822Sdim	  break;
3027218822Sdim	case N_BSS | N_EXT:
3028218822Sdim	  section = obj_bsssec (abfd);
3029218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3030218822Sdim	  break;
3031218822Sdim	case N_INDR | N_EXT:
3032218822Sdim	  /* An indirect symbol.  The next symbol is the symbol
3033218822Sdim	     which this one really is.  */
3034218822Sdim	  BFD_ASSERT (p + 1 < pend);
3035218822Sdim	  ++p;
3036218822Sdim	  string = strings + GET_WORD (abfd, p->e_strx);
3037218822Sdim	  section = bfd_ind_section_ptr;
3038218822Sdim	  flags |= BSF_INDIRECT;
3039218822Sdim	  break;
3040218822Sdim	case N_COMM | N_EXT:
3041218822Sdim	  section = bfd_com_section_ptr;
3042218822Sdim	  break;
3043218822Sdim	case N_SETA: case N_SETA | N_EXT:
3044218822Sdim	  section = bfd_abs_section_ptr;
3045218822Sdim	  flags |= BSF_CONSTRUCTOR;
3046218822Sdim	  break;
3047218822Sdim	case N_SETT: case N_SETT | N_EXT:
3048218822Sdim	  section = obj_textsec (abfd);
3049218822Sdim	  flags |= BSF_CONSTRUCTOR;
3050218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3051218822Sdim	  break;
3052218822Sdim	case N_SETD: case N_SETD | N_EXT:
3053218822Sdim	  section = obj_datasec (abfd);
3054218822Sdim	  flags |= BSF_CONSTRUCTOR;
3055218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3056218822Sdim	  break;
3057218822Sdim	case N_SETB: case N_SETB | N_EXT:
3058218822Sdim	  section = obj_bsssec (abfd);
3059218822Sdim	  flags |= BSF_CONSTRUCTOR;
3060218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3061218822Sdim	  break;
3062218822Sdim	case N_WARNING:
3063218822Sdim	  /* A warning symbol.  The next symbol is the one to warn
3064218822Sdim	     about.  If there is no next symbol, just look away.  */
3065218822Sdim	  if (p + 1 >= pend)
3066218822Sdim	    return TRUE;
3067218822Sdim	  ++p;
3068218822Sdim	  string = name;
3069218822Sdim	  name = strings + GET_WORD (abfd, p->e_strx);
3070218822Sdim	  section = bfd_und_section_ptr;
3071218822Sdim	  flags |= BSF_WARNING;
3072218822Sdim	  break;
3073218822Sdim	case N_WEAKU:
3074218822Sdim	  section = bfd_und_section_ptr;
3075218822Sdim	  flags = BSF_WEAK;
3076218822Sdim	  break;
3077218822Sdim	case N_WEAKA:
3078218822Sdim	  section = bfd_abs_section_ptr;
3079218822Sdim	  flags = BSF_WEAK;
3080218822Sdim	  break;
3081218822Sdim	case N_WEAKT:
3082218822Sdim	  section = obj_textsec (abfd);
3083218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3084218822Sdim	  flags = BSF_WEAK;
3085218822Sdim	  break;
3086218822Sdim	case N_WEAKD:
3087218822Sdim	  section = obj_datasec (abfd);
3088218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3089218822Sdim	  flags = BSF_WEAK;
3090218822Sdim	  break;
3091218822Sdim	case N_WEAKB:
3092218822Sdim	  section = obj_bsssec (abfd);
3093218822Sdim	  value -= bfd_get_section_vma (abfd, section);
3094218822Sdim	  flags = BSF_WEAK;
3095218822Sdim	  break;
3096218822Sdim	}
3097218822Sdim
3098218822Sdim      if (! ((*add_one_symbol)
3099218822Sdim	     (info, abfd, name, flags, section, value, string, copy, FALSE,
3100218822Sdim	      (struct bfd_link_hash_entry **) sym_hash)))
3101130561Sobrien	return FALSE;
310233965Sjdp
3103218822Sdim      /* Restrict the maximum alignment of a common symbol based on
3104218822Sdim	 the architecture, since a.out has no way to represent
3105218822Sdim	 alignment requirements of a section in a .o file.  FIXME:
3106218822Sdim	 This isn't quite right: it should use the architecture of the
3107218822Sdim	 output file, not the input files.  */
3108218822Sdim      if ((*sym_hash)->root.type == bfd_link_hash_common
3109218822Sdim	  && ((*sym_hash)->root.u.c.p->alignment_power >
3110218822Sdim	      bfd_get_arch_info (abfd)->section_align_power))
3111218822Sdim	(*sym_hash)->root.u.c.p->alignment_power =
3112218822Sdim	  bfd_get_arch_info (abfd)->section_align_power;
3113218822Sdim
3114218822Sdim      /* If this is a set symbol, and we are not building sets, then
3115218822Sdim	 it is possible for the hash entry to not have been set.  In
3116218822Sdim	 such a case, treat the symbol as not globally defined.  */
3117218822Sdim      if ((*sym_hash)->root.type == bfd_link_hash_new)
3118218822Sdim	{
3119218822Sdim	  BFD_ASSERT ((flags & BSF_CONSTRUCTOR) != 0);
3120218822Sdim	  *sym_hash = NULL;
3121218822Sdim	}
3122218822Sdim
3123218822Sdim      if (type == (N_INDR | N_EXT) || type == N_WARNING)
3124218822Sdim	++sym_hash;
312533965Sjdp    }
312633965Sjdp
3127130561Sobrien  return TRUE;
312833965Sjdp}
312933965Sjdp
313033965Sjdp/* Free up the internal symbols read from an a.out file.  */
313133965Sjdp
3132130561Sobrienstatic bfd_boolean
3133218822Sdimaout_link_free_symbols (bfd *abfd)
313433965Sjdp{
3135218822Sdim  if (obj_aout_external_syms (abfd) != NULL)
313633965Sjdp    {
313733965Sjdp#ifdef USE_MMAP
313833965Sjdp      bfd_free_window (&obj_aout_sym_window (abfd));
313933965Sjdp#else
3140218822Sdim      free ((void *) obj_aout_external_syms (abfd));
314133965Sjdp#endif
3142218822Sdim      obj_aout_external_syms (abfd) = NULL;
314333965Sjdp    }
3144218822Sdim  if (obj_aout_external_strings (abfd) != NULL)
314533965Sjdp    {
314633965Sjdp#ifdef USE_MMAP
314733965Sjdp      bfd_free_window (&obj_aout_string_window (abfd));
314833965Sjdp#else
3149218822Sdim      free ((void *) obj_aout_external_strings (abfd));
315033965Sjdp#endif
3151218822Sdim      obj_aout_external_strings (abfd) = NULL;
315233965Sjdp    }
3153130561Sobrien  return TRUE;
315433965Sjdp}
315533965Sjdp
3156218822Sdim/* Add symbols from an a.out object file.  */
3157218822Sdim
3158218822Sdimstatic bfd_boolean
3159218822Sdimaout_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
3160218822Sdim{
3161218822Sdim  if (! aout_get_external_symbols (abfd))
3162218822Sdim    return FALSE;
3163218822Sdim  if (! aout_link_add_symbols (abfd, info))
3164218822Sdim    return FALSE;
3165218822Sdim  if (! info->keep_memory)
3166218822Sdim    {
3167218822Sdim      if (! aout_link_free_symbols (abfd))
3168218822Sdim	return FALSE;
3169218822Sdim    }
3170218822Sdim  return TRUE;
3171218822Sdim}
3172218822Sdim
317333965Sjdp/* Look through the internal symbols to see if this object file should
317433965Sjdp   be included in the link.  We should include this object file if it
317533965Sjdp   defines any symbols which are currently undefined.  If this object
317633965Sjdp   file defines a common symbol, then we may adjust the size of the
317733965Sjdp   known symbol but we do not include the object file in the link
317833965Sjdp   (unless there is some other reason to include it).  */
317933965Sjdp
3180130561Sobrienstatic bfd_boolean
3181218822Sdimaout_link_check_ar_symbols (bfd *abfd,
3182218822Sdim			    struct bfd_link_info *info,
3183218822Sdim			    bfd_boolean *pneeded)
318433965Sjdp{
3185218822Sdim  struct external_nlist *p;
318633965Sjdp  struct external_nlist *pend;
318733965Sjdp  char *strings;
318833965Sjdp
3189130561Sobrien  *pneeded = FALSE;
319033965Sjdp
319133965Sjdp  /* Look through all the symbols.  */
319233965Sjdp  p = obj_aout_external_syms (abfd);
319333965Sjdp  pend = p + obj_aout_external_sym_count (abfd);
319433965Sjdp  strings = obj_aout_external_strings (abfd);
319533965Sjdp  for (; p < pend; p++)
319633965Sjdp    {
319789857Sobrien      int type = H_GET_8 (abfd, p->e_type);
319833965Sjdp      const char *name;
319933965Sjdp      struct bfd_link_hash_entry *h;
320033965Sjdp
320133965Sjdp      /* Ignore symbols that are not externally visible.  This is an
320233965Sjdp	 optimization only, as we check the type more thoroughly
320333965Sjdp	 below.  */
320433965Sjdp      if (((type & N_EXT) == 0
320533965Sjdp	   || (type & N_STAB) != 0
320633965Sjdp	   || type == N_FN)
320733965Sjdp	  && type != N_WEAKA
320833965Sjdp	  && type != N_WEAKT
320933965Sjdp	  && type != N_WEAKD
321033965Sjdp	  && type != N_WEAKB)
321133965Sjdp	{
321233965Sjdp	  if (type == N_WARNING
321333965Sjdp	      || type == N_INDR)
321433965Sjdp	    ++p;
321533965Sjdp	  continue;
321633965Sjdp	}
321733965Sjdp
321833965Sjdp      name = strings + GET_WORD (abfd, p->e_strx);
3219130561Sobrien      h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
322033965Sjdp
322133965Sjdp      /* We are only interested in symbols that are currently
322233965Sjdp	 undefined or common.  */
3223218822Sdim      if (h == NULL
322433965Sjdp	  || (h->type != bfd_link_hash_undefined
322533965Sjdp	      && h->type != bfd_link_hash_common))
322633965Sjdp	{
322733965Sjdp	  if (type == (N_INDR | N_EXT))
322833965Sjdp	    ++p;
322933965Sjdp	  continue;
323033965Sjdp	}
323133965Sjdp
323233965Sjdp      if (type == (N_TEXT | N_EXT)
323333965Sjdp	  || type == (N_DATA | N_EXT)
323433965Sjdp	  || type == (N_BSS | N_EXT)
323533965Sjdp	  || type == (N_ABS | N_EXT)
323633965Sjdp	  || type == (N_INDR | N_EXT))
323733965Sjdp	{
323833965Sjdp	  /* This object file defines this symbol.  We must link it
323933965Sjdp	     in.  This is true regardless of whether the current
3240130561Sobrien	     definition of the symbol is undefined or common.
3241130561Sobrien
3242130561Sobrien             If the current definition is common, we have a case in
3243130561Sobrien	     which we have already seen an object file including:
324433965Sjdp	         int a;
3245130561Sobrien	     and this object file from the archive includes:
324633965Sjdp	         int a = 5;
3247130561Sobrien	     In such a case, whether to include this object is target
3248130561Sobrien             dependant for backward compatibility.
324933965Sjdp
325033965Sjdp	     FIXME: The SunOS 4.1.3 linker will pull in the archive
325133965Sjdp	     element if the symbol is defined in the .data section,
325233965Sjdp	     but not if it is defined in the .text section.  That
3253130561Sobrien	     seems a bit crazy to me, and it has not been implemented
3254130561Sobrien	     yet.  However, it might be correct.  */
3255130561Sobrien	  if (h->type == bfd_link_hash_common)
3256130561Sobrien	    {
3257130561Sobrien	      int skip = 0;
3258130561Sobrien
3259130561Sobrien	      switch (info->common_skip_ar_aymbols)
3260130561Sobrien		{
3261130561Sobrien		case bfd_link_common_skip_text:
3262130561Sobrien		  skip = (type == (N_TEXT | N_EXT));
3263130561Sobrien		  break;
3264130561Sobrien		case bfd_link_common_skip_data:
3265130561Sobrien		  skip = (type == (N_DATA | N_EXT));
3266130561Sobrien		  break;
3267130561Sobrien		default:
3268130561Sobrien		case bfd_link_common_skip_all:
3269130561Sobrien		  skip = 1;
3270130561Sobrien		  break;
3271130561Sobrien		}
3272130561Sobrien
3273130561Sobrien	      if (skip)
3274130561Sobrien		continue;
3275130561Sobrien	    }
3276130561Sobrien
327733965Sjdp	  if (! (*info->callbacks->add_archive_element) (info, abfd, name))
3278130561Sobrien	    return FALSE;
3279130561Sobrien	  *pneeded = TRUE;
3280130561Sobrien	  return TRUE;
328133965Sjdp	}
328233965Sjdp
328333965Sjdp      if (type == (N_UNDF | N_EXT))
328433965Sjdp	{
328533965Sjdp	  bfd_vma value;
328633965Sjdp
328733965Sjdp	  value = GET_WORD (abfd, p->e_value);
328833965Sjdp	  if (value != 0)
328933965Sjdp	    {
329033965Sjdp	      /* This symbol is common in the object from the archive
329133965Sjdp		 file.  */
329233965Sjdp	      if (h->type == bfd_link_hash_undefined)
329333965Sjdp		{
329433965Sjdp		  bfd *symbfd;
329533965Sjdp		  unsigned int power;
329633965Sjdp
329733965Sjdp		  symbfd = h->u.undef.abfd;
3298218822Sdim		  if (symbfd == NULL)
329933965Sjdp		    {
330033965Sjdp		      /* This symbol was created as undefined from
330133965Sjdp			 outside BFD.  We assume that we should link
330233965Sjdp			 in the object file.  This is done for the -u
330333965Sjdp			 option in the linker.  */
330433965Sjdp		      if (! (*info->callbacks->add_archive_element) (info,
330533965Sjdp								     abfd,
330633965Sjdp								     name))
3307130561Sobrien			return FALSE;
3308130561Sobrien		      *pneeded = TRUE;
3309130561Sobrien		      return TRUE;
331033965Sjdp		    }
331133965Sjdp		  /* Turn the current link symbol into a common
331233965Sjdp		     symbol.  It is already on the undefs list.  */
331333965Sjdp		  h->type = bfd_link_hash_common;
3314218822Sdim		  h->u.c.p = bfd_hash_allocate (&info->hash->table,
3315218822Sdim						sizeof (struct bfd_link_hash_common_entry));
331633965Sjdp		  if (h->u.c.p == NULL)
3317130561Sobrien		    return FALSE;
331833965Sjdp
331933965Sjdp		  h->u.c.size = value;
332033965Sjdp
332133965Sjdp		  /* FIXME: This isn't quite right.  The maximum
332233965Sjdp		     alignment of a common symbol should be set by the
332333965Sjdp		     architecture of the output file, not of the input
332433965Sjdp		     file.  */
332533965Sjdp		  power = bfd_log2 (value);
332633965Sjdp		  if (power > bfd_get_arch_info (abfd)->section_align_power)
332733965Sjdp		    power = bfd_get_arch_info (abfd)->section_align_power;
332833965Sjdp		  h->u.c.p->alignment_power = power;
332933965Sjdp
333033965Sjdp		  h->u.c.p->section = bfd_make_section_old_way (symbfd,
333133965Sjdp								"COMMON");
333233965Sjdp		}
333333965Sjdp	      else
333433965Sjdp		{
333533965Sjdp		  /* Adjust the size of the common symbol if
333633965Sjdp		     necessary.  */
333733965Sjdp		  if (value > h->u.c.size)
333833965Sjdp		    h->u.c.size = value;
333933965Sjdp		}
334033965Sjdp	    }
334133965Sjdp	}
334233965Sjdp
334333965Sjdp      if (type == N_WEAKA
334433965Sjdp	  || type == N_WEAKT
334533965Sjdp	  || type == N_WEAKD
334633965Sjdp	  || type == N_WEAKB)
334733965Sjdp	{
334833965Sjdp	  /* This symbol is weak but defined.  We must pull it in if
334933965Sjdp	     the current link symbol is undefined, but we don't want
335033965Sjdp	     it if the current link symbol is common.  */
335133965Sjdp	  if (h->type == bfd_link_hash_undefined)
335233965Sjdp	    {
335333965Sjdp	      if (! (*info->callbacks->add_archive_element) (info, abfd, name))
3354130561Sobrien		return FALSE;
3355130561Sobrien	      *pneeded = TRUE;
3356130561Sobrien	      return TRUE;
335733965Sjdp	    }
335833965Sjdp	}
335933965Sjdp    }
336033965Sjdp
336133965Sjdp  /* We do not need this object file.  */
3362130561Sobrien  return TRUE;
336333965Sjdp}
3364218822Sdim/* Check a single archive element to see if we need to include it in
3365218822Sdim   the link.  *PNEEDED is set according to whether this element is
3366218822Sdim   needed in the link or not.  This is called from
3367218822Sdim   _bfd_generic_link_add_archive_symbols.  */
336833965Sjdp
3369130561Sobrienstatic bfd_boolean
3370218822Sdimaout_link_check_archive_element (bfd *abfd,
3371218822Sdim				 struct bfd_link_info *info,
3372218822Sdim				 bfd_boolean *pneeded)
337333965Sjdp{
3374218822Sdim  if (! aout_get_external_symbols (abfd))
3375218822Sdim    return FALSE;
337633965Sjdp
3377218822Sdim  if (! aout_link_check_ar_symbols (abfd, info, pneeded))
3378218822Sdim    return FALSE;
337933965Sjdp
3380218822Sdim  if (*pneeded)
338133965Sjdp    {
3382218822Sdim      if (! aout_link_add_symbols (abfd, info))
3383130561Sobrien	return FALSE;
338433965Sjdp    }
338533965Sjdp
3386218822Sdim  if (! info->keep_memory || ! *pneeded)
338733965Sjdp    {
3388218822Sdim      if (! aout_link_free_symbols (abfd))
3389130561Sobrien	return FALSE;
3390218822Sdim    }
339133965Sjdp
3392218822Sdim  return TRUE;
3393218822Sdim}
339433965Sjdp
3395218822Sdim/* Given an a.out BFD, add symbols to the global hash table as
3396218822Sdim   appropriate.  */
339733965Sjdp
3398218822Sdimbfd_boolean
3399218822SdimNAME (aout, link_add_symbols) (bfd *abfd, struct bfd_link_info *info)
3400218822Sdim{
3401218822Sdim  switch (bfd_get_format (abfd))
3402218822Sdim    {
3403218822Sdim    case bfd_object:
3404218822Sdim      return aout_link_add_object_symbols (abfd, info);
3405218822Sdim    case bfd_archive:
3406218822Sdim      return _bfd_generic_link_add_archive_symbols
3407218822Sdim	(abfd, info, aout_link_check_archive_element);
3408218822Sdim    default:
3409218822Sdim      bfd_set_error (bfd_error_wrong_format);
3410218822Sdim      return FALSE;
341133965Sjdp    }
341233965Sjdp}
341333965Sjdp
341433965Sjdp/* A hash table used for header files with N_BINCL entries.  */
341533965Sjdp
341633965Sjdpstruct aout_link_includes_table
341733965Sjdp{
341833965Sjdp  struct bfd_hash_table root;
341933965Sjdp};
342033965Sjdp
342133965Sjdp/* A linked list of totals that we have found for a particular header
342233965Sjdp   file.  */
342333965Sjdp
342433965Sjdpstruct aout_link_includes_totals
342533965Sjdp{
342633965Sjdp  struct aout_link_includes_totals *next;
342733965Sjdp  bfd_vma total;
342833965Sjdp};
342933965Sjdp
343033965Sjdp/* An entry in the header file hash table.  */
343133965Sjdp
343233965Sjdpstruct aout_link_includes_entry
343333965Sjdp{
343433965Sjdp  struct bfd_hash_entry root;
343533965Sjdp  /* List of totals we have found for this file.  */
343633965Sjdp  struct aout_link_includes_totals *totals;
343733965Sjdp};
343833965Sjdp
343933965Sjdp/* Look up an entry in an the header file hash table.  */
344033965Sjdp
344189857Sobrien#define aout_link_includes_lookup(table, string, create, copy)		\
344289857Sobrien  ((struct aout_link_includes_entry *)					\
344333965Sjdp   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
344433965Sjdp
344533965Sjdp/* During the final link step we need to pass around a bunch of
344633965Sjdp   information, so we do it in an instance of this structure.  */
344733965Sjdp
344833965Sjdpstruct aout_final_link_info
344933965Sjdp{
345033965Sjdp  /* General link information.  */
345133965Sjdp  struct bfd_link_info *info;
345233965Sjdp  /* Output bfd.  */
345333965Sjdp  bfd *output_bfd;
345433965Sjdp  /* Reloc file positions.  */
345533965Sjdp  file_ptr treloff, dreloff;
345633965Sjdp  /* File position of symbols.  */
345733965Sjdp  file_ptr symoff;
345833965Sjdp  /* String table.  */
345933965Sjdp  struct bfd_strtab_hash *strtab;
346033965Sjdp  /* Header file hash table.  */
346133965Sjdp  struct aout_link_includes_table includes;
346233965Sjdp  /* A buffer large enough to hold the contents of any section.  */
346333965Sjdp  bfd_byte *contents;
346433965Sjdp  /* A buffer large enough to hold the relocs of any section.  */
3465218822Sdim  void * relocs;
346633965Sjdp  /* A buffer large enough to hold the symbol map of any input BFD.  */
346733965Sjdp  int *symbol_map;
346833965Sjdp  /* A buffer large enough to hold output symbols of any input BFD.  */
346933965Sjdp  struct external_nlist *output_syms;
347033965Sjdp};
347133965Sjdp
347233965Sjdp/* The function to create a new entry in the header file hash table.  */
347333965Sjdp
347433965Sjdpstatic struct bfd_hash_entry *
3475218822Sdimaout_link_includes_newfunc (struct bfd_hash_entry *entry,
3476218822Sdim			    struct bfd_hash_table *table,
3477218822Sdim			    const char *string)
347833965Sjdp{
347933965Sjdp  struct aout_link_includes_entry *ret =
348033965Sjdp    (struct aout_link_includes_entry *) entry;
348133965Sjdp
348233965Sjdp  /* Allocate the structure if it has not already been allocated by a
348333965Sjdp     subclass.  */
3484218822Sdim  if (ret == NULL)
3485218822Sdim    ret = bfd_hash_allocate (table, sizeof (* ret));
3486218822Sdim  if (ret == NULL)
3487218822Sdim    return NULL;
348833965Sjdp
348933965Sjdp  /* Call the allocation method of the superclass.  */
349033965Sjdp  ret = ((struct aout_link_includes_entry *)
349133965Sjdp	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
349233965Sjdp  if (ret)
349333965Sjdp    {
349433965Sjdp      /* Set local fields.  */
349533965Sjdp      ret->totals = NULL;
349633965Sjdp    }
349733965Sjdp
349833965Sjdp  return (struct bfd_hash_entry *) ret;
349933965Sjdp}
350033965Sjdp
350133965Sjdp/* Write out a symbol that was not associated with an a.out input
350233965Sjdp   object.  */
350333965Sjdp
3504130561Sobrienstatic bfd_boolean
3505218822Sdimaout_link_write_other_symbol (struct aout_link_hash_entry *h, void * data)
350633965Sjdp{
350733965Sjdp  struct aout_final_link_info *finfo = (struct aout_final_link_info *) data;
350833965Sjdp  bfd *output_bfd;
350933965Sjdp  int type;
351033965Sjdp  bfd_vma val;
351133965Sjdp  struct external_nlist outsym;
351233965Sjdp  bfd_size_type indx;
351389857Sobrien  bfd_size_type amt;
351433965Sjdp
351594536Sobrien  if (h->root.type == bfd_link_hash_warning)
351694536Sobrien    {
351794536Sobrien      h = (struct aout_link_hash_entry *) h->root.u.i.link;
351894536Sobrien      if (h->root.type == bfd_link_hash_new)
3519130561Sobrien	return TRUE;
352094536Sobrien    }
352194536Sobrien
352233965Sjdp  output_bfd = finfo->output_bfd;
352333965Sjdp
352433965Sjdp  if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL)
352533965Sjdp    {
352633965Sjdp      if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol)
352733965Sjdp	     (output_bfd, finfo->info, h)))
352833965Sjdp	{
352933965Sjdp	  /* FIXME: No way to handle errors.  */
353033965Sjdp	  abort ();
353133965Sjdp	}
353233965Sjdp    }
353333965Sjdp
353433965Sjdp  if (h->written)
3535130561Sobrien    return TRUE;
353633965Sjdp
3537130561Sobrien  h->written = TRUE;
353833965Sjdp
353933965Sjdp  /* An indx of -2 means the symbol must be written.  */
354033965Sjdp  if (h->indx != -2
354133965Sjdp      && (finfo->info->strip == strip_all
354233965Sjdp	  || (finfo->info->strip == strip_some
354333965Sjdp	      && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
3544130561Sobrien				  FALSE, FALSE) == NULL)))
3545130561Sobrien    return TRUE;
354633965Sjdp
354733965Sjdp  switch (h->root.type)
354833965Sjdp    {
354933965Sjdp    default:
355094536Sobrien    case bfd_link_hash_warning:
355133965Sjdp      abort ();
355233965Sjdp      /* Avoid variable not initialized warnings.  */
3553130561Sobrien      return TRUE;
355433965Sjdp    case bfd_link_hash_new:
355533965Sjdp      /* This can happen for set symbols when sets are not being
355633965Sjdp         built.  */
3557130561Sobrien      return TRUE;
355833965Sjdp    case bfd_link_hash_undefined:
355933965Sjdp      type = N_UNDF | N_EXT;
356033965Sjdp      val = 0;
356133965Sjdp      break;
356233965Sjdp    case bfd_link_hash_defined:
356333965Sjdp    case bfd_link_hash_defweak:
356433965Sjdp      {
356533965Sjdp	asection *sec;
356633965Sjdp
356733965Sjdp	sec = h->root.u.def.section->output_section;
356833965Sjdp	BFD_ASSERT (bfd_is_abs_section (sec)
356933965Sjdp		    || sec->owner == output_bfd);
357033965Sjdp	if (sec == obj_textsec (output_bfd))
357133965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT;
357233965Sjdp	else if (sec == obj_datasec (output_bfd))
357333965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD;
357433965Sjdp	else if (sec == obj_bsssec (output_bfd))
357533965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB;
357633965Sjdp	else
357733965Sjdp	  type = h->root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA;
357833965Sjdp	type |= N_EXT;
357933965Sjdp	val = (h->root.u.def.value
358033965Sjdp	       + sec->vma
358133965Sjdp	       + h->root.u.def.section->output_offset);
358233965Sjdp      }
358333965Sjdp      break;
358433965Sjdp    case bfd_link_hash_common:
358533965Sjdp      type = N_UNDF | N_EXT;
358633965Sjdp      val = h->root.u.c.size;
358733965Sjdp      break;
358833965Sjdp    case bfd_link_hash_undefweak:
358933965Sjdp      type = N_WEAKU;
359033965Sjdp      val = 0;
359133965Sjdp    case bfd_link_hash_indirect:
359294536Sobrien      /* We ignore these symbols, since the indirected symbol is
359394536Sobrien	 already in the hash table.  */
3594130561Sobrien      return TRUE;
359533965Sjdp    }
359633965Sjdp
359789857Sobrien  H_PUT_8 (output_bfd, type, outsym.e_type);
359889857Sobrien  H_PUT_8 (output_bfd, 0, outsym.e_other);
359989857Sobrien  H_PUT_16 (output_bfd, 0, outsym.e_desc);
360033965Sjdp  indx = add_to_stringtab (output_bfd, finfo->strtab, h->root.root.string,
3601130561Sobrien			   FALSE);
360289857Sobrien  if (indx == - (bfd_size_type) 1)
3603218822Sdim    /* FIXME: No way to handle errors.  */
3604218822Sdim    abort ();
3605218822Sdim
360633965Sjdp  PUT_WORD (output_bfd, indx, outsym.e_strx);
360733965Sjdp  PUT_WORD (output_bfd, val, outsym.e_value);
360833965Sjdp
360989857Sobrien  amt = EXTERNAL_NLIST_SIZE;
361033965Sjdp  if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0
3611218822Sdim      || bfd_bwrite ((void *) &outsym, amt, output_bfd) != amt)
3612218822Sdim    /* FIXME: No way to handle errors.  */
3613218822Sdim    abort ();
361433965Sjdp
361533965Sjdp  finfo->symoff += EXTERNAL_NLIST_SIZE;
361633965Sjdp  h->indx = obj_aout_external_sym_count (output_bfd);
361733965Sjdp  ++obj_aout_external_sym_count (output_bfd);
361833965Sjdp
3619130561Sobrien  return TRUE;
362033965Sjdp}
362133965Sjdp
3622218822Sdim/* Handle a link order which is supposed to generate a reloc.  */
362333965Sjdp
3624130561Sobrienstatic bfd_boolean
3625218822Sdimaout_link_reloc_link_order (struct aout_final_link_info *finfo,
3626218822Sdim			    asection *o,
3627218822Sdim			    struct bfd_link_order *p)
362833965Sjdp{
3629218822Sdim  struct bfd_link_order_reloc *pr;
3630218822Sdim  int r_index;
3631218822Sdim  int r_extern;
3632218822Sdim  reloc_howto_type *howto;
3633218822Sdim  file_ptr *reloff_ptr = NULL;
3634218822Sdim  struct reloc_std_external srel;
3635218822Sdim  struct reloc_ext_external erel;
3636218822Sdim  void * rel_ptr;
3637218822Sdim  bfd_size_type amt;
363833965Sjdp
3639218822Sdim  pr = p->u.reloc.p;
364033965Sjdp
3641218822Sdim  if (p->type == bfd_section_reloc_link_order)
3642218822Sdim    {
3643218822Sdim      r_extern = 0;
3644218822Sdim      if (bfd_is_abs_section (pr->u.section))
3645218822Sdim	r_index = N_ABS | N_EXT;
3646218822Sdim      else
3647218822Sdim	{
3648218822Sdim	  BFD_ASSERT (pr->u.section->owner == finfo->output_bfd);
3649218822Sdim	  r_index = pr->u.section->target_index;
3650218822Sdim	}
3651218822Sdim    }
365233965Sjdp  else
365333965Sjdp    {
3654218822Sdim      struct aout_link_hash_entry *h;
3655218822Sdim
3656218822Sdim      BFD_ASSERT (p->type == bfd_symbol_reloc_link_order);
3657218822Sdim      r_extern = 1;
3658218822Sdim      h = ((struct aout_link_hash_entry *)
3659218822Sdim	   bfd_wrapped_link_hash_lookup (finfo->output_bfd, finfo->info,
3660218822Sdim					 pr->u.name, FALSE, FALSE, TRUE));
3661218822Sdim      if (h != NULL
3662218822Sdim	  && h->indx >= 0)
3663218822Sdim	r_index = h->indx;
3664218822Sdim      else if (h != NULL)
366533965Sjdp	{
3666218822Sdim	  /* We decided to strip this symbol, but it turns out that we
3667218822Sdim	     can't.  Note that we lose the other and desc information
3668218822Sdim	     here.  I don't think that will ever matter for a global
3669218822Sdim	     symbol.  */
3670218822Sdim	  h->indx = -2;
3671218822Sdim	  h->written = FALSE;
3672218822Sdim	  if (! aout_link_write_other_symbol (h, (void *) finfo))
3673130561Sobrien	    return FALSE;
3674218822Sdim	  r_index = h->indx;
367533965Sjdp	}
3676218822Sdim      else
3677218822Sdim	{
3678218822Sdim	  if (! ((*finfo->info->callbacks->unattached_reloc)
3679218822Sdim		 (finfo->info, pr->u.name, NULL, NULL, (bfd_vma) 0)))
3680218822Sdim	    return FALSE;
3681218822Sdim	  r_index = 0;
3682218822Sdim	}
368333965Sjdp    }
368433965Sjdp
3685218822Sdim  howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc);
3686218822Sdim  if (howto == 0)
368733965Sjdp    {
3688218822Sdim      bfd_set_error (bfd_error_bad_value);
3689218822Sdim      return FALSE;
369033965Sjdp    }
3691218822Sdim
3692218822Sdim  if (o == obj_textsec (finfo->output_bfd))
3693218822Sdim    reloff_ptr = &finfo->treloff;
3694218822Sdim  else if (o == obj_datasec (finfo->output_bfd))
3695218822Sdim    reloff_ptr = &finfo->dreloff;
369633965Sjdp  else
3697218822Sdim    abort ();
3698218822Sdim
3699218822Sdim  if (obj_reloc_entry_size (finfo->output_bfd) == RELOC_STD_SIZE)
370033965Sjdp    {
3701218822Sdim#ifdef MY_put_reloc
3702218822Sdim      MY_put_reloc (finfo->output_bfd, r_extern, r_index, p->offset, howto,
3703218822Sdim		    &srel);
3704218822Sdim#else
3705218822Sdim      {
3706218822Sdim	int r_pcrel;
3707218822Sdim	int r_baserel;
3708218822Sdim	int r_jmptable;
3709218822Sdim	int r_relative;
3710218822Sdim	int r_length;
371133965Sjdp
3712218822Sdim	r_pcrel = (int) howto->pc_relative;
3713218822Sdim	r_baserel = (howto->type & 8) != 0;
3714218822Sdim	r_jmptable = (howto->type & 16) != 0;
3715218822Sdim	r_relative = (howto->type & 32) != 0;
3716218822Sdim	r_length = howto->size;
371733965Sjdp
3718218822Sdim	PUT_WORD (finfo->output_bfd, p->offset, srel.r_address);
3719218822Sdim	if (bfd_header_big_endian (finfo->output_bfd))
3720218822Sdim	  {
3721218822Sdim	    srel.r_index[0] = r_index >> 16;
3722218822Sdim	    srel.r_index[1] = r_index >> 8;
3723218822Sdim	    srel.r_index[2] = r_index;
3724218822Sdim	    srel.r_type[0] =
3725218822Sdim	      ((r_extern ?     RELOC_STD_BITS_EXTERN_BIG : 0)
3726218822Sdim	       | (r_pcrel ?    RELOC_STD_BITS_PCREL_BIG : 0)
3727218822Sdim	       | (r_baserel ?  RELOC_STD_BITS_BASEREL_BIG : 0)
3728218822Sdim	       | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
3729218822Sdim	       | (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
3730218822Sdim	       | (r_length <<  RELOC_STD_BITS_LENGTH_SH_BIG));
3731218822Sdim	  }
3732218822Sdim	else
3733218822Sdim	  {
3734218822Sdim	    srel.r_index[2] = r_index >> 16;
3735218822Sdim	    srel.r_index[1] = r_index >> 8;
3736218822Sdim	    srel.r_index[0] = r_index;
3737218822Sdim	    srel.r_type[0] =
3738218822Sdim	      ((r_extern ?     RELOC_STD_BITS_EXTERN_LITTLE : 0)
3739218822Sdim	       | (r_pcrel ?    RELOC_STD_BITS_PCREL_LITTLE : 0)
3740218822Sdim	       | (r_baserel ?  RELOC_STD_BITS_BASEREL_LITTLE : 0)
3741218822Sdim	       | (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
3742218822Sdim	       | (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
3743218822Sdim	       | (r_length <<  RELOC_STD_BITS_LENGTH_SH_LITTLE));
3744218822Sdim	  }
3745218822Sdim      }
3746218822Sdim#endif
3747218822Sdim      rel_ptr = (void *) &srel;
3748218822Sdim
3749218822Sdim      /* We have to write the addend into the object file, since
3750218822Sdim	 standard a.out relocs are in place.  It would be more
3751218822Sdim	 reliable if we had the current contents of the file here,
3752218822Sdim	 rather than assuming zeroes, but we can't read the file since
3753218822Sdim	 it was opened using bfd_openw.  */
3754218822Sdim      if (pr->addend != 0)
3755218822Sdim	{
3756218822Sdim	  bfd_size_type size;
3757218822Sdim	  bfd_reloc_status_type r;
3758218822Sdim	  bfd_byte *buf;
3759218822Sdim	  bfd_boolean ok;
3760218822Sdim
3761218822Sdim	  size = bfd_get_reloc_size (howto);
3762218822Sdim	  buf = bfd_zmalloc (size);
3763218822Sdim	  if (buf == NULL)
3764218822Sdim	    return FALSE;
3765218822Sdim	  r = MY_relocate_contents (howto, finfo->output_bfd,
3766218822Sdim				    (bfd_vma) pr->addend, buf);
3767218822Sdim	  switch (r)
3768218822Sdim	    {
3769218822Sdim	    case bfd_reloc_ok:
3770218822Sdim	      break;
3771218822Sdim	    default:
3772218822Sdim	    case bfd_reloc_outofrange:
3773218822Sdim	      abort ();
3774218822Sdim	    case bfd_reloc_overflow:
3775218822Sdim	      if (! ((*finfo->info->callbacks->reloc_overflow)
3776218822Sdim		     (finfo->info, NULL,
3777218822Sdim		      (p->type == bfd_section_reloc_link_order
3778218822Sdim		       ? bfd_section_name (finfo->output_bfd,
3779218822Sdim					   pr->u.section)
3780218822Sdim		       : pr->u.name),
3781218822Sdim		      howto->name, pr->addend, NULL, NULL, (bfd_vma) 0)))
3782218822Sdim		{
3783218822Sdim		  free (buf);
3784218822Sdim		  return FALSE;
3785218822Sdim		}
3786218822Sdim	      break;
3787218822Sdim	    }
3788218822Sdim	  ok = bfd_set_section_contents (finfo->output_bfd, o, (void *) buf,
3789218822Sdim					 (file_ptr) p->offset, size);
3790218822Sdim	  free (buf);
3791218822Sdim	  if (! ok)
3792218822Sdim	    return FALSE;
3793218822Sdim	}
3794218822Sdim    }
3795218822Sdim  else
379633965Sjdp    {
3797218822Sdim#ifdef MY_put_ext_reloc
3798218822Sdim      MY_put_ext_reloc (finfo->output_bfd, r_extern, r_index, p->offset,
3799218822Sdim			howto, &erel, pr->addend);
3800218822Sdim#else
3801218822Sdim      PUT_WORD (finfo->output_bfd, p->offset, erel.r_address);
380233965Sjdp
3803218822Sdim      if (bfd_header_big_endian (finfo->output_bfd))
3804218822Sdim	{
3805218822Sdim	  erel.r_index[0] = r_index >> 16;
3806218822Sdim	  erel.r_index[1] = r_index >> 8;
3807218822Sdim	  erel.r_index[2] = r_index;
3808218822Sdim	  erel.r_type[0] =
3809218822Sdim	    ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
3810218822Sdim	     | (howto->type << RELOC_EXT_BITS_TYPE_SH_BIG));
3811218822Sdim	}
3812218822Sdim      else
3813218822Sdim	{
3814218822Sdim	  erel.r_index[2] = r_index >> 16;
3815218822Sdim	  erel.r_index[1] = r_index >> 8;
3816218822Sdim	  erel.r_index[0] = r_index;
3817218822Sdim	  erel.r_type[0] =
3818218822Sdim	    (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
3819218822Sdim	      | (howto->type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
3820218822Sdim	}
3821218822Sdim
3822218822Sdim      PUT_WORD (finfo->output_bfd, (bfd_vma) pr->addend, erel.r_addend);
3823218822Sdim#endif /* MY_put_ext_reloc */
3824218822Sdim
3825218822Sdim      rel_ptr = (void *) &erel;
382633965Sjdp    }
382733965Sjdp
3828218822Sdim  amt = obj_reloc_entry_size (finfo->output_bfd);
3829218822Sdim  if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0
3830218822Sdim      || bfd_bwrite (rel_ptr, amt, finfo->output_bfd) != amt)
3831218822Sdim    return FALSE;
3832218822Sdim
3833218822Sdim  *reloff_ptr += obj_reloc_entry_size (finfo->output_bfd);
3834218822Sdim
3835218822Sdim  /* Assert that the relocs have not run into the symbols, and that n
3836218822Sdim     the text relocs have not run into the data relocs.  */
3837218822Sdim  BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
3838218822Sdim	      && (reloff_ptr != &finfo->treloff
3839218822Sdim		  || (*reloff_ptr
3840218822Sdim		      <= obj_datasec (finfo->output_bfd)->rel_filepos)));
3841218822Sdim
3842130561Sobrien  return TRUE;
384333965Sjdp}
384433965Sjdp
384533965Sjdp/* Get the section corresponding to a reloc index.  */
384633965Sjdp
384733965Sjdpstatic INLINE asection *
3848218822Sdimaout_reloc_index_to_section (bfd *abfd, int indx)
384933965Sjdp{
385033965Sjdp  switch (indx & N_TYPE)
385133965Sjdp    {
3852218822Sdim    case N_TEXT:   return obj_textsec (abfd);
3853218822Sdim    case N_DATA:   return obj_datasec (abfd);
3854218822Sdim    case N_BSS:    return obj_bsssec (abfd);
385533965Sjdp    case N_ABS:
3856218822Sdim    case N_UNDF:   return bfd_abs_section_ptr;
3857218822Sdim    default:       abort ();
385833965Sjdp    }
385960484Sobrien  return NULL;
386033965Sjdp}
386133965Sjdp
386233965Sjdp/* Relocate an a.out section using standard a.out relocs.  */
386333965Sjdp
3864130561Sobrienstatic bfd_boolean
3865218822Sdimaout_link_input_section_std (struct aout_final_link_info *finfo,
3866218822Sdim			     bfd *input_bfd,
3867218822Sdim			     asection *input_section,
3868218822Sdim			     struct reloc_std_external *relocs,
3869218822Sdim			     bfd_size_type rel_size,
3870218822Sdim			     bfd_byte *contents)
387133965Sjdp{
3872130561Sobrien  bfd_boolean (*check_dynamic_reloc)
3873218822Sdim    (struct bfd_link_info *, bfd *, asection *,
3874218822Sdim	     struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *,
3875218822Sdim	     bfd_vma *);
387633965Sjdp  bfd *output_bfd;
3877130561Sobrien  bfd_boolean relocatable;
387833965Sjdp  struct external_nlist *syms;
387933965Sjdp  char *strings;
388033965Sjdp  struct aout_link_hash_entry **sym_hashes;
388133965Sjdp  int *symbol_map;
388233965Sjdp  bfd_size_type reloc_count;
3883218822Sdim  struct reloc_std_external *rel;
388433965Sjdp  struct reloc_std_external *rel_end;
388533965Sjdp
388633965Sjdp  output_bfd = finfo->output_bfd;
388733965Sjdp  check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
388833965Sjdp
388933965Sjdp  BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE);
389033965Sjdp  BFD_ASSERT (input_bfd->xvec->header_byteorder
389133965Sjdp	      == output_bfd->xvec->header_byteorder);
389233965Sjdp
3893130561Sobrien  relocatable = finfo->info->relocatable;
389433965Sjdp  syms = obj_aout_external_syms (input_bfd);
389533965Sjdp  strings = obj_aout_external_strings (input_bfd);
389633965Sjdp  sym_hashes = obj_aout_sym_hashes (input_bfd);
389733965Sjdp  symbol_map = finfo->symbol_map;
389833965Sjdp
389933965Sjdp  reloc_count = rel_size / RELOC_STD_SIZE;
390033965Sjdp  rel = relocs;
390133965Sjdp  rel_end = rel + reloc_count;
390233965Sjdp  for (; rel < rel_end; rel++)
390333965Sjdp    {
390433965Sjdp      bfd_vma r_addr;
390533965Sjdp      int r_index;
390633965Sjdp      int r_extern;
390733965Sjdp      int r_pcrel;
390833965Sjdp      int r_baserel = 0;
390933965Sjdp      reloc_howto_type *howto;
391033965Sjdp      struct aout_link_hash_entry *h = NULL;
391133965Sjdp      bfd_vma relocation;
391233965Sjdp      bfd_reloc_status_type r;
391333965Sjdp
391433965Sjdp      r_addr = GET_SWORD (input_bfd, rel->r_address);
391533965Sjdp
391633965Sjdp#ifdef MY_reloc_howto
391789857Sobrien      howto = MY_reloc_howto (input_bfd, rel, r_index, r_extern, r_pcrel);
391877298Sobrien#else
391933965Sjdp      {
392033965Sjdp	int r_jmptable;
392133965Sjdp	int r_relative;
392233965Sjdp	int r_length;
392333965Sjdp	unsigned int howto_idx;
392433965Sjdp
392533965Sjdp	if (bfd_header_big_endian (input_bfd))
392633965Sjdp	  {
3927107492Sobrien	    r_index   =  (((unsigned int) rel->r_index[0] << 16)
3928107492Sobrien			  | ((unsigned int) rel->r_index[1] << 8)
392933965Sjdp			  | rel->r_index[2]);
393033965Sjdp	    r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
393133965Sjdp	    r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
393233965Sjdp	    r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
393333965Sjdp	    r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
393433965Sjdp	    r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
393533965Sjdp	    r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
393633965Sjdp			 >> RELOC_STD_BITS_LENGTH_SH_BIG);
393733965Sjdp	  }
393833965Sjdp	else
393933965Sjdp	  {
3940107492Sobrien	    r_index   = (((unsigned int) rel->r_index[2] << 16)
3941107492Sobrien			 | ((unsigned int) rel->r_index[1] << 8)
394233965Sjdp			 | rel->r_index[0]);
394333965Sjdp	    r_extern  = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
394433965Sjdp	    r_pcrel   = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
394533965Sjdp	    r_baserel = (0 != (rel->r_type[0]
394633965Sjdp			       & RELOC_STD_BITS_BASEREL_LITTLE));
394733965Sjdp	    r_jmptable= (0 != (rel->r_type[0]
394833965Sjdp			       & RELOC_STD_BITS_JMPTABLE_LITTLE));
394933965Sjdp	    r_relative= (0 != (rel->r_type[0]
395033965Sjdp			       & RELOC_STD_BITS_RELATIVE_LITTLE));
395133965Sjdp	    r_length  = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
395233965Sjdp			 >> RELOC_STD_BITS_LENGTH_SH_LITTLE);
395333965Sjdp	  }
395433965Sjdp
395533965Sjdp	howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
395633965Sjdp		     + 16 * r_jmptable + 32 * r_relative);
395733965Sjdp	BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
395833965Sjdp	howto = howto_table_std + howto_idx;
395933965Sjdp      }
396033965Sjdp#endif
396133965Sjdp
3962130561Sobrien      if (relocatable)
396333965Sjdp	{
3964130561Sobrien	  /* We are generating a relocatable output file, and must
396533965Sjdp	     modify the reloc accordingly.  */
396633965Sjdp	  if (r_extern)
396733965Sjdp	    {
396833965Sjdp	      /* If we know the symbol this relocation is against,
396933965Sjdp		 convert it into a relocation against a section.  This
397033965Sjdp		 is what the native linker does.  */
397133965Sjdp	      h = sym_hashes[r_index];
3972218822Sdim	      if (h != NULL
397333965Sjdp		  && (h->root.type == bfd_link_hash_defined
397433965Sjdp		      || h->root.type == bfd_link_hash_defweak))
397533965Sjdp		{
397633965Sjdp		  asection *output_section;
397733965Sjdp
397833965Sjdp		  /* Change the r_extern value.  */
397933965Sjdp		  if (bfd_header_big_endian (output_bfd))
398033965Sjdp		    rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_BIG;
398133965Sjdp		  else
398233965Sjdp		    rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_LITTLE;
398333965Sjdp
398433965Sjdp		  /* Compute a new r_index.  */
398533965Sjdp		  output_section = h->root.u.def.section->output_section;
398633965Sjdp		  if (output_section == obj_textsec (output_bfd))
398733965Sjdp		    r_index = N_TEXT;
398833965Sjdp		  else if (output_section == obj_datasec (output_bfd))
398933965Sjdp		    r_index = N_DATA;
399033965Sjdp		  else if (output_section == obj_bsssec (output_bfd))
399133965Sjdp		    r_index = N_BSS;
399233965Sjdp		  else
399333965Sjdp		    r_index = N_ABS;
399433965Sjdp
399533965Sjdp		  /* Add the symbol value and the section VMA to the
399633965Sjdp		     addend stored in the contents.  */
399733965Sjdp		  relocation = (h->root.u.def.value
399833965Sjdp				+ output_section->vma
399933965Sjdp				+ h->root.u.def.section->output_offset);
400033965Sjdp		}
400133965Sjdp	      else
400233965Sjdp		{
400333965Sjdp		  /* We must change r_index according to the symbol
400433965Sjdp		     map.  */
400533965Sjdp		  r_index = symbol_map[r_index];
400633965Sjdp
400733965Sjdp		  if (r_index == -1)
400833965Sjdp		    {
400933965Sjdp		      if (h != NULL)
401033965Sjdp			{
401133965Sjdp			  /* We decided to strip this symbol, but it
401233965Sjdp                             turns out that we can't.  Note that we
401333965Sjdp                             lose the other and desc information here.
401433965Sjdp                             I don't think that will ever matter for a
401533965Sjdp                             global symbol.  */
401633965Sjdp			  if (h->indx < 0)
401733965Sjdp			    {
401833965Sjdp			      h->indx = -2;
4019130561Sobrien			      h->written = FALSE;
402033965Sjdp			      if (! aout_link_write_other_symbol (h,
4021218822Sdim								  (void *) finfo))
4022130561Sobrien				return FALSE;
402333965Sjdp			    }
402433965Sjdp			  r_index = h->indx;
402533965Sjdp			}
402633965Sjdp		      else
402733965Sjdp			{
402833965Sjdp			  const char *name;
402933965Sjdp
403033965Sjdp			  name = strings + GET_WORD (input_bfd,
403133965Sjdp						     syms[r_index].e_strx);
403233965Sjdp			  if (! ((*finfo->info->callbacks->unattached_reloc)
403333965Sjdp				 (finfo->info, name, input_bfd, input_section,
403433965Sjdp				  r_addr)))
4035130561Sobrien			    return FALSE;
403633965Sjdp			  r_index = 0;
403733965Sjdp			}
403833965Sjdp		    }
403933965Sjdp
404033965Sjdp		  relocation = 0;
404133965Sjdp		}
404233965Sjdp
404333965Sjdp	      /* Write out the new r_index value.  */
404433965Sjdp	      if (bfd_header_big_endian (output_bfd))
404533965Sjdp		{
404633965Sjdp		  rel->r_index[0] = r_index >> 16;
404733965Sjdp		  rel->r_index[1] = r_index >> 8;
404833965Sjdp		  rel->r_index[2] = r_index;
404933965Sjdp		}
405033965Sjdp	      else
405133965Sjdp		{
405233965Sjdp		  rel->r_index[2] = r_index >> 16;
405333965Sjdp		  rel->r_index[1] = r_index >> 8;
405433965Sjdp		  rel->r_index[0] = r_index;
405533965Sjdp		}
405633965Sjdp	    }
405733965Sjdp	  else
405833965Sjdp	    {
405933965Sjdp	      asection *section;
406033965Sjdp
406133965Sjdp	      /* This is a relocation against a section.  We must
406233965Sjdp		 adjust by the amount that the section moved.  */
406333965Sjdp	      section = aout_reloc_index_to_section (input_bfd, r_index);
406433965Sjdp	      relocation = (section->output_section->vma
406533965Sjdp			    + section->output_offset
406633965Sjdp			    - section->vma);
406733965Sjdp	    }
406833965Sjdp
406933965Sjdp	  /* Change the address of the relocation.  */
407033965Sjdp	  PUT_WORD (output_bfd,
407133965Sjdp		    r_addr + input_section->output_offset,
407233965Sjdp		    rel->r_address);
407333965Sjdp
407433965Sjdp	  /* Adjust a PC relative relocation by removing the reference
407533965Sjdp	     to the original address in the section and including the
407633965Sjdp	     reference to the new address.  */
407733965Sjdp	  if (r_pcrel)
407833965Sjdp	    relocation -= (input_section->output_section->vma
407933965Sjdp			   + input_section->output_offset
408033965Sjdp			   - input_section->vma);
408133965Sjdp
408233965Sjdp#ifdef MY_relocatable_reloc
408333965Sjdp	  MY_relocatable_reloc (howto, output_bfd, rel, relocation, r_addr);
408433965Sjdp#endif
408533965Sjdp
408633965Sjdp	  if (relocation == 0)
408733965Sjdp	    r = bfd_reloc_ok;
408833965Sjdp	  else
408933965Sjdp	    r = MY_relocate_contents (howto,
409033965Sjdp					input_bfd, relocation,
409133965Sjdp					contents + r_addr);
409233965Sjdp	}
409333965Sjdp      else
409433965Sjdp	{
4095130561Sobrien	  bfd_boolean hundef;
409633965Sjdp
409733965Sjdp	  /* We are generating an executable, and must do a full
409833965Sjdp	     relocation.  */
4099130561Sobrien	  hundef = FALSE;
410060484Sobrien
410133965Sjdp	  if (r_extern)
410233965Sjdp	    {
410333965Sjdp	      h = sym_hashes[r_index];
410433965Sjdp
4105218822Sdim	      if (h != NULL
410633965Sjdp		  && (h->root.type == bfd_link_hash_defined
410733965Sjdp		      || h->root.type == bfd_link_hash_defweak))
410833965Sjdp		{
410933965Sjdp		  relocation = (h->root.u.def.value
411033965Sjdp				+ h->root.u.def.section->output_section->vma
411133965Sjdp				+ h->root.u.def.section->output_offset);
411233965Sjdp		}
4113218822Sdim	      else if (h != NULL
411433965Sjdp		       && h->root.type == bfd_link_hash_undefweak)
411533965Sjdp		relocation = 0;
411633965Sjdp	      else
411733965Sjdp		{
4118130561Sobrien		  hundef = TRUE;
411933965Sjdp		  relocation = 0;
412033965Sjdp		}
412133965Sjdp	    }
412233965Sjdp	  else
412333965Sjdp	    {
412433965Sjdp	      asection *section;
412533965Sjdp
412633965Sjdp	      section = aout_reloc_index_to_section (input_bfd, r_index);
412733965Sjdp	      relocation = (section->output_section->vma
412833965Sjdp			    + section->output_offset
412933965Sjdp			    - section->vma);
413033965Sjdp	      if (r_pcrel)
413133965Sjdp		relocation += input_section->vma;
413233965Sjdp	    }
413333965Sjdp
413433965Sjdp	  if (check_dynamic_reloc != NULL)
413533965Sjdp	    {
4136130561Sobrien	      bfd_boolean skip;
413733965Sjdp
413833965Sjdp	      if (! ((*check_dynamic_reloc)
413933965Sjdp		     (finfo->info, input_bfd, input_section, h,
4140218822Sdim		      (void *) rel, contents, &skip, &relocation)))
4141130561Sobrien		return FALSE;
414233965Sjdp	      if (skip)
414333965Sjdp		continue;
414433965Sjdp	    }
414533965Sjdp
414633965Sjdp	  /* Now warn if a global symbol is undefined.  We could not
414733965Sjdp             do this earlier, because check_dynamic_reloc might want
414833965Sjdp             to skip this reloc.  */
414933965Sjdp	  if (hundef && ! finfo->info->shared && ! r_baserel)
415033965Sjdp	    {
415133965Sjdp	      const char *name;
415233965Sjdp
415333965Sjdp	      if (h != NULL)
415433965Sjdp		name = h->root.root.string;
415533965Sjdp	      else
415633965Sjdp		name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
415733965Sjdp	      if (! ((*finfo->info->callbacks->undefined_symbol)
415860484Sobrien		     (finfo->info, name, input_bfd, input_section,
4159130561Sobrien		     r_addr, TRUE)))
4160130561Sobrien		return FALSE;
416133965Sjdp	    }
416233965Sjdp
416333965Sjdp	  r = MY_final_link_relocate (howto,
416433965Sjdp				      input_bfd, input_section,
416533965Sjdp				      contents, r_addr, relocation,
416633965Sjdp				      (bfd_vma) 0);
416733965Sjdp	}
416833965Sjdp
416933965Sjdp      if (r != bfd_reloc_ok)
417033965Sjdp	{
417133965Sjdp	  switch (r)
417233965Sjdp	    {
417333965Sjdp	    default:
417433965Sjdp	    case bfd_reloc_outofrange:
417533965Sjdp	      abort ();
417633965Sjdp	    case bfd_reloc_overflow:
417733965Sjdp	      {
417833965Sjdp		const char *name;
417933965Sjdp
418033965Sjdp		if (h != NULL)
4181218822Sdim		  name = NULL;
418233965Sjdp		else if (r_extern)
418333965Sjdp		  name = strings + GET_WORD (input_bfd,
418433965Sjdp					     syms[r_index].e_strx);
418533965Sjdp		else
418633965Sjdp		  {
418733965Sjdp		    asection *s;
418833965Sjdp
418933965Sjdp		    s = aout_reloc_index_to_section (input_bfd, r_index);
419033965Sjdp		    name = bfd_section_name (input_bfd, s);
419133965Sjdp		  }
419233965Sjdp		if (! ((*finfo->info->callbacks->reloc_overflow)
4193218822Sdim		       (finfo->info, (h ? &h->root : NULL), name,
4194218822Sdim			howto->name, (bfd_vma) 0, input_bfd,
4195218822Sdim			input_section, r_addr)))
4196130561Sobrien		  return FALSE;
419733965Sjdp	      }
419833965Sjdp	      break;
419933965Sjdp	    }
420033965Sjdp	}
420133965Sjdp    }
420233965Sjdp
4203130561Sobrien  return TRUE;
420433965Sjdp}
420533965Sjdp
420633965Sjdp/* Relocate an a.out section using extended a.out relocs.  */
420733965Sjdp
4208130561Sobrienstatic bfd_boolean
4209218822Sdimaout_link_input_section_ext (struct aout_final_link_info *finfo,
4210218822Sdim			     bfd *input_bfd,
4211218822Sdim			     asection *input_section,
4212218822Sdim			     struct reloc_ext_external *relocs,
4213218822Sdim			     bfd_size_type rel_size,
4214218822Sdim			     bfd_byte *contents)
421533965Sjdp{
4216130561Sobrien  bfd_boolean (*check_dynamic_reloc)
4217218822Sdim    (struct bfd_link_info *, bfd *, asection *,
4218218822Sdim	     struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *,
4219218822Sdim	     bfd_vma *);
422033965Sjdp  bfd *output_bfd;
4221130561Sobrien  bfd_boolean relocatable;
422233965Sjdp  struct external_nlist *syms;
422333965Sjdp  char *strings;
422433965Sjdp  struct aout_link_hash_entry **sym_hashes;
422533965Sjdp  int *symbol_map;
422633965Sjdp  bfd_size_type reloc_count;
4227218822Sdim  struct reloc_ext_external *rel;
422833965Sjdp  struct reloc_ext_external *rel_end;
422933965Sjdp
423033965Sjdp  output_bfd = finfo->output_bfd;
423133965Sjdp  check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
423233965Sjdp
423333965Sjdp  BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE);
423433965Sjdp  BFD_ASSERT (input_bfd->xvec->header_byteorder
423533965Sjdp	      == output_bfd->xvec->header_byteorder);
423633965Sjdp
4237130561Sobrien  relocatable = finfo->info->relocatable;
423833965Sjdp  syms = obj_aout_external_syms (input_bfd);
423933965Sjdp  strings = obj_aout_external_strings (input_bfd);
424033965Sjdp  sym_hashes = obj_aout_sym_hashes (input_bfd);
424133965Sjdp  symbol_map = finfo->symbol_map;
424233965Sjdp
424333965Sjdp  reloc_count = rel_size / RELOC_EXT_SIZE;
424433965Sjdp  rel = relocs;
424533965Sjdp  rel_end = rel + reloc_count;
424633965Sjdp  for (; rel < rel_end; rel++)
424733965Sjdp    {
424833965Sjdp      bfd_vma r_addr;
424933965Sjdp      int r_index;
425033965Sjdp      int r_extern;
425133965Sjdp      unsigned int r_type;
425233965Sjdp      bfd_vma r_addend;
425333965Sjdp      struct aout_link_hash_entry *h = NULL;
425433965Sjdp      asection *r_section = NULL;
425533965Sjdp      bfd_vma relocation;
425633965Sjdp
425733965Sjdp      r_addr = GET_SWORD (input_bfd, rel->r_address);
425833965Sjdp
425933965Sjdp      if (bfd_header_big_endian (input_bfd))
426033965Sjdp	{
4261107492Sobrien	  r_index  = (((unsigned int) rel->r_index[0] << 16)
4262107492Sobrien		      | ((unsigned int) rel->r_index[1] << 8)
426333965Sjdp		      | rel->r_index[2]);
426433965Sjdp	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
426533965Sjdp	  r_type   = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
426633965Sjdp		      >> RELOC_EXT_BITS_TYPE_SH_BIG);
426733965Sjdp	}
426833965Sjdp      else
426933965Sjdp	{
4270107492Sobrien	  r_index  = (((unsigned int) rel->r_index[2] << 16)
4271107492Sobrien		      | ((unsigned int) rel->r_index[1] << 8)
427233965Sjdp		      | rel->r_index[0]);
427333965Sjdp	  r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
427433965Sjdp	  r_type   = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
427533965Sjdp		      >> RELOC_EXT_BITS_TYPE_SH_LITTLE);
427633965Sjdp	}
427733965Sjdp
427833965Sjdp      r_addend = GET_SWORD (input_bfd, rel->r_addend);
427933965Sjdp
428033965Sjdp      BFD_ASSERT (r_type < TABLE_SIZE (howto_table_ext));
428133965Sjdp
4282130561Sobrien      if (relocatable)
428333965Sjdp	{
4284130561Sobrien	  /* We are generating a relocatable output file, and must
428533965Sjdp	     modify the reloc accordingly.  */
428633965Sjdp	  if (r_extern
4287107492Sobrien	      || r_type == (unsigned int) RELOC_BASE10
4288107492Sobrien	      || r_type == (unsigned int) RELOC_BASE13
4289107492Sobrien	      || r_type == (unsigned int) RELOC_BASE22)
429033965Sjdp	    {
429133965Sjdp	      /* If we know the symbol this relocation is against,
429233965Sjdp		 convert it into a relocation against a section.  This
429333965Sjdp		 is what the native linker does.  */
4294107492Sobrien	      if (r_type == (unsigned int) RELOC_BASE10
4295107492Sobrien		  || r_type == (unsigned int) RELOC_BASE13
4296107492Sobrien		  || r_type == (unsigned int) RELOC_BASE22)
429733965Sjdp		h = NULL;
429833965Sjdp	      else
429933965Sjdp		h = sym_hashes[r_index];
4300218822Sdim	      if (h != NULL
430133965Sjdp		  && (h->root.type == bfd_link_hash_defined
430233965Sjdp		      || h->root.type == bfd_link_hash_defweak))
430333965Sjdp		{
430433965Sjdp		  asection *output_section;
430533965Sjdp
430633965Sjdp		  /* Change the r_extern value.  */
430733965Sjdp		  if (bfd_header_big_endian (output_bfd))
430833965Sjdp		    rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_BIG;
430933965Sjdp		  else
431033965Sjdp		    rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_LITTLE;
431133965Sjdp
431233965Sjdp		  /* Compute a new r_index.  */
431333965Sjdp		  output_section = h->root.u.def.section->output_section;
431433965Sjdp		  if (output_section == obj_textsec (output_bfd))
431533965Sjdp		    r_index = N_TEXT;
431633965Sjdp		  else if (output_section == obj_datasec (output_bfd))
431733965Sjdp		    r_index = N_DATA;
431833965Sjdp		  else if (output_section == obj_bsssec (output_bfd))
431933965Sjdp		    r_index = N_BSS;
432033965Sjdp		  else
432133965Sjdp		    r_index = N_ABS;
432233965Sjdp
432333965Sjdp		  /* Add the symbol value and the section VMA to the
432433965Sjdp		     addend.  */
432533965Sjdp		  relocation = (h->root.u.def.value
432633965Sjdp				+ output_section->vma
432733965Sjdp				+ h->root.u.def.section->output_offset);
432833965Sjdp
432933965Sjdp		  /* Now RELOCATION is the VMA of the final
433033965Sjdp		     destination.  If this is a PC relative reloc,
433133965Sjdp		     then ADDEND is the negative of the source VMA.
433233965Sjdp		     We want to set ADDEND to the difference between
433333965Sjdp		     the destination VMA and the source VMA, which
433433965Sjdp		     means we must adjust RELOCATION by the change in
433533965Sjdp		     the source VMA.  This is done below.  */
433633965Sjdp		}
433733965Sjdp	      else
433833965Sjdp		{
433933965Sjdp		  /* We must change r_index according to the symbol
434033965Sjdp		     map.  */
434133965Sjdp		  r_index = symbol_map[r_index];
434233965Sjdp
434333965Sjdp		  if (r_index == -1)
434433965Sjdp		    {
434533965Sjdp		      if (h != NULL)
434633965Sjdp			{
434733965Sjdp			  /* We decided to strip this symbol, but it
434833965Sjdp                             turns out that we can't.  Note that we
434933965Sjdp                             lose the other and desc information here.
435033965Sjdp                             I don't think that will ever matter for a
435133965Sjdp                             global symbol.  */
435233965Sjdp			  if (h->indx < 0)
435333965Sjdp			    {
435433965Sjdp			      h->indx = -2;
4355130561Sobrien			      h->written = FALSE;
435633965Sjdp			      if (! aout_link_write_other_symbol (h,
4357218822Sdim								  (void *) finfo))
4358130561Sobrien				return FALSE;
435933965Sjdp			    }
436033965Sjdp			  r_index = h->indx;
436133965Sjdp			}
436233965Sjdp		      else
436333965Sjdp			{
436433965Sjdp			  const char *name;
436533965Sjdp
436633965Sjdp			  name = strings + GET_WORD (input_bfd,
436733965Sjdp						     syms[r_index].e_strx);
436833965Sjdp			  if (! ((*finfo->info->callbacks->unattached_reloc)
436933965Sjdp				 (finfo->info, name, input_bfd, input_section,
437033965Sjdp				  r_addr)))
4371130561Sobrien			    return FALSE;
437233965Sjdp			  r_index = 0;
437333965Sjdp			}
437433965Sjdp		    }
437533965Sjdp
437633965Sjdp		  relocation = 0;
437733965Sjdp
437833965Sjdp		  /* If this is a PC relative reloc, then the addend
437933965Sjdp		     is the negative of the source VMA.  We must
438033965Sjdp		     adjust it by the change in the source VMA.  This
438133965Sjdp		     is done below.  */
438233965Sjdp		}
438333965Sjdp
438433965Sjdp	      /* Write out the new r_index value.  */
438533965Sjdp	      if (bfd_header_big_endian (output_bfd))
438633965Sjdp		{
438733965Sjdp		  rel->r_index[0] = r_index >> 16;
438833965Sjdp		  rel->r_index[1] = r_index >> 8;
438933965Sjdp		  rel->r_index[2] = r_index;
439033965Sjdp		}
439133965Sjdp	      else
439233965Sjdp		{
439333965Sjdp		  rel->r_index[2] = r_index >> 16;
439433965Sjdp		  rel->r_index[1] = r_index >> 8;
439533965Sjdp		  rel->r_index[0] = r_index;
439633965Sjdp		}
439733965Sjdp	    }
439833965Sjdp	  else
439933965Sjdp	    {
440033965Sjdp	      /* This is a relocation against a section.  We must
440133965Sjdp		 adjust by the amount that the section moved.  */
440233965Sjdp	      r_section = aout_reloc_index_to_section (input_bfd, r_index);
440333965Sjdp	      relocation = (r_section->output_section->vma
440433965Sjdp			    + r_section->output_offset
440533965Sjdp			    - r_section->vma);
440633965Sjdp
440733965Sjdp	      /* If this is a PC relative reloc, then the addend is
440833965Sjdp		 the difference in VMA between the destination and the
440933965Sjdp		 source.  We have just adjusted for the change in VMA
441033965Sjdp		 of the destination, so we must also adjust by the
441133965Sjdp		 change in VMA of the source.  This is done below.  */
441233965Sjdp	    }
441333965Sjdp
441433965Sjdp	  /* As described above, we must always adjust a PC relative
441533965Sjdp	     reloc by the change in VMA of the source.  However, if
441633965Sjdp	     pcrel_offset is set, then the addend does not include the
441733965Sjdp	     location within the section, in which case we don't need
441833965Sjdp	     to adjust anything.  */
441933965Sjdp	  if (howto_table_ext[r_type].pc_relative
442033965Sjdp	      && ! howto_table_ext[r_type].pcrel_offset)
442133965Sjdp	    relocation -= (input_section->output_section->vma
442233965Sjdp			   + input_section->output_offset
442333965Sjdp			   - input_section->vma);
442433965Sjdp
442533965Sjdp	  /* Change the addend if necessary.  */
442633965Sjdp	  if (relocation != 0)
442733965Sjdp	    PUT_WORD (output_bfd, r_addend + relocation, rel->r_addend);
442833965Sjdp
442933965Sjdp	  /* Change the address of the relocation.  */
443033965Sjdp	  PUT_WORD (output_bfd,
443133965Sjdp		    r_addr + input_section->output_offset,
443233965Sjdp		    rel->r_address);
443333965Sjdp	}
443433965Sjdp      else
443533965Sjdp	{
4436130561Sobrien	  bfd_boolean hundef;
443733965Sjdp	  bfd_reloc_status_type r;
443833965Sjdp
443933965Sjdp	  /* We are generating an executable, and must do a full
444033965Sjdp	     relocation.  */
4441130561Sobrien	  hundef = FALSE;
444260484Sobrien
444333965Sjdp	  if (r_extern)
444433965Sjdp	    {
444533965Sjdp	      h = sym_hashes[r_index];
444633965Sjdp
4447218822Sdim	      if (h != NULL
444833965Sjdp		  && (h->root.type == bfd_link_hash_defined
444933965Sjdp		      || h->root.type == bfd_link_hash_defweak))
445033965Sjdp		{
445133965Sjdp		  relocation = (h->root.u.def.value
445233965Sjdp				+ h->root.u.def.section->output_section->vma
445333965Sjdp				+ h->root.u.def.section->output_offset);
445433965Sjdp		}
4455218822Sdim	      else if (h != NULL
445633965Sjdp		       && h->root.type == bfd_link_hash_undefweak)
445733965Sjdp		relocation = 0;
445833965Sjdp	      else
445933965Sjdp		{
4460130561Sobrien		  hundef = TRUE;
446133965Sjdp		  relocation = 0;
446233965Sjdp		}
446333965Sjdp	    }
4464107492Sobrien	  else if (r_type == (unsigned int) RELOC_BASE10
4465107492Sobrien		   || r_type == (unsigned int) RELOC_BASE13
4466107492Sobrien		   || r_type == (unsigned int) RELOC_BASE22)
446733965Sjdp	    {
446833965Sjdp	      struct external_nlist *sym;
446933965Sjdp	      int type;
447033965Sjdp
447133965Sjdp	      /* For base relative relocs, r_index is always an index
447233965Sjdp                 into the symbol table, even if r_extern is 0.  */
447333965Sjdp	      sym = syms + r_index;
447489857Sobrien	      type = H_GET_8 (input_bfd, sym->e_type);
447533965Sjdp	      if ((type & N_TYPE) == N_TEXT
447633965Sjdp		  || type == N_WEAKT)
447733965Sjdp		r_section = obj_textsec (input_bfd);
447833965Sjdp	      else if ((type & N_TYPE) == N_DATA
447933965Sjdp		       || type == N_WEAKD)
448033965Sjdp		r_section = obj_datasec (input_bfd);
448133965Sjdp	      else if ((type & N_TYPE) == N_BSS
448233965Sjdp		       || type == N_WEAKB)
448333965Sjdp		r_section = obj_bsssec (input_bfd);
448433965Sjdp	      else if ((type & N_TYPE) == N_ABS
448533965Sjdp		       || type == N_WEAKA)
448633965Sjdp		r_section = bfd_abs_section_ptr;
448733965Sjdp	      else
448833965Sjdp		abort ();
448933965Sjdp	      relocation = (r_section->output_section->vma
449033965Sjdp			    + r_section->output_offset
449133965Sjdp			    + (GET_WORD (input_bfd, sym->e_value)
449233965Sjdp			       - r_section->vma));
449333965Sjdp	    }
449433965Sjdp	  else
449533965Sjdp	    {
449633965Sjdp	      r_section = aout_reloc_index_to_section (input_bfd, r_index);
449733965Sjdp
449833965Sjdp	      /* If this is a PC relative reloc, then R_ADDEND is the
449933965Sjdp		 difference between the two vmas, or
450033965Sjdp		   old_dest_sec + old_dest_off - (old_src_sec + old_src_off)
450133965Sjdp		 where
450233965Sjdp		   old_dest_sec == section->vma
450333965Sjdp		 and
450433965Sjdp		   old_src_sec == input_section->vma
450533965Sjdp		 and
450633965Sjdp		   old_src_off == r_addr
450733965Sjdp
450833965Sjdp		 _bfd_final_link_relocate expects RELOCATION +
450933965Sjdp		 R_ADDEND to be the VMA of the destination minus
451033965Sjdp		 r_addr (the minus r_addr is because this relocation
451133965Sjdp		 is not pcrel_offset, which is a bit confusing and
451233965Sjdp		 should, perhaps, be changed), or
451333965Sjdp		   new_dest_sec
451433965Sjdp		 where
451533965Sjdp		   new_dest_sec == output_section->vma + output_offset
451633965Sjdp		 We arrange for this to happen by setting RELOCATION to
451733965Sjdp		   new_dest_sec + old_src_sec - old_dest_sec
451833965Sjdp
451933965Sjdp		 If this is not a PC relative reloc, then R_ADDEND is
452033965Sjdp		 simply the VMA of the destination, so we set
452133965Sjdp		 RELOCATION to the change in the destination VMA, or
452233965Sjdp		   new_dest_sec - old_dest_sec
452333965Sjdp		 */
452433965Sjdp	      relocation = (r_section->output_section->vma
452533965Sjdp			    + r_section->output_offset
452633965Sjdp			    - r_section->vma);
452733965Sjdp	      if (howto_table_ext[r_type].pc_relative)
452833965Sjdp		relocation += input_section->vma;
452933965Sjdp	    }
453033965Sjdp
453133965Sjdp	  if (check_dynamic_reloc != NULL)
453233965Sjdp	    {
4533130561Sobrien	      bfd_boolean skip;
453433965Sjdp
453533965Sjdp	      if (! ((*check_dynamic_reloc)
453633965Sjdp		     (finfo->info, input_bfd, input_section, h,
4537218822Sdim		      (void *) rel, contents, &skip, &relocation)))
4538130561Sobrien		return FALSE;
453933965Sjdp	      if (skip)
454033965Sjdp		continue;
454133965Sjdp	    }
454233965Sjdp
454333965Sjdp	  /* Now warn if a global symbol is undefined.  We could not
454433965Sjdp             do this earlier, because check_dynamic_reloc might want
454533965Sjdp             to skip this reloc.  */
454633965Sjdp	  if (hundef
454733965Sjdp	      && ! finfo->info->shared
4548107492Sobrien	      && r_type != (unsigned int) RELOC_BASE10
4549107492Sobrien	      && r_type != (unsigned int) RELOC_BASE13
4550107492Sobrien	      && r_type != (unsigned int) RELOC_BASE22)
455133965Sjdp	    {
455233965Sjdp	      const char *name;
455333965Sjdp
455433965Sjdp	      if (h != NULL)
455533965Sjdp		name = h->root.root.string;
455633965Sjdp	      else
455733965Sjdp		name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
455833965Sjdp	      if (! ((*finfo->info->callbacks->undefined_symbol)
455960484Sobrien		     (finfo->info, name, input_bfd, input_section,
4560130561Sobrien		     r_addr, TRUE)))
4561130561Sobrien		return FALSE;
456233965Sjdp	    }
456333965Sjdp
4564107492Sobrien	  if (r_type != (unsigned int) RELOC_SPARC_REV32)
456560484Sobrien	    r = MY_final_link_relocate (howto_table_ext + r_type,
456660484Sobrien					input_bfd, input_section,
456760484Sobrien					contents, r_addr, relocation,
456860484Sobrien					r_addend);
456960484Sobrien	  else
457060484Sobrien	    {
457160484Sobrien	      bfd_vma x;
457260484Sobrien
457360484Sobrien	      x = bfd_get_32 (input_bfd, contents + r_addr);
457460484Sobrien	      x = x + relocation + r_addend;
457560484Sobrien	      bfd_putl32 (/*input_bfd,*/ x, contents + r_addr);
457660484Sobrien	      r = bfd_reloc_ok;
457760484Sobrien	    }
457860484Sobrien
457933965Sjdp	  if (r != bfd_reloc_ok)
458033965Sjdp	    {
458133965Sjdp	      switch (r)
458233965Sjdp		{
458333965Sjdp		default:
458433965Sjdp		case bfd_reloc_outofrange:
458533965Sjdp		  abort ();
458633965Sjdp		case bfd_reloc_overflow:
458733965Sjdp		  {
458833965Sjdp		    const char *name;
458933965Sjdp
459033965Sjdp		    if (h != NULL)
4591218822Sdim		      name = NULL;
459233965Sjdp		    else if (r_extern
4593107492Sobrien			     || r_type == (unsigned int) RELOC_BASE10
4594107492Sobrien			     || r_type == (unsigned int) RELOC_BASE13
4595107492Sobrien			     || r_type == (unsigned int) RELOC_BASE22)
459633965Sjdp		      name = strings + GET_WORD (input_bfd,
459733965Sjdp						 syms[r_index].e_strx);
459833965Sjdp		    else
459933965Sjdp		      {
460033965Sjdp			asection *s;
460133965Sjdp
460233965Sjdp			s = aout_reloc_index_to_section (input_bfd, r_index);
460333965Sjdp			name = bfd_section_name (input_bfd, s);
460433965Sjdp		      }
460533965Sjdp		    if (! ((*finfo->info->callbacks->reloc_overflow)
4606218822Sdim			   (finfo->info, (h ? &h->root : NULL), name,
4607218822Sdim			    howto_table_ext[r_type].name,
460833965Sjdp			    r_addend, input_bfd, input_section, r_addr)))
4609130561Sobrien		      return FALSE;
461033965Sjdp		  }
461133965Sjdp		  break;
461233965Sjdp		}
461333965Sjdp	    }
461433965Sjdp	}
461533965Sjdp    }
461633965Sjdp
4617130561Sobrien  return TRUE;
461833965Sjdp}
461933965Sjdp
4620218822Sdim/* Link an a.out section into the output file.  */
462133965Sjdp
4622130561Sobrienstatic bfd_boolean
4623218822Sdimaout_link_input_section (struct aout_final_link_info *finfo,
4624218822Sdim			 bfd *input_bfd,
4625218822Sdim			 asection *input_section,
4626218822Sdim			 file_ptr *reloff_ptr,
4627218822Sdim			 bfd_size_type rel_size)
462833965Sjdp{
4629218822Sdim  bfd_size_type input_size;
4630218822Sdim  void * relocs;
463133965Sjdp
4632218822Sdim  /* Get the section contents.  */
4633218822Sdim  input_size = input_section->size;
4634218822Sdim  if (! bfd_get_section_contents (input_bfd, input_section,
4635218822Sdim				  (void *) finfo->contents,
4636218822Sdim				  (file_ptr) 0, input_size))
4637218822Sdim    return FALSE;
463833965Sjdp
4639218822Sdim  /* Read in the relocs if we haven't already done it.  */
4640218822Sdim  if (aout_section_data (input_section) != NULL
4641218822Sdim      && aout_section_data (input_section)->relocs != NULL)
4642218822Sdim    relocs = aout_section_data (input_section)->relocs;
4643218822Sdim  else
464433965Sjdp    {
4645218822Sdim      relocs = finfo->relocs;
4646218822Sdim      if (rel_size > 0)
464733965Sjdp	{
4648218822Sdim	  if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
4649218822Sdim	      || bfd_bread (relocs, rel_size, input_bfd) != rel_size)
4650218822Sdim	    return FALSE;
465133965Sjdp	}
465233965Sjdp    }
4653218822Sdim
4654218822Sdim  /* Relocate the section contents.  */
4655218822Sdim  if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
4656218822Sdim    {
4657218822Sdim      if (! aout_link_input_section_std (finfo, input_bfd, input_section,
4658218822Sdim					 (struct reloc_std_external *) relocs,
4659218822Sdim					 rel_size, finfo->contents))
4660218822Sdim	return FALSE;
4661218822Sdim    }
466233965Sjdp  else
466333965Sjdp    {
4664218822Sdim      if (! aout_link_input_section_ext (finfo, input_bfd, input_section,
4665218822Sdim					 (struct reloc_ext_external *) relocs,
4666218822Sdim					 rel_size, finfo->contents))
4667218822Sdim	return FALSE;
4668218822Sdim    }
4669218822Sdim
4670218822Sdim  /* Write out the section contents.  */
4671218822Sdim  if (! bfd_set_section_contents (finfo->output_bfd,
4672218822Sdim				  input_section->output_section,
4673218822Sdim				  (void *) finfo->contents,
4674218822Sdim				  (file_ptr) input_section->output_offset,
4675218822Sdim				  input_size))
4676218822Sdim    return FALSE;
4677218822Sdim
4678218822Sdim  /* If we are producing relocatable output, the relocs were
4679218822Sdim     modified, and we now write them out.  */
4680218822Sdim  if (finfo->info->relocatable && rel_size > 0)
4681218822Sdim    {
4682218822Sdim      if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
4683218822Sdim	return FALSE;
4684218822Sdim      if (bfd_bwrite (relocs, rel_size, finfo->output_bfd) != rel_size)
4685218822Sdim	return FALSE;
4686218822Sdim      *reloff_ptr += rel_size;
4687218822Sdim
4688218822Sdim      /* Assert that the relocs have not run into the symbols, and
4689218822Sdim	 that if these are the text relocs they have not run into the
4690218822Sdim	 data relocs.  */
4691218822Sdim      BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
4692218822Sdim		  && (reloff_ptr != &finfo->treloff
4693218822Sdim		      || (*reloff_ptr
4694218822Sdim			  <= obj_datasec (finfo->output_bfd)->rel_filepos)));
4695218822Sdim    }
4696218822Sdim
4697218822Sdim  return TRUE;
4698218822Sdim}
4699218822Sdim
4700218822Sdim/* Adjust and write out the symbols for an a.out file.  Set the new
4701218822Sdim   symbol indices into a symbol_map.  */
4702218822Sdim
4703218822Sdimstatic bfd_boolean
4704218822Sdimaout_link_write_symbols (struct aout_final_link_info *finfo, bfd *input_bfd)
4705218822Sdim{
4706218822Sdim  bfd *output_bfd;
4707218822Sdim  bfd_size_type sym_count;
4708218822Sdim  char *strings;
4709218822Sdim  enum bfd_link_strip strip;
4710218822Sdim  enum bfd_link_discard discard;
4711218822Sdim  struct external_nlist *outsym;
4712218822Sdim  bfd_size_type strtab_index;
4713218822Sdim  struct external_nlist *sym;
4714218822Sdim  struct external_nlist *sym_end;
4715218822Sdim  struct aout_link_hash_entry **sym_hash;
4716218822Sdim  int *symbol_map;
4717218822Sdim  bfd_boolean pass;
4718218822Sdim  bfd_boolean skip_next;
4719218822Sdim
4720218822Sdim  output_bfd = finfo->output_bfd;
4721218822Sdim  sym_count = obj_aout_external_sym_count (input_bfd);
4722218822Sdim  strings = obj_aout_external_strings (input_bfd);
4723218822Sdim  strip = finfo->info->strip;
4724218822Sdim  discard = finfo->info->discard;
4725218822Sdim  outsym = finfo->output_syms;
4726218822Sdim
4727218822Sdim  /* First write out a symbol for this object file, unless we are
4728218822Sdim     discarding such symbols.  */
4729218822Sdim  if (strip != strip_all
4730218822Sdim      && (strip != strip_some
4731218822Sdim	  || bfd_hash_lookup (finfo->info->keep_hash, input_bfd->filename,
4732218822Sdim			      FALSE, FALSE) != NULL)
4733218822Sdim      && discard != discard_all)
4734218822Sdim    {
4735218822Sdim      H_PUT_8 (output_bfd, N_TEXT, outsym->e_type);
4736218822Sdim      H_PUT_8 (output_bfd, 0, outsym->e_other);
4737218822Sdim      H_PUT_16 (output_bfd, 0, outsym->e_desc);
4738218822Sdim      strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
4739218822Sdim				       input_bfd->filename, FALSE);
4740218822Sdim      if (strtab_index == (bfd_size_type) -1)
4741218822Sdim	return FALSE;
4742218822Sdim      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
4743218822Sdim      PUT_WORD (output_bfd,
4744218822Sdim		(bfd_get_section_vma (output_bfd,
4745218822Sdim				      obj_textsec (input_bfd)->output_section)
4746218822Sdim		 + obj_textsec (input_bfd)->output_offset),
4747218822Sdim		outsym->e_value);
4748218822Sdim      ++obj_aout_external_sym_count (output_bfd);
4749218822Sdim      ++outsym;
4750218822Sdim    }
4751218822Sdim
4752218822Sdim  pass = FALSE;
4753218822Sdim  skip_next = FALSE;
4754218822Sdim  sym = obj_aout_external_syms (input_bfd);
4755218822Sdim  sym_end = sym + sym_count;
4756218822Sdim  sym_hash = obj_aout_sym_hashes (input_bfd);
4757218822Sdim  symbol_map = finfo->symbol_map;
4758218822Sdim  memset (symbol_map, 0, (size_t) sym_count * sizeof *symbol_map);
4759218822Sdim  for (; sym < sym_end; sym++, sym_hash++, symbol_map++)
4760218822Sdim    {
4761218822Sdim      const char *name;
4762218822Sdim      int type;
476333965Sjdp      struct aout_link_hash_entry *h;
4764218822Sdim      bfd_boolean skip;
4765218822Sdim      asection *symsec;
4766218822Sdim      bfd_vma val = 0;
4767218822Sdim      bfd_boolean copy;
476833965Sjdp
4769218822Sdim      /* We set *symbol_map to 0 above for all symbols.  If it has
4770218822Sdim         already been set to -1 for this symbol, it means that we are
4771218822Sdim         discarding it because it appears in a duplicate header file.
4772218822Sdim         See the N_BINCL code below.  */
4773218822Sdim      if (*symbol_map == -1)
4774218822Sdim	continue;
4775218822Sdim
4776218822Sdim      /* Initialize *symbol_map to -1, which means that the symbol was
4777218822Sdim         not copied into the output file.  We will change it later if
4778218822Sdim         we do copy the symbol over.  */
4779218822Sdim      *symbol_map = -1;
4780218822Sdim
4781218822Sdim      type = H_GET_8 (input_bfd, sym->e_type);
4782218822Sdim      name = strings + GET_WORD (input_bfd, sym->e_strx);
4783218822Sdim
4784218822Sdim      h = NULL;
4785218822Sdim
4786218822Sdim      if (pass)
478733965Sjdp	{
4788218822Sdim	  /* Pass this symbol through.  It is the target of an
4789218822Sdim	     indirect or warning symbol.  */
4790218822Sdim	  val = GET_WORD (input_bfd, sym->e_value);
4791218822Sdim	  pass = FALSE;
4792218822Sdim	}
4793218822Sdim      else if (skip_next)
4794218822Sdim	{
4795218822Sdim	  /* Skip this symbol, which is the target of an indirect
4796218822Sdim	     symbol that we have changed to no longer be an indirect
479733965Sjdp	     symbol.  */
4798218822Sdim	  skip_next = FALSE;
4799218822Sdim	  continue;
480033965Sjdp	}
480133965Sjdp      else
480233965Sjdp	{
4803218822Sdim	  struct aout_link_hash_entry *hresolve;
4804218822Sdim
4805218822Sdim	  /* We have saved the hash table entry for this symbol, if
4806218822Sdim	     there is one.  Note that we could just look it up again
4807218822Sdim	     in the hash table, provided we first check that it is an
4808218822Sdim	     external symbol.  */
4809218822Sdim	  h = *sym_hash;
4810218822Sdim
4811218822Sdim	  /* Use the name from the hash table, in case the symbol was
4812218822Sdim             wrapped.  */
4813218822Sdim	  if (h != NULL
4814218822Sdim	      && h->root.type != bfd_link_hash_warning)
4815218822Sdim	    name = h->root.root.string;
4816218822Sdim
4817218822Sdim	  /* If this is an indirect or warning symbol, then change
4818218822Sdim	     hresolve to the base symbol.  We also change *sym_hash so
4819218822Sdim	     that the relocation routines relocate against the real
4820218822Sdim	     symbol.  */
4821218822Sdim	  hresolve = h;
4822218822Sdim	  if (h != (struct aout_link_hash_entry *) NULL
4823218822Sdim	      && (h->root.type == bfd_link_hash_indirect
4824218822Sdim		  || h->root.type == bfd_link_hash_warning))
4825218822Sdim	    {
4826218822Sdim	      hresolve = (struct aout_link_hash_entry *) h->root.u.i.link;
4827218822Sdim	      while (hresolve->root.type == bfd_link_hash_indirect
4828218822Sdim		     || hresolve->root.type == bfd_link_hash_warning)
4829218822Sdim		hresolve = ((struct aout_link_hash_entry *)
4830218822Sdim			    hresolve->root.u.i.link);
4831218822Sdim	      *sym_hash = hresolve;
4832218822Sdim	    }
4833218822Sdim
4834218822Sdim	  /* If the symbol has already been written out, skip it.  */
4835218822Sdim	  if (h != NULL
4836218822Sdim	      && h->written)
4837218822Sdim	    {
4838218822Sdim	      if ((type & N_TYPE) == N_INDR
4839218822Sdim		  || type == N_WARNING)
4840218822Sdim		skip_next = TRUE;
4841218822Sdim	      *symbol_map = h->indx;
4842218822Sdim	      continue;
4843218822Sdim	    }
4844218822Sdim
4845218822Sdim	  /* See if we are stripping this symbol.  */
4846218822Sdim	  skip = FALSE;
4847218822Sdim	  switch (strip)
4848218822Sdim	    {
4849218822Sdim	    case strip_none:
4850218822Sdim	      break;
4851218822Sdim	    case strip_debugger:
4852218822Sdim	      if ((type & N_STAB) != 0)
4853218822Sdim		skip = TRUE;
4854218822Sdim	      break;
4855218822Sdim	    case strip_some:
4856218822Sdim	      if (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, FALSE)
4857218822Sdim		  == NULL)
4858218822Sdim		skip = TRUE;
4859218822Sdim	      break;
4860218822Sdim	    case strip_all:
4861218822Sdim	      skip = TRUE;
4862218822Sdim	      break;
4863218822Sdim	    }
4864218822Sdim	  if (skip)
4865218822Sdim	    {
4866218822Sdim	      if (h != NULL)
4867218822Sdim		h->written = TRUE;
4868218822Sdim	      continue;
4869218822Sdim	    }
4870218822Sdim
4871218822Sdim	  /* Get the value of the symbol.  */
4872218822Sdim	  if ((type & N_TYPE) == N_TEXT
4873218822Sdim	      || type == N_WEAKT)
4874218822Sdim	    symsec = obj_textsec (input_bfd);
4875218822Sdim	  else if ((type & N_TYPE) == N_DATA
4876218822Sdim		   || type == N_WEAKD)
4877218822Sdim	    symsec = obj_datasec (input_bfd);
4878218822Sdim	  else if ((type & N_TYPE) == N_BSS
4879218822Sdim		   || type == N_WEAKB)
4880218822Sdim	    symsec = obj_bsssec (input_bfd);
4881218822Sdim	  else if ((type & N_TYPE) == N_ABS
4882218822Sdim		   || type == N_WEAKA)
4883218822Sdim	    symsec = bfd_abs_section_ptr;
4884218822Sdim	  else if (((type & N_TYPE) == N_INDR
4885218822Sdim		    && (hresolve == NULL
4886218822Sdim			|| (hresolve->root.type != bfd_link_hash_defined
4887218822Sdim			    && hresolve->root.type != bfd_link_hash_defweak
4888218822Sdim			    && hresolve->root.type != bfd_link_hash_common)))
4889218822Sdim		   || type == N_WARNING)
4890218822Sdim	    {
4891218822Sdim	      /* Pass the next symbol through unchanged.  The
4892218822Sdim		 condition above for indirect symbols is so that if
4893218822Sdim		 the indirect symbol was defined, we output it with
4894218822Sdim		 the correct definition so the debugger will
4895218822Sdim		 understand it.  */
4896218822Sdim	      pass = TRUE;
4897218822Sdim	      val = GET_WORD (input_bfd, sym->e_value);
4898218822Sdim	      symsec = NULL;
4899218822Sdim	    }
4900218822Sdim	  else if ((type & N_STAB) != 0)
4901218822Sdim	    {
4902218822Sdim	      val = GET_WORD (input_bfd, sym->e_value);
4903218822Sdim	      symsec = NULL;
4904218822Sdim	    }
4905218822Sdim	  else
4906218822Sdim	    {
4907218822Sdim	      /* If we get here with an indirect symbol, it means that
4908218822Sdim		 we are outputting it with a real definition.  In such
4909218822Sdim		 a case we do not want to output the next symbol,
4910218822Sdim		 which is the target of the indirection.  */
4911218822Sdim	      if ((type & N_TYPE) == N_INDR)
4912218822Sdim		skip_next = TRUE;
4913218822Sdim
4914218822Sdim	      symsec = NULL;
4915218822Sdim
4916218822Sdim	      /* We need to get the value from the hash table.  We use
4917218822Sdim		 hresolve so that if we have defined an indirect
4918218822Sdim		 symbol we output the final definition.  */
4919218822Sdim	      if (h == NULL)
4920218822Sdim		{
4921218822Sdim		  switch (type & N_TYPE)
4922218822Sdim		    {
4923218822Sdim		    case N_SETT:
4924218822Sdim		      symsec = obj_textsec (input_bfd);
4925218822Sdim		      break;
4926218822Sdim		    case N_SETD:
4927218822Sdim		      symsec = obj_datasec (input_bfd);
4928218822Sdim		      break;
4929218822Sdim		    case N_SETB:
4930218822Sdim		      symsec = obj_bsssec (input_bfd);
4931218822Sdim		      break;
4932218822Sdim		    case N_SETA:
4933218822Sdim		      symsec = bfd_abs_section_ptr;
4934218822Sdim		      break;
4935218822Sdim		    default:
4936218822Sdim		      val = 0;
4937218822Sdim		      break;
4938218822Sdim		    }
4939218822Sdim		}
4940218822Sdim	      else if (hresolve->root.type == bfd_link_hash_defined
4941218822Sdim		       || hresolve->root.type == bfd_link_hash_defweak)
4942218822Sdim		{
4943218822Sdim		  asection *input_section;
4944218822Sdim		  asection *output_section;
4945218822Sdim
4946218822Sdim		  /* This case usually means a common symbol which was
4947218822Sdim		     turned into a defined symbol.  */
4948218822Sdim		  input_section = hresolve->root.u.def.section;
4949218822Sdim		  output_section = input_section->output_section;
4950218822Sdim		  BFD_ASSERT (bfd_is_abs_section (output_section)
4951218822Sdim			      || output_section->owner == output_bfd);
4952218822Sdim		  val = (hresolve->root.u.def.value
4953218822Sdim			 + bfd_get_section_vma (output_bfd, output_section)
4954218822Sdim			 + input_section->output_offset);
4955218822Sdim
4956218822Sdim		  /* Get the correct type based on the section.  If
4957218822Sdim		     this is a constructed set, force it to be
4958218822Sdim		     globally visible.  */
4959218822Sdim		  if (type == N_SETT
4960218822Sdim		      || type == N_SETD
4961218822Sdim		      || type == N_SETB
4962218822Sdim		      || type == N_SETA)
4963218822Sdim		    type |= N_EXT;
4964218822Sdim
4965218822Sdim		  type &=~ N_TYPE;
4966218822Sdim
4967218822Sdim		  if (output_section == obj_textsec (output_bfd))
4968218822Sdim		    type |= (hresolve->root.type == bfd_link_hash_defined
4969218822Sdim			     ? N_TEXT
4970218822Sdim			     : N_WEAKT);
4971218822Sdim		  else if (output_section == obj_datasec (output_bfd))
4972218822Sdim		    type |= (hresolve->root.type == bfd_link_hash_defined
4973218822Sdim			     ? N_DATA
4974218822Sdim			     : N_WEAKD);
4975218822Sdim		  else if (output_section == obj_bsssec (output_bfd))
4976218822Sdim		    type |= (hresolve->root.type == bfd_link_hash_defined
4977218822Sdim			     ? N_BSS
4978218822Sdim			     : N_WEAKB);
4979218822Sdim		  else
4980218822Sdim		    type |= (hresolve->root.type == bfd_link_hash_defined
4981218822Sdim			     ? N_ABS
4982218822Sdim			     : N_WEAKA);
4983218822Sdim		}
4984218822Sdim	      else if (hresolve->root.type == bfd_link_hash_common)
4985218822Sdim		val = hresolve->root.u.c.size;
4986218822Sdim	      else if (hresolve->root.type == bfd_link_hash_undefweak)
4987218822Sdim		{
4988218822Sdim		  val = 0;
4989218822Sdim		  type = N_WEAKU;
4990218822Sdim		}
4991218822Sdim	      else
4992218822Sdim		val = 0;
4993218822Sdim	    }
4994218822Sdim	  if (symsec != NULL)
4995218822Sdim	    val = (symsec->output_section->vma
4996218822Sdim		   + symsec->output_offset
4997218822Sdim		   + (GET_WORD (input_bfd, sym->e_value)
4998218822Sdim		      - symsec->vma));
4999218822Sdim
5000218822Sdim	  /* If this is a global symbol set the written flag, and if
5001218822Sdim	     it is a local symbol see if we should discard it.  */
5002218822Sdim	  if (h != NULL)
5003218822Sdim	    {
5004218822Sdim	      h->written = TRUE;
5005218822Sdim	      h->indx = obj_aout_external_sym_count (output_bfd);
5006218822Sdim	    }
5007218822Sdim	  else if ((type & N_TYPE) != N_SETT
5008218822Sdim		   && (type & N_TYPE) != N_SETD
5009218822Sdim		   && (type & N_TYPE) != N_SETB
5010218822Sdim		   && (type & N_TYPE) != N_SETA)
5011218822Sdim	    {
5012218822Sdim	      switch (discard)
5013218822Sdim		{
5014218822Sdim		case discard_none:
5015218822Sdim		case discard_sec_merge:
5016218822Sdim		  break;
5017218822Sdim		case discard_l:
5018218822Sdim		  if ((type & N_STAB) == 0
5019218822Sdim		      && bfd_is_local_label_name (input_bfd, name))
5020218822Sdim		    skip = TRUE;
5021218822Sdim		  break;
5022218822Sdim		case discard_all:
5023218822Sdim		  skip = TRUE;
5024218822Sdim		  break;
5025218822Sdim		}
5026218822Sdim	      if (skip)
5027218822Sdim		{
5028218822Sdim		  pass = FALSE;
5029218822Sdim		  continue;
5030218822Sdim		}
5031218822Sdim	    }
5032218822Sdim
5033218822Sdim	  /* An N_BINCL symbol indicates the start of the stabs
5034218822Sdim	     entries for a header file.  We need to scan ahead to the
5035218822Sdim	     next N_EINCL symbol, ignoring nesting, adding up all the
5036218822Sdim	     characters in the symbol names, not including the file
5037218822Sdim	     numbers in types (the first number after an open
5038218822Sdim	     parenthesis).  */
5039218822Sdim	  if (type == (int) N_BINCL)
5040218822Sdim	    {
5041218822Sdim	      struct external_nlist *incl_sym;
5042218822Sdim	      int nest;
5043218822Sdim	      struct aout_link_includes_entry *incl_entry;
5044218822Sdim	      struct aout_link_includes_totals *t;
5045218822Sdim
5046218822Sdim	      val = 0;
5047218822Sdim	      nest = 0;
5048218822Sdim	      for (incl_sym = sym + 1; incl_sym < sym_end; incl_sym++)
5049218822Sdim		{
5050218822Sdim		  int incl_type;
5051218822Sdim
5052218822Sdim		  incl_type = H_GET_8 (input_bfd, incl_sym->e_type);
5053218822Sdim		  if (incl_type == (int) N_EINCL)
5054218822Sdim		    {
5055218822Sdim		      if (nest == 0)
5056218822Sdim			break;
5057218822Sdim		      --nest;
5058218822Sdim		    }
5059218822Sdim		  else if (incl_type == (int) N_BINCL)
5060218822Sdim		    ++nest;
5061218822Sdim		  else if (nest == 0)
5062218822Sdim		    {
5063218822Sdim		      const char *s;
5064218822Sdim
5065218822Sdim		      s = strings + GET_WORD (input_bfd, incl_sym->e_strx);
5066218822Sdim		      for (; *s != '\0'; s++)
5067218822Sdim			{
5068218822Sdim			  val += *s;
5069218822Sdim			  if (*s == '(')
5070218822Sdim			    {
5071218822Sdim			      /* Skip the file number.  */
5072218822Sdim			      ++s;
5073218822Sdim			      while (ISDIGIT (*s))
5074218822Sdim				++s;
5075218822Sdim			      --s;
5076218822Sdim			    }
5077218822Sdim			}
5078218822Sdim		    }
5079218822Sdim		}
5080218822Sdim
5081218822Sdim	      /* If we have already included a header file with the
5082218822Sdim                 same value, then replace this one with an N_EXCL
5083218822Sdim                 symbol.  */
5084218822Sdim	      copy = (bfd_boolean) (! finfo->info->keep_memory);
5085218822Sdim	      incl_entry = aout_link_includes_lookup (&finfo->includes,
5086218822Sdim						      name, TRUE, copy);
5087218822Sdim	      if (incl_entry == NULL)
5088218822Sdim		return FALSE;
5089218822Sdim	      for (t = incl_entry->totals; t != NULL; t = t->next)
5090218822Sdim		if (t->total == val)
5091218822Sdim		  break;
5092218822Sdim	      if (t == NULL)
5093218822Sdim		{
5094218822Sdim		  /* This is the first time we have seen this header
5095218822Sdim                     file with this set of stabs strings.  */
5096218822Sdim		  t = bfd_hash_allocate (&finfo->includes.root,
5097218822Sdim					 sizeof *t);
5098218822Sdim		  if (t == NULL)
5099218822Sdim		    return FALSE;
5100218822Sdim		  t->total = val;
5101218822Sdim		  t->next = incl_entry->totals;
5102218822Sdim		  incl_entry->totals = t;
5103218822Sdim		}
5104218822Sdim	      else
5105218822Sdim		{
5106218822Sdim		  int *incl_map;
5107218822Sdim
5108218822Sdim		  /* This is a duplicate header file.  We must change
5109218822Sdim                     it to be an N_EXCL entry, and mark all the
5110218822Sdim                     included symbols to prevent outputting them.  */
5111218822Sdim		  type = (int) N_EXCL;
5112218822Sdim
5113218822Sdim		  nest = 0;
5114218822Sdim		  for (incl_sym = sym + 1, incl_map = symbol_map + 1;
5115218822Sdim		       incl_sym < sym_end;
5116218822Sdim		       incl_sym++, incl_map++)
5117218822Sdim		    {
5118218822Sdim		      int incl_type;
5119218822Sdim
5120218822Sdim		      incl_type = H_GET_8 (input_bfd, incl_sym->e_type);
5121218822Sdim		      if (incl_type == (int) N_EINCL)
5122218822Sdim			{
5123218822Sdim			  if (nest == 0)
5124218822Sdim			    {
5125218822Sdim			      *incl_map = -1;
5126218822Sdim			      break;
5127218822Sdim			    }
5128218822Sdim			  --nest;
5129218822Sdim			}
5130218822Sdim		      else if (incl_type == (int) N_BINCL)
5131218822Sdim			++nest;
5132218822Sdim		      else if (nest == 0)
5133218822Sdim			*incl_map = -1;
5134218822Sdim		    }
5135218822Sdim		}
5136218822Sdim	    }
513733965Sjdp	}
5138218822Sdim
5139218822Sdim      /* Copy this symbol into the list of symbols we are going to
5140218822Sdim	 write out.  */
5141218822Sdim      H_PUT_8 (output_bfd, type, outsym->e_type);
5142218822Sdim      H_PUT_8 (output_bfd, H_GET_8 (input_bfd, sym->e_other), outsym->e_other);
5143218822Sdim      H_PUT_16 (output_bfd, H_GET_16 (input_bfd, sym->e_desc), outsym->e_desc);
5144218822Sdim      copy = FALSE;
5145218822Sdim      if (! finfo->info->keep_memory)
5146218822Sdim	{
5147218822Sdim	  /* name points into a string table which we are going to
5148218822Sdim	     free.  If there is a hash table entry, use that string.
5149218822Sdim	     Otherwise, copy name into memory.  */
5150218822Sdim	  if (h != NULL)
5151218822Sdim	    name = h->root.root.string;
5152218822Sdim	  else
5153218822Sdim	    copy = TRUE;
5154218822Sdim	}
5155218822Sdim      strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
5156218822Sdim				       name, copy);
5157218822Sdim      if (strtab_index == (bfd_size_type) -1)
5158218822Sdim	return FALSE;
5159218822Sdim      PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
5160218822Sdim      PUT_WORD (output_bfd, val, outsym->e_value);
5161218822Sdim      *symbol_map = obj_aout_external_sym_count (output_bfd);
5162218822Sdim      ++obj_aout_external_sym_count (output_bfd);
5163218822Sdim      ++outsym;
516433965Sjdp    }
516533965Sjdp
5166218822Sdim  /* Write out the output symbols we have just constructed.  */
5167218822Sdim  if (outsym > finfo->output_syms)
516833965Sjdp    {
5169218822Sdim      bfd_size_type outsym_size;
5170218822Sdim
5171218822Sdim      if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0)
5172218822Sdim	return FALSE;
5173218822Sdim      outsym_size = outsym - finfo->output_syms;
5174218822Sdim      outsym_size *= EXTERNAL_NLIST_SIZE;
5175218822Sdim      if (bfd_bwrite ((void *) finfo->output_syms, outsym_size, output_bfd)
5176218822Sdim	  != outsym_size)
5177218822Sdim	return FALSE;
5178218822Sdim      finfo->symoff += outsym_size;
517933965Sjdp    }
518033965Sjdp
5181218822Sdim  return TRUE;
5182218822Sdim}
518333965Sjdp
5184218822Sdim/* Link an a.out input BFD into the output file.  */
5185218822Sdim
5186218822Sdimstatic bfd_boolean
5187218822Sdimaout_link_input_bfd (struct aout_final_link_info *finfo, bfd *input_bfd)
5188218822Sdim{
5189218822Sdim  bfd_size_type sym_count;
5190218822Sdim
5191218822Sdim  BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object);
5192218822Sdim
5193218822Sdim  /* If this is a dynamic object, it may need special handling.  */
5194218822Sdim  if ((input_bfd->flags & DYNAMIC) != 0
5195218822Sdim      && aout_backend_info (input_bfd)->link_dynamic_object != NULL)
5196218822Sdim    return ((*aout_backend_info (input_bfd)->link_dynamic_object)
5197218822Sdim	    (finfo->info, input_bfd));
5198218822Sdim
5199218822Sdim  /* Get the symbols.  We probably have them already, unless
5200218822Sdim     finfo->info->keep_memory is FALSE.  */
5201218822Sdim  if (! aout_get_external_symbols (input_bfd))
5202218822Sdim    return FALSE;
5203218822Sdim
5204218822Sdim  sym_count = obj_aout_external_sym_count (input_bfd);
5205218822Sdim
5206218822Sdim  /* Write out the symbols and get a map of the new indices.  The map
5207218822Sdim     is placed into finfo->symbol_map.  */
5208218822Sdim  if (! aout_link_write_symbols (finfo, input_bfd))
5209218822Sdim    return FALSE;
5210218822Sdim
5211218822Sdim  /* Relocate and write out the sections.  These functions use the
5212218822Sdim     symbol map created by aout_link_write_symbols.  The linker_mark
5213218822Sdim     field will be set if these sections are to be included in the
5214218822Sdim     link, which will normally be the case.  */
5215218822Sdim  if (obj_textsec (input_bfd)->linker_mark)
521633965Sjdp    {
5217218822Sdim      if (! aout_link_input_section (finfo, input_bfd,
5218218822Sdim				     obj_textsec (input_bfd),
5219218822Sdim				     &finfo->treloff,
5220218822Sdim				     exec_hdr (input_bfd)->a_trsize))
5221218822Sdim	return FALSE;
5222218822Sdim    }
5223218822Sdim  if (obj_datasec (input_bfd)->linker_mark)
5224218822Sdim    {
5225218822Sdim      if (! aout_link_input_section (finfo, input_bfd,
5226218822Sdim				     obj_datasec (input_bfd),
5227218822Sdim				     &finfo->dreloff,
5228218822Sdim				     exec_hdr (input_bfd)->a_drsize))
5229218822Sdim	return FALSE;
5230218822Sdim    }
523133965Sjdp
5232218822Sdim  /* If we are not keeping memory, we don't need the symbols any
5233218822Sdim     longer.  We still need them if we are keeping memory, because the
5234218822Sdim     strings in the hash table point into them.  */
5235218822Sdim  if (! finfo->info->keep_memory)
5236218822Sdim    {
5237218822Sdim      if (! aout_link_free_symbols (input_bfd))
5238218822Sdim	return FALSE;
5239218822Sdim    }
524033965Sjdp
5241218822Sdim  return TRUE;
5242218822Sdim}
524333965Sjdp
5244218822Sdim/* Do the final link step.  This is called on the output BFD.  The
5245218822Sdim   INFO structure should point to a list of BFDs linked through the
5246218822Sdim   link_next field which can be used to find each BFD which takes part
5247218822Sdim   in the output.  Also, each section in ABFD should point to a list
5248218822Sdim   of bfd_link_order structures which list all the input sections for
5249218822Sdim   the output section.  */
5250218822Sdim
5251218822Sdimbfd_boolean
5252218822SdimNAME (aout, final_link) (bfd *abfd,
5253218822Sdim			 struct bfd_link_info *info,
5254218822Sdim			 void (*callback) (bfd *, file_ptr *, file_ptr *, file_ptr *))
5255218822Sdim{
5256218822Sdim  struct aout_final_link_info aout_info;
5257218822Sdim  bfd_boolean includes_hash_initialized = FALSE;
5258218822Sdim  bfd *sub;
5259218822Sdim  bfd_size_type trsize, drsize;
5260218822Sdim  bfd_size_type max_contents_size;
5261218822Sdim  bfd_size_type max_relocs_size;
5262218822Sdim  bfd_size_type max_sym_count;
5263218822Sdim  bfd_size_type text_size;
5264218822Sdim  file_ptr text_end;
5265218822Sdim  struct bfd_link_order *p;
5266218822Sdim  asection *o;
5267218822Sdim  bfd_boolean have_link_order_relocs;
5268218822Sdim
5269218822Sdim  if (info->shared)
5270218822Sdim    abfd->flags |= DYNAMIC;
5271218822Sdim
5272218822Sdim  aout_info.info = info;
5273218822Sdim  aout_info.output_bfd = abfd;
5274218822Sdim  aout_info.contents = NULL;
5275218822Sdim  aout_info.relocs = NULL;
5276218822Sdim  aout_info.symbol_map = NULL;
5277218822Sdim  aout_info.output_syms = NULL;
5278218822Sdim
5279218822Sdim  if (!bfd_hash_table_init_n (&aout_info.includes.root,
5280218822Sdim			      aout_link_includes_newfunc,
5281218822Sdim			      sizeof (struct aout_link_includes_entry),
5282218822Sdim			      251))
5283218822Sdim    goto error_return;
5284218822Sdim  includes_hash_initialized = TRUE;
5285218822Sdim
5286218822Sdim  /* Figure out the largest section size.  Also, if generating
5287218822Sdim     relocatable output, count the relocs.  */
5288218822Sdim  trsize = 0;
5289218822Sdim  drsize = 0;
5290218822Sdim  max_contents_size = 0;
5291218822Sdim  max_relocs_size = 0;
5292218822Sdim  max_sym_count = 0;
5293218822Sdim  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
5294218822Sdim    {
5295218822Sdim      bfd_size_type sz;
5296218822Sdim
5297218822Sdim      if (info->relocatable)
529833965Sjdp	{
5299218822Sdim	  if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
5300218822Sdim	    {
5301218822Sdim	      trsize += exec_hdr (sub)->a_trsize;
5302218822Sdim	      drsize += exec_hdr (sub)->a_drsize;
5303218822Sdim	    }
5304218822Sdim	  else
5305218822Sdim	    {
5306218822Sdim	      /* FIXME: We need to identify the .text and .data sections
5307218822Sdim		 and call get_reloc_upper_bound and canonicalize_reloc to
5308218822Sdim		 work out the number of relocs needed, and then multiply
5309218822Sdim		 by the reloc size.  */
5310218822Sdim	      (*_bfd_error_handler)
5311218822Sdim		(_("%s: relocatable link from %s to %s not supported"),
5312218822Sdim		 bfd_get_filename (abfd),
5313218822Sdim		 sub->xvec->name, abfd->xvec->name);
5314218822Sdim	      bfd_set_error (bfd_error_invalid_operation);
5315218822Sdim	      goto error_return;
5316218822Sdim	    }
5317218822Sdim	}
531833965Sjdp
5319218822Sdim      if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
5320218822Sdim	{
5321218822Sdim	  sz = obj_textsec (sub)->size;
5322218822Sdim	  if (sz > max_contents_size)
5323218822Sdim	    max_contents_size = sz;
5324218822Sdim	  sz = obj_datasec (sub)->size;
5325218822Sdim	  if (sz > max_contents_size)
5326218822Sdim	    max_contents_size = sz;
5327218822Sdim
5328218822Sdim	  sz = exec_hdr (sub)->a_trsize;
5329218822Sdim	  if (sz > max_relocs_size)
5330218822Sdim	    max_relocs_size = sz;
5331218822Sdim	  sz = exec_hdr (sub)->a_drsize;
5332218822Sdim	  if (sz > max_relocs_size)
5333218822Sdim	    max_relocs_size = sz;
5334218822Sdim
5335218822Sdim	  sz = obj_aout_external_sym_count (sub);
5336218822Sdim	  if (sz > max_sym_count)
5337218822Sdim	    max_sym_count = sz;
5338218822Sdim	}
5339218822Sdim    }
5340218822Sdim
5341218822Sdim  if (info->relocatable)
5342218822Sdim    {
5343218822Sdim      if (obj_textsec (abfd) != NULL)
5344218822Sdim	trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd)
5345218822Sdim						 ->map_head.link_order)
5346218822Sdim		   * obj_reloc_entry_size (abfd));
5347218822Sdim      if (obj_datasec (abfd) != NULL)
5348218822Sdim	drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd)
5349218822Sdim						 ->map_head.link_order)
5350218822Sdim		   * obj_reloc_entry_size (abfd));
5351218822Sdim    }
5352218822Sdim
5353218822Sdim  exec_hdr (abfd)->a_trsize = trsize;
5354218822Sdim  exec_hdr (abfd)->a_drsize = drsize;
5355218822Sdim
5356218822Sdim  exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
5357218822Sdim
5358218822Sdim  /* Adjust the section sizes and vmas according to the magic number.
5359218822Sdim     This sets a_text, a_data and a_bss in the exec_hdr and sets the
5360218822Sdim     filepos for each section.  */
5361218822Sdim  if (! NAME (aout, adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
5362218822Sdim    goto error_return;
5363218822Sdim
5364218822Sdim  /* The relocation and symbol file positions differ among a.out
5365218822Sdim     targets.  We are passed a callback routine from the backend
5366218822Sdim     specific code to handle this.
5367218822Sdim     FIXME: At this point we do not know how much space the symbol
5368218822Sdim     table will require.  This will not work for any (nonstandard)
5369218822Sdim     a.out target that needs to know the symbol table size before it
5370218822Sdim     can compute the relocation file positions.  This may or may not
5371218822Sdim     be the case for the hp300hpux target, for example.  */
5372218822Sdim  (*callback) (abfd, &aout_info.treloff, &aout_info.dreloff,
5373218822Sdim	       &aout_info.symoff);
5374218822Sdim  obj_textsec (abfd)->rel_filepos = aout_info.treloff;
5375218822Sdim  obj_datasec (abfd)->rel_filepos = aout_info.dreloff;
5376218822Sdim  obj_sym_filepos (abfd) = aout_info.symoff;
5377218822Sdim
5378218822Sdim  /* We keep a count of the symbols as we output them.  */
5379218822Sdim  obj_aout_external_sym_count (abfd) = 0;
5380218822Sdim
5381218822Sdim  /* We accumulate the string table as we write out the symbols.  */
5382218822Sdim  aout_info.strtab = _bfd_stringtab_init ();
5383218822Sdim  if (aout_info.strtab == NULL)
5384218822Sdim    goto error_return;
5385218822Sdim
5386218822Sdim  /* Allocate buffers to hold section contents and relocs.  */
5387218822Sdim  aout_info.contents = bfd_malloc (max_contents_size);
5388218822Sdim  aout_info.relocs = bfd_malloc (max_relocs_size);
5389218822Sdim  aout_info.symbol_map = bfd_malloc (max_sym_count * sizeof (int *));
5390218822Sdim  aout_info.output_syms = bfd_malloc ((max_sym_count + 1)
5391218822Sdim				      * sizeof (struct external_nlist));
5392218822Sdim  if ((aout_info.contents == NULL && max_contents_size != 0)
5393218822Sdim      || (aout_info.relocs == NULL && max_relocs_size != 0)
5394218822Sdim      || (aout_info.symbol_map == NULL && max_sym_count != 0)
5395218822Sdim      || aout_info.output_syms == NULL)
5396218822Sdim    goto error_return;
5397218822Sdim
5398218822Sdim  /* If we have a symbol named __DYNAMIC, force it out now.  This is
5399218822Sdim     required by SunOS.  Doing this here rather than in sunos.c is a
5400218822Sdim     hack, but it's easier than exporting everything which would be
5401218822Sdim     needed.  */
5402218822Sdim  {
5403218822Sdim    struct aout_link_hash_entry *h;
5404218822Sdim
5405218822Sdim    h = aout_link_hash_lookup (aout_hash_table (info), "__DYNAMIC",
5406218822Sdim			       FALSE, FALSE, FALSE);
5407218822Sdim    if (h != NULL)
5408218822Sdim      aout_link_write_other_symbol (h, &aout_info);
5409218822Sdim  }
5410218822Sdim
5411218822Sdim  /* The most time efficient way to do the link would be to read all
5412218822Sdim     the input object files into memory and then sort out the
5413218822Sdim     information into the output file.  Unfortunately, that will
5414218822Sdim     probably use too much memory.  Another method would be to step
5415218822Sdim     through everything that composes the text section and write it
5416218822Sdim     out, and then everything that composes the data section and write
5417218822Sdim     it out, and then write out the relocs, and then write out the
5418218822Sdim     symbols.  Unfortunately, that requires reading stuff from each
5419218822Sdim     input file several times, and we will not be able to keep all the
5420218822Sdim     input files open simultaneously, and reopening them will be slow.
5421218822Sdim
5422218822Sdim     What we do is basically process one input file at a time.  We do
5423218822Sdim     everything we need to do with an input file once--copy over the
5424218822Sdim     section contents, handle the relocation information, and write
5425218822Sdim     out the symbols--and then we throw away the information we read
5426218822Sdim     from it.  This approach requires a lot of lseeks of the output
5427218822Sdim     file, which is unfortunate but still faster than reopening a lot
5428218822Sdim     of files.
5429218822Sdim
5430218822Sdim     We use the output_has_begun field of the input BFDs to see
5431218822Sdim     whether we have already handled it.  */
5432218822Sdim  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
5433218822Sdim    sub->output_has_begun = FALSE;
5434218822Sdim
5435218822Sdim  /* Mark all sections which are to be included in the link.  This
5436218822Sdim     will normally be every section.  We need to do this so that we
5437218822Sdim     can identify any sections which the linker has decided to not
5438218822Sdim     include.  */
5439218822Sdim  for (o = abfd->sections; o != NULL; o = o->next)
5440218822Sdim    {
5441218822Sdim      for (p = o->map_head.link_order; p != NULL; p = p->next)
5442218822Sdim	if (p->type == bfd_indirect_link_order)
5443218822Sdim	  p->u.indirect.section->linker_mark = TRUE;
5444218822Sdim    }
5445218822Sdim
5446218822Sdim  have_link_order_relocs = FALSE;
5447218822Sdim  for (o = abfd->sections; o != NULL; o = o->next)
5448218822Sdim    {
5449218822Sdim      for (p = o->map_head.link_order;
5450218822Sdim	   p != NULL;
5451218822Sdim	   p = p->next)
5452218822Sdim	{
5453218822Sdim	  if (p->type == bfd_indirect_link_order
5454218822Sdim	      && (bfd_get_flavour (p->u.indirect.section->owner)
5455218822Sdim		  == bfd_target_aout_flavour))
545633965Sjdp	    {
5457218822Sdim	      bfd *input_bfd;
5458218822Sdim
5459218822Sdim	      input_bfd = p->u.indirect.section->owner;
5460218822Sdim	      if (! input_bfd->output_has_begun)
546133965Sjdp		{
5462218822Sdim		  if (! aout_link_input_bfd (&aout_info, input_bfd))
5463218822Sdim		    goto error_return;
5464218822Sdim		  input_bfd->output_has_begun = TRUE;
546533965Sjdp		}
546633965Sjdp	    }
5467218822Sdim	  else if (p->type == bfd_section_reloc_link_order
5468218822Sdim		   || p->type == bfd_symbol_reloc_link_order)
5469218822Sdim	    {
5470218822Sdim	      /* These are handled below.  */
5471218822Sdim	      have_link_order_relocs = TRUE;
5472218822Sdim	    }
5473218822Sdim	  else
5474218822Sdim	    {
5475218822Sdim	      if (! _bfd_default_link_order (abfd, info, o, p))
5476218822Sdim		goto error_return;
5477218822Sdim	    }
547833965Sjdp	}
547933965Sjdp    }
5480218822Sdim
5481218822Sdim  /* Write out any symbols that we have not already written out.  */
5482218822Sdim  aout_link_hash_traverse (aout_hash_table (info),
5483218822Sdim			   aout_link_write_other_symbol,
5484218822Sdim			   (void *) &aout_info);
5485218822Sdim
5486218822Sdim  /* Now handle any relocs we were asked to create by the linker.
5487218822Sdim     These did not come from any input file.  We must do these after
5488218822Sdim     we have written out all the symbols, so that we know the symbol
5489218822Sdim     indices to use.  */
5490218822Sdim  if (have_link_order_relocs)
549133965Sjdp    {
5492218822Sdim      for (o = abfd->sections; o != NULL; o = o->next)
549333965Sjdp	{
5494218822Sdim	  for (p = o->map_head.link_order;
5495218822Sdim	       p != NULL;
5496218822Sdim	       p = p->next)
5497218822Sdim	    {
5498218822Sdim	      if (p->type == bfd_section_reloc_link_order
5499218822Sdim		  || p->type == bfd_symbol_reloc_link_order)
5500218822Sdim		{
5501218822Sdim		  if (! aout_link_reloc_link_order (&aout_info, o, p))
5502218822Sdim		    goto error_return;
5503218822Sdim		}
5504218822Sdim	    }
550533965Sjdp	}
5506218822Sdim    }
550733965Sjdp
5508218822Sdim  if (aout_info.contents != NULL)
5509218822Sdim    {
5510218822Sdim      free (aout_info.contents);
5511218822Sdim      aout_info.contents = NULL;
5512218822Sdim    }
5513218822Sdim  if (aout_info.relocs != NULL)
5514218822Sdim    {
5515218822Sdim      free (aout_info.relocs);
5516218822Sdim      aout_info.relocs = NULL;
5517218822Sdim    }
5518218822Sdim  if (aout_info.symbol_map != NULL)
5519218822Sdim    {
5520218822Sdim      free (aout_info.symbol_map);
5521218822Sdim      aout_info.symbol_map = NULL;
5522218822Sdim    }
5523218822Sdim  if (aout_info.output_syms != NULL)
5524218822Sdim    {
5525218822Sdim      free (aout_info.output_syms);
5526218822Sdim      aout_info.output_syms = NULL;
5527218822Sdim    }
5528218822Sdim  if (includes_hash_initialized)
5529218822Sdim    {
5530218822Sdim      bfd_hash_table_free (&aout_info.includes.root);
5531218822Sdim      includes_hash_initialized = FALSE;
5532218822Sdim    }
553333965Sjdp
5534218822Sdim  /* Finish up any dynamic linking we may be doing.  */
5535218822Sdim  if (aout_backend_info (abfd)->finish_dynamic_link != NULL)
5536218822Sdim    {
5537218822Sdim      if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info))
5538218822Sdim	goto error_return;
553933965Sjdp    }
554033965Sjdp
5541218822Sdim  /* Update the header information.  */
5542218822Sdim  abfd->symcount = obj_aout_external_sym_count (abfd);
5543218822Sdim  exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE;
5544218822Sdim  obj_str_filepos (abfd) = obj_sym_filepos (abfd) + exec_hdr (abfd)->a_syms;
5545218822Sdim  obj_textsec (abfd)->reloc_count =
5546218822Sdim    exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd);
5547218822Sdim  obj_datasec (abfd)->reloc_count =
5548218822Sdim    exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd);
554933965Sjdp
5550218822Sdim  /* Write out the string table, unless there are no symbols.  */
5551218822Sdim  if (abfd->symcount > 0)
5552218822Sdim    {
5553218822Sdim      if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
5554218822Sdim	  || ! emit_stringtab (abfd, aout_info.strtab))
5555218822Sdim	goto error_return;
5556218822Sdim    }
5557218822Sdim  else if (obj_textsec (abfd)->reloc_count == 0
5558218822Sdim	   && obj_datasec (abfd)->reloc_count == 0)
5559218822Sdim    {
5560218822Sdim      bfd_byte b;
5561218822Sdim      file_ptr pos;
556233965Sjdp
5563218822Sdim      b = 0;
5564218822Sdim      pos = obj_datasec (abfd)->filepos + exec_hdr (abfd)->a_data - 1;
5565218822Sdim      if (bfd_seek (abfd, pos, SEEK_SET) != 0
5566218822Sdim	  || bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
5567218822Sdim	goto error_return;
5568218822Sdim    }
556933965Sjdp
5570130561Sobrien  return TRUE;
5571218822Sdim
5572218822Sdim error_return:
5573218822Sdim  if (aout_info.contents != NULL)
5574218822Sdim    free (aout_info.contents);
5575218822Sdim  if (aout_info.relocs != NULL)
5576218822Sdim    free (aout_info.relocs);
5577218822Sdim  if (aout_info.symbol_map != NULL)
5578218822Sdim    free (aout_info.symbol_map);
5579218822Sdim  if (aout_info.output_syms != NULL)
5580218822Sdim    free (aout_info.output_syms);
5581218822Sdim  if (includes_hash_initialized)
5582218822Sdim    bfd_hash_table_free (&aout_info.includes.root);
5583218822Sdim  return FALSE;
558433965Sjdp}
5585