#define KEEPIT udata.i
#include "bfd.h"
#include "sysdep.h"
#include "safe-ctype.h"
#include "bfdlink.h"
#include "libaout.h"
#include "libbfd.h"
#include "aout/aout64.h"
#include "aout/stab_gnu.h"
#include "aout/ar.h"
reloc_howto_type * NAME (aout, reloc_type_lookup) (bfd *, bfd_reloc_code_real_type);
#ifndef CTOR_TABLE_RELOC_HOWTO
#define CTOR_TABLE_RELOC_IDX 2
#define CTOR_TABLE_RELOC_HOWTO(BFD) \
((obj_reloc_entry_size (BFD) == RELOC_EXT_SIZE \
? howto_table_ext : howto_table_std) \
+ CTOR_TABLE_RELOC_IDX)
#endif
#ifndef MY_swap_std_reloc_in
#define MY_swap_std_reloc_in NAME (aout, swap_std_reloc_in)
#endif
#ifndef MY_swap_ext_reloc_in
#define MY_swap_ext_reloc_in NAME (aout, swap_ext_reloc_in)
#endif
#ifndef MY_swap_std_reloc_out
#define MY_swap_std_reloc_out NAME (aout, swap_std_reloc_out)
#endif
#ifndef MY_swap_ext_reloc_out
#define MY_swap_ext_reloc_out NAME (aout, swap_ext_reloc_out)
#endif
#ifndef MY_final_link_relocate
#define MY_final_link_relocate _bfd_final_link_relocate
#endif
#ifndef MY_relocate_contents
#define MY_relocate_contents _bfd_relocate_contents
#endif
#define howto_table_ext NAME (aout, ext_howto_table)
#define howto_table_std NAME (aout, std_howto_table)
reloc_howto_type howto_table_ext[] =
{
HOWTO (RELOC_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "8", FALSE, 0, 0x000000ff, FALSE),
HOWTO (RELOC_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "16", FALSE, 0, 0x0000ffff, FALSE),
HOWTO (RELOC_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "32", FALSE, 0, 0xffffffff, FALSE),
HOWTO (RELOC_DISP8, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "DISP8", FALSE, 0, 0x000000ff, FALSE),
HOWTO (RELOC_DISP16, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "DISP16", FALSE, 0, 0x0000ffff, FALSE),
HOWTO (RELOC_DISP32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "DISP32", FALSE, 0, 0xffffffff, FALSE),
HOWTO (RELOC_WDISP30, 2, 2, 30, TRUE, 0, complain_overflow_signed, 0, "WDISP30", FALSE, 0, 0x3fffffff, FALSE),
HOWTO (RELOC_WDISP22, 2, 2, 22, TRUE, 0, complain_overflow_signed, 0, "WDISP22", FALSE, 0, 0x003fffff, FALSE),
HOWTO (RELOC_HI22, 10, 2, 22, FALSE, 0, complain_overflow_bitfield, 0, "HI22", FALSE, 0, 0x003fffff, FALSE),
HOWTO (RELOC_22, 0, 2, 22, FALSE, 0, complain_overflow_bitfield, 0, "22", FALSE, 0, 0x003fffff, FALSE),
HOWTO (RELOC_13, 0, 2, 13, FALSE, 0, complain_overflow_bitfield, 0, "13", FALSE, 0, 0x00001fff, FALSE),
HOWTO (RELOC_LO10, 0, 2, 10, FALSE, 0, complain_overflow_dont, 0, "LO10", FALSE, 0, 0x000003ff, FALSE),
HOWTO (RELOC_SFA_BASE,0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "SFA_BASE", FALSE, 0, 0xffffffff, FALSE),
HOWTO (RELOC_SFA_OFF13,0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "SFA_OFF13", FALSE, 0, 0xffffffff, FALSE),
HOWTO (RELOC_BASE10, 0, 2, 10, FALSE, 0, complain_overflow_dont, 0, "BASE10", FALSE, 0, 0x000003ff, FALSE),
HOWTO (RELOC_BASE13, 0, 2, 13, FALSE, 0, complain_overflow_signed, 0, "BASE13", FALSE, 0, 0x00001fff, FALSE),
HOWTO (RELOC_BASE22, 10, 2, 22, FALSE, 0, complain_overflow_bitfield, 0, "BASE22", FALSE, 0, 0x003fffff, FALSE),
HOWTO (RELOC_PC10, 0, 2, 10, TRUE, 0, complain_overflow_dont, 0, "PC10", FALSE, 0, 0x000003ff, TRUE),
HOWTO (RELOC_PC22, 10, 2, 22, TRUE, 0, complain_overflow_signed, 0, "PC22", FALSE, 0, 0x003fffff, TRUE),
HOWTO (RELOC_JMP_TBL, 2, 2, 30, TRUE, 0, complain_overflow_signed, 0, "JMP_TBL", FALSE, 0, 0x3fffffff, FALSE),
HOWTO (RELOC_SEGOFF16,0, 2, 0, FALSE, 0, complain_overflow_bitfield, 0, "SEGOFF16", FALSE, 0, 0x00000000, FALSE),
HOWTO (RELOC_GLOB_DAT,0, 2, 0, FALSE, 0, complain_overflow_bitfield, 0, "GLOB_DAT", FALSE, 0, 0x00000000, FALSE),
HOWTO (RELOC_JMP_SLOT,0, 2, 0, FALSE, 0, complain_overflow_bitfield, 0, "JMP_SLOT", FALSE, 0, 0x00000000, FALSE),
HOWTO (RELOC_RELATIVE,0, 2, 0, FALSE, 0, complain_overflow_bitfield, 0, "RELATIVE", FALSE, 0, 0x00000000, FALSE),
HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, 0, "R_SPARC_NONE",FALSE, 0, 0x00000000, TRUE),
HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, 0, "R_SPARC_NONE",FALSE, 0, 0x00000000, TRUE),
#define RELOC_SPARC_REV32 RELOC_WDISP19
HOWTO (RELOC_SPARC_REV32, 0, 2, 32, FALSE, 0, complain_overflow_dont, 0,"R_SPARC_REV32",FALSE, 0, 0xffffffff, FALSE),
};
reloc_howto_type howto_table_std[] =
{
HOWTO ( 0, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,0,"8", TRUE, 0x000000ff,0x000000ff, FALSE),
HOWTO ( 1, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,0,"16", TRUE, 0x0000ffff,0x0000ffff, FALSE),
HOWTO ( 2, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,0,"32", TRUE, 0xffffffff,0xffffffff, FALSE),
HOWTO ( 3, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,0,"64", TRUE, 0xdeaddead,0xdeaddead, FALSE),
HOWTO ( 4, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0,"DISP8", TRUE, 0x000000ff,0x000000ff, FALSE),
HOWTO ( 5, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0,"DISP16", TRUE, 0x0000ffff,0x0000ffff, FALSE),
HOWTO ( 6, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0,"DISP32", TRUE, 0xffffffff,0xffffffff, FALSE),
HOWTO ( 7, 0, 4, 64, TRUE, 0, complain_overflow_signed, 0,"DISP64", TRUE, 0xfeedface,0xfeedface, FALSE),
HOWTO ( 8, 0, 2, 0, FALSE, 0, complain_overflow_bitfield,0,"GOT_REL", FALSE, 0,0x00000000, FALSE),
HOWTO ( 9, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,0,"BASE16", FALSE,0xffffffff,0xffffffff, FALSE),
HOWTO (10, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,0,"BASE32", FALSE,0xffffffff,0xffffffff, FALSE),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
HOWTO (16, 0, 2, 0, FALSE, 0, complain_overflow_bitfield,0,"JMP_TABLE", FALSE, 0,0x00000000, FALSE),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
HOWTO (32, 0, 2, 0, FALSE, 0, complain_overflow_bitfield,0,"RELATIVE", FALSE, 0,0x00000000, FALSE),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
EMPTY_HOWTO (-1),
HOWTO (40, 0, 2, 0, FALSE, 0, complain_overflow_bitfield,0,"BASEREL", FALSE, 0,0x00000000, FALSE),
};
#define TABLE_SIZE(TABLE) (sizeof (TABLE) / sizeof (TABLE[0]))
reloc_howto_type *
NAME (aout, reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code)
{
#define EXT(i, j) case i: return & howto_table_ext [j]
#define STD(i, j) case i: return & howto_table_std [j]
int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE;
if (code == BFD_RELOC_CTOR)
switch (bfd_get_arch_info (abfd)->bits_per_address)
{
case 32:
code = BFD_RELOC_32;
break;
case 64:
code = BFD_RELOC_64;
break;
}
if (ext)
switch (code)
{
EXT (BFD_RELOC_8, 0);
EXT (BFD_RELOC_16, 1);
EXT (BFD_RELOC_32, 2);
EXT (BFD_RELOC_HI22, 8);
EXT (BFD_RELOC_LO10, 11);
EXT (BFD_RELOC_32_PCREL_S2, 6);
EXT (BFD_RELOC_SPARC_WDISP22, 7);
EXT (BFD_RELOC_SPARC13, 10);
EXT (BFD_RELOC_SPARC_GOT10, 14);
EXT (BFD_RELOC_SPARC_BASE13, 15);
EXT (BFD_RELOC_SPARC_GOT13, 15);
EXT (BFD_RELOC_SPARC_GOT22, 16);
EXT (BFD_RELOC_SPARC_PC10, 17);
EXT (BFD_RELOC_SPARC_PC22, 18);
EXT (BFD_RELOC_SPARC_WPLT30, 19);
EXT (BFD_RELOC_SPARC_REV32, 26);
default:
return NULL;
}
else
switch (code)
{
STD (BFD_RELOC_8, 0);
STD (BFD_RELOC_16, 1);
STD (BFD_RELOC_32, 2);
STD (BFD_RELOC_8_PCREL, 4);
STD (BFD_RELOC_16_PCREL, 5);
STD (BFD_RELOC_32_PCREL, 6);
STD (BFD_RELOC_16_BASEREL, 9);
STD (BFD_RELOC_32_BASEREL, 10);
default:
return NULL;
}
}
#ifndef NAME_swap_exec_header_in
void
NAME (aout, swap_exec_header_in) (bfd *abfd,
struct external_exec *bytes,
struct internal_exec *execp)
{
memset ((void *) execp, 0, sizeof (struct internal_exec));
execp->a_info = H_GET_32 (abfd, bytes->e_info);
execp->a_text = GET_WORD (abfd, bytes->e_text);
execp->a_data = GET_WORD (abfd, bytes->e_data);
execp->a_bss = GET_WORD (abfd, bytes->e_bss);
execp->a_syms = GET_WORD (abfd, bytes->e_syms);
execp->a_entry = GET_WORD (abfd, bytes->e_entry);
execp->a_trsize = GET_WORD (abfd, bytes->e_trsize);
execp->a_drsize = GET_WORD (abfd, bytes->e_drsize);
}
#define NAME_swap_exec_header_in NAME (aout, swap_exec_header_in)
#endif
void
NAME (aout, swap_exec_header_out) (bfd *abfd,
struct internal_exec *execp,
struct external_exec *bytes)
{
H_PUT_32 (abfd, execp->a_info , bytes->e_info);
PUT_WORD (abfd, execp->a_text , bytes->e_text);
PUT_WORD (abfd, execp->a_data , bytes->e_data);
PUT_WORD (abfd, execp->a_bss , bytes->e_bss);
PUT_WORD (abfd, execp->a_syms , bytes->e_syms);
PUT_WORD (abfd, execp->a_entry , bytes->e_entry);
PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize);
PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize);
}
bfd_boolean
NAME (aout, make_sections) (bfd *abfd)
{
if (obj_textsec (abfd) == NULL && bfd_make_section (abfd, ".text") == NULL)
return FALSE;
if (obj_datasec (abfd) == NULL && bfd_make_section (abfd, ".data") == NULL)
return FALSE;
if (obj_bsssec (abfd) == NULL && bfd_make_section (abfd, ".bss") == NULL)
return FALSE;
return TRUE;
}
const bfd_target *
NAME (aout, some_aout_object_p) (bfd *abfd,
struct internal_exec *execp,
const bfd_target *(*callback_to_real_object_p) (bfd *))
{
struct aout_data_struct *rawptr, *oldrawptr;
const bfd_target *result;
bfd_size_type amt = sizeof (* rawptr);
rawptr = bfd_zalloc (abfd, amt);
if (rawptr == NULL)
return NULL;
oldrawptr = abfd->tdata.aout_data;
abfd->tdata.aout_data = rawptr;
if (oldrawptr != NULL)
*abfd->tdata.aout_data = *oldrawptr;
abfd->tdata.aout_data->a.hdr = &rawptr->e;
*(abfd->tdata.aout_data->a.hdr) = *execp;
execp = abfd->tdata.aout_data->a.hdr;
abfd->flags = BFD_NO_FLAGS;
if (execp->a_drsize || execp->a_trsize)
abfd->flags |= HAS_RELOC;
if (execp->a_syms)
abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS;
if (N_DYNAMIC (*execp))
abfd->flags |= DYNAMIC;
if (N_MAGIC (*execp) == ZMAGIC)
{
abfd->flags |= D_PAGED | WP_TEXT;
adata (abfd).magic = z_magic;
}
else if (N_MAGIC (*execp) == QMAGIC)
{
abfd->flags |= D_PAGED | WP_TEXT;
adata (abfd).magic = z_magic;
adata (abfd).subformat = q_magic_format;
}
else if (N_MAGIC (*execp) == NMAGIC)
{
abfd->flags |= WP_TEXT;
adata (abfd).magic = n_magic;
}
else if (N_MAGIC (*execp) == OMAGIC
|| N_MAGIC (*execp) == BMAGIC)
adata (abfd).magic = o_magic;
else
abort ();
bfd_get_start_address (abfd) = execp->a_entry;
obj_aout_symbols (abfd) = NULL;
bfd_get_symcount (abfd) = execp->a_syms / sizeof (struct external_nlist);
obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
obj_symbol_entry_size (abfd) = EXTERNAL_NLIST_SIZE;
#ifdef USE_MMAP
bfd_init_window (&obj_aout_sym_window (abfd));
bfd_init_window (&obj_aout_string_window (abfd));
#endif
obj_aout_external_syms (abfd) = NULL;
obj_aout_external_strings (abfd) = NULL;
obj_aout_sym_hashes (abfd) = NULL;
if (! NAME (aout, make_sections) (abfd))
goto error_ret;
obj_datasec (abfd)->size = execp->a_data;
obj_bsssec (abfd)->size = execp->a_bss;
obj_textsec (abfd)->flags =
(execp->a_trsize != 0
? (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_RELOC)
: (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS));
obj_datasec (abfd)->flags =
(execp->a_drsize != 0
? (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS | SEC_RELOC)
: (SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS));
obj_bsssec (abfd)->flags = SEC_ALLOC;
#ifdef THIS_IS_ONLY_DOCUMENTATION
struct exec *execp = exec_hdr (abfd);
obj_textsec (abfd)->size = N_TXTSIZE (*execp);
obj_textsec (abfd)->vma = N_TXTADDR (*execp);
obj_datasec (abfd)->vma = N_DATADDR (*execp);
obj_bsssec (abfd)->vma = N_BSSADDR (*execp);
obj_textsec (abfd)->filepos = N_TXTOFF (*execp);
obj_datasec (abfd)->filepos = N_DATOFF (*execp);
obj_textsec (abfd)->rel_filepos = N_TRELOFF (*execp);
obj_datasec (abfd)->rel_filepos = N_DRELOFF (*execp);
obj_str_filepos (abfd) = N_STROFF (*execp);
obj_sym_filepos (abfd) = N_SYMOFF (*execp);
switch (N_MACHTYPE (*exec_hdr (abfd)))
{
default:
abfd->obj_arch = bfd_arch_obscure;
break;
}
adata (abfd)->page_size = TARGET_PAGE_SIZE;
adata (abfd)->segment_size = SEGMENT_SIZE;
adata (abfd)->exec_bytes_size = EXEC_BYTES_SIZE;
return abfd->xvec;
#endif
result = (*callback_to_real_object_p) (abfd);
if (execp->a_entry != 0
|| (execp->a_entry >= obj_textsec (abfd)->vma
&& execp->a_entry < (obj_textsec (abfd)->vma
+ obj_textsec (abfd)->size)))
abfd->flags |= EXEC_P;
#ifdef STAT_FOR_EXEC
else
{
struct stat stat_buf;
if (abfd->iostream != NULL
&& (abfd->flags & BFD_IN_MEMORY) == 0
&& (fstat (fileno ((FILE *) (abfd->iostream)), &stat_buf) == 0)
&& ((stat_buf.st_mode & 0111) != 0))
abfd->flags |= EXEC_P;
}
#endif
if (result)
return result;
error_ret:
bfd_release (abfd, rawptr);
abfd->tdata.aout_data = oldrawptr;
return NULL;
}
bfd_boolean
NAME (aout, mkobject) (bfd *abfd)
{
struct aout_data_struct *rawptr;
bfd_size_type amt = sizeof (* rawptr);
bfd_set_error (bfd_error_system_call);
rawptr = bfd_zalloc (abfd, amt);
if (rawptr == NULL)
return FALSE;
abfd->tdata.aout_data = rawptr;
exec_hdr (abfd) = &(rawptr->e);
obj_textsec (abfd) = NULL;
obj_datasec (abfd) = NULL;
obj_bsssec (abfd) = NULL;
return TRUE;
}
enum machine_type
NAME (aout, machine_type) (enum bfd_architecture arch,
unsigned long machine,
bfd_boolean *unknown)
{
enum machine_type arch_flags;
arch_flags = M_UNKNOWN;
*unknown = TRUE;
switch (arch)
{
case bfd_arch_sparc:
if (machine == 0
|| machine == bfd_mach_sparc
|| machine == bfd_mach_sparc_sparclite
|| machine == bfd_mach_sparc_sparclite_le
|| machine == bfd_mach_sparc_v9)
arch_flags = M_SPARC;
else if (machine == bfd_mach_sparc_sparclet)
arch_flags = M_SPARCLET;
break;
case bfd_arch_m68k:
switch (machine)
{
case 0: arch_flags = M_68010; break;
case bfd_mach_m68000: arch_flags = M_UNKNOWN; *unknown = FALSE; break;
case bfd_mach_m68010: arch_flags = M_68010; break;
case bfd_mach_m68020: arch_flags = M_68020; break;
default: arch_flags = M_UNKNOWN; break;
}
break;
case bfd_arch_i386:
if (machine == 0
|| machine == bfd_mach_i386_i386
|| machine == bfd_mach_i386_i386_intel_syntax)
arch_flags = M_386;
break;
case bfd_arch_a29k:
if (machine == 0)
arch_flags = M_29K;
break;
case bfd_arch_arm:
if (machine == 0)
arch_flags = M_ARM;
break;
case bfd_arch_mips:
switch (machine)
{
case 0:
case bfd_mach_mips3000:
case bfd_mach_mips3900:
arch_flags = M_MIPS1;
break;
case bfd_mach_mips6000:
arch_flags = M_MIPS2;
break;
case bfd_mach_mips4000:
case bfd_mach_mips4010:
case bfd_mach_mips4100:
case bfd_mach_mips4300:
case bfd_mach_mips4400:
case bfd_mach_mips4600:
case bfd_mach_mips4650:
case bfd_mach_mips8000:
case bfd_mach_mips9000:
case bfd_mach_mips10000:
case bfd_mach_mips12000:
case bfd_mach_mips16:
case bfd_mach_mipsisa32:
case bfd_mach_mipsisa32r2:
case bfd_mach_mips5:
case bfd_mach_mipsisa64:
case bfd_mach_mipsisa64r2:
case bfd_mach_mips_sb1:
arch_flags = M_MIPS2;
break;
default:
arch_flags = M_UNKNOWN;
break;
}
break;
case bfd_arch_ns32k:
switch (machine)
{
case 0: arch_flags = M_NS32532; break;
case 32032: arch_flags = M_NS32032; break;
case 32532: arch_flags = M_NS32532; break;
default: arch_flags = M_UNKNOWN; break;
}
break;
case bfd_arch_vax:
*unknown = FALSE;
break;
case bfd_arch_cris:
if (machine == 0 || machine == 255)
arch_flags = M_CRIS;
break;
case bfd_arch_m88k:
*unknown = FALSE;
break;
default:
arch_flags = M_UNKNOWN;
}
if (arch_flags != M_UNKNOWN)
*unknown = FALSE;
return arch_flags;
}
bfd_boolean
NAME (aout, set_arch_mach) (bfd *abfd,
enum bfd_architecture arch,
unsigned long machine)
{
if (! bfd_default_set_arch_mach (abfd, arch, machine))
return FALSE;
if (arch != bfd_arch_unknown)
{
bfd_boolean unknown;
NAME (aout, machine_type) (arch, machine, &unknown);
if (unknown)
return FALSE;
}
switch (arch)
{
case bfd_arch_sparc:
case bfd_arch_a29k:
case bfd_arch_mips:
obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
break;
default:
obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
break;
}
return (*aout_backend_info (abfd)->set_sizes) (abfd);
}
static void
adjust_o_magic (bfd *abfd, struct internal_exec *execp)
{
file_ptr pos = adata (abfd).exec_bytes_size;
bfd_vma vma = 0;
int pad = 0;
obj_textsec (abfd)->filepos = pos;
if (!obj_textsec (abfd)->user_set_vma)
obj_textsec (abfd)->vma = vma;
else
vma = obj_textsec (abfd)->vma;
pos += obj_textsec (abfd)->size;
vma += obj_textsec (abfd)->size;
if (!obj_datasec (abfd)->user_set_vma)
{
obj_textsec (abfd)->size += pad;
pos += pad;
vma += pad;
obj_datasec (abfd)->vma = vma;
}
else
vma = obj_datasec (abfd)->vma;
obj_datasec (abfd)->filepos = pos;
pos += obj_datasec (abfd)->size;
vma += obj_datasec (abfd)->size;
if (!obj_bsssec (abfd)->user_set_vma)
{
obj_datasec (abfd)->size += pad;
pos += pad;
vma += pad;
obj_bsssec (abfd)->vma = vma;
}
else
{
pad = obj_bsssec (abfd)->vma - vma;
if (pad > 0)
{
obj_datasec (abfd)->size += pad;
pos += pad;
}
}
obj_bsssec (abfd)->filepos = pos;
execp->a_text = obj_textsec (abfd)->size;
execp->a_data = obj_datasec (abfd)->size;
execp->a_bss = obj_bsssec (abfd)->size;
N_SET_MAGIC (*execp, OMAGIC);
}
static void
adjust_z_magic (bfd *abfd, struct internal_exec *execp)
{
bfd_size_type data_pad, text_pad;
file_ptr text_end;
const struct aout_backend_data *abdp;
bfd_boolean ztih;
abdp = aout_backend_info (abfd);
ztih = (abdp != NULL
&& (abdp->text_includes_header
|| obj_aout_subformat (abfd) == q_magic_format));
obj_textsec (abfd)->filepos = (ztih
? adata (abfd).exec_bytes_size
: adata (abfd).zmagic_disk_block_size);
if (! obj_textsec (abfd)->user_set_vma)
{
obj_textsec (abfd)->vma = ((abfd->flags & HAS_RELOC)
? 0
: (ztih
? (abdp->default_text_vma
+ adata (abfd).exec_bytes_size)
: abdp->default_text_vma));
text_pad = 0;
}
else
{
if (ztih)
text_pad = ((obj_textsec (abfd)->filepos - obj_textsec (abfd)->vma)
& (adata (abfd).page_size - 1));
else
text_pad = ((- obj_textsec (abfd)->vma)
& (adata (abfd).page_size - 1));
}
if (ztih)
{
text_end = obj_textsec (abfd)->filepos + obj_textsec (abfd)->size;
text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
}
else
{
text_end = obj_textsec (abfd)->size;
text_pad += BFD_ALIGN (text_end, adata (abfd).page_size) - text_end;
text_end += obj_textsec (abfd)->filepos;
}
obj_textsec (abfd)->size += text_pad;
text_end += text_pad;
if (!obj_datasec (abfd)->user_set_vma)
{
bfd_vma vma;
vma = obj_textsec (abfd)->vma + obj_textsec (abfd)->size;
obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size);
}
if (abdp && abdp->zmagic_mapped_contiguous)
{
asection * text = obj_textsec (abfd);
asection * data = obj_datasec (abfd);
text_pad = data->vma - (text->vma + text->size);
if (text_pad > 0)
text->size += text_pad;
}
obj_datasec (abfd)->filepos = (obj_textsec (abfd)->filepos
+ obj_textsec (abfd)->size);
execp->a_text = obj_textsec (abfd)->size;
if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted)))
execp->a_text += adata (abfd).exec_bytes_size;
if (obj_aout_subformat (abfd) == q_magic_format)
N_SET_MAGIC (*execp, QMAGIC);
else
N_SET_MAGIC (*execp, ZMAGIC);
obj_datasec (abfd)->size
= align_power (obj_datasec (abfd)->size,
obj_bsssec (abfd)->alignment_power);
execp->a_data = BFD_ALIGN (obj_datasec (abfd)->size,
adata (abfd).page_size);
data_pad = execp->a_data - obj_datasec (abfd)->size;
if (!obj_bsssec (abfd)->user_set_vma)
obj_bsssec (abfd)->vma = (obj_datasec (abfd)->vma
+ obj_datasec (abfd)->size);
if (align_power (obj_bsssec (abfd)->vma, obj_bsssec (abfd)->alignment_power)
== obj_datasec (abfd)->vma + obj_datasec (abfd)->size)
execp->a_bss = (data_pad > obj_bsssec (abfd)->size
? 0 : obj_bsssec (abfd)->size - data_pad);
else
execp->a_bss = obj_bsssec (abfd)->size;
}
static void
adjust_n_magic (bfd *abfd, struct internal_exec *execp)
{
file_ptr pos = adata (abfd).exec_bytes_size;
bfd_vma vma = 0;
int pad;
obj_textsec (abfd)->filepos = pos;
if (!obj_textsec (abfd)->user_set_vma)
obj_textsec (abfd)->vma = vma;
else
vma = obj_textsec (abfd)->vma;
pos += obj_textsec (abfd)->size;
vma += obj_textsec (abfd)->size;
obj_datasec (abfd)->filepos = pos;
if (!obj_datasec (abfd)->user_set_vma)
obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size);
vma = obj_datasec (abfd)->vma;
vma += obj_datasec (abfd)->size;
pad = align_power (vma, obj_bsssec (abfd)->alignment_power) - vma;
obj_datasec (abfd)->size += pad;
pos += obj_datasec (abfd)->size;
if (!obj_bsssec (abfd)->user_set_vma)
obj_bsssec (abfd)->vma = vma;
else
vma = obj_bsssec (abfd)->vma;
execp->a_text = obj_textsec (abfd)->size;
execp->a_data = obj_datasec (abfd)->size;
execp->a_bss = obj_bsssec (abfd)->size;
N_SET_MAGIC (*execp, NMAGIC);
}
bfd_boolean
NAME (aout, adjust_sizes_and_vmas) (bfd *abfd,
bfd_size_type *text_size,
file_ptr *text_end ATTRIBUTE_UNUSED)
{
struct internal_exec *execp = exec_hdr (abfd);
if (! NAME (aout, make_sections) (abfd))
return FALSE;
if (adata (abfd).magic != undecided_magic)
return TRUE;
obj_textsec (abfd)->size =
align_power (obj_textsec (abfd)->size,
obj_textsec (abfd)->alignment_power);
*text_size = obj_textsec (abfd)->size;
if (abfd->flags & D_PAGED)
adata (abfd).magic = z_magic;
else if (abfd->flags & WP_TEXT)
adata (abfd).magic = n_magic;
else
adata (abfd).magic = o_magic;
#ifdef BFD_AOUT_DEBUG
#if __GNUC__ >= 2
fprintf (stderr, "%s text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x,%x>\n",
({ char *str;
switch (adata (abfd).magic)
{
case n_magic: str = "NMAGIC"; break;
case o_magic: str = "OMAGIC"; break;
case z_magic: str = "ZMAGIC"; break;
default: abort ();
}
str;
}),
obj_textsec (abfd)->vma, obj_textsec (abfd)->size,
obj_textsec (abfd)->alignment_power,
obj_datasec (abfd)->vma, obj_datasec (abfd)->size,
obj_datasec (abfd)->alignment_power,
obj_bsssec (abfd)->vma, obj_bsssec (abfd)->size,
obj_bsssec (abfd)->alignment_power);
#endif
#endif
switch (adata (abfd).magic)
{
case o_magic:
adjust_o_magic (abfd, execp);
break;
case z_magic:
adjust_z_magic (abfd, execp);
break;
case n_magic:
adjust_n_magic (abfd, execp);
break;
default:
abort ();
}
#ifdef BFD_AOUT_DEBUG
fprintf (stderr, " text=<%x,%x,%x> data=<%x,%x,%x> bss=<%x,%x>\n",
obj_textsec (abfd)->vma, obj_textsec (abfd)->size,
obj_textsec (abfd)->filepos,
obj_datasec (abfd)->vma, obj_datasec (abfd)->size,
obj_datasec (abfd)->filepos,
obj_bsssec (abfd)->vma, obj_bsssec (abfd)->size);
#endif
return TRUE;
}
bfd_boolean
NAME (aout, new_section_hook) (bfd *abfd, asection *newsect)
{
newsect->alignment_power = bfd_get_arch_info (abfd)->section_align_power;
if (bfd_get_format (abfd) == bfd_object)
{
if (obj_textsec (abfd) == NULL && !strcmp (newsect->name, ".text"))
{
obj_textsec (abfd)= newsect;
newsect->target_index = N_TEXT;
return TRUE;
}
if (obj_datasec (abfd) == NULL && !strcmp (newsect->name, ".data"))
{
obj_datasec (abfd) = newsect;
newsect->target_index = N_DATA;
return TRUE;
}
if (obj_bsssec (abfd) == NULL && !strcmp (newsect->name, ".bss"))
{
obj_bsssec (abfd) = newsect;
newsect->target_index = N_BSS;
return TRUE;
}
}
return TRUE;
}
bfd_boolean
NAME (aout, set_section_contents) (bfd *abfd,
sec_ptr section,
const void * location,
file_ptr offset,
bfd_size_type count)
{
file_ptr text_end;
bfd_size_type text_size;
if (! abfd->output_has_begun)
{
if (! NAME (aout, adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
return FALSE;
}
if (section == obj_bsssec (abfd))
{
bfd_set_error (bfd_error_no_contents);
return FALSE;
}
if (section != obj_textsec (abfd)
&& section != obj_datasec (abfd))
{
if (aout_section_merge_with_text_p (abfd, section))
section->filepos = obj_textsec (abfd)->filepos +
(section->vma - obj_textsec (abfd)->vma);
else
{
(*_bfd_error_handler)
(_("%s: can not represent section `%s' in a.out object file format"),
bfd_get_filename (abfd), bfd_get_section_name (abfd, section));
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
}
if (count != 0)
{
if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
|| bfd_bwrite (location, count, abfd) != count)
return FALSE;
}
return TRUE;
}
static bfd_boolean
aout_get_external_symbols (bfd *abfd)
{
if (obj_aout_external_syms (abfd) == NULL)
{
bfd_size_type count;
struct external_nlist *syms;
bfd_size_type amt;
count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE;
#ifdef USE_MMAP
if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd),
exec_hdr (abfd)->a_syms,
&obj_aout_sym_window (abfd), TRUE))
return FALSE;
syms = (struct external_nlist *) obj_aout_sym_window (abfd).data;
#else
syms = bfd_malloc (count * EXTERNAL_NLIST_SIZE);
if (syms == NULL && count != 0)
return FALSE;
amt = exec_hdr (abfd)->a_syms;
if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
|| bfd_bread (syms, amt, abfd) != amt)
{
free (syms);
return FALSE;
}
#endif
obj_aout_external_syms (abfd) = syms;
obj_aout_external_sym_count (abfd) = count;
}
if (obj_aout_external_strings (abfd) == NULL
&& exec_hdr (abfd)->a_syms != 0)
{
unsigned char string_chars[BYTES_IN_WORD];
bfd_size_type stringsize;
char *strings;
bfd_size_type amt = BYTES_IN_WORD;
if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
|| bfd_bread ((void *) string_chars, amt, abfd) != amt)
return FALSE;
stringsize = GET_WORD (abfd, string_chars);
#ifdef USE_MMAP
if (! bfd_get_file_window (abfd, obj_str_filepos (abfd), stringsize,
&obj_aout_string_window (abfd), TRUE))
return FALSE;
strings = (char *) obj_aout_string_window (abfd).data;
#else
strings = bfd_malloc (stringsize + 1);
if (strings == NULL)
return FALSE;
amt = stringsize - BYTES_IN_WORD;
if (bfd_bread (strings + BYTES_IN_WORD, amt, abfd) != amt)
{
free (strings);
return FALSE;
}
#endif
strings[0] = '\0';
strings[stringsize - 1] = 0;
obj_aout_external_strings (abfd) = strings;
obj_aout_external_string_size (abfd) = stringsize;
}
return TRUE;
}
static bfd_boolean
translate_from_native_sym_flags (bfd *abfd, aout_symbol_type *cache_ptr)
{
flagword visible;
if ((cache_ptr->type & N_STAB) != 0
|| cache_ptr->type == N_FN)
{
asection *sec;
cache_ptr->symbol.flags = BSF_DEBUGGING;
switch (cache_ptr->type & N_TYPE)
{
case N_TEXT:
case N_FN:
sec = obj_textsec (abfd);
break;
case N_DATA:
sec = obj_datasec (abfd);
break;
case N_BSS:
sec = obj_bsssec (abfd);
break;
default:
case N_ABS:
sec = bfd_abs_section_ptr;
break;
}
cache_ptr->symbol.section = sec;
cache_ptr->symbol.value -= sec->vma;
return TRUE;
}
if ((cache_ptr->type & N_EXT) == 0)
visible = BSF_LOCAL;
else
visible = BSF_GLOBAL;
switch (cache_ptr->type)
{
default:
case N_ABS: case N_ABS | N_EXT:
cache_ptr->symbol.section = bfd_abs_section_ptr;
cache_ptr->symbol.flags = visible;
break;
case N_UNDF | N_EXT:
if (cache_ptr->symbol.value != 0)
{
cache_ptr->symbol.flags = BSF_GLOBAL;
cache_ptr->symbol.section = bfd_com_section_ptr;
}
else
{
cache_ptr->symbol.flags = 0;
cache_ptr->symbol.section = bfd_und_section_ptr;
}
break;
case N_TEXT: case N_TEXT | N_EXT:
cache_ptr->symbol.section = obj_textsec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = visible;
break;
case N_SETV: case N_SETV | N_EXT:
case N_DATA: case N_DATA | N_EXT:
cache_ptr->symbol.section = obj_datasec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = visible;
break;
case N_BSS: case N_BSS | N_EXT:
cache_ptr->symbol.section = obj_bsssec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = visible;
break;
case N_SETA: case N_SETA | N_EXT:
case N_SETT: case N_SETT | N_EXT:
case N_SETD: case N_SETD | N_EXT:
case N_SETB: case N_SETB | N_EXT:
{
switch (cache_ptr->type & N_TYPE)
{
case N_SETA:
cache_ptr->symbol.section = bfd_abs_section_ptr;
break;
case N_SETT:
cache_ptr->symbol.section = obj_textsec (abfd);
break;
case N_SETD:
cache_ptr->symbol.section = obj_datasec (abfd);
break;
case N_SETB:
cache_ptr->symbol.section = obj_bsssec (abfd);
break;
}
cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
}
break;
case N_WARNING:
cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
cache_ptr->symbol.section = bfd_abs_section_ptr;
break;
case N_INDR: case N_INDR | N_EXT:
cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible;
cache_ptr->symbol.section = bfd_ind_section_ptr;
break;
case N_WEAKU:
cache_ptr->symbol.section = bfd_und_section_ptr;
cache_ptr->symbol.flags = BSF_WEAK;
break;
case N_WEAKA:
cache_ptr->symbol.section = bfd_abs_section_ptr;
cache_ptr->symbol.flags = BSF_WEAK;
break;
case N_WEAKT:
cache_ptr->symbol.section = obj_textsec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = BSF_WEAK;
break;
case N_WEAKD:
cache_ptr->symbol.section = obj_datasec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = BSF_WEAK;
break;
case N_WEAKB:
cache_ptr->symbol.section = obj_bsssec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = BSF_WEAK;
break;
}
return TRUE;
}
static bfd_boolean
translate_to_native_sym_flags (bfd *abfd,
asymbol *cache_ptr,
struct external_nlist *sym_pointer)
{
bfd_vma value = cache_ptr->value;
asection *sec;
bfd_vma off;
sym_pointer->e_type[0] &= ~N_TYPE;
sec = bfd_get_section (cache_ptr);
off = 0;
if (sec == NULL)
{
(*_bfd_error_handler)
(_("%s: can not represent section for symbol `%s' in a.out object file format"),
bfd_get_filename (abfd),
cache_ptr->name != NULL ? cache_ptr->name : _("*unknown*"));
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
if (sec->output_section != NULL)
{
off = sec->output_offset;
sec = sec->output_section;
}
if (bfd_is_abs_section (sec))
sym_pointer->e_type[0] |= N_ABS;
else if (sec == obj_textsec (abfd))
sym_pointer->e_type[0] |= N_TEXT;
else if (sec == obj_datasec (abfd))
sym_pointer->e_type[0] |= N_DATA;
else if (sec == obj_bsssec (abfd))
sym_pointer->e_type[0] |= N_BSS;
else if (bfd_is_und_section (sec))
sym_pointer->e_type[0] = N_UNDF | N_EXT;
else if (bfd_is_ind_section (sec))
sym_pointer->e_type[0] = N_INDR;
else if (bfd_is_com_section (sec))
sym_pointer->e_type[0] = N_UNDF | N_EXT;
else
{
if (aout_section_merge_with_text_p (abfd, sec))
sym_pointer->e_type[0] |= N_TEXT;
else
{
(*_bfd_error_handler)
(_("%s: can not represent section `%s' in a.out object file format"),
bfd_get_filename (abfd), bfd_get_section_name (abfd, sec));
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
}
value += sec->vma + off;
if ((cache_ptr->flags & BSF_WARNING) != 0)
sym_pointer->e_type[0] = N_WARNING;
if ((cache_ptr->flags & BSF_DEBUGGING) != 0)
sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type;
else if ((cache_ptr->flags & BSF_GLOBAL) != 0)
sym_pointer->e_type[0] |= N_EXT;
else if ((cache_ptr->flags & BSF_LOCAL) != 0)
sym_pointer->e_type[0] &= ~N_EXT;
if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0)
{
int type = ((aout_symbol_type *) cache_ptr)->type;
switch (type)
{
case N_ABS: type = N_SETA; break;
case N_TEXT: type = N_SETT; break;
case N_DATA: type = N_SETD; break;
case N_BSS: type = N_SETB; break;
}
sym_pointer->e_type[0] = type;
}
if ((cache_ptr->flags & BSF_WEAK) != 0)
{
int type;
switch (sym_pointer->e_type[0] & N_TYPE)
{
default:
case N_ABS: type = N_WEAKA; break;
case N_TEXT: type = N_WEAKT; break;
case N_DATA: type = N_WEAKD; break;
case N_BSS: type = N_WEAKB; break;
case N_UNDF: type = N_WEAKU; break;
}
sym_pointer->e_type[0] = type;
}
PUT_WORD (abfd, value, sym_pointer->e_value);
return TRUE;
}
asymbol *
NAME (aout, make_empty_symbol) (bfd *abfd)
{
bfd_size_type amt = sizeof (aout_symbol_type);
aout_symbol_type *new = bfd_zalloc (abfd, amt);
if (!new)
return NULL;
new->symbol.the_bfd = abfd;
return &new->symbol;
}
bfd_boolean
NAME (aout, translate_symbol_table) (bfd *abfd,
aout_symbol_type *in,
struct external_nlist *ext,
bfd_size_type count,
char *str,
bfd_size_type strsize,
bfd_boolean dynamic)
{
struct external_nlist *ext_end;
ext_end = ext + count;
for (; ext < ext_end; ext++, in++)
{
bfd_vma x;
x = GET_WORD (abfd, ext->e_strx);
in->symbol.the_bfd = abfd;
if (x == 0 && ! dynamic)
in->symbol.name = "";
else if (x < strsize)
in->symbol.name = str + x;
else
return FALSE;
in->symbol.value = GET_SWORD (abfd, ext->e_value);
in->desc = H_GET_16 (abfd, ext->e_desc);
in->other = H_GET_8 (abfd, ext->e_other);
in->type = H_GET_8 (abfd, ext->e_type);
in->symbol.udata.p = NULL;
if (! translate_from_native_sym_flags (abfd, in))
return FALSE;
if (dynamic)
in->symbol.flags |= BSF_DYNAMIC;
}
return TRUE;
}
bfd_boolean
NAME (aout, slurp_symbol_table) (bfd *abfd)
{
struct external_nlist *old_external_syms;
aout_symbol_type *cached;
bfd_size_type cached_size;
if (obj_aout_symbols (abfd) != NULL)
return TRUE;
old_external_syms = obj_aout_external_syms (abfd);
if (! aout_get_external_symbols (abfd))
return FALSE;
cached_size = obj_aout_external_sym_count (abfd);
cached_size *= sizeof (aout_symbol_type);
cached = bfd_zmalloc (cached_size);
if (cached == NULL && cached_size != 0)
return FALSE;
if (! (NAME (aout, translate_symbol_table)
(abfd, cached,
obj_aout_external_syms (abfd),
obj_aout_external_sym_count (abfd),
obj_aout_external_strings (abfd),
obj_aout_external_string_size (abfd),
FALSE)))
{
free (cached);
return FALSE;
}
bfd_get_symcount (abfd) = obj_aout_external_sym_count (abfd);
obj_aout_symbols (abfd) = cached;
if (old_external_syms == NULL
&& obj_aout_external_syms (abfd) != NULL)
{
#ifdef USE_MMAP
bfd_free_window (&obj_aout_sym_window (abfd));
#else
free (obj_aout_external_syms (abfd));
#endif
obj_aout_external_syms (abfd) = NULL;
}
return TRUE;
}
static inline bfd_size_type
add_to_stringtab (bfd *abfd,
struct bfd_strtab_hash *tab,
const char *str,
bfd_boolean copy)
{
bfd_boolean hash;
bfd_size_type index;
if (str == 0 || *str == '\0')
return 0;
hash = TRUE;
if ((abfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
hash = FALSE;
index = _bfd_stringtab_add (tab, str, hash, copy);
if (index != (bfd_size_type) -1)
index += BYTES_IN_WORD;
return index;
}
static bfd_boolean
emit_stringtab (bfd *abfd, struct bfd_strtab_hash *tab)
{
bfd_byte buffer[BYTES_IN_WORD];
bfd_size_type amt = BYTES_IN_WORD;
PUT_WORD (abfd, _bfd_stringtab_size (tab) + BYTES_IN_WORD, buffer);
if (bfd_bwrite ((void *) buffer, amt, abfd) != amt)
return FALSE;
return _bfd_stringtab_emit (abfd, tab);
}
bfd_boolean
NAME (aout, write_syms) (bfd *abfd)
{
unsigned int count ;
asymbol **generic = bfd_get_outsymbols (abfd);
struct bfd_strtab_hash *strtab;
strtab = _bfd_stringtab_init ();
if (strtab == NULL)
return FALSE;
for (count = 0; count < bfd_get_symcount (abfd); count++)
{
asymbol *g = generic[count];
bfd_size_type indx;
struct external_nlist nsp;
bfd_size_type amt;
indx = add_to_stringtab (abfd, strtab, g->name, FALSE);
if (indx == (bfd_size_type) -1)
goto error_return;
PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx);
if (bfd_asymbol_flavour (g) == abfd->xvec->flavour)
{
H_PUT_16 (abfd, aout_symbol (g)->desc, nsp.e_desc);
H_PUT_8 (abfd, aout_symbol (g)->other, nsp.e_other);
H_PUT_8 (abfd, aout_symbol (g)->type, nsp.e_type);
}
else
{
H_PUT_16 (abfd, 0, nsp.e_desc);
H_PUT_8 (abfd, 0, nsp.e_other);
H_PUT_8 (abfd, 0, nsp.e_type);
}
if (! translate_to_native_sym_flags (abfd, g, &nsp))
goto error_return;
amt = EXTERNAL_NLIST_SIZE;
if (bfd_bwrite ((void *) &nsp, amt, abfd) != amt)
goto error_return;
g->KEEPIT = count;
}
if (! emit_stringtab (abfd, strtab))
goto error_return;
_bfd_stringtab_free (strtab);
return TRUE;
error_return:
_bfd_stringtab_free (strtab);
return FALSE;
}
long
NAME (aout, canonicalize_symtab) (bfd *abfd, asymbol **location)
{
unsigned int counter = 0;
aout_symbol_type *symbase;
if (!NAME (aout, slurp_symbol_table) (abfd))
return -1;
for (symbase = obj_aout_symbols (abfd);
counter++ < bfd_get_symcount (abfd);
)
*(location++) = (asymbol *) (symbase++);
*location++ =0;
return bfd_get_symcount (abfd);
}
extern void NAME (aout, swap_std_reloc_out)
(bfd *, arelent *, struct reloc_std_external *);
void
NAME (aout, swap_std_reloc_out) (bfd *abfd,
arelent *g,
struct reloc_std_external *natptr)
{
int r_index;
asymbol *sym = *(g->sym_ptr_ptr);
int r_extern;
unsigned int r_length;
int r_pcrel;
int r_baserel, r_jmptable, r_relative;
asection *output_section = sym->section->output_section;
PUT_WORD (abfd, g->address, natptr->r_address);
r_length = g->howto->size ;
r_pcrel = (int) g->howto->pc_relative;
r_baserel = (g->howto->type & 8) != 0;
r_jmptable = (g->howto->type & 16) != 0;
r_relative = (g->howto->type & 32) != 0;
if (bfd_is_com_section (output_section)
|| bfd_is_abs_section (output_section)
|| bfd_is_und_section (output_section))
{
if (bfd_abs_section_ptr->symbol == sym)
{
r_index = N_ABS;
r_extern = 0;
}
else
{
r_extern = 1;
r_index = (*(g->sym_ptr_ptr))->KEEPIT;
}
}
else
{
r_extern = 0;
r_index = output_section->target_index;
}
if (bfd_header_big_endian (abfd))
{
natptr->r_index[0] = r_index >> 16;
natptr->r_index[1] = r_index >> 8;
natptr->r_index[2] = r_index;
natptr->r_type[0] = ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
| (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
| (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
| (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
| (r_length << RELOC_STD_BITS_LENGTH_SH_BIG));
}
else
{
natptr->r_index[2] = r_index >> 16;
natptr->r_index[1] = r_index >> 8;
natptr->r_index[0] = r_index;
natptr->r_type[0] = ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
| (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
| (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
| (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
| (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE));
}
}
extern void NAME (aout, swap_ext_reloc_out)
(bfd *, arelent *, struct reloc_ext_external *);
void
NAME (aout, swap_ext_reloc_out) (bfd *abfd,
arelent *g,
struct reloc_ext_external *natptr)
{
int r_index;
int r_extern;
unsigned int r_type;
bfd_vma r_addend;
asymbol *sym = *(g->sym_ptr_ptr);
asection *output_section = sym->section->output_section;
PUT_WORD (abfd, g->address, natptr->r_address);
r_type = (unsigned int) g->howto->type;
r_addend = g->addend;
if ((sym->flags & BSF_SECTION_SYM) != 0)
r_addend += (*(g->sym_ptr_ptr))->section->output_section->vma;
if (bfd_is_abs_section (bfd_get_section (sym)))
{
r_extern = 0;
r_index = N_ABS;
}
else if ((sym->flags & BSF_SECTION_SYM) == 0)
{
if (bfd_is_und_section (bfd_get_section (sym))
|| (sym->flags & BSF_GLOBAL) != 0)
r_extern = 1;
else
r_extern = 0;
r_index = (*(g->sym_ptr_ptr))->KEEPIT;
}
else
{
r_extern = 0;
r_index = output_section->target_index;
}
if (bfd_header_big_endian (abfd))
{
natptr->r_index[0] = r_index >> 16;
natptr->r_index[1] = r_index >> 8;
natptr->r_index[2] = r_index;
natptr->r_type[0] = ((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
| (r_type << RELOC_EXT_BITS_TYPE_SH_BIG));
}
else
{
natptr->r_index[2] = r_index >> 16;
natptr->r_index[1] = r_index >> 8;
natptr->r_index[0] = r_index;
natptr->r_type[0] = ((r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
| (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE));
}
PUT_WORD (abfd, r_addend, natptr->r_addend);
}
#define MOVE_ADDRESS(ad) \
if (r_extern) \
{ \
\
cache_ptr->sym_ptr_ptr = symbols + r_index; \
cache_ptr->addend = ad; \
} \
else \
{ \
\
switch (r_index) \
{ \
case N_TEXT: \
case N_TEXT | N_EXT: \
cache_ptr->sym_ptr_ptr = obj_textsec (abfd)->symbol_ptr_ptr; \
cache_ptr->addend = ad - su->textsec->vma; \
break; \
case N_DATA: \
case N_DATA | N_EXT: \
cache_ptr->sym_ptr_ptr = obj_datasec (abfd)->symbol_ptr_ptr; \
cache_ptr->addend = ad - su->datasec->vma; \
break; \
case N_BSS: \
case N_BSS | N_EXT: \
cache_ptr->sym_ptr_ptr = obj_bsssec (abfd)->symbol_ptr_ptr; \
cache_ptr->addend = ad - su->bsssec->vma; \
break; \
default: \
case N_ABS: \
case N_ABS | N_EXT: \
cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; \
cache_ptr->addend = ad; \
break; \
} \
}
void
NAME (aout, swap_ext_reloc_in) (bfd *abfd,
struct reloc_ext_external *bytes,
arelent *cache_ptr,
asymbol **symbols,
bfd_size_type symcount)
{
unsigned int r_index;
int r_extern;
unsigned int r_type;
struct aoutdata *su = &(abfd->tdata.aout_data->a);
cache_ptr->address = (GET_SWORD (abfd, bytes->r_address));
if (bfd_header_big_endian (abfd))
{
r_index = (((unsigned int) bytes->r_index[0] << 16)
| ((unsigned int) bytes->r_index[1] << 8)
| bytes->r_index[2]);
r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
r_type = ((bytes->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
>> RELOC_EXT_BITS_TYPE_SH_BIG);
}
else
{
r_index = (((unsigned int) bytes->r_index[2] << 16)
| ((unsigned int) bytes->r_index[1] << 8)
| bytes->r_index[0]);
r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
r_type = ((bytes->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
>> RELOC_EXT_BITS_TYPE_SH_LITTLE);
}
cache_ptr->howto = howto_table_ext + r_type;
if (r_type == (unsigned int) RELOC_BASE10
|| r_type == (unsigned int) RELOC_BASE13
|| r_type == (unsigned int) RELOC_BASE22)
r_extern = 1;
if (r_extern && r_index > symcount)
{
r_extern = 0;
r_index = N_ABS;
}
MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend));
}
void
NAME (aout, swap_std_reloc_in) (bfd *abfd,
struct reloc_std_external *bytes,
arelent *cache_ptr,
asymbol **symbols,
bfd_size_type symcount)
{
unsigned int r_index;
int r_extern;
unsigned int r_length;
int r_pcrel;
int r_baserel, r_jmptable, r_relative;
struct aoutdata *su = &(abfd->tdata.aout_data->a);
unsigned int howto_idx;
cache_ptr->address = H_GET_32 (abfd, bytes->r_address);
if (bfd_header_big_endian (abfd))
{
r_index = (((unsigned int) bytes->r_index[0] << 16)
| ((unsigned int) bytes->r_index[1] << 8)
| bytes->r_index[2]);
r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
r_length = ((bytes->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
>> RELOC_STD_BITS_LENGTH_SH_BIG);
}
else
{
r_index = (((unsigned int) bytes->r_index[2] << 16)
| ((unsigned int) bytes->r_index[1] << 8)
| bytes->r_index[0]);
r_extern = (0 != (bytes->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
r_pcrel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
r_baserel = (0 != (bytes->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
r_jmptable= (0 != (bytes->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
r_relative= (0 != (bytes->r_type[0] & RELOC_STD_BITS_RELATIVE_LITTLE));
r_length = ((bytes->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
>> RELOC_STD_BITS_LENGTH_SH_LITTLE);
}
howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
+ 16 * r_jmptable + 32 * r_relative);
BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
cache_ptr->howto = howto_table_std + howto_idx;
BFD_ASSERT (cache_ptr->howto->type != (unsigned int) -1);
if (r_baserel)
r_extern = 1;
if (r_extern && r_index > symcount)
{
r_extern = 0;
r_index = N_ABS;
}
MOVE_ADDRESS (0);
}
bfd_boolean
NAME (aout, slurp_reloc_table) (bfd *abfd, sec_ptr asect, asymbol **symbols)
{
bfd_size_type count;
bfd_size_type reloc_size;
void * relocs;
arelent *reloc_cache;
size_t each_size;
unsigned int counter = 0;
arelent *cache_ptr;
bfd_size_type amt;
if (asect->relocation)
return TRUE;
if (asect->flags & SEC_CONSTRUCTOR)
return TRUE;
if (asect == obj_datasec (abfd))
reloc_size = exec_hdr (abfd)->a_drsize;
else if (asect == obj_textsec (abfd))
reloc_size = exec_hdr (abfd)->a_trsize;
else if (asect == obj_bsssec (abfd))
reloc_size = 0;
else
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0)
return FALSE;
each_size = obj_reloc_entry_size (abfd);
count = reloc_size / each_size;
amt = count * sizeof (arelent);
reloc_cache = bfd_zmalloc (amt);
if (reloc_cache == NULL && count != 0)
return FALSE;
relocs = bfd_malloc (reloc_size);
if (relocs == NULL && reloc_size != 0)
{
free (reloc_cache);
return FALSE;
}
if (bfd_bread (relocs, reloc_size, abfd) != reloc_size)
{
free (relocs);
free (reloc_cache);
return FALSE;
}
cache_ptr = reloc_cache;
if (each_size == RELOC_EXT_SIZE)
{
struct reloc_ext_external *rptr = (struct reloc_ext_external *) relocs;
for (; counter < count; counter++, rptr++, cache_ptr++)
MY_swap_ext_reloc_in (abfd, rptr, cache_ptr, symbols,
(bfd_size_type) bfd_get_symcount (abfd));
}
else
{
struct reloc_std_external *rptr = (struct reloc_std_external *) relocs;
for (; counter < count; counter++, rptr++, cache_ptr++)
MY_swap_std_reloc_in (abfd, rptr, cache_ptr, symbols,
(bfd_size_type) bfd_get_symcount (abfd));
}
free (relocs);
asect->relocation = reloc_cache;
asect->reloc_count = cache_ptr - reloc_cache;
return TRUE;
}
bfd_boolean
NAME (aout, squirt_out_relocs) (bfd *abfd, asection *section)
{
arelent **generic;
unsigned char *native, *natptr;
size_t each_size;
unsigned int count = section->reloc_count;
bfd_size_type natsize;
if (count == 0 || section->orelocation == NULL)
return TRUE;
each_size = obj_reloc_entry_size (abfd);
natsize = (bfd_size_type) each_size * count;
native = bfd_zalloc (abfd, natsize);
if (!native)
return FALSE;
generic = section->orelocation;
if (each_size == RELOC_EXT_SIZE)
{
for (natptr = native;
count != 0;
--count, natptr += each_size, ++generic)
MY_swap_ext_reloc_out (abfd, *generic,
(struct reloc_ext_external *) natptr);
}
else
{
for (natptr = native;
count != 0;
--count, natptr += each_size, ++generic)
MY_swap_std_reloc_out (abfd, *generic,
(struct reloc_std_external *) natptr);
}
if (bfd_bwrite ((void *) native, natsize, abfd) != natsize)
{
bfd_release (abfd, native);
return FALSE;
}
bfd_release (abfd, native);
return TRUE;
}
long
NAME (aout, canonicalize_reloc) (bfd *abfd,
sec_ptr section,
arelent **relptr,
asymbol **symbols)
{
arelent *tblptr = section->relocation;
unsigned int count;
if (section == obj_bsssec (abfd))
{
*relptr = NULL;
return 0;
}
if (!(tblptr || NAME (aout, slurp_reloc_table) (abfd, section, symbols)))
return -1;
if (section->flags & SEC_CONSTRUCTOR)
{
arelent_chain *chain = section->constructor_chain;
for (count = 0; count < section->reloc_count; count ++)
{
*relptr ++ = &chain->relent;
chain = chain->next;
}
}
else
{
tblptr = section->relocation;
for (count = 0; count++ < section->reloc_count; )
{
*relptr++ = tblptr++;
}
}
*relptr = 0;
return section->reloc_count;
}
long
NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect)
{
if (bfd_get_format (abfd) != bfd_object)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
if (asect->flags & SEC_CONSTRUCTOR)
return sizeof (arelent *) * (asect->reloc_count + 1);
if (asect == obj_datasec (abfd))
return sizeof (arelent *)
* ((exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd))
+ 1);
if (asect == obj_textsec (abfd))
return sizeof (arelent *)
* ((exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd))
+ 1);
if (asect == obj_bsssec (abfd))
return sizeof (arelent *);
if (asect == obj_bsssec (abfd))
return 0;
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
long
NAME (aout, get_symtab_upper_bound) (bfd *abfd)
{
if (!NAME (aout, slurp_symbol_table) (abfd))
return -1;
return (bfd_get_symcount (abfd)+1) * (sizeof (aout_symbol_type *));
}
alent *
NAME (aout, get_lineno) (bfd *ignore_abfd ATTRIBUTE_UNUSED,
asymbol *ignore_symbol ATTRIBUTE_UNUSED)
{
return NULL;
}
void
NAME (aout, get_symbol_info) (bfd *ignore_abfd ATTRIBUTE_UNUSED,
asymbol *symbol,
symbol_info *ret)
{
bfd_symbol_info (symbol, ret);
if (ret->type == '?')
{
int type_code = aout_symbol (symbol)->type & 0xff;
const char *stab_name = bfd_get_stab_name (type_code);
static char buf[10];
if (stab_name == NULL)
{
sprintf (buf, "(%d)", type_code);
stab_name = buf;
}
ret->type = '-';
ret->stab_type = type_code;
ret->stab_other = (unsigned) (aout_symbol (symbol)->other & 0xff);
ret->stab_desc = (unsigned) (aout_symbol (symbol)->desc & 0xffff);
ret->stab_name = stab_name;
}
}
void
NAME (aout, print_symbol) (bfd *abfd,
void * afile,
asymbol *symbol,
bfd_print_symbol_type how)
{
FILE *file = (FILE *)afile;
switch (how)
{
case bfd_print_symbol_name:
if (symbol->name)
fprintf (file,"%s", symbol->name);
break;
case bfd_print_symbol_more:
fprintf (file,"%4x %2x %2x",
(unsigned) (aout_symbol (symbol)->desc & 0xffff),
(unsigned) (aout_symbol (symbol)->other & 0xff),
(unsigned) (aout_symbol (symbol)->type));
break;
case bfd_print_symbol_all:
{
const char *section_name = symbol->section->name;
bfd_print_symbol_vandf (abfd, (void *)file, symbol);
fprintf (file," %-5s %04x %02x %02x",
section_name,
(unsigned) (aout_symbol (symbol)->desc & 0xffff),
(unsigned) (aout_symbol (symbol)->other & 0xff),
(unsigned) (aout_symbol (symbol)->type & 0xff));
if (symbol->name)
fprintf (file," %s", symbol->name);
}
break;
}
}
#define MINISYM_THRESHOLD (1000000 / sizeof (asymbol))
long
NAME (aout, read_minisymbols) (bfd *abfd,
bfd_boolean dynamic,
void * *minisymsp,
unsigned int *sizep)
{
if (dynamic)
return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
if (! aout_get_external_symbols (abfd))
return -1;
if (obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
return _bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep);
*minisymsp = (void *) obj_aout_external_syms (abfd);
obj_aout_external_syms (abfd) = NULL;
*sizep = EXTERNAL_NLIST_SIZE;
return obj_aout_external_sym_count (abfd);
}
asymbol *
NAME (aout, minisymbol_to_symbol) (bfd *abfd,
bfd_boolean dynamic,
const void * minisym,
asymbol *sym)
{
if (dynamic
|| obj_aout_external_sym_count (abfd) < MINISYM_THRESHOLD)
return _bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym);
memset (sym, 0, sizeof (aout_symbol_type));
if (! (NAME (aout, translate_symbol_table)
(abfd,
(aout_symbol_type *) sym,
(struct external_nlist *) minisym,
(bfd_size_type) 1,
obj_aout_external_strings (abfd),
obj_aout_external_string_size (abfd),
FALSE)))
return NULL;
return sym;
}
bfd_boolean
NAME (aout, find_nearest_line) (bfd *abfd,
asection *section,
asymbol **symbols,
bfd_vma offset,
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *line_ptr)
{
asymbol **p;
const char *directory_name = NULL;
const char *main_file_name = NULL;
const char *current_file_name = NULL;
const char *line_file_name = NULL;
const char *line_directory_name = NULL;
bfd_vma low_line_vma = 0;
bfd_vma low_func_vma = 0;
asymbol *func = 0;
bfd_size_type filelen, funclen;
char *buf;
*filename_ptr = abfd->filename;
*functionname_ptr = 0;
*line_ptr = 0;
if (symbols != NULL)
{
for (p = symbols; *p; p++)
{
aout_symbol_type *q = (aout_symbol_type *) (*p);
next:
switch (q->type)
{
case N_TEXT:
if (q->symbol.value <= offset
&& ((q->symbol.value > low_line_vma
&& (line_file_name != NULL
|| *line_ptr != 0))
|| (q->symbol.value > low_func_vma
&& func != NULL)))
{
const char *symname;
symname = q->symbol.name;
if (strcmp (symname + strlen (symname) - 2, ".o") == 0)
{
if (q->symbol.value > low_line_vma)
{
*line_ptr = 0;
line_file_name = NULL;
}
if (q->symbol.value > low_func_vma)
func = NULL;
}
}
break;
case N_SO:
if (q->symbol.value <= offset)
{
if (q->symbol.value > low_line_vma)
{
*line_ptr = 0;
line_file_name = NULL;
}
if (q->symbol.value > low_func_vma)
func = NULL;
}
main_file_name = current_file_name = q->symbol.name;
p++;
if (*p == NULL)
goto done;
q = (aout_symbol_type *) (*p);
if (q->type != (int)N_SO)
goto next;
directory_name = current_file_name;
main_file_name = current_file_name = q->symbol.name;
if (obj_textsec (abfd) != section)
goto done;
break;
case N_SOL:
current_file_name = q->symbol.name;
break;
case N_SLINE:
case N_DSLINE:
case N_BSLINE:
if (q->symbol.value >= low_line_vma
&& q->symbol.value <= offset)
{
*line_ptr = q->desc;
low_line_vma = q->symbol.value;
line_file_name = current_file_name;
line_directory_name = directory_name;
}
break;
case N_FUN:
{
if (q->symbol.value >= low_func_vma &&
q->symbol.value <= offset)
{
low_func_vma = q->symbol.value;
func = (asymbol *)q;
}
else if (q->symbol.value > offset)
goto done;
}
break;
}
}
}
done:
if (*line_ptr != 0)
{
main_file_name = line_file_name;
directory_name = line_directory_name;
}
if (main_file_name == NULL
|| IS_ABSOLUTE_PATH (main_file_name)
|| directory_name == NULL)
filelen = 0;
else
filelen = strlen (directory_name) + strlen (main_file_name);
if (func == NULL)
funclen = 0;
else
funclen = strlen (bfd_asymbol_name (func));
if (adata (abfd).line_buf != NULL)
free (adata (abfd).line_buf);
if (filelen + funclen == 0)
adata (abfd).line_buf = buf = NULL;
else
{
buf = bfd_malloc (filelen + funclen + 3);
adata (abfd).line_buf = buf;
if (buf == NULL)
return FALSE;
}
if (main_file_name != NULL)
{
if (IS_ABSOLUTE_PATH (main_file_name) || directory_name == NULL)
*filename_ptr = main_file_name;
else
{
sprintf (buf, "%s%s", directory_name, main_file_name);
*filename_ptr = buf;
buf += filelen + 1;
}
}
if (func)
{
const char *function = func->name;
char *colon;
if (bfd_get_symbol_leading_char (abfd) == '\0')
strcpy (buf, function);
else
{
buf[0] = bfd_get_symbol_leading_char (abfd);
strcpy (buf + 1, function);
}
colon = strchr (buf, ':');
if (colon != NULL)
*colon = '\0';
*functionname_ptr = buf;
}
return TRUE;
}
int
NAME (aout, sizeof_headers) (bfd *abfd, bfd_boolean execable ATTRIBUTE_UNUSED)
{
return adata (abfd).exec_bytes_size;
}
bfd_boolean
NAME (aout, bfd_free_cached_info) (bfd *abfd)
{
asection *o;
if (bfd_get_format (abfd) != bfd_object
|| abfd->tdata.aout_data == NULL)
return TRUE;
#define BFCI_FREE(x) if (x != NULL) { free (x); x = NULL; }
BFCI_FREE (obj_aout_symbols (abfd));
#ifdef USE_MMAP
obj_aout_external_syms (abfd) = 0;
bfd_free_window (&obj_aout_sym_window (abfd));
bfd_free_window (&obj_aout_string_window (abfd));
obj_aout_external_strings (abfd) = 0;
#else
BFCI_FREE (obj_aout_external_syms (abfd));
BFCI_FREE (obj_aout_external_strings (abfd));
#endif
for (o = abfd->sections; o != NULL; o = o->next)
BFCI_FREE (o->relocation);
#undef BFCI_FREE
return TRUE;
}
struct bfd_hash_entry *
NAME (aout, link_hash_newfunc) (struct bfd_hash_entry *entry,
struct bfd_hash_table *table,
const char *string)
{
struct aout_link_hash_entry *ret = (struct aout_link_hash_entry *) entry;
if (ret == NULL)
ret = bfd_hash_allocate (table, sizeof (* ret));
if (ret == NULL)
return NULL;
ret = ((struct aout_link_hash_entry *)
_bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret)
{
ret->written = FALSE;
ret->indx = -1;
}
return (struct bfd_hash_entry *) ret;
}
bfd_boolean
NAME (aout, link_hash_table_init) (struct aout_link_hash_table *table,
bfd *abfd,
struct bfd_hash_entry *(*newfunc)
(struct bfd_hash_entry *, struct bfd_hash_table *,
const char *))
{
return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
}
struct bfd_link_hash_table *
NAME (aout, link_hash_table_create) (bfd *abfd)
{
struct aout_link_hash_table *ret;
bfd_size_type amt = sizeof (* ret);
ret = bfd_malloc (amt);
if (ret == NULL)
return NULL;
if (! NAME (aout, link_hash_table_init) (ret, abfd,
NAME (aout, link_hash_newfunc)))
{
free (ret);
return NULL;
}
return &ret->root;
}
static bfd_boolean
aout_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
{
bfd_boolean (*add_one_symbol)
(struct bfd_link_info *, bfd *, const char *, flagword, asection *,
bfd_vma, const char *, bfd_boolean, bfd_boolean,
struct bfd_link_hash_entry **);
struct external_nlist *syms;
bfd_size_type sym_count;
char *strings;
bfd_boolean copy;
struct aout_link_hash_entry **sym_hash;
struct external_nlist *p;
struct external_nlist *pend;
bfd_size_type amt;
syms = obj_aout_external_syms (abfd);
sym_count = obj_aout_external_sym_count (abfd);
strings = obj_aout_external_strings (abfd);
if (info->keep_memory)
copy = FALSE;
else
copy = TRUE;
if (aout_backend_info (abfd)->add_dynamic_symbols != NULL)
{
if (! ((*aout_backend_info (abfd)->add_dynamic_symbols)
(abfd, info, &syms, &sym_count, &strings)))
return FALSE;
}
amt = sym_count * sizeof (struct aout_link_hash_entry *);
sym_hash = bfd_alloc (abfd, amt);
if (sym_hash == NULL && sym_count != 0)
return FALSE;
obj_aout_sym_hashes (abfd) = sym_hash;
add_one_symbol = aout_backend_info (abfd)->add_one_symbol;
if (add_one_symbol == NULL)
add_one_symbol = _bfd_generic_link_add_one_symbol;
p = syms;
pend = p + sym_count;
for (; p < pend; p++, sym_hash++)
{
int type;
const char *name;
bfd_vma value;
asection *section;
flagword flags;
const char *string;
*sym_hash = NULL;
type = H_GET_8 (abfd, p->e_type);
if ((type & N_STAB) != 0)
continue;
name = strings + GET_WORD (abfd, p->e_strx);
value = GET_WORD (abfd, p->e_value);
flags = BSF_GLOBAL;
string = NULL;
switch (type)
{
default:
abort ();
case N_UNDF:
case N_ABS:
case N_TEXT:
case N_DATA:
case N_BSS:
case N_FN_SEQ:
case N_COMM:
case N_SETV:
case N_FN:
continue;
case N_INDR:
++p;
++sym_hash;
continue;
case N_UNDF | N_EXT:
if (value == 0)
{
section = bfd_und_section_ptr;
flags = 0;
}
else
section = bfd_com_section_ptr;
break;
case N_ABS | N_EXT:
section = bfd_abs_section_ptr;
break;
case N_TEXT | N_EXT:
section = obj_textsec (abfd);
value -= bfd_get_section_vma (abfd, section);
break;
case N_DATA | N_EXT:
case N_SETV | N_EXT:
section = obj_datasec (abfd);
value -= bfd_get_section_vma (abfd, section);
break;
case N_BSS | N_EXT:
section = obj_bsssec (abfd);
value -= bfd_get_section_vma (abfd, section);
break;
case N_INDR | N_EXT:
BFD_ASSERT (p + 1 < pend);
++p;
string = strings + GET_WORD (abfd, p->e_strx);
section = bfd_ind_section_ptr;
flags |= BSF_INDIRECT;
break;
case N_COMM | N_EXT:
section = bfd_com_section_ptr;
break;
case N_SETA: case N_SETA | N_EXT:
section = bfd_abs_section_ptr;
flags |= BSF_CONSTRUCTOR;
break;
case N_SETT: case N_SETT | N_EXT:
section = obj_textsec (abfd);
flags |= BSF_CONSTRUCTOR;
value -= bfd_get_section_vma (abfd, section);
break;
case N_SETD: case N_SETD | N_EXT:
section = obj_datasec (abfd);
flags |= BSF_CONSTRUCTOR;
value -= bfd_get_section_vma (abfd, section);
break;
case N_SETB: case N_SETB | N_EXT:
section = obj_bsssec (abfd);
flags |= BSF_CONSTRUCTOR;
value -= bfd_get_section_vma (abfd, section);
break;
case N_WARNING:
if (p + 1 >= pend)
return TRUE;
++p;
string = name;
name = strings + GET_WORD (abfd, p->e_strx);
section = bfd_und_section_ptr;
flags |= BSF_WARNING;
break;
case N_WEAKU:
section = bfd_und_section_ptr;
flags = BSF_WEAK;
break;
case N_WEAKA:
section = bfd_abs_section_ptr;
flags = BSF_WEAK;
break;
case N_WEAKT:
section = obj_textsec (abfd);
value -= bfd_get_section_vma (abfd, section);
flags = BSF_WEAK;
break;
case N_WEAKD:
section = obj_datasec (abfd);
value -= bfd_get_section_vma (abfd, section);
flags = BSF_WEAK;
break;
case N_WEAKB:
section = obj_bsssec (abfd);
value -= bfd_get_section_vma (abfd, section);
flags = BSF_WEAK;
break;
}
if (! ((*add_one_symbol)
(info, abfd, name, flags, section, value, string, copy, FALSE,
(struct bfd_link_hash_entry **) sym_hash)))
return FALSE;
if ((*sym_hash)->root.type == bfd_link_hash_common
&& ((*sym_hash)->root.u.c.p->alignment_power >
bfd_get_arch_info (abfd)->section_align_power))
(*sym_hash)->root.u.c.p->alignment_power =
bfd_get_arch_info (abfd)->section_align_power;
if ((*sym_hash)->root.type == bfd_link_hash_new)
{
BFD_ASSERT ((flags & BSF_CONSTRUCTOR) != 0);
*sym_hash = NULL;
}
if (type == (N_INDR | N_EXT) || type == N_WARNING)
++sym_hash;
}
return TRUE;
}
static bfd_boolean
aout_link_free_symbols (bfd *abfd)
{
if (obj_aout_external_syms (abfd) != NULL)
{
#ifdef USE_MMAP
bfd_free_window (&obj_aout_sym_window (abfd));
#else
free ((void *) obj_aout_external_syms (abfd));
#endif
obj_aout_external_syms (abfd) = NULL;
}
if (obj_aout_external_strings (abfd) != NULL)
{
#ifdef USE_MMAP
bfd_free_window (&obj_aout_string_window (abfd));
#else
free ((void *) obj_aout_external_strings (abfd));
#endif
obj_aout_external_strings (abfd) = NULL;
}
return TRUE;
}
static bfd_boolean
aout_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
{
if (! aout_get_external_symbols (abfd))
return FALSE;
if (! aout_link_add_symbols (abfd, info))
return FALSE;
if (! info->keep_memory)
{
if (! aout_link_free_symbols (abfd))
return FALSE;
}
return TRUE;
}
static bfd_boolean
aout_link_check_ar_symbols (bfd *abfd,
struct bfd_link_info *info,
bfd_boolean *pneeded)
{
struct external_nlist *p;
struct external_nlist *pend;
char *strings;
*pneeded = FALSE;
p = obj_aout_external_syms (abfd);
pend = p + obj_aout_external_sym_count (abfd);
strings = obj_aout_external_strings (abfd);
for (; p < pend; p++)
{
int type = H_GET_8 (abfd, p->e_type);
const char *name;
struct bfd_link_hash_entry *h;
if (((type & N_EXT) == 0
|| (type & N_STAB) != 0
|| type == N_FN)
&& type != N_WEAKA
&& type != N_WEAKT
&& type != N_WEAKD
&& type != N_WEAKB)
{
if (type == N_WARNING
|| type == N_INDR)
++p;
continue;
}
name = strings + GET_WORD (abfd, p->e_strx);
h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
if (h == NULL
|| (h->type != bfd_link_hash_undefined
&& h->type != bfd_link_hash_common))
{
if (type == (N_INDR | N_EXT))
++p;
continue;
}
if (type == (N_TEXT | N_EXT)
|| type == (N_DATA | N_EXT)
|| type == (N_BSS | N_EXT)
|| type == (N_ABS | N_EXT)
|| type == (N_INDR | N_EXT))
{
if (h->type == bfd_link_hash_common)
{
int skip = 0;
switch (info->common_skip_ar_aymbols)
{
case bfd_link_common_skip_text:
skip = (type == (N_TEXT | N_EXT));
break;
case bfd_link_common_skip_data:
skip = (type == (N_DATA | N_EXT));
break;
default:
case bfd_link_common_skip_all:
skip = 1;
break;
}
if (skip)
continue;
}
if (! (*info->callbacks->add_archive_element) (info, abfd, name))
return FALSE;
*pneeded = TRUE;
return TRUE;
}
if (type == (N_UNDF | N_EXT))
{
bfd_vma value;
value = GET_WORD (abfd, p->e_value);
if (value != 0)
{
if (h->type == bfd_link_hash_undefined)
{
bfd *symbfd;
unsigned int power;
symbfd = h->u.undef.abfd;
if (symbfd == NULL)
{
if (! (*info->callbacks->add_archive_element) (info,
abfd,
name))
return FALSE;
*pneeded = TRUE;
return TRUE;
}
h->type = bfd_link_hash_common;
h->u.c.p = bfd_hash_allocate (&info->hash->table,
sizeof (struct bfd_link_hash_common_entry));
if (h->u.c.p == NULL)
return FALSE;
h->u.c.size = value;
power = bfd_log2 (value);
if (power > bfd_get_arch_info (abfd)->section_align_power)
power = bfd_get_arch_info (abfd)->section_align_power;
h->u.c.p->alignment_power = power;
h->u.c.p->section = bfd_make_section_old_way (symbfd,
"COMMON");
}
else
{
if (value > h->u.c.size)
h->u.c.size = value;
}
}
}
if (type == N_WEAKA
|| type == N_WEAKT
|| type == N_WEAKD
|| type == N_WEAKB)
{
if (h->type == bfd_link_hash_undefined)
{
if (! (*info->callbacks->add_archive_element) (info, abfd, name))
return FALSE;
*pneeded = TRUE;
return TRUE;
}
}
}
return TRUE;
}
static bfd_boolean
aout_link_check_archive_element (bfd *abfd,
struct bfd_link_info *info,
bfd_boolean *pneeded)
{
if (! aout_get_external_symbols (abfd))
return FALSE;
if (! aout_link_check_ar_symbols (abfd, info, pneeded))
return FALSE;
if (*pneeded)
{
if (! aout_link_add_symbols (abfd, info))
return FALSE;
}
if (! info->keep_memory || ! *pneeded)
{
if (! aout_link_free_symbols (abfd))
return FALSE;
}
return TRUE;
}
bfd_boolean
NAME (aout, link_add_symbols) (bfd *abfd, struct bfd_link_info *info)
{
switch (bfd_get_format (abfd))
{
case bfd_object:
return aout_link_add_object_symbols (abfd, info);
case bfd_archive:
return _bfd_generic_link_add_archive_symbols
(abfd, info, aout_link_check_archive_element);
default:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
}
struct aout_link_includes_table
{
struct bfd_hash_table root;
};
struct aout_link_includes_totals
{
struct aout_link_includes_totals *next;
bfd_vma total;
};
struct aout_link_includes_entry
{
struct bfd_hash_entry root;
struct aout_link_includes_totals *totals;
};
#define aout_link_includes_lookup(table, string, create, copy) \
((struct aout_link_includes_entry *) \
bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
struct aout_final_link_info
{
struct bfd_link_info *info;
bfd *output_bfd;
file_ptr treloff, dreloff;
file_ptr symoff;
struct bfd_strtab_hash *strtab;
struct aout_link_includes_table includes;
bfd_byte *contents;
void * relocs;
int *symbol_map;
struct external_nlist *output_syms;
};
static struct bfd_hash_entry *
aout_link_includes_newfunc (struct bfd_hash_entry *entry,
struct bfd_hash_table *table,
const char *string)
{
struct aout_link_includes_entry *ret =
(struct aout_link_includes_entry *) entry;
if (ret == NULL)
ret = bfd_hash_allocate (table, sizeof (* ret));
if (ret == NULL)
return NULL;
ret = ((struct aout_link_includes_entry *)
bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
if (ret)
{
ret->totals = NULL;
}
return (struct bfd_hash_entry *) ret;
}
static bfd_boolean
aout_link_write_other_symbol (struct aout_link_hash_entry *h, void * data)
{
struct aout_final_link_info *finfo = (struct aout_final_link_info *) data;
bfd *output_bfd;
int type;
bfd_vma val;
struct external_nlist outsym;
bfd_size_type indx;
bfd_size_type amt;
if (h->root.type == bfd_link_hash_warning)
{
h = (struct aout_link_hash_entry *) h->root.u.i.link;
if (h->root.type == bfd_link_hash_new)
return TRUE;
}
output_bfd = finfo->output_bfd;
if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL)
{
if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol)
(output_bfd, finfo->info, h)))
{
abort ();
}
}
if (h->written)
return TRUE;
h->written = TRUE;
if (h->indx != -2
&& (finfo->info->strip == strip_all
|| (finfo->info->strip == strip_some
&& bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
FALSE, FALSE) == NULL)))
return TRUE;
switch (h->root.type)
{
default:
case bfd_link_hash_warning:
abort ();
return TRUE;
case bfd_link_hash_new:
return TRUE;
case bfd_link_hash_undefined:
type = N_UNDF | N_EXT;
val = 0;
break;
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
{
asection *sec;
sec = h->root.u.def.section->output_section;
BFD_ASSERT (bfd_is_abs_section (sec)
|| sec->owner == output_bfd);
if (sec == obj_textsec (output_bfd))
type = h->root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT;
else if (sec == obj_datasec (output_bfd))
type = h->root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD;
else if (sec == obj_bsssec (output_bfd))
type = h->root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB;
else
type = h->root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA;
type |= N_EXT;
val = (h->root.u.def.value
+ sec->vma
+ h->root.u.def.section->output_offset);
}
break;
case bfd_link_hash_common:
type = N_UNDF | N_EXT;
val = h->root.u.c.size;
break;
case bfd_link_hash_undefweak:
type = N_WEAKU;
val = 0;
case bfd_link_hash_indirect:
return TRUE;
}
H_PUT_8 (output_bfd, type, outsym.e_type);
H_PUT_8 (output_bfd, 0, outsym.e_other);
H_PUT_16 (output_bfd, 0, outsym.e_desc);
indx = add_to_stringtab (output_bfd, finfo->strtab, h->root.root.string,
FALSE);
if (indx == - (bfd_size_type) 1)
abort ();
PUT_WORD (output_bfd, indx, outsym.e_strx);
PUT_WORD (output_bfd, val, outsym.e_value);
amt = EXTERNAL_NLIST_SIZE;
if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0
|| bfd_bwrite ((void *) &outsym, amt, output_bfd) != amt)
abort ();
finfo->symoff += EXTERNAL_NLIST_SIZE;
h->indx = obj_aout_external_sym_count (output_bfd);
++obj_aout_external_sym_count (output_bfd);
return TRUE;
}
static bfd_boolean
aout_link_reloc_link_order (struct aout_final_link_info *finfo,
asection *o,
struct bfd_link_order *p)
{
struct bfd_link_order_reloc *pr;
int r_index;
int r_extern;
reloc_howto_type *howto;
file_ptr *reloff_ptr = NULL;
struct reloc_std_external srel;
struct reloc_ext_external erel;
void * rel_ptr;
bfd_size_type amt;
pr = p->u.reloc.p;
if (p->type == bfd_section_reloc_link_order)
{
r_extern = 0;
if (bfd_is_abs_section (pr->u.section))
r_index = N_ABS | N_EXT;
else
{
BFD_ASSERT (pr->u.section->owner == finfo->output_bfd);
r_index = pr->u.section->target_index;
}
}
else
{
struct aout_link_hash_entry *h;
BFD_ASSERT (p->type == bfd_symbol_reloc_link_order);
r_extern = 1;
h = ((struct aout_link_hash_entry *)
bfd_wrapped_link_hash_lookup (finfo->output_bfd, finfo->info,
pr->u.name, FALSE, FALSE, TRUE));
if (h != NULL
&& h->indx >= 0)
r_index = h->indx;
else if (h != NULL)
{
h->indx = -2;
h->written = FALSE;
if (! aout_link_write_other_symbol (h, (void *) finfo))
return FALSE;
r_index = h->indx;
}
else
{
if (! ((*finfo->info->callbacks->unattached_reloc)
(finfo->info, pr->u.name, NULL, NULL, (bfd_vma) 0)))
return FALSE;
r_index = 0;
}
}
howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc);
if (howto == 0)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (o == obj_textsec (finfo->output_bfd))
reloff_ptr = &finfo->treloff;
else if (o == obj_datasec (finfo->output_bfd))
reloff_ptr = &finfo->dreloff;
else
abort ();
if (obj_reloc_entry_size (finfo->output_bfd) == RELOC_STD_SIZE)
{
#ifdef MY_put_reloc
MY_put_reloc (finfo->output_bfd, r_extern, r_index, p->offset, howto,
&srel);
#else
{
int r_pcrel;
int r_baserel;
int r_jmptable;
int r_relative;
int r_length;
r_pcrel = (int) howto->pc_relative;
r_baserel = (howto->type & 8) != 0;
r_jmptable = (howto->type & 16) != 0;
r_relative = (howto->type & 32) != 0;
r_length = howto->size;
PUT_WORD (finfo->output_bfd, p->offset, srel.r_address);
if (bfd_header_big_endian (finfo->output_bfd))
{
srel.r_index[0] = r_index >> 16;
srel.r_index[1] = r_index >> 8;
srel.r_index[2] = r_index;
srel.r_type[0] =
((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0)
| (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0)
| (r_baserel ? RELOC_STD_BITS_BASEREL_BIG : 0)
| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_BIG : 0)
| (r_relative ? RELOC_STD_BITS_RELATIVE_BIG : 0)
| (r_length << RELOC_STD_BITS_LENGTH_SH_BIG));
}
else
{
srel.r_index[2] = r_index >> 16;
srel.r_index[1] = r_index >> 8;
srel.r_index[0] = r_index;
srel.r_type[0] =
((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0)
| (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0)
| (r_baserel ? RELOC_STD_BITS_BASEREL_LITTLE : 0)
| (r_jmptable ? RELOC_STD_BITS_JMPTABLE_LITTLE : 0)
| (r_relative ? RELOC_STD_BITS_RELATIVE_LITTLE : 0)
| (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE));
}
}
#endif
rel_ptr = (void *) &srel;
if (pr->addend != 0)
{
bfd_size_type size;
bfd_reloc_status_type r;
bfd_byte *buf;
bfd_boolean ok;
size = bfd_get_reloc_size (howto);
buf = bfd_zmalloc (size);
if (buf == NULL)
return FALSE;
r = MY_relocate_contents (howto, finfo->output_bfd,
(bfd_vma) pr->addend, buf);
switch (r)
{
case bfd_reloc_ok:
break;
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
if (! ((*finfo->info->callbacks->reloc_overflow)
(finfo->info, NULL,
(p->type == bfd_section_reloc_link_order
? bfd_section_name (finfo->output_bfd,
pr->u.section)
: pr->u.name),
howto->name, pr->addend, NULL, NULL, (bfd_vma) 0)))
{
free (buf);
return FALSE;
}
break;
}
ok = bfd_set_section_contents (finfo->output_bfd, o, (void *) buf,
(file_ptr) p->offset, size);
free (buf);
if (! ok)
return FALSE;
}
}
else
{
#ifdef MY_put_ext_reloc
MY_put_ext_reloc (finfo->output_bfd, r_extern, r_index, p->offset,
howto, &erel, pr->addend);
#else
PUT_WORD (finfo->output_bfd, p->offset, erel.r_address);
if (bfd_header_big_endian (finfo->output_bfd))
{
erel.r_index[0] = r_index >> 16;
erel.r_index[1] = r_index >> 8;
erel.r_index[2] = r_index;
erel.r_type[0] =
((r_extern ? RELOC_EXT_BITS_EXTERN_BIG : 0)
| (howto->type << RELOC_EXT_BITS_TYPE_SH_BIG));
}
else
{
erel.r_index[2] = r_index >> 16;
erel.r_index[1] = r_index >> 8;
erel.r_index[0] = r_index;
erel.r_type[0] =
(r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0)
| (howto->type << RELOC_EXT_BITS_TYPE_SH_LITTLE);
}
PUT_WORD (finfo->output_bfd, (bfd_vma) pr->addend, erel.r_addend);
#endif
rel_ptr = (void *) &erel;
}
amt = obj_reloc_entry_size (finfo->output_bfd);
if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0
|| bfd_bwrite (rel_ptr, amt, finfo->output_bfd) != amt)
return FALSE;
*reloff_ptr += obj_reloc_entry_size (finfo->output_bfd);
BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
&& (reloff_ptr != &finfo->treloff
|| (*reloff_ptr
<= obj_datasec (finfo->output_bfd)->rel_filepos)));
return TRUE;
}
static INLINE asection *
aout_reloc_index_to_section (bfd *abfd, int indx)
{
switch (indx & N_TYPE)
{
case N_TEXT: return obj_textsec (abfd);
case N_DATA: return obj_datasec (abfd);
case N_BSS: return obj_bsssec (abfd);
case N_ABS:
case N_UNDF: return bfd_abs_section_ptr;
default: abort ();
}
return NULL;
}
static bfd_boolean
aout_link_input_section_std (struct aout_final_link_info *finfo,
bfd *input_bfd,
asection *input_section,
struct reloc_std_external *relocs,
bfd_size_type rel_size,
bfd_byte *contents)
{
bfd_boolean (*check_dynamic_reloc)
(struct bfd_link_info *, bfd *, asection *,
struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *,
bfd_vma *);
bfd *output_bfd;
bfd_boolean relocatable;
struct external_nlist *syms;
char *strings;
struct aout_link_hash_entry **sym_hashes;
int *symbol_map;
bfd_size_type reloc_count;
struct reloc_std_external *rel;
struct reloc_std_external *rel_end;
output_bfd = finfo->output_bfd;
check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE);
BFD_ASSERT (input_bfd->xvec->header_byteorder
== output_bfd->xvec->header_byteorder);
relocatable = finfo->info->relocatable;
syms = obj_aout_external_syms (input_bfd);
strings = obj_aout_external_strings (input_bfd);
sym_hashes = obj_aout_sym_hashes (input_bfd);
symbol_map = finfo->symbol_map;
reloc_count = rel_size / RELOC_STD_SIZE;
rel = relocs;
rel_end = rel + reloc_count;
for (; rel < rel_end; rel++)
{
bfd_vma r_addr;
int r_index;
int r_extern;
int r_pcrel;
int r_baserel = 0;
reloc_howto_type *howto;
struct aout_link_hash_entry *h = NULL;
bfd_vma relocation;
bfd_reloc_status_type r;
r_addr = GET_SWORD (input_bfd, rel->r_address);
#ifdef MY_reloc_howto
howto = MY_reloc_howto (input_bfd, rel, r_index, r_extern, r_pcrel);
#else
{
int r_jmptable;
int r_relative;
int r_length;
unsigned int howto_idx;
if (bfd_header_big_endian (input_bfd))
{
r_index = (((unsigned int) rel->r_index[0] << 16)
| ((unsigned int) rel->r_index[1] << 8)
| rel->r_index[2]);
r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG));
r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
r_baserel = (0 != (rel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
r_jmptable= (0 != (rel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
r_relative= (0 != (rel->r_type[0] & RELOC_STD_BITS_RELATIVE_BIG));
r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG)
>> RELOC_STD_BITS_LENGTH_SH_BIG);
}
else
{
r_index = (((unsigned int) rel->r_index[2] << 16)
| ((unsigned int) rel->r_index[1] << 8)
| rel->r_index[0]);
r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE));
r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
r_baserel = (0 != (rel->r_type[0]
& RELOC_STD_BITS_BASEREL_LITTLE));
r_jmptable= (0 != (rel->r_type[0]
& RELOC_STD_BITS_JMPTABLE_LITTLE));
r_relative= (0 != (rel->r_type[0]
& RELOC_STD_BITS_RELATIVE_LITTLE));
r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE)
>> RELOC_STD_BITS_LENGTH_SH_LITTLE);
}
howto_idx = (r_length + 4 * r_pcrel + 8 * r_baserel
+ 16 * r_jmptable + 32 * r_relative);
BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std));
howto = howto_table_std + howto_idx;
}
#endif
if (relocatable)
{
if (r_extern)
{
h = sym_hashes[r_index];
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
asection *output_section;
if (bfd_header_big_endian (output_bfd))
rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_BIG;
else
rel->r_type[0] &=~ RELOC_STD_BITS_EXTERN_LITTLE;
output_section = h->root.u.def.section->output_section;
if (output_section == obj_textsec (output_bfd))
r_index = N_TEXT;
else if (output_section == obj_datasec (output_bfd))
r_index = N_DATA;
else if (output_section == obj_bsssec (output_bfd))
r_index = N_BSS;
else
r_index = N_ABS;
relocation = (h->root.u.def.value
+ output_section->vma
+ h->root.u.def.section->output_offset);
}
else
{
r_index = symbol_map[r_index];
if (r_index == -1)
{
if (h != NULL)
{
if (h->indx < 0)
{
h->indx = -2;
h->written = FALSE;
if (! aout_link_write_other_symbol (h,
(void *) finfo))
return FALSE;
}
r_index = h->indx;
}
else
{
const char *name;
name = strings + GET_WORD (input_bfd,
syms[r_index].e_strx);
if (! ((*finfo->info->callbacks->unattached_reloc)
(finfo->info, name, input_bfd, input_section,
r_addr)))
return FALSE;
r_index = 0;
}
}
relocation = 0;
}
if (bfd_header_big_endian (output_bfd))
{
rel->r_index[0] = r_index >> 16;
rel->r_index[1] = r_index >> 8;
rel->r_index[2] = r_index;
}
else
{
rel->r_index[2] = r_index >> 16;
rel->r_index[1] = r_index >> 8;
rel->r_index[0] = r_index;
}
}
else
{
asection *section;
section = aout_reloc_index_to_section (input_bfd, r_index);
relocation = (section->output_section->vma
+ section->output_offset
- section->vma);
}
PUT_WORD (output_bfd,
r_addr + input_section->output_offset,
rel->r_address);
if (r_pcrel)
relocation -= (input_section->output_section->vma
+ input_section->output_offset
- input_section->vma);
#ifdef MY_relocatable_reloc
MY_relocatable_reloc (howto, output_bfd, rel, relocation, r_addr);
#endif
if (relocation == 0)
r = bfd_reloc_ok;
else
r = MY_relocate_contents (howto,
input_bfd, relocation,
contents + r_addr);
}
else
{
bfd_boolean hundef;
hundef = FALSE;
if (r_extern)
{
h = sym_hashes[r_index];
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
relocation = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
}
else if (h != NULL
&& h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
hundef = TRUE;
relocation = 0;
}
}
else
{
asection *section;
section = aout_reloc_index_to_section (input_bfd, r_index);
relocation = (section->output_section->vma
+ section->output_offset
- section->vma);
if (r_pcrel)
relocation += input_section->vma;
}
if (check_dynamic_reloc != NULL)
{
bfd_boolean skip;
if (! ((*check_dynamic_reloc)
(finfo->info, input_bfd, input_section, h,
(void *) rel, contents, &skip, &relocation)))
return FALSE;
if (skip)
continue;
}
if (hundef && ! finfo->info->shared && ! r_baserel)
{
const char *name;
if (h != NULL)
name = h->root.root.string;
else
name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
if (! ((*finfo->info->callbacks->undefined_symbol)
(finfo->info, name, input_bfd, input_section,
r_addr, TRUE)))
return FALSE;
}
r = MY_final_link_relocate (howto,
input_bfd, input_section,
contents, r_addr, relocation,
(bfd_vma) 0);
}
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
{
const char *name;
if (h != NULL)
name = NULL;
else if (r_extern)
name = strings + GET_WORD (input_bfd,
syms[r_index].e_strx);
else
{
asection *s;
s = aout_reloc_index_to_section (input_bfd, r_index);
name = bfd_section_name (input_bfd, s);
}
if (! ((*finfo->info->callbacks->reloc_overflow)
(finfo->info, (h ? &h->root : NULL), name,
howto->name, (bfd_vma) 0, input_bfd,
input_section, r_addr)))
return FALSE;
}
break;
}
}
}
return TRUE;
}
static bfd_boolean
aout_link_input_section_ext (struct aout_final_link_info *finfo,
bfd *input_bfd,
asection *input_section,
struct reloc_ext_external *relocs,
bfd_size_type rel_size,
bfd_byte *contents)
{
bfd_boolean (*check_dynamic_reloc)
(struct bfd_link_info *, bfd *, asection *,
struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *,
bfd_vma *);
bfd *output_bfd;
bfd_boolean relocatable;
struct external_nlist *syms;
char *strings;
struct aout_link_hash_entry **sym_hashes;
int *symbol_map;
bfd_size_type reloc_count;
struct reloc_ext_external *rel;
struct reloc_ext_external *rel_end;
output_bfd = finfo->output_bfd;
check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc;
BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE);
BFD_ASSERT (input_bfd->xvec->header_byteorder
== output_bfd->xvec->header_byteorder);
relocatable = finfo->info->relocatable;
syms = obj_aout_external_syms (input_bfd);
strings = obj_aout_external_strings (input_bfd);
sym_hashes = obj_aout_sym_hashes (input_bfd);
symbol_map = finfo->symbol_map;
reloc_count = rel_size / RELOC_EXT_SIZE;
rel = relocs;
rel_end = rel + reloc_count;
for (; rel < rel_end; rel++)
{
bfd_vma r_addr;
int r_index;
int r_extern;
unsigned int r_type;
bfd_vma r_addend;
struct aout_link_hash_entry *h = NULL;
asection *r_section = NULL;
bfd_vma relocation;
r_addr = GET_SWORD (input_bfd, rel->r_address);
if (bfd_header_big_endian (input_bfd))
{
r_index = (((unsigned int) rel->r_index[0] << 16)
| ((unsigned int) rel->r_index[1] << 8)
| rel->r_index[2]);
r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG));
r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
>> RELOC_EXT_BITS_TYPE_SH_BIG);
}
else
{
r_index = (((unsigned int) rel->r_index[2] << 16)
| ((unsigned int) rel->r_index[1] << 8)
| rel->r_index[0]);
r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE));
r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE)
>> RELOC_EXT_BITS_TYPE_SH_LITTLE);
}
r_addend = GET_SWORD (input_bfd, rel->r_addend);
BFD_ASSERT (r_type < TABLE_SIZE (howto_table_ext));
if (relocatable)
{
if (r_extern
|| r_type == (unsigned int) RELOC_BASE10
|| r_type == (unsigned int) RELOC_BASE13
|| r_type == (unsigned int) RELOC_BASE22)
{
if (r_type == (unsigned int) RELOC_BASE10
|| r_type == (unsigned int) RELOC_BASE13
|| r_type == (unsigned int) RELOC_BASE22)
h = NULL;
else
h = sym_hashes[r_index];
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
asection *output_section;
if (bfd_header_big_endian (output_bfd))
rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_BIG;
else
rel->r_type[0] &=~ RELOC_EXT_BITS_EXTERN_LITTLE;
output_section = h->root.u.def.section->output_section;
if (output_section == obj_textsec (output_bfd))
r_index = N_TEXT;
else if (output_section == obj_datasec (output_bfd))
r_index = N_DATA;
else if (output_section == obj_bsssec (output_bfd))
r_index = N_BSS;
else
r_index = N_ABS;
relocation = (h->root.u.def.value
+ output_section->vma
+ h->root.u.def.section->output_offset);
}
else
{
r_index = symbol_map[r_index];
if (r_index == -1)
{
if (h != NULL)
{
if (h->indx < 0)
{
h->indx = -2;
h->written = FALSE;
if (! aout_link_write_other_symbol (h,
(void *) finfo))
return FALSE;
}
r_index = h->indx;
}
else
{
const char *name;
name = strings + GET_WORD (input_bfd,
syms[r_index].e_strx);
if (! ((*finfo->info->callbacks->unattached_reloc)
(finfo->info, name, input_bfd, input_section,
r_addr)))
return FALSE;
r_index = 0;
}
}
relocation = 0;
}
if (bfd_header_big_endian (output_bfd))
{
rel->r_index[0] = r_index >> 16;
rel->r_index[1] = r_index >> 8;
rel->r_index[2] = r_index;
}
else
{
rel->r_index[2] = r_index >> 16;
rel->r_index[1] = r_index >> 8;
rel->r_index[0] = r_index;
}
}
else
{
r_section = aout_reloc_index_to_section (input_bfd, r_index);
relocation = (r_section->output_section->vma
+ r_section->output_offset
- r_section->vma);
}
if (howto_table_ext[r_type].pc_relative
&& ! howto_table_ext[r_type].pcrel_offset)
relocation -= (input_section->output_section->vma
+ input_section->output_offset
- input_section->vma);
if (relocation != 0)
PUT_WORD (output_bfd, r_addend + relocation, rel->r_addend);
PUT_WORD (output_bfd,
r_addr + input_section->output_offset,
rel->r_address);
}
else
{
bfd_boolean hundef;
bfd_reloc_status_type r;
hundef = FALSE;
if (r_extern)
{
h = sym_hashes[r_index];
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
relocation = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
}
else if (h != NULL
&& h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
hundef = TRUE;
relocation = 0;
}
}
else if (r_type == (unsigned int) RELOC_BASE10
|| r_type == (unsigned int) RELOC_BASE13
|| r_type == (unsigned int) RELOC_BASE22)
{
struct external_nlist *sym;
int type;
sym = syms + r_index;
type = H_GET_8 (input_bfd, sym->e_type);
if ((type & N_TYPE) == N_TEXT
|| type == N_WEAKT)
r_section = obj_textsec (input_bfd);
else if ((type & N_TYPE) == N_DATA
|| type == N_WEAKD)
r_section = obj_datasec (input_bfd);
else if ((type & N_TYPE) == N_BSS
|| type == N_WEAKB)
r_section = obj_bsssec (input_bfd);
else if ((type & N_TYPE) == N_ABS
|| type == N_WEAKA)
r_section = bfd_abs_section_ptr;
else
abort ();
relocation = (r_section->output_section->vma
+ r_section->output_offset
+ (GET_WORD (input_bfd, sym->e_value)
- r_section->vma));
}
else
{
r_section = aout_reloc_index_to_section (input_bfd, r_index);
relocation = (r_section->output_section->vma
+ r_section->output_offset
- r_section->vma);
if (howto_table_ext[r_type].pc_relative)
relocation += input_section->vma;
}
if (check_dynamic_reloc != NULL)
{
bfd_boolean skip;
if (! ((*check_dynamic_reloc)
(finfo->info, input_bfd, input_section, h,
(void *) rel, contents, &skip, &relocation)))
return FALSE;
if (skip)
continue;
}
if (hundef
&& ! finfo->info->shared
&& r_type != (unsigned int) RELOC_BASE10
&& r_type != (unsigned int) RELOC_BASE13
&& r_type != (unsigned int) RELOC_BASE22)
{
const char *name;
if (h != NULL)
name = h->root.root.string;
else
name = strings + GET_WORD (input_bfd, syms[r_index].e_strx);
if (! ((*finfo->info->callbacks->undefined_symbol)
(finfo->info, name, input_bfd, input_section,
r_addr, TRUE)))
return FALSE;
}
if (r_type != (unsigned int) RELOC_SPARC_REV32)
r = MY_final_link_relocate (howto_table_ext + r_type,
input_bfd, input_section,
contents, r_addr, relocation,
r_addend);
else
{
bfd_vma x;
x = bfd_get_32 (input_bfd, contents + r_addr);
x = x + relocation + r_addend;
bfd_putl32 ( x, contents + r_addr);
r = bfd_reloc_ok;
}
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
{
const char *name;
if (h != NULL)
name = NULL;
else if (r_extern
|| r_type == (unsigned int) RELOC_BASE10
|| r_type == (unsigned int) RELOC_BASE13
|| r_type == (unsigned int) RELOC_BASE22)
name = strings + GET_WORD (input_bfd,
syms[r_index].e_strx);
else
{
asection *s;
s = aout_reloc_index_to_section (input_bfd, r_index);
name = bfd_section_name (input_bfd, s);
}
if (! ((*finfo->info->callbacks->reloc_overflow)
(finfo->info, (h ? &h->root : NULL), name,
howto_table_ext[r_type].name,
r_addend, input_bfd, input_section, r_addr)))
return FALSE;
}
break;
}
}
}
}
return TRUE;
}
static bfd_boolean
aout_link_input_section (struct aout_final_link_info *finfo,
bfd *input_bfd,
asection *input_section,
file_ptr *reloff_ptr,
bfd_size_type rel_size)
{
bfd_size_type input_size;
void * relocs;
input_size = input_section->size;
if (! bfd_get_section_contents (input_bfd, input_section,
(void *) finfo->contents,
(file_ptr) 0, input_size))
return FALSE;
if (aout_section_data (input_section) != NULL
&& aout_section_data (input_section)->relocs != NULL)
relocs = aout_section_data (input_section)->relocs;
else
{
relocs = finfo->relocs;
if (rel_size > 0)
{
if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
|| bfd_bread (relocs, rel_size, input_bfd) != rel_size)
return FALSE;
}
}
if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
{
if (! aout_link_input_section_std (finfo, input_bfd, input_section,
(struct reloc_std_external *) relocs,
rel_size, finfo->contents))
return FALSE;
}
else
{
if (! aout_link_input_section_ext (finfo, input_bfd, input_section,
(struct reloc_ext_external *) relocs,
rel_size, finfo->contents))
return FALSE;
}
if (! bfd_set_section_contents (finfo->output_bfd,
input_section->output_section,
(void *) finfo->contents,
(file_ptr) input_section->output_offset,
input_size))
return FALSE;
if (finfo->info->relocatable && rel_size > 0)
{
if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
return FALSE;
if (bfd_bwrite (relocs, rel_size, finfo->output_bfd) != rel_size)
return FALSE;
*reloff_ptr += rel_size;
BFD_ASSERT (*reloff_ptr <= obj_sym_filepos (finfo->output_bfd)
&& (reloff_ptr != &finfo->treloff
|| (*reloff_ptr
<= obj_datasec (finfo->output_bfd)->rel_filepos)));
}
return TRUE;
}
static bfd_boolean
aout_link_write_symbols (struct aout_final_link_info *finfo, bfd *input_bfd)
{
bfd *output_bfd;
bfd_size_type sym_count;
char *strings;
enum bfd_link_strip strip;
enum bfd_link_discard discard;
struct external_nlist *outsym;
bfd_size_type strtab_index;
struct external_nlist *sym;
struct external_nlist *sym_end;
struct aout_link_hash_entry **sym_hash;
int *symbol_map;
bfd_boolean pass;
bfd_boolean skip_next;
output_bfd = finfo->output_bfd;
sym_count = obj_aout_external_sym_count (input_bfd);
strings = obj_aout_external_strings (input_bfd);
strip = finfo->info->strip;
discard = finfo->info->discard;
outsym = finfo->output_syms;
if (strip != strip_all
&& (strip != strip_some
|| bfd_hash_lookup (finfo->info->keep_hash, input_bfd->filename,
FALSE, FALSE) != NULL)
&& discard != discard_all)
{
H_PUT_8 (output_bfd, N_TEXT, outsym->e_type);
H_PUT_8 (output_bfd, 0, outsym->e_other);
H_PUT_16 (output_bfd, 0, outsym->e_desc);
strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
input_bfd->filename, FALSE);
if (strtab_index == (bfd_size_type) -1)
return FALSE;
PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
PUT_WORD (output_bfd,
(bfd_get_section_vma (output_bfd,
obj_textsec (input_bfd)->output_section)
+ obj_textsec (input_bfd)->output_offset),
outsym->e_value);
++obj_aout_external_sym_count (output_bfd);
++outsym;
}
pass = FALSE;
skip_next = FALSE;
sym = obj_aout_external_syms (input_bfd);
sym_end = sym + sym_count;
sym_hash = obj_aout_sym_hashes (input_bfd);
symbol_map = finfo->symbol_map;
memset (symbol_map, 0, (size_t) sym_count * sizeof *symbol_map);
for (; sym < sym_end; sym++, sym_hash++, symbol_map++)
{
const char *name;
int type;
struct aout_link_hash_entry *h;
bfd_boolean skip;
asection *symsec;
bfd_vma val = 0;
bfd_boolean copy;
if (*symbol_map == -1)
continue;
*symbol_map = -1;
type = H_GET_8 (input_bfd, sym->e_type);
name = strings + GET_WORD (input_bfd, sym->e_strx);
h = NULL;
if (pass)
{
val = GET_WORD (input_bfd, sym->e_value);
pass = FALSE;
}
else if (skip_next)
{
skip_next = FALSE;
continue;
}
else
{
struct aout_link_hash_entry *hresolve;
h = *sym_hash;
if (h != NULL
&& h->root.type != bfd_link_hash_warning)
name = h->root.root.string;
hresolve = h;
if (h != (struct aout_link_hash_entry *) NULL
&& (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning))
{
hresolve = (struct aout_link_hash_entry *) h->root.u.i.link;
while (hresolve->root.type == bfd_link_hash_indirect
|| hresolve->root.type == bfd_link_hash_warning)
hresolve = ((struct aout_link_hash_entry *)
hresolve->root.u.i.link);
*sym_hash = hresolve;
}
if (h != NULL
&& h->written)
{
if ((type & N_TYPE) == N_INDR
|| type == N_WARNING)
skip_next = TRUE;
*symbol_map = h->indx;
continue;
}
skip = FALSE;
switch (strip)
{
case strip_none:
break;
case strip_debugger:
if ((type & N_STAB) != 0)
skip = TRUE;
break;
case strip_some:
if (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, FALSE)
== NULL)
skip = TRUE;
break;
case strip_all:
skip = TRUE;
break;
}
if (skip)
{
if (h != NULL)
h->written = TRUE;
continue;
}
if ((type & N_TYPE) == N_TEXT
|| type == N_WEAKT)
symsec = obj_textsec (input_bfd);
else if ((type & N_TYPE) == N_DATA
|| type == N_WEAKD)
symsec = obj_datasec (input_bfd);
else if ((type & N_TYPE) == N_BSS
|| type == N_WEAKB)
symsec = obj_bsssec (input_bfd);
else if ((type & N_TYPE) == N_ABS
|| type == N_WEAKA)
symsec = bfd_abs_section_ptr;
else if (((type & N_TYPE) == N_INDR
&& (hresolve == NULL
|| (hresolve->root.type != bfd_link_hash_defined
&& hresolve->root.type != bfd_link_hash_defweak
&& hresolve->root.type != bfd_link_hash_common)))
|| type == N_WARNING)
{
pass = TRUE;
val = GET_WORD (input_bfd, sym->e_value);
symsec = NULL;
}
else if ((type & N_STAB) != 0)
{
val = GET_WORD (input_bfd, sym->e_value);
symsec = NULL;
}
else
{
if ((type & N_TYPE) == N_INDR)
skip_next = TRUE;
symsec = NULL;
if (h == NULL)
{
switch (type & N_TYPE)
{
case N_SETT:
symsec = obj_textsec (input_bfd);
break;
case N_SETD:
symsec = obj_datasec (input_bfd);
break;
case N_SETB:
symsec = obj_bsssec (input_bfd);
break;
case N_SETA:
symsec = bfd_abs_section_ptr;
break;
default:
val = 0;
break;
}
}
else if (hresolve->root.type == bfd_link_hash_defined
|| hresolve->root.type == bfd_link_hash_defweak)
{
asection *input_section;
asection *output_section;
input_section = hresolve->root.u.def.section;
output_section = input_section->output_section;
BFD_ASSERT (bfd_is_abs_section (output_section)
|| output_section->owner == output_bfd);
val = (hresolve->root.u.def.value
+ bfd_get_section_vma (output_bfd, output_section)
+ input_section->output_offset);
if (type == N_SETT
|| type == N_SETD
|| type == N_SETB
|| type == N_SETA)
type |= N_EXT;
type &=~ N_TYPE;
if (output_section == obj_textsec (output_bfd))
type |= (hresolve->root.type == bfd_link_hash_defined
? N_TEXT
: N_WEAKT);
else if (output_section == obj_datasec (output_bfd))
type |= (hresolve->root.type == bfd_link_hash_defined
? N_DATA
: N_WEAKD);
else if (output_section == obj_bsssec (output_bfd))
type |= (hresolve->root.type == bfd_link_hash_defined
? N_BSS
: N_WEAKB);
else
type |= (hresolve->root.type == bfd_link_hash_defined
? N_ABS
: N_WEAKA);
}
else if (hresolve->root.type == bfd_link_hash_common)
val = hresolve->root.u.c.size;
else if (hresolve->root.type == bfd_link_hash_undefweak)
{
val = 0;
type = N_WEAKU;
}
else
val = 0;
}
if (symsec != NULL)
val = (symsec->output_section->vma
+ symsec->output_offset
+ (GET_WORD (input_bfd, sym->e_value)
- symsec->vma));
if (h != NULL)
{
h->written = TRUE;
h->indx = obj_aout_external_sym_count (output_bfd);
}
else if ((type & N_TYPE) != N_SETT
&& (type & N_TYPE) != N_SETD
&& (type & N_TYPE) != N_SETB
&& (type & N_TYPE) != N_SETA)
{
switch (discard)
{
case discard_none:
case discard_sec_merge:
break;
case discard_l:
if ((type & N_STAB) == 0
&& bfd_is_local_label_name (input_bfd, name))
skip = TRUE;
break;
case discard_all:
skip = TRUE;
break;
}
if (skip)
{
pass = FALSE;
continue;
}
}
if (type == (int) N_BINCL)
{
struct external_nlist *incl_sym;
int nest;
struct aout_link_includes_entry *incl_entry;
struct aout_link_includes_totals *t;
val = 0;
nest = 0;
for (incl_sym = sym + 1; incl_sym < sym_end; incl_sym++)
{
int incl_type;
incl_type = H_GET_8 (input_bfd, incl_sym->e_type);
if (incl_type == (int) N_EINCL)
{
if (nest == 0)
break;
--nest;
}
else if (incl_type == (int) N_BINCL)
++nest;
else if (nest == 0)
{
const char *s;
s = strings + GET_WORD (input_bfd, incl_sym->e_strx);
for (; *s != '\0'; s++)
{
val += *s;
if (*s == '(')
{
++s;
while (ISDIGIT (*s))
++s;
--s;
}
}
}
}
copy = (bfd_boolean) (! finfo->info->keep_memory);
incl_entry = aout_link_includes_lookup (&finfo->includes,
name, TRUE, copy);
if (incl_entry == NULL)
return FALSE;
for (t = incl_entry->totals; t != NULL; t = t->next)
if (t->total == val)
break;
if (t == NULL)
{
t = bfd_hash_allocate (&finfo->includes.root,
sizeof *t);
if (t == NULL)
return FALSE;
t->total = val;
t->next = incl_entry->totals;
incl_entry->totals = t;
}
else
{
int *incl_map;
type = (int) N_EXCL;
nest = 0;
for (incl_sym = sym + 1, incl_map = symbol_map + 1;
incl_sym < sym_end;
incl_sym++, incl_map++)
{
int incl_type;
incl_type = H_GET_8 (input_bfd, incl_sym->e_type);
if (incl_type == (int) N_EINCL)
{
if (nest == 0)
{
*incl_map = -1;
break;
}
--nest;
}
else if (incl_type == (int) N_BINCL)
++nest;
else if (nest == 0)
*incl_map = -1;
}
}
}
}
H_PUT_8 (output_bfd, type, outsym->e_type);
H_PUT_8 (output_bfd, H_GET_8 (input_bfd, sym->e_other), outsym->e_other);
H_PUT_16 (output_bfd, H_GET_16 (input_bfd, sym->e_desc), outsym->e_desc);
copy = FALSE;
if (! finfo->info->keep_memory)
{
if (h != NULL)
name = h->root.root.string;
else
copy = TRUE;
}
strtab_index = add_to_stringtab (output_bfd, finfo->strtab,
name, copy);
if (strtab_index == (bfd_size_type) -1)
return FALSE;
PUT_WORD (output_bfd, strtab_index, outsym->e_strx);
PUT_WORD (output_bfd, val, outsym->e_value);
*symbol_map = obj_aout_external_sym_count (output_bfd);
++obj_aout_external_sym_count (output_bfd);
++outsym;
}
if (outsym > finfo->output_syms)
{
bfd_size_type outsym_size;
if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0)
return FALSE;
outsym_size = outsym - finfo->output_syms;
outsym_size *= EXTERNAL_NLIST_SIZE;
if (bfd_bwrite ((void *) finfo->output_syms, outsym_size, output_bfd)
!= outsym_size)
return FALSE;
finfo->symoff += outsym_size;
}
return TRUE;
}
static bfd_boolean
aout_link_input_bfd (struct aout_final_link_info *finfo, bfd *input_bfd)
{
bfd_size_type sym_count;
BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object);
if ((input_bfd->flags & DYNAMIC) != 0
&& aout_backend_info (input_bfd)->link_dynamic_object != NULL)
return ((*aout_backend_info (input_bfd)->link_dynamic_object)
(finfo->info, input_bfd));
if (! aout_get_external_symbols (input_bfd))
return FALSE;
sym_count = obj_aout_external_sym_count (input_bfd);
if (! aout_link_write_symbols (finfo, input_bfd))
return FALSE;
if (obj_textsec (input_bfd)->linker_mark)
{
if (! aout_link_input_section (finfo, input_bfd,
obj_textsec (input_bfd),
&finfo->treloff,
exec_hdr (input_bfd)->a_trsize))
return FALSE;
}
if (obj_datasec (input_bfd)->linker_mark)
{
if (! aout_link_input_section (finfo, input_bfd,
obj_datasec (input_bfd),
&finfo->dreloff,
exec_hdr (input_bfd)->a_drsize))
return FALSE;
}
if (! finfo->info->keep_memory)
{
if (! aout_link_free_symbols (input_bfd))
return FALSE;
}
return TRUE;
}
bfd_boolean
NAME (aout, final_link) (bfd *abfd,
struct bfd_link_info *info,
void (*callback) (bfd *, file_ptr *, file_ptr *, file_ptr *))
{
struct aout_final_link_info aout_info;
bfd_boolean includes_hash_initialized = FALSE;
bfd *sub;
bfd_size_type trsize, drsize;
bfd_size_type max_contents_size;
bfd_size_type max_relocs_size;
bfd_size_type max_sym_count;
bfd_size_type text_size;
file_ptr text_end;
struct bfd_link_order *p;
asection *o;
bfd_boolean have_link_order_relocs;
if (info->shared)
abfd->flags |= DYNAMIC;
aout_info.info = info;
aout_info.output_bfd = abfd;
aout_info.contents = NULL;
aout_info.relocs = NULL;
aout_info.symbol_map = NULL;
aout_info.output_syms = NULL;
if (! bfd_hash_table_init_n (&aout_info.includes.root,
aout_link_includes_newfunc,
251))
goto error_return;
includes_hash_initialized = TRUE;
trsize = 0;
drsize = 0;
max_contents_size = 0;
max_relocs_size = 0;
max_sym_count = 0;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
bfd_size_type sz;
if (info->relocatable)
{
if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
{
trsize += exec_hdr (sub)->a_trsize;
drsize += exec_hdr (sub)->a_drsize;
}
else
{
(*_bfd_error_handler)
(_("%s: relocatable link from %s to %s not supported"),
bfd_get_filename (abfd),
sub->xvec->name, abfd->xvec->name);
bfd_set_error (bfd_error_invalid_operation);
goto error_return;
}
}
if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
{
sz = obj_textsec (sub)->size;
if (sz > max_contents_size)
max_contents_size = sz;
sz = obj_datasec (sub)->size;
if (sz > max_contents_size)
max_contents_size = sz;
sz = exec_hdr (sub)->a_trsize;
if (sz > max_relocs_size)
max_relocs_size = sz;
sz = exec_hdr (sub)->a_drsize;
if (sz > max_relocs_size)
max_relocs_size = sz;
sz = obj_aout_external_sym_count (sub);
if (sz > max_sym_count)
max_sym_count = sz;
}
}
if (info->relocatable)
{
if (obj_textsec (abfd) != NULL)
trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd)
->map_head.link_order)
* obj_reloc_entry_size (abfd));
if (obj_datasec (abfd) != NULL)
drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd)
->map_head.link_order)
* obj_reloc_entry_size (abfd));
}
exec_hdr (abfd)->a_trsize = trsize;
exec_hdr (abfd)->a_drsize = drsize;
exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd);
if (! NAME (aout, adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
goto error_return;
(*callback) (abfd, &aout_info.treloff, &aout_info.dreloff,
&aout_info.symoff);
obj_textsec (abfd)->rel_filepos = aout_info.treloff;
obj_datasec (abfd)->rel_filepos = aout_info.dreloff;
obj_sym_filepos (abfd) = aout_info.symoff;
obj_aout_external_sym_count (abfd) = 0;
aout_info.strtab = _bfd_stringtab_init ();
if (aout_info.strtab == NULL)
goto error_return;
aout_info.contents = bfd_malloc (max_contents_size);
aout_info.relocs = bfd_malloc (max_relocs_size);
aout_info.symbol_map = bfd_malloc (max_sym_count * sizeof (int *));
aout_info.output_syms = bfd_malloc ((max_sym_count + 1)
* sizeof (struct external_nlist));
if ((aout_info.contents == NULL && max_contents_size != 0)
|| (aout_info.relocs == NULL && max_relocs_size != 0)
|| (aout_info.symbol_map == NULL && max_sym_count != 0)
|| aout_info.output_syms == NULL)
goto error_return;
{
struct aout_link_hash_entry *h;
h = aout_link_hash_lookup (aout_hash_table (info), "__DYNAMIC",
FALSE, FALSE, FALSE);
if (h != NULL)
aout_link_write_other_symbol (h, &aout_info);
}
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
sub->output_has_begun = FALSE;
for (o = abfd->sections; o != NULL; o = o->next)
{
for (p = o->map_head.link_order; p != NULL; p = p->next)
if (p->type == bfd_indirect_link_order)
p->u.indirect.section->linker_mark = TRUE;
}
have_link_order_relocs = FALSE;
for (o = abfd->sections; o != NULL; o = o->next)
{
for (p = o->map_head.link_order;
p != NULL;
p = p->next)
{
if (p->type == bfd_indirect_link_order
&& (bfd_get_flavour (p->u.indirect.section->owner)
== bfd_target_aout_flavour))
{
bfd *input_bfd;
input_bfd = p->u.indirect.section->owner;
if (! input_bfd->output_has_begun)
{
if (! aout_link_input_bfd (&aout_info, input_bfd))
goto error_return;
input_bfd->output_has_begun = TRUE;
}
}
else if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
{
have_link_order_relocs = TRUE;
}
else
{
if (! _bfd_default_link_order (abfd, info, o, p))
goto error_return;
}
}
}
aout_link_hash_traverse (aout_hash_table (info),
aout_link_write_other_symbol,
(void *) &aout_info);
if (have_link_order_relocs)
{
for (o = abfd->sections; o != NULL; o = o->next)
{
for (p = o->map_head.link_order;
p != NULL;
p = p->next)
{
if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
{
if (! aout_link_reloc_link_order (&aout_info, o, p))
goto error_return;
}
}
}
}
if (aout_info.contents != NULL)
{
free (aout_info.contents);
aout_info.contents = NULL;
}
if (aout_info.relocs != NULL)
{
free (aout_info.relocs);
aout_info.relocs = NULL;
}
if (aout_info.symbol_map != NULL)
{
free (aout_info.symbol_map);
aout_info.symbol_map = NULL;
}
if (aout_info.output_syms != NULL)
{
free (aout_info.output_syms);
aout_info.output_syms = NULL;
}
if (includes_hash_initialized)
{
bfd_hash_table_free (&aout_info.includes.root);
includes_hash_initialized = FALSE;
}
if (aout_backend_info (abfd)->finish_dynamic_link != NULL)
{
if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info))
goto error_return;
}
abfd->symcount = obj_aout_external_sym_count (abfd);
exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE;
obj_str_filepos (abfd) = obj_sym_filepos (abfd) + exec_hdr (abfd)->a_syms;
obj_textsec (abfd)->reloc_count =
exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd);
obj_datasec (abfd)->reloc_count =
exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd);
if (abfd->symcount > 0)
{
if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0
|| ! emit_stringtab (abfd, aout_info.strtab))
goto error_return;
}
else if (obj_textsec (abfd)->reloc_count == 0
&& obj_datasec (abfd)->reloc_count == 0)
{
bfd_byte b;
file_ptr pos;
b = 0;
pos = obj_datasec (abfd)->filepos + exec_hdr (abfd)->a_data - 1;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|| bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
goto error_return;
}
return TRUE;
error_return:
if (aout_info.contents != NULL)
free (aout_info.contents);
if (aout_info.relocs != NULL)
free (aout_info.relocs);
if (aout_info.symbol_map != NULL)
free (aout_info.symbol_map);
if (aout_info.output_syms != NULL)
free (aout_info.output_syms);
if (includes_hash_initialized)
bfd_hash_table_free (&aout_info.includes.root);
return FALSE;
}