#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "coff/powerpc.h"
#include "coff/internal.h"
#include "coff/pe.h"
#ifdef BADMAG
#undef BADMAG
#endif
#define BADMAG(x) PPCBADMAG(x)
#include "libcoff.h"
extern bfd_boolean ppc_bfd_coff_final_link
PARAMS ((bfd *, struct bfd_link_info *));
extern void dump_toc PARAMS ((PTR));
#define SET_UNALLOCATED(x) ((x) = 1)
#define IS_UNALLOCATED(x) ((x) == 1)
#define IS_WRITTEN(x) ((x) & 1)
#define MARK_AS_WRITTEN(x) ((x) |= 1)
#define MAKE_ADDR_AGAIN(x) ((x) &= ~1)
#ifdef DEBUG_HASH
#define EYE "krkjunk"
#define HASH_CHECK_DCL char eye_catcher[8];
#define HASH_CHECK_INIT(ret) strcpy(ret->eye_catcher, EYE)
#define HASH_CHECK(addr) \
if (strcmp(addr->eye_catcher, EYE) != 0) \
{ \
fprintf (stderr,\
_("File %s, line %d, Hash check failure, bad eye %8s\n"), \
__FILE__, __LINE__, addr->eye_catcher); \
abort (); \
}
#else
#define HASH_CHECK_DCL
#define HASH_CHECK_INIT(ret)
#define HASH_CHECK(addr)
#endif
struct ppc_coff_link_hash_entry
{
struct coff_link_hash_entry root;
bfd_vma toc_offset;
int symbol_is_glue;
unsigned long int glue_insn;
HASH_CHECK_DCL
};
struct ppc_coff_link_hash_table
{
struct coff_link_hash_table root;
};
static struct bfd_hash_entry *ppc_coff_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
const char *));
static bfd_boolean ppc_coff_link_hash_table_init
PARAMS ((struct ppc_coff_link_hash_table *, bfd *,
struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
struct bfd_hash_table *,
const char *)));
static struct bfd_link_hash_table *ppc_coff_link_hash_table_create
PARAMS ((bfd *));
static bfd_boolean coff_ppc_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
struct internal_reloc *, struct internal_syment *, asection **));
static reloc_howto_type *coff_ppc_rtype_to_howto
PARAMS ((bfd *, asection *, struct internal_reloc *,
struct coff_link_hash_entry *, struct internal_syment *,
bfd_vma *));
static struct bfd_hash_entry *
ppc_coff_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct ppc_coff_link_hash_entry *ret =
(struct ppc_coff_link_hash_entry *) entry;
if (ret == (struct ppc_coff_link_hash_entry *) NULL)
ret = (struct ppc_coff_link_hash_entry *)
bfd_hash_allocate (table,
sizeof (struct ppc_coff_link_hash_entry));
if (ret == (struct ppc_coff_link_hash_entry *) NULL)
return NULL;
ret = ((struct ppc_coff_link_hash_entry *)
_bfd_coff_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret)
{
SET_UNALLOCATED(ret->toc_offset);
ret->symbol_is_glue = 0;
ret->glue_insn = 0;
HASH_CHECK_INIT(ret);
}
return (struct bfd_hash_entry *) ret;
}
static bfd_boolean
ppc_coff_link_hash_table_init (table, abfd, newfunc)
struct ppc_coff_link_hash_table *table;
bfd *abfd;
struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
struct bfd_hash_table *,
const char *));
{
return _bfd_coff_link_hash_table_init (&table->root, abfd, newfunc);
}
static struct bfd_link_hash_table *
ppc_coff_link_hash_table_create (abfd)
bfd *abfd;
{
struct ppc_coff_link_hash_table *ret;
bfd_size_type amt = sizeof (struct ppc_coff_link_hash_table);
ret = (struct ppc_coff_link_hash_table *) bfd_malloc (amt);
if (ret == NULL)
return NULL;
if (! ppc_coff_link_hash_table_init (ret, abfd,
ppc_coff_link_hash_newfunc))
{
free (ret);
return (struct bfd_link_hash_table *) NULL;
}
return &ret->root.root;
}
#define coff_bfd_link_hash_table_create ppc_coff_link_hash_table_create
#define TOC_LOAD_ADJUSTMENT (-32768)
#define TOC_SECTION_NAME ".private.toc"
#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
#define MINUS_ONE (((bfd_vma)0) - 1)
#define IMAGE_REL_PPC_ABSOLUTE 0x0000
#define IMAGE_REL_PPC_ADDR64 0x0001
#define IMAGE_REL_PPC_ADDR32 0x0002
#define IMAGE_REL_PPC_ADDR24 0x0003
#define IMAGE_REL_PPC_ADDR16 0x0004
#define IMAGE_REL_PPC_ADDR14 0x0005
#define IMAGE_REL_PPC_REL24 0x0006
#define IMAGE_REL_PPC_REL14 0x0007
#define IMAGE_REL_PPC_TOCREL16 0x0008
#define IMAGE_REL_PPC_TOCREL14 0x0009
#define IMAGE_REL_PPC_ADDR32NB 0x000A
#define IMAGE_REL_PPC_SECREL 0x000B
#define IMAGE_REL_PPC_SECTION 0x000C
#define IMAGE_REL_PPC_IFGLUE 0x000D
#define IMAGE_REL_PPC_IMGLUE 0x000E
#define IMAGE_REL_PPC_SECREL16 0x000F
#define IMAGE_REL_PPC_REFHI 0x0010
#define IMAGE_REL_PPC_REFLO 0x0011
#define IMAGE_REL_PPC_PAIR 0x0012
#define IMAGE_REL_PPC_TOCREL16_DEFN 0x0013
#define IMAGE_REL_PPC_NEG 0x0100
#define IMAGE_REL_PPC_BRTAKEN 0x0200
#define IMAGE_REL_PPC_BRNTAKEN 0x0400
#define IMAGE_REL_PPC_TOCDEFN 0x0800
#define IMAGE_REL_PPC_TYPEMASK 0x00FF
#define IMAGE_REL_PPC_FLAGMASK 0x0F00
#define EXTRACT_TYPE(x) ((x) & IMAGE_REL_PPC_TYPEMASK)
#define EXTRACT_FLAGS(x) ((x) & IMAGE_REL_PPC_FLAGMASK)
#define EXTRACT_JUNK(x) \
((x) & ~(IMAGE_REL_PPC_TYPEMASK | IMAGE_REL_PPC_FLAGMASK))
static bfd_reloc_status_type ppc_refhi_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
#if 0
static bfd_reloc_status_type ppc_reflo_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
#endif
static bfd_reloc_status_type ppc_pair_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
static bfd_reloc_status_type ppc_toc16_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
#if 0
static bfd_reloc_status_type ppc_addr32nb_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
#endif
static bfd_reloc_status_type ppc_section_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
static bfd_reloc_status_type ppc_secrel_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
static bfd_reloc_status_type ppc_imglue_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
bfd *output_bfd,
char **error));
static bfd_boolean in_reloc_p PARAMS((bfd *abfd, reloc_howto_type *howto));
static reloc_howto_type ppc_coff_howto_table[] =
{
HOWTO (IMAGE_REL_PPC_ABSOLUTE,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
0,
"ABSOLUTE",
FALSE,
0x00,
0x00,
FALSE),
HOWTO(IMAGE_REL_PPC_ADDR64,
0,
3,
64,
FALSE,
0,
complain_overflow_bitfield,
0,
"ADDR64",
TRUE,
MINUS_ONE,
MINUS_ONE,
FALSE),
HOWTO (IMAGE_REL_PPC_ADDR32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"ADDR32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (IMAGE_REL_PPC_ADDR24,
0,
2,
26,
FALSE,
0,
complain_overflow_bitfield,
0,
"ADDR24",
TRUE,
0x07fffffc,
0x07fffffc,
FALSE),
HOWTO (IMAGE_REL_PPC_ADDR16,
0,
1,
16,
FALSE,
0,
complain_overflow_signed,
0,
"ADDR16",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (IMAGE_REL_PPC_ADDR14,
1,
1,
16,
FALSE,
0,
complain_overflow_signed,
0,
"ADDR16",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (IMAGE_REL_PPC_REL24,
0,
2,
26,
TRUE,
0,
complain_overflow_signed,
0,
"REL24",
TRUE,
0x3fffffc,
0x3fffffc,
FALSE),
HOWTO (IMAGE_REL_PPC_ADDR14,
1,
1,
16,
FALSE,
0,
complain_overflow_signed,
0,
"ADDR16",
TRUE,
0xffff,
0xffff,
TRUE),
HOWTO (IMAGE_REL_PPC_TOCREL16,
0,
1,
16,
FALSE,
0,
complain_overflow_dont,
ppc_toc16_reloc,
"TOCREL16",
FALSE,
0xffff,
0xffff,
FALSE),
HOWTO (IMAGE_REL_PPC_TOCREL14,
1,
1,
16,
FALSE,
0,
complain_overflow_signed,
0,
"TOCREL14",
FALSE,
0xffff,
0xffff,
FALSE),
HOWTO (IMAGE_REL_PPC_ADDR32NB,
0,
2,
32,
FALSE,
0,
complain_overflow_signed,
0,
"ADDR32NB",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (IMAGE_REL_PPC_SECREL,
0,
2,
32,
FALSE,
0,
complain_overflow_signed,
ppc_secrel_reloc,
"SECREL",
TRUE,
0xffffffff,
0xffffffff,
TRUE),
HOWTO (IMAGE_REL_PPC_SECTION,
0,
2,
32,
FALSE,
0,
complain_overflow_signed,
ppc_section_reloc,
"SECTION",
TRUE,
0xffffffff,
0xffffffff,
TRUE),
HOWTO (IMAGE_REL_PPC_IFGLUE,
0,
2,
32,
FALSE,
0,
complain_overflow_signed,
0,
"IFGLUE",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (IMAGE_REL_PPC_IMGLUE,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
ppc_imglue_reloc,
"IMGLUE",
FALSE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (IMAGE_REL_PPC_SECREL16,
0,
1,
16,
FALSE,
0,
complain_overflow_signed,
0,
"SECREL16",
TRUE,
0xffff,
0xffff,
TRUE),
HOWTO (IMAGE_REL_PPC_REFHI,
0,
1,
16,
FALSE,
0,
complain_overflow_signed,
ppc_refhi_reloc,
"REFHI",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (IMAGE_REL_PPC_REFLO,
0,
1,
16,
FALSE,
0,
complain_overflow_signed,
ppc_refhi_reloc,
"REFLO",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (IMAGE_REL_PPC_PAIR,
0,
1,
16,
FALSE,
0,
complain_overflow_signed,
ppc_pair_reloc,
"PAIR",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO ( (IMAGE_REL_PPC_TOCREL16 | IMAGE_REL_PPC_TOCDEFN),
0,
1,
16,
FALSE,
0,
complain_overflow_dont,
0,
"TOCREL16, TOCDEFN",
FALSE,
0xffff,
0xffff,
FALSE),
};
#ifdef DEBUG_RELOC
#define UN_IMPL(x) \
{ \
static int i; \
if (i == 0) \
{ \
i = 1; \
fprintf (stderr,_("Unimplemented Relocation -- %s\n"),x); \
} \
}
#define DUMP_RELOC(n,r) \
{ \
fprintf (stderr,"%s sym %d, addr %d, addend %d\n", \
n, (*(r->sym_ptr_ptr))->name, \
r->address, r->addend); \
}
#define DUMP_RELOC2(n,r) \
{ \
fprintf (stderr,"%s sym %d, r_vaddr %d %s\n", \
n, r->r_symndx, r->r_vaddr,\
(((r->r_type) & IMAGE_REL_PPC_TOCDEFN) == 0) \
?" ":" TOCDEFN" ); \
}
#else
#define UN_IMPL(x)
#define DUMP_RELOC(n,r)
#define DUMP_RELOC2(n,r)
#endif
extern bfd* bfd_of_toc_owner;
extern long int global_toc_size;
extern long int import_table_size;
extern long int first_thunk_address;
extern long int thunk_size;
enum toc_type
{
default_toc,
toc_32,
toc_64
};
enum ref_category
{
priv,
pub,
tocdata
};
struct list_ele
{
struct list_ele *next;
bfd_vma addr;
enum ref_category cat;
int offset;
const char *name;
};
extern struct list_ele *head;
extern struct list_ele *tail;
static void record_toc
PARAMS ((asection *, bfd_signed_vma, enum ref_category, const char *));
static void
record_toc (toc_section, our_toc_offset, cat, name)
asection *toc_section;
bfd_signed_vma our_toc_offset;
enum ref_category cat;
const char *name;
{
bfd_size_type amt = sizeof (struct list_ele);
struct list_ele *t = (struct list_ele *) bfd_malloc (amt);
if (t == NULL)
abort ();
t->next = 0;
t->offset = our_toc_offset;
t->name = name;
t->cat = cat;
t->addr = toc_section->output_offset + our_toc_offset;
if (head == 0)
{
head = t;
tail = t;
}
else
{
tail->next = t;
tail = t;
}
}
#ifdef COFF_IMAGE_WITH_PE
static bfd_boolean ppc_record_toc_entry
PARAMS ((bfd *, struct bfd_link_info *, asection *, int, enum toc_type));
static void ppc_mark_symbol_as_glue
PARAMS ((bfd *, int, struct internal_reloc *));
static bfd_boolean
ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
bfd *abfd;
struct bfd_link_info *info ATTRIBUTE_UNUSED;
asection *sec ATTRIBUTE_UNUSED;
int sym;
enum toc_type toc_kind ATTRIBUTE_UNUSED;
{
struct ppc_coff_link_hash_entry *h;
const char *name;
int *local_syms;
h = 0;
h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
if (h != 0)
{
HASH_CHECK(h);
}
if (h == 0)
{
local_syms = obj_coff_local_toc_table(abfd);
if (local_syms == 0)
{
unsigned int i;
bfd_size_type amt;
amt = (bfd_size_type) obj_raw_syment_count (abfd) * sizeof (int);
local_syms = (int *) bfd_zalloc (abfd, amt);
if (local_syms == 0)
return FALSE;
obj_coff_local_toc_table (abfd) = local_syms;
for (i = 0; i < obj_raw_syment_count (abfd); ++i)
{
SET_UNALLOCATED (local_syms[i]);
}
}
if (IS_UNALLOCATED(local_syms[sym]))
{
local_syms[sym] = global_toc_size;
global_toc_size += 4;
if (global_toc_size > 65535)
{
(*_bfd_error_handler) (_("TOC overflow"));
bfd_set_error (bfd_error_file_too_big);
return FALSE;
}
}
}
else
{
name = h->root.root.root.string;
if (IS_UNALLOCATED(h->toc_offset))
{
h->toc_offset = global_toc_size;
global_toc_size += 4;
if (global_toc_size >= 65535)
{
(*_bfd_error_handler) (_("TOC overflow"));
bfd_set_error (bfd_error_file_too_big);
return FALSE;
}
}
}
return TRUE;
}
static void
ppc_mark_symbol_as_glue(abfd, sym, rel)
bfd *abfd;
int sym;
struct internal_reloc *rel;
{
struct ppc_coff_link_hash_entry *h;
h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
HASH_CHECK(h);
h->symbol_is_glue = 1;
h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr);
return;
}
#endif
static bfd_boolean in_reloc_p(abfd, howto)
bfd * abfd ATTRIBUTE_UNUSED;
reloc_howto_type *howto;
{
return
(! howto->pc_relative)
&& (howto->type != IMAGE_REL_PPC_ADDR32NB)
&& (howto->type != IMAGE_REL_PPC_TOCREL16)
&& (howto->type != IMAGE_REL_PPC_IMGLUE)
&& (howto->type != IMAGE_REL_PPC_IFGLUE)
&& (howto->type != IMAGE_REL_PPC_SECREL)
&& (howto->type != IMAGE_REL_PPC_SECTION)
&& (howto->type != IMAGE_REL_PPC_SECREL16)
&& (howto->type != IMAGE_REL_PPC_REFHI)
&& (howto->type != IMAGE_REL_PPC_REFLO)
&& (howto->type != IMAGE_REL_PPC_PAIR)
&& (howto->type != IMAGE_REL_PPC_TOCREL16_DEFN) ;
}
#if 0
static bfd_reloc_status_type
pe_ppc_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol_in;
PTR data;
asection *input_section;
bfd *output_bfd;
char **error_message;
{
static bfd_boolean part1_consth_active = FALSE;
static unsigned long part1_consth_value;
unsigned long sym_value;
unsigned short r_type;
unsigned long addr = reloc_entry->address ;
r_type = reloc_entry->howto->type;
if (output_bfd)
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
if (symbol_in != NULL
&& bfd_is_und_section (symbol_in->section))
{
if (r_type == IMAGE_REL_PPC_REFHI)
{
part1_consth_active = TRUE;
part1_consth_value = 0;
}
return(bfd_reloc_undefined);
}
if ((part1_consth_active) && (r_type != IMAGE_REL_PPC_PAIR))
{
part1_consth_active = FALSE;
*error_message = (char *) _("Missing PAIR");
return(bfd_reloc_dangerous);
}
sym_value = get_symbol_value(symbol_in);
return(bfd_reloc_ok);
}
#endif
static bfd_boolean
coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
contents, relocs, syms, sections)
bfd *output_bfd;
struct bfd_link_info *info;
bfd *input_bfd;
asection *input_section;
bfd_byte *contents;
struct internal_reloc *relocs;
struct internal_syment *syms;
asection **sections;
{
struct internal_reloc *rel;
struct internal_reloc *relend;
bfd_boolean hihalf;
bfd_vma hihalf_val;
asection *toc_section = 0;
bfd_vma relocation;
reloc_howto_type *howto = 0;
if (info->relocateable)
return TRUE;
hihalf = FALSE;
hihalf_val = 0;
rel = relocs;
relend = rel + input_section->reloc_count;
for (; rel < relend; rel++)
{
long symndx;
struct ppc_coff_link_hash_entry *h;
struct internal_syment *sym;
bfd_vma val;
asection *sec;
bfd_reloc_status_type rstat;
bfd_byte *loc;
unsigned short r_type = EXTRACT_TYPE (rel->r_type);
unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
symndx = rel->r_symndx;
loc = contents + rel->r_vaddr - input_section->vma;
howto = ppc_coff_howto_table + r_type;
if (symndx == -1)
{
h = NULL;
sym = NULL;
}
else
{
h = (struct ppc_coff_link_hash_entry *)
(obj_coff_sym_hashes (input_bfd)[symndx]);
if (h != 0)
{
HASH_CHECK(h);
}
sym = syms + symndx;
}
if (r_type == IMAGE_REL_PPC_IMGLUE && h == 0)
{
abort ();
}
sec = NULL;
val = 0;
if (h == NULL)
{
if (symndx == -1)
sec = bfd_abs_section_ptr;
else
{
sec = sections[symndx];
val = (sec->output_section->vma
+ sec->output_offset
+ sym->n_value);
if (! obj_pe (output_bfd))
val -= sec->vma;
}
}
else
{
HASH_CHECK(h);
if (h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
{
sec = h->root.root.u.def.section;
val = (h->root.root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else
{
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.root.string, input_bfd, input_section,
rel->r_vaddr - input_section->vma, TRUE)))
return FALSE;
}
}
rstat = bfd_reloc_ok;
switch (r_type)
{
default:
(*_bfd_error_handler)
(_("%s: unsupported relocation type 0x%02x"),
bfd_archive_filename (input_bfd), r_type);
bfd_set_error (bfd_error_bad_value);
return FALSE;
case IMAGE_REL_PPC_TOCREL16:
{
bfd_signed_vma our_toc_offset;
int fixit;
DUMP_RELOC2(howto->name, rel);
if (toc_section == 0)
{
toc_section = bfd_get_section_by_name (bfd_of_toc_owner,
TOC_SECTION_NAME);
if ( toc_section == NULL )
{
abort ();
}
}
fixit = FALSE;
if (h == 0)
{
int *local_toc_table;
const char *name;
sym = syms + symndx;
name = sym->_n._n_name;
local_toc_table = obj_coff_local_toc_table(input_bfd);
our_toc_offset = local_toc_table[symndx];
if (IS_WRITTEN(our_toc_offset))
{
MAKE_ADDR_AGAIN(our_toc_offset);
}
else
{
record_toc (toc_section, our_toc_offset, priv,
strdup (name));
bfd_put_32 (output_bfd, val,
toc_section->contents + our_toc_offset);
MARK_AS_WRITTEN(local_toc_table[symndx]);
fixit = TRUE;
}
}
else
{
const char *name = h->root.root.root.string;
our_toc_offset = h->toc_offset;
if ((r_flags & IMAGE_REL_PPC_TOCDEFN)
== IMAGE_REL_PPC_TOCDEFN )
{
our_toc_offset = val - (toc_section->output_section->vma
+ toc_section->output_offset);
if ((bfd_vma) our_toc_offset >= 65535)
{
(*_bfd_error_handler)
(_("%s: Relocation for %s of %lx exceeds Toc size limit"),
bfd_archive_filename (input_bfd), name,
(unsigned long) our_toc_offset);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
record_toc (toc_section, our_toc_offset, pub,
strdup (name));
}
else if (IS_WRITTEN(our_toc_offset))
{
MAKE_ADDR_AGAIN(our_toc_offset);
}
else
{
record_toc(toc_section, our_toc_offset, pub,
strdup (name));
bfd_put_32 (output_bfd, val,
toc_section->contents + our_toc_offset);
MARK_AS_WRITTEN(h->toc_offset);
fixit = TRUE;
}
}
if (fixit && info->base_file)
{
bfd_vma addr = (toc_section->output_section->vma
+ toc_section->output_offset + our_toc_offset);
if (coff_data(output_bfd)->pe)
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
fwrite (&addr, 1,4, (FILE *) info->base_file);
}
if ((r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN
&& (bfd_vma) our_toc_offset > toc_section->_raw_size)
{
(*_bfd_error_handler)
(_("%s: Relocation exceeds allocated TOC (%lx)"),
bfd_archive_filename (input_bfd),
(unsigned long) toc_section->_raw_size);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
relocation = our_toc_offset + TOC_LOAD_ADJUSTMENT;
rstat = _bfd_relocate_contents (howto, input_bfd, relocation, loc);
}
break;
case IMAGE_REL_PPC_IFGLUE:
{
bfd_vma x;
const char *my_name;
DUMP_RELOC2(howto->name, rel);
if (h != 0)
{
my_name = h->root.root.root.string;
if (h->symbol_is_glue == 1)
{
x = bfd_get_32 (input_bfd, loc);
bfd_put_32 (input_bfd, (bfd_vma) h->glue_insn, loc);
}
}
}
break;
case IMAGE_REL_PPC_SECREL:
break;
case IMAGE_REL_PPC_SECTION:
break;
case IMAGE_REL_PPC_ABSOLUTE:
{
const char *my_name;
if (h == 0)
my_name = (syms+symndx)->_n._n_name;
else
{
my_name = h->root.root.root.string;
}
fprintf (stderr,
_("Warning: unsupported reloc %s <file %s, section %s>\n"),
howto->name,
bfd_archive_filename(input_bfd),
input_section->name);
fprintf (stderr,"sym %ld (%s), r_vaddr %ld (%lx)\n",
rel->r_symndx, my_name, (long) rel->r_vaddr,
(unsigned long) rel->r_vaddr);
}
break;
case IMAGE_REL_PPC_IMGLUE:
{
const char *my_name;
if (h->symbol_is_glue == 1)
break;
my_name = h->root.root.root.string;
(*_bfd_error_handler)
(_("%s: Out of order IMGLUE reloc for %s"),
bfd_archive_filename (input_bfd), my_name);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
case IMAGE_REL_PPC_ADDR32NB:
{
const char *name = 0;
DUMP_RELOC2(howto->name, rel);
if (strncmp(".idata$2",input_section->name,8) == 0 && first_thunk_address == 0)
{
int idata5offset;
struct coff_link_hash_entry *myh;
myh = coff_link_hash_lookup (coff_hash_table (info),
"__idata5_magic__",
FALSE, FALSE, TRUE);
first_thunk_address = myh->root.u.def.value +
sec->output_section->vma +
sec->output_offset -
pe_data(output_bfd)->pe_opthdr.ImageBase;
idata5offset = myh->root.u.def.value;
myh = coff_link_hash_lookup (coff_hash_table (info),
"__idata6_magic__",
FALSE, FALSE, TRUE);
thunk_size = myh->root.u.def.value - idata5offset;
myh = coff_link_hash_lookup (coff_hash_table (info),
"__idata4_magic__",
FALSE, FALSE, TRUE);
import_table_size = myh->root.u.def.value;
}
if (h == 0)
{
sym = syms + symndx;
name = sym->_n._n_name;
}
else
{
char *target = 0;
name = h->root.root.root.string;
if (strcmp(".idata$2", name) == 0)
target = "__idata2_magic__";
else if (strcmp(".idata$4", name) == 0)
target = "__idata4_magic__";
else if (strcmp(".idata$5", name) == 0)
target = "__idata5_magic__";
if (target != 0)
{
struct coff_link_hash_entry *myh;
myh = coff_link_hash_lookup (coff_hash_table (info),
target,
FALSE, FALSE, TRUE);
if (myh == 0)
{
abort ();
}
val = myh->root.u.def.value +
sec->output_section->vma + sec->output_offset;
if (first_thunk_address == 0)
{
int idata5offset;
myh = coff_link_hash_lookup (coff_hash_table (info),
"__idata5_magic__",
FALSE, FALSE, TRUE);
first_thunk_address = myh->root.u.def.value +
sec->output_section->vma +
sec->output_offset -
pe_data(output_bfd)->pe_opthdr.ImageBase;
idata5offset = myh->root.u.def.value;
myh = coff_link_hash_lookup (coff_hash_table (info),
"__idata6_magic__",
FALSE, FALSE, TRUE);
thunk_size = myh->root.u.def.value - idata5offset;
myh = coff_link_hash_lookup (coff_hash_table (info),
"__idata4_magic__",
FALSE, FALSE, TRUE);
import_table_size = myh->root.u.def.value;
}
}
}
rstat = _bfd_relocate_contents (howto,
input_bfd,
val -
pe_data(output_bfd)->pe_opthdr.ImageBase,
loc);
}
break;
case IMAGE_REL_PPC_REL24:
DUMP_RELOC2(howto->name, rel);
val -= (input_section->output_section->vma
+ input_section->output_offset);
rstat = _bfd_relocate_contents (howto,
input_bfd,
val,
loc);
break;
case IMAGE_REL_PPC_ADDR16:
case IMAGE_REL_PPC_ADDR24:
case IMAGE_REL_PPC_ADDR32:
DUMP_RELOC2(howto->name, rel);
rstat = _bfd_relocate_contents (howto,
input_bfd,
val,
loc);
break;
}
if ( info->base_file )
{
if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
{
bfd_vma addr = rel->r_vaddr
- input_section->vma
+ input_section->output_offset
+ input_section->output_section->vma;
if (coff_data(output_bfd)->pe)
{
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
}
fwrite (&addr, 1,4, (FILE *) info->base_file);
}
}
switch (rstat)
{
default:
abort ();
case bfd_reloc_ok:
break;
case bfd_reloc_overflow:
{
const char *name;
char buf[SYMNMLEN + 1];
if (symndx == -1)
name = "*ABS*";
else if (h != NULL)
name = h->root.root.root.string;
else if (sym == NULL)
name = "*unknown*";
else if (sym->_n._n_n._n_zeroes == 0
&& sym->_n._n_n._n_offset != 0)
name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
else
{
strncpy (buf, sym->_n._n_name, SYMNMLEN);
buf[SYMNMLEN] = '\0';
name = buf;
}
if (! ((*info->callbacks->reloc_overflow)
(info, name, howto->name,
(bfd_vma) 0, input_bfd,
input_section, rel->r_vaddr - input_section->vma)))
{
return FALSE;
}
}
}
}
return TRUE;
}
#ifdef COFF_IMAGE_WITH_PE
long int global_toc_size = 4;
bfd* bfd_of_toc_owner = 0;
long int import_table_size;
long int first_thunk_address;
long int thunk_size;
struct list_ele *head;
struct list_ele *tail;
static char *
h1 = N_("\n\t\t\tTOC MAPPING\n\n");
static char *
h2 = N_(" TOC disassembly Comments Name\n");
static char *
h3 = N_(" Offset spelling (if present)\n");
void
dump_toc (vfile)
PTR vfile;
{
FILE *file = (FILE *) vfile;
struct list_ele *t;
fprintf (file, _(h1));
fprintf (file, _(h2));
fprintf (file, _(h3));
for (t = head; t != 0; t=t->next)
{
const char *cat = "";
if (t->cat == priv)
cat = _("private ");
else if (t->cat == pub)
cat = _("public ");
else if (t->cat == tocdata)
cat = _("data-in-toc ");
if (t->offset > global_toc_size)
{
if (t->offset <= global_toc_size + thunk_size)
cat = _("IAT reference ");
else
{
fprintf (file,
_("**** global_toc_size %ld(%lx), thunk_size %ld(%lx)\n"),
global_toc_size, global_toc_size,
thunk_size, thunk_size);
cat = _("Out of bounds!");
}
}
fprintf (file,
" %04lx (%d)", (unsigned long) t->offset, t->offset - 32768);
fprintf (file,
" %s %s\n",
cat, t->name);
}
fprintf (file, "\n");
}
bfd_boolean
ppc_allocate_toc_section (info)
struct bfd_link_info *info ATTRIBUTE_UNUSED;
{
asection *s;
bfd_byte *foo;
bfd_size_type amt;
static char test_char = '1';
if ( global_toc_size == 0 )
return TRUE;
if (bfd_of_toc_owner == 0)
{
abort ();
}
s = bfd_get_section_by_name ( bfd_of_toc_owner , TOC_SECTION_NAME);
if (s == NULL)
{
abort ();
}
amt = global_toc_size;
foo = (bfd_byte *) bfd_alloc (bfd_of_toc_owner, amt);
memset(foo, test_char, (size_t) global_toc_size);
s->_raw_size = s->_cooked_size = global_toc_size;
s->contents = foo;
return TRUE;
}
bfd_boolean
ppc_process_before_allocation (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
asection *sec;
struct internal_reloc *i, *rel;
_bfd_coff_get_external_symbols(abfd);
sec = abfd->sections;
if (sec == 0)
{
return TRUE;
}
for (; sec != 0; sec = sec->next)
{
if (sec->reloc_count == 0)
continue;
i=_bfd_coff_read_internal_relocs(abfd,sec,1,0,0,0);
if (i == 0)
abort ();
for (rel=i;rel<i+sec->reloc_count;++rel)
{
unsigned short r_type = EXTRACT_TYPE (rel->r_type);
unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
bfd_boolean ok = TRUE;
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
switch(r_type)
{
case IMAGE_REL_PPC_TOCREL16:
if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN )
ok = ppc_record_toc_entry(abfd, info, sec,
rel->r_symndx, default_toc);
if (!ok)
return FALSE;
break;
case IMAGE_REL_PPC_IMGLUE:
ppc_mark_symbol_as_glue(abfd, rel->r_symndx, rel);
break;
default:
break;
}
}
}
return TRUE;
}
#endif
static bfd_reloc_status_type
ppc_refhi_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
UN_IMPL("REFHI");
DUMP_RELOC("REFHI",reloc_entry);
if (output_bfd == (bfd *) NULL)
return bfd_reloc_continue;
return bfd_reloc_undefined;
}
#if 0
static bfd_reloc_status_type
ppc_reflo_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
PTR data;
asection *input_section;
bfd *output_bfd;
char **error_message;
{
UN_IMPL("REFLO");
DUMP_RELOC("REFLO",reloc_entry);
if (output_bfd == (bfd *) NULL)
return bfd_reloc_continue;
return bfd_reloc_undefined;
}
#endif
static bfd_reloc_status_type
ppc_pair_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
UN_IMPL("PAIR");
DUMP_RELOC("PAIR",reloc_entry);
if (output_bfd == (bfd *) NULL)
return bfd_reloc_continue;
return bfd_reloc_undefined;
}
static bfd_reloc_status_type
ppc_toc16_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
UN_IMPL("TOCREL16");
DUMP_RELOC("TOCREL16",reloc_entry);
if (output_bfd == (bfd *) NULL)
{
return bfd_reloc_continue;
}
return bfd_reloc_ok;
}
#if 0
static bfd_reloc_status_type
ppc_addr32nb_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
PTR data;
asection *input_section;
bfd *output_bfd;
char **error_message;
{
UN_IMPL("ADDR32NB");
DUMP_RELOC("ADDR32NB",reloc_entry);
return bfd_reloc_ok;
}
#endif
static bfd_reloc_status_type
ppc_secrel_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
UN_IMPL("SECREL");
DUMP_RELOC("SECREL",reloc_entry);
if (output_bfd == (bfd *) NULL)
return bfd_reloc_continue;
return bfd_reloc_ok;
}
static bfd_reloc_status_type
ppc_section_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
UN_IMPL("SECTION");
DUMP_RELOC("SECTION",reloc_entry);
if (output_bfd == (bfd *) NULL)
return bfd_reloc_continue;
return bfd_reloc_ok;
}
static bfd_reloc_status_type
ppc_imglue_reloc (abfd,
reloc_entry,
symbol,
data,
input_section,
output_bfd,
error_message)
bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry ATTRIBUTE_UNUSED;
asymbol *symbol ATTRIBUTE_UNUSED;
PTR data ATTRIBUTE_UNUSED;
asection *input_section ATTRIBUTE_UNUSED;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
UN_IMPL("IMGLUE");
DUMP_RELOC("IMGLUE",reloc_entry);
if (output_bfd == (bfd *) NULL)
return bfd_reloc_continue;
return bfd_reloc_ok;
}
#define MAX_RELOC_INDEX \
(sizeof (ppc_coff_howto_table) / sizeof (ppc_coff_howto_table[0]) - 1)
static void ppc_coff_rtype2howto PARAMS ((arelent *relent,
struct internal_reloc *internal));
static void
ppc_coff_rtype2howto (relent, internal)
arelent *relent;
struct internal_reloc *internal;
{
reloc_howto_type *howto;
unsigned short r_type = EXTRACT_TYPE (internal->r_type);
unsigned short r_flags = EXTRACT_FLAGS(internal->r_type);
unsigned short junk = EXTRACT_JUNK (internal->r_type);
if ( r_type > MAX_RELOC_INDEX )
abort ();
if ( junk != 0 )
abort ();
switch(r_type)
{
case IMAGE_REL_PPC_ADDR16:
case IMAGE_REL_PPC_REL24:
case IMAGE_REL_PPC_ADDR24:
case IMAGE_REL_PPC_ADDR32:
case IMAGE_REL_PPC_IFGLUE:
case IMAGE_REL_PPC_ADDR32NB:
case IMAGE_REL_PPC_SECTION:
case IMAGE_REL_PPC_SECREL:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
howto = ppc_coff_howto_table + r_type;
break;
case IMAGE_REL_PPC_IMGLUE:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
howto = ppc_coff_howto_table + r_type;
break;
case IMAGE_REL_PPC_TOCREL16:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
if (r_flags & IMAGE_REL_PPC_TOCDEFN)
howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN;
else
howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16;
break;
default:
fprintf (stderr,
_("Warning: Unsupported reloc %s [%d] used -- it may not work.\n"),
ppc_coff_howto_table[r_type].name,
r_type);
howto = ppc_coff_howto_table + r_type;
break;
}
relent->howto = howto;
}
static reloc_howto_type *
coff_ppc_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
struct internal_reloc *rel;
struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
struct internal_syment *sym ATTRIBUTE_UNUSED;
bfd_vma *addendp;
{
reloc_howto_type *howto;
unsigned short r_type = EXTRACT_TYPE (rel->r_type);
unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
unsigned short junk = EXTRACT_JUNK (rel->r_type);
if ( r_type > MAX_RELOC_INDEX )
abort ();
if ( junk != 0 )
abort ();
switch(r_type)
{
case IMAGE_REL_PPC_ADDR32NB:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
*addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
howto = ppc_coff_howto_table + r_type;
break;
case IMAGE_REL_PPC_TOCREL16:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
if (r_flags & IMAGE_REL_PPC_TOCDEFN)
howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN;
else
howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16;
break;
case IMAGE_REL_PPC_ADDR16:
case IMAGE_REL_PPC_REL24:
case IMAGE_REL_PPC_ADDR24:
case IMAGE_REL_PPC_ADDR32:
case IMAGE_REL_PPC_IFGLUE:
case IMAGE_REL_PPC_SECTION:
case IMAGE_REL_PPC_SECREL:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
howto = ppc_coff_howto_table + r_type;
break;
case IMAGE_REL_PPC_IMGLUE:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
howto = ppc_coff_howto_table + r_type;
break;
default:
fprintf (stderr,
_("Warning: Unsupported reloc %s [%d] used -- it may not work.\n"),
ppc_coff_howto_table[r_type].name,
r_type);
howto = ppc_coff_howto_table + r_type;
break;
}
return howto;
}
#define HOW2MAP(bfd_rtype,ppc_rtype) \
case bfd_rtype: return &ppc_coff_howto_table[ppc_rtype]
static reloc_howto_type *ppc_coff_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static reloc_howto_type *
ppc_coff_reloc_type_lookup (abfd, code)
bfd *abfd ATTRIBUTE_UNUSED;
bfd_reloc_code_real_type code;
{
switch (code)
{
HOW2MAP(BFD_RELOC_32_GOTOFF, IMAGE_REL_PPC_IMGLUE);
HOW2MAP(BFD_RELOC_16_GOT_PCREL, IMAGE_REL_PPC_IFGLUE);
HOW2MAP(BFD_RELOC_16, IMAGE_REL_PPC_ADDR16);
HOW2MAP(BFD_RELOC_PPC_B26, IMAGE_REL_PPC_REL24);
HOW2MAP(BFD_RELOC_PPC_BA26, IMAGE_REL_PPC_ADDR24);
HOW2MAP(BFD_RELOC_PPC_TOC16, IMAGE_REL_PPC_TOCREL16);
HOW2MAP(BFD_RELOC_16_GOTOFF, IMAGE_REL_PPC_TOCREL16_DEFN);
HOW2MAP(BFD_RELOC_32, IMAGE_REL_PPC_ADDR32);
HOW2MAP(BFD_RELOC_RVA, IMAGE_REL_PPC_ADDR32NB);
default:
return NULL;
}
}
#undef HOW2MAP
#define RTYPE2HOWTO(cache_ptr, dst) ppc_coff_rtype2howto (cache_ptr, dst)
#define coff_bfd_reloc_type_lookup ppc_coff_reloc_type_lookup
#define coff_rtype_to_howto coff_ppc_rtype_to_howto
#define coff_relocate_section coff_ppc_relocate_section
#define coff_bfd_final_link ppc_bfd_coff_final_link
#ifndef COFF_IMAGE_WITH_PE
#if 0
#define coff_swap_sym_in_hook ppc_coff_swap_sym_in_hook
#endif
#endif
#define SELECT_RELOC(internal, howto) {internal.r_type=howto->type;}
#define COFF_PAGE_SIZE 0x1000
#define POWERPC_LE_PE
#define COFF_SECTION_ALIGNMENT_ENTRIES \
{ COFF_SECTION_NAME_EXACT_MATCH (".idata$2"), \
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
{ COFF_SECTION_NAME_EXACT_MATCH (".idata$3"), \
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
{ COFF_SECTION_NAME_EXACT_MATCH (".idata$4"), \
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
{ COFF_SECTION_NAME_EXACT_MATCH (".idata$5"), \
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
{ COFF_SECTION_NAME_EXACT_MATCH (".idata$6"), \
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 1 }, \
{ COFF_SECTION_NAME_EXACT_MATCH (".reloc"), \
COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 1 }
#include "coffcode.h"
#ifndef COFF_IMAGE_WITH_PE
#if 0
static void ppc_coff_swap_sym_in_hook PARAMS ((bfd *, PTR, PTR));
static void
ppc_coff_swap_sym_in_hook (abfd, ext1, in1)
bfd *abfd;
PTR ext1 ATTRIBUTE_UNUSED;
PTR in1;
{
struct internal_syment *in = (struct internal_syment *)in1;
if (bfd_of_toc_owner != 0)
return;
if (strcmp(in->_n._n_name, ".toc") == 0)
{
flagword flags;
register asection *s;
s = bfd_get_section_by_name ( abfd , TOC_SECTION_NAME);
if (s != NULL)
{
return;
}
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ;
s = bfd_make_section (abfd, TOC_SECTION_NAME);
if (s == NULL
|| !bfd_set_section_flags (abfd, s, flags)
|| !bfd_set_section_alignment (abfd, s, 2))
{
abort ();
}
bfd_of_toc_owner = abfd;
}
return;
}
#endif
#endif
#ifndef COFF_IMAGE_WITH_PE
static bfd_boolean ppc_do_last PARAMS ((bfd *));
static bfd *ppc_get_last PARAMS ((void));
static bfd_boolean
ppc_do_last (abfd)
bfd *abfd;
{
if (abfd == bfd_of_toc_owner)
return TRUE;
else
return FALSE;
}
static bfd *
ppc_get_last()
{
return bfd_of_toc_owner;
}
bfd_boolean
ppc_bfd_coff_final_link (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
bfd_size_type symesz;
struct coff_final_link_info finfo;
bfd_boolean debug_merge_allocated;
asection *o;
struct bfd_link_order *p;
bfd_size_type max_sym_count;
bfd_size_type max_lineno_count;
bfd_size_type max_reloc_count;
bfd_size_type max_output_reloc_count;
bfd_size_type max_contents_size;
file_ptr rel_filepos;
unsigned int relsz;
file_ptr line_filepos;
unsigned int linesz;
bfd *sub;
bfd_byte *external_relocs = NULL;
char strbuf[STRING_SIZE_SIZE];
bfd_size_type amt;
symesz = bfd_coff_symesz (abfd);
finfo.info = info;
finfo.output_bfd = abfd;
finfo.strtab = NULL;
finfo.section_info = NULL;
finfo.last_file_index = -1;
finfo.last_bf_index = -1;
finfo.internal_syms = NULL;
finfo.sec_ptrs = NULL;
finfo.sym_indices = NULL;
finfo.outsyms = NULL;
finfo.linenos = NULL;
finfo.contents = NULL;
finfo.external_relocs = NULL;
finfo.internal_relocs = NULL;
debug_merge_allocated = FALSE;
coff_data (abfd)->link_info = info;
finfo.strtab = _bfd_stringtab_init ();
if (finfo.strtab == NULL)
goto error_return;
if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
goto error_return;
debug_merge_allocated = TRUE;
if (! abfd->output_has_begun)
{
if (! bfd_coff_compute_section_file_positions (abfd))
return FALSE;
}
rel_filepos = obj_relocbase (abfd);
relsz = bfd_coff_relsz (abfd);
max_contents_size = 0;
max_lineno_count = 0;
max_reloc_count = 0;
for (o = abfd->sections; o != NULL; o = o->next)
{
o->reloc_count = 0;
o->lineno_count = 0;
for (p = o->link_order_head; p != NULL; p = p->next)
{
if (p->type == bfd_indirect_link_order)
{
asection *sec;
sec = p->u.indirect.section;
sec->linker_mark = TRUE;
if (info->strip == strip_none
|| info->strip == strip_some)
o->lineno_count += sec->lineno_count;
if (info->relocateable)
o->reloc_count += sec->reloc_count;
if (sec->_raw_size > max_contents_size)
max_contents_size = sec->_raw_size;
if (sec->lineno_count > max_lineno_count)
max_lineno_count = sec->lineno_count;
if (sec->reloc_count > max_reloc_count)
max_reloc_count = sec->reloc_count;
}
else if (info->relocateable
&& (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order))
++o->reloc_count;
}
if (o->reloc_count == 0)
o->rel_filepos = 0;
else
{
o->flags |= SEC_RELOC;
o->rel_filepos = rel_filepos;
rel_filepos += o->reloc_count * relsz;
}
}
if (info->relocateable)
{
unsigned int i;
amt = abfd->section_count + 1;
amt *= sizeof (struct coff_link_section_info);
finfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt);
if (finfo.section_info == NULL)
goto error_return;
for (i = 0; i <= abfd->section_count; i++)
{
finfo.section_info[i].relocs = NULL;
finfo.section_info[i].rel_hashes = NULL;
}
}
line_filepos = rel_filepos;
linesz = bfd_coff_linesz (abfd);
max_output_reloc_count = 0;
for (o = abfd->sections; o != NULL; o = o->next)
{
if (o->lineno_count == 0)
o->line_filepos = 0;
else
{
o->line_filepos = line_filepos;
line_filepos += o->lineno_count * linesz;
}
if (o->reloc_count != 0)
{
BFD_ASSERT (info->relocateable);
amt = o->reloc_count;
amt *= sizeof (struct internal_reloc);
finfo.section_info[o->target_index].relocs =
(struct internal_reloc *) bfd_malloc (amt);
amt = o->reloc_count;
amt *= sizeof (struct coff_link_hash_entry *);
finfo.section_info[o->target_index].rel_hashes =
(struct coff_link_hash_entry **) bfd_malloc (amt);
if (finfo.section_info[o->target_index].relocs == NULL
|| finfo.section_info[o->target_index].rel_hashes == NULL)
goto error_return;
if (o->reloc_count > max_output_reloc_count)
max_output_reloc_count = o->reloc_count;
}
o->reloc_count = 0;
o->lineno_count = 0;
}
obj_sym_filepos (abfd) = line_filepos;
max_sym_count = 0;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
bfd_size_type sz;
sub->output_has_begun = FALSE;
sz = obj_raw_syment_count (sub);
if (sz > max_sym_count)
max_sym_count = sz;
}
amt = max_sym_count * sizeof (struct internal_syment);
finfo.internal_syms = (struct internal_syment *) bfd_malloc (amt);
amt = max_sym_count * sizeof (asection *);
finfo.sec_ptrs = (asection **) bfd_malloc (amt);
amt = max_sym_count * sizeof (long);
finfo.sym_indices = (long *) bfd_malloc (amt);
amt = (max_sym_count + 1) * symesz;
finfo.outsyms = (bfd_byte *) bfd_malloc (amt);
amt = max_lineno_count * bfd_coff_linesz (abfd);
finfo.linenos = (bfd_byte *) bfd_malloc (amt);
finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
if (! info->relocateable)
{
amt = max_reloc_count * sizeof (struct internal_reloc);
finfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt);
}
if ((finfo.internal_syms == NULL && max_sym_count > 0)
|| (finfo.sec_ptrs == NULL && max_sym_count > 0)
|| (finfo.sym_indices == NULL && max_sym_count > 0)
|| finfo.outsyms == NULL
|| (finfo.linenos == NULL && max_lineno_count > 0)
|| (finfo.contents == NULL && max_contents_size > 0)
|| (finfo.external_relocs == NULL && max_reloc_count > 0)
|| (! info->relocateable
&& finfo.internal_relocs == NULL
&& max_reloc_count > 0))
goto error_return;
obj_raw_syment_count (abfd) = 0;
if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
{
if (! bfd_coff_start_final_link (abfd, info))
goto error_return;
}
for (o = abfd->sections; o != NULL; o = o->next)
{
for (p = o->link_order_head; p != NULL; p = p->next)
{
if (p->type == bfd_indirect_link_order
&& (bfd_get_flavour (p->u.indirect.section->owner)
== bfd_target_coff_flavour))
{
sub = p->u.indirect.section->owner;
#ifdef POWERPC_LE_PE
if (! sub->output_has_begun && !ppc_do_last(sub))
#else
if (! sub->output_has_begun)
#endif
{
if (! _bfd_coff_link_input_bfd (&finfo, sub))
goto error_return;
sub->output_has_begun = TRUE;
}
}
else if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
{
if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
goto error_return;
}
else
{
if (! _bfd_default_link_order (abfd, info, o, p))
goto error_return;
}
}
}
#ifdef POWERPC_LE_PE
{
bfd* last_one = ppc_get_last();
if (last_one)
{
if (! _bfd_coff_link_input_bfd (&finfo, last_one))
goto error_return;
}
last_one->output_has_begun = TRUE;
}
#endif
coff_debug_merge_hash_table_free (&finfo.debug_merge);
debug_merge_allocated = FALSE;
if (finfo.internal_syms != NULL)
{
free (finfo.internal_syms);
finfo.internal_syms = NULL;
}
if (finfo.sec_ptrs != NULL)
{
free (finfo.sec_ptrs);
finfo.sec_ptrs = NULL;
}
if (finfo.sym_indices != NULL)
{
free (finfo.sym_indices);
finfo.sym_indices = NULL;
}
if (finfo.linenos != NULL)
{
free (finfo.linenos);
finfo.linenos = NULL;
}
if (finfo.contents != NULL)
{
free (finfo.contents);
finfo.contents = NULL;
}
if (finfo.external_relocs != NULL)
{
free (finfo.external_relocs);
finfo.external_relocs = NULL;
}
if (finfo.internal_relocs != NULL)
{
free (finfo.internal_relocs);
finfo.internal_relocs = NULL;
}
if (finfo.last_file_index != -1
&& (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
{
file_ptr pos;
finfo.last_file.n_value = obj_raw_syment_count (abfd);
bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
(PTR) finfo.outsyms);
pos = obj_sym_filepos (abfd) + finfo.last_file_index * symesz;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|| bfd_bwrite (finfo.outsyms, symesz, abfd) != symesz)
return FALSE;
}
finfo.failed = FALSE;
coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym,
(PTR) &finfo);
if (finfo.failed)
goto error_return;
if (finfo.outsyms != NULL)
{
free (finfo.outsyms);
finfo.outsyms = NULL;
}
if (info->relocateable)
{
amt = max_output_reloc_count * relsz;
external_relocs = (bfd_byte *) bfd_malloc (amt);
if (external_relocs == NULL)
goto error_return;
for (o = abfd->sections; o != NULL; o = o->next)
{
struct internal_reloc *irel;
struct internal_reloc *irelend;
struct coff_link_hash_entry **rel_hash;
bfd_byte *erel;
if (o->reloc_count == 0)
continue;
irel = finfo.section_info[o->target_index].relocs;
irelend = irel + o->reloc_count;
rel_hash = finfo.section_info[o->target_index].rel_hashes;
erel = external_relocs;
for (; irel < irelend; irel++, rel_hash++, erel += relsz)
{
if (*rel_hash != NULL)
{
BFD_ASSERT ((*rel_hash)->indx >= 0);
irel->r_symndx = (*rel_hash)->indx;
}
bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel);
}
amt = relsz * o->reloc_count;
if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0
|| bfd_bwrite ((PTR) external_relocs, amt, abfd) != amt)
goto error_return;
}
free (external_relocs);
external_relocs = NULL;
}
if (finfo.section_info != NULL)
{
unsigned int i;
for (i = 0; i < abfd->section_count; i++)
{
if (finfo.section_info[i].relocs != NULL)
free (finfo.section_info[i].relocs);
if (finfo.section_info[i].rel_hashes != NULL)
free (finfo.section_info[i].rel_hashes);
}
free (finfo.section_info);
finfo.section_info = NULL;
}
if (coff_hash_table (info)->stab_info != NULL)
{
if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
return FALSE;
}
if (obj_raw_syment_count (abfd) != 0)
{
file_ptr pos;
pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz;
if (bfd_seek (abfd, pos, SEEK_SET) != 0)
return FALSE;
#if STRING_SIZE_SIZE == 4
H_PUT_32 (abfd,
_bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
strbuf);
#else
#error Change H_PUT_32 above
#endif
if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd)
!= STRING_SIZE_SIZE)
return FALSE;
if (! _bfd_stringtab_emit (abfd, finfo.strtab))
return FALSE;
}
_bfd_stringtab_free (finfo.strtab);
bfd_get_symcount (abfd) = 0;
return TRUE;
error_return:
if (debug_merge_allocated)
coff_debug_merge_hash_table_free (&finfo.debug_merge);
if (finfo.strtab != NULL)
_bfd_stringtab_free (finfo.strtab);
if (finfo.section_info != NULL)
{
unsigned int i;
for (i = 0; i < abfd->section_count; i++)
{
if (finfo.section_info[i].relocs != NULL)
free (finfo.section_info[i].relocs);
if (finfo.section_info[i].rel_hashes != NULL)
free (finfo.section_info[i].rel_hashes);
}
free (finfo.section_info);
}
if (finfo.internal_syms != NULL)
free (finfo.internal_syms);
if (finfo.sec_ptrs != NULL)
free (finfo.sec_ptrs);
if (finfo.sym_indices != NULL)
free (finfo.sym_indices);
if (finfo.outsyms != NULL)
free (finfo.outsyms);
if (finfo.linenos != NULL)
free (finfo.linenos);
if (finfo.contents != NULL)
free (finfo.contents);
if (finfo.external_relocs != NULL)
free (finfo.external_relocs);
if (finfo.internal_relocs != NULL)
free (finfo.internal_relocs);
if (external_relocs != NULL)
free (external_relocs);
return FALSE;
}
#endif
#ifdef TARGET_BIG_SYM
extern const bfd_target TARGET_BIG_SYM;
#endif
#ifdef TARGET_LITTLE_SYM
const bfd_target TARGET_LITTLE_SYM =
{
TARGET_LITTLE_NAME,
bfd_target_coff_flavour,
BFD_ENDIAN_LITTLE,
BFD_ENDIAN_LITTLE,
(HAS_RELOC | EXEC_P |
HAS_LINENO | HAS_DEBUG |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
#ifndef COFF_WITH_PE
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC),
#else
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
#endif
0,
'/',
15,
bfd_getl64, bfd_getl_signed_64, bfd_putl64,
bfd_getl32, bfd_getl_signed_32, bfd_putl32,
bfd_getl16, bfd_getl_signed_16, bfd_putl16,
bfd_getl64, bfd_getl_signed_64, bfd_putl64,
bfd_getl32, bfd_getl_signed_32, bfd_putl32,
bfd_getl16, bfd_getl_signed_16, bfd_putl16,
{_bfd_dummy_target, coff_object_p,
bfd_generic_archive_p, coff_object_p },
{bfd_false, coff_mkobject, _bfd_generic_mkarchive,
bfd_false},
{bfd_false, coff_write_object_contents,
_bfd_write_archive_contents, bfd_false},
BFD_JUMP_TABLE_GENERIC (coff),
BFD_JUMP_TABLE_COPY (coff),
BFD_JUMP_TABLE_CORE (_bfd_nocore),
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
BFD_JUMP_TABLE_SYMBOLS (coff),
BFD_JUMP_TABLE_RELOCS (coff),
BFD_JUMP_TABLE_WRITE (coff),
BFD_JUMP_TABLE_LINK (coff),
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
#ifdef TARGET_BIG_SYM
& TARGET_BIG_SYM,
#else
NULL,
#endif
COFF_SWAP_TABLE
};
#endif
#ifdef TARGET_BIG_SYM
const bfd_target TARGET_BIG_SYM =
{
TARGET_BIG_NAME,
bfd_target_coff_flavour,
BFD_ENDIAN_BIG,
BFD_ENDIAN_BIG,
(HAS_RELOC | EXEC_P |
HAS_LINENO | HAS_DEBUG |
HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
#ifndef COFF_WITH_PE
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC),
#else
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
#endif
0,
'/',
15,
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16,
bfd_getb64, bfd_getb_signed_64, bfd_putb64,
bfd_getb32, bfd_getb_signed_32, bfd_putb32,
bfd_getb16, bfd_getb_signed_16, bfd_putb16,
{_bfd_dummy_target, coff_object_p,
bfd_generic_archive_p, coff_object_p },
{bfd_false, coff_mkobject, _bfd_generic_mkarchive,
bfd_false},
{bfd_false, coff_write_object_contents,
_bfd_write_archive_contents, bfd_false},
BFD_JUMP_TABLE_GENERIC (coff),
BFD_JUMP_TABLE_COPY (coff),
BFD_JUMP_TABLE_CORE (_bfd_nocore),
BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
BFD_JUMP_TABLE_SYMBOLS (coff),
BFD_JUMP_TABLE_RELOCS (coff),
BFD_JUMP_TABLE_WRITE (coff),
BFD_JUMP_TABLE_LINK (coff),
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
#ifdef TARGET_LITTLE_SYM
& TARGET_LITTLE_SYM,
#else
NULL,
#endif
COFF_SWAP_TABLE
};
#endif