#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#define ARCH_SIZE 32
#include "nlm/ppc-ext.h"
#define Nlm_External_Fixed_Header Nlm32_powerpc_External_Fixed_Header
#include "libnlm.h"
#ifdef OLDFORMAT
static bfd_boolean
nlm_powerpc_backend_object_p (bfd *abfd)
{
struct nlm32_powerpc_external_prefix_header s;
if (bfd_bread (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
return FALSE;
if (memcmp (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature) != 0
|| H_GET_32 (abfd, s.headerVersion) != NLM32_POWERPC_HEADER_VERSION)
return FALSE;
return TRUE;
}
static bfd_boolean
nlm_powerpc_write_prefix (bfd *abfd)
{
struct nlm32_powerpc_external_prefix_header s;
memset (&s, 0, sizeof s);
memcpy (s.signature, NLM32_POWERPC_SIGNATURE, sizeof s.signature);
H_PUT_32 (abfd, NLM32_POWERPC_HEADER_VERSION, s.headerVersion);
H_PUT_32 (abfd, 0, s.origins);
if (bfd_bwrite (& s, (bfd_size_type) sizeof s, abfd) != sizeof s)
return FALSE;
return TRUE;
}
static reloc_howto_type nlm_powerpc_howto_table[] =
{
HOWTO (0,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_POS",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (1,
0,
-2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_NEG",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (2,
0,
2,
32,
TRUE,
0,
complain_overflow_signed,
0,
"R_REL",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (3,
0,
1,
16,
FALSE,
0,
complain_overflow_signed,
0,
"R_TOC",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (4,
1,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RTB",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (5,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_GL",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (6,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_TCL",
TRUE,
0xffff,
0xffff,
FALSE),
{ 7 },
HOWTO (8,
0,
2,
26,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_BA",
TRUE,
0x3fffffc,
0x3fffffc,
FALSE),
{ 9 },
HOWTO (0xa,
0,
2,
26,
TRUE,
0,
complain_overflow_signed,
0,
"R_BR",
TRUE,
0x3fffffc,
0x3fffffc,
FALSE),
{ 0xb },
HOWTO (0xc,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RL",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0xd,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RLA",
TRUE,
0xffff,
0xffff,
FALSE),
{ 0xe },
HOWTO (0xf,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_REF",
FALSE,
0,
0,
FALSE),
{ 0x10 },
{ 0x11 },
HOWTO (0x12,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_TRL",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x13,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_TRLA",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x14,
1,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RRTBI",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (0x15,
1,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RRTBA",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (0x16,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_CAI",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x17,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_REL",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x18,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RBA",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x19,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_RBAC",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x1a,
0,
2,
26,
FALSE,
0,
complain_overflow_signed,
0,
"R_REL",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (0x1b,
0,
2,
16,
FALSE,
0,
complain_overflow_bitfield,
0,
"R_REL",
TRUE,
0xffff,
0xffff,
FALSE)
};
#define HOWTO_COUNT (sizeof nlm_powerpc_howto_table \
/ sizeof nlm_powerpc_howto_table[0])
static bfd_boolean
nlm_powerpc_read_reloc (bfd *abfd,
nlmNAME (symbol_type) *sym,
asection **secp,
arelent *rel)
{
struct nlm32_powerpc_external_reloc ext;
bfd_vma l_vaddr;
unsigned long l_symndx;
int l_rtype;
int l_rsecnm;
asection *code_sec, *data_sec, *bss_sec;
if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
return FALSE;
l_vaddr = H_GET_32 (abfd, ext.l_vaddr);
l_symndx = H_GET_32 (abfd, ext.l_symndx);
l_rtype = H_GET_16 (abfd, ext.l_rtype);
l_rsecnm = H_GET_16 (abfd, ext.l_rsecnm);
code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
if (sym != NULL)
rel->sym_ptr_ptr = NULL;
else
{
asection *sec;
if (l_symndx == 0)
sec = code_sec;
else if (l_symndx == 1)
sec = data_sec;
else if (l_symndx == 2)
sec = bss_sec;
else
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
rel->sym_ptr_ptr = sec->symbol_ptr_ptr;
}
rel->addend = 0;
BFD_ASSERT ((l_rtype & 0xff) < HOWTO_COUNT);
rel->howto = nlm_powerpc_howto_table + (l_rtype & 0xff);
BFD_ASSERT (rel->howto->name != NULL
&& ((l_rtype & 0x8000) != 0
? (rel->howto->complain_on_overflow
== complain_overflow_signed)
: (rel->howto->complain_on_overflow
== complain_overflow_bitfield))
&& ((l_rtype >> 8) & 0x1f) == rel->howto->bitsize - 1);
if (l_rsecnm == 0)
*secp = code_sec;
else if (l_rsecnm == 1)
{
*secp = data_sec;
l_vaddr -= code_sec->size;
}
else
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
rel->address = l_vaddr;
return TRUE;
}
#else
static reloc_howto_type nlm_powerpc_howto =
HOWTO (0,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"32",
TRUE,
0xffffffff,
0xffffffff,
FALSE);
static bfd_boolean
nlm_powerpc_read_reloc (bfd *abfd,
nlmNAME (symbol_type) *sym,
asection **secp,
arelent *rel)
{
bfd_byte temp[4];
bfd_vma val;
const char *name;
if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
return FALSE;
val = bfd_get_32 (abfd, temp);
if ((val & NLM_HIBIT) == 0)
name = NLM_INITIALIZED_DATA_NAME;
else
{
name = NLM_CODE_NAME;
val &=~ NLM_HIBIT;
}
*secp = bfd_get_section_by_name (abfd, name);
if (sym == NULL)
{
if ((val & (NLM_HIBIT >> 1)) == 0)
name = NLM_INITIALIZED_DATA_NAME;
else
{
name = NLM_CODE_NAME;
val &=~ (NLM_HIBIT >> 1);
}
rel->sym_ptr_ptr = bfd_get_section_by_name (abfd, name)->symbol_ptr_ptr;
}
rel->howto = & nlm_powerpc_howto;
rel->address = val << 2;
rel->addend = 0;
return TRUE;
}
#endif
static bfd_boolean
nlm_powerpc_mangle_relocs (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec ATTRIBUTE_UNUSED,
const void * data ATTRIBUTE_UNUSED,
bfd_vma offset ATTRIBUTE_UNUSED,
bfd_size_type count ATTRIBUTE_UNUSED)
{
return TRUE;
}
static bfd_boolean
nlm_powerpc_read_import (bfd * abfd, nlmNAME (symbol_type) * sym)
{
struct nlm_relent *nlm_relocs;
bfd_size_type rcount;
bfd_byte temp[NLM_TARGET_LONG_SIZE];
unsigned char symlength;
char *name;
if (bfd_bread (& symlength, (bfd_size_type) sizeof (symlength), abfd)
!= sizeof (symlength))
return FALSE;
sym -> symbol.the_bfd = abfd;
name = bfd_alloc (abfd, (bfd_size_type) symlength + 1);
if (name == NULL)
return FALSE;
if (bfd_bread (name, (bfd_size_type) symlength, abfd) != symlength)
return FALSE;
name[symlength] = '\0';
sym -> symbol.name = name;
sym -> symbol.flags = 0;
sym -> symbol.value = 0;
sym -> symbol.section = bfd_und_section_ptr;
if (bfd_bread (temp, (bfd_size_type) sizeof (temp), abfd)
!= sizeof (temp))
return FALSE;
rcount = H_GET_32 (abfd, temp);
nlm_relocs = bfd_alloc (abfd, rcount * sizeof (struct nlm_relent));
if (nlm_relocs == NULL)
return FALSE;
sym -> relocs = nlm_relocs;
sym -> rcnt = 0;
while (sym -> rcnt < rcount)
{
asection *section;
if (! nlm_powerpc_read_reloc (abfd, sym, §ion, &nlm_relocs -> reloc))
return FALSE;
nlm_relocs -> section = section;
nlm_relocs++;
sym -> rcnt++;
}
return TRUE;
}
#ifndef OLDFORMAT
static bfd_boolean
nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
{
asymbol *sym;
bfd_vma val;
bfd_byte temp[4];
if (rel->addend != 0
|| rel->howto == NULL
|| rel->howto->rightshift != 0
|| rel->howto->size != 2
|| rel->howto->bitsize != 32
|| rel->howto->bitpos != 0
|| rel->howto->pc_relative
|| (rel->howto->src_mask != 0xffffffff && rel->addend != 0)
|| rel->howto->dst_mask != 0xffffffff)
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
sym = *rel->sym_ptr_ptr;
val = bfd_get_section_vma (abfd, sec) + rel->address;
if ((val & 3) != 0)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
val >>= 2;
if (bfd_get_section_flags (abfd, sec) & SEC_DATA)
val -= nlm_get_data_low (abfd);
else
{
val -= nlm_get_text_low (abfd);
val |= NLM_HIBIT;
}
if (! bfd_is_und_section (bfd_get_section (sym)))
{
if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
val |= NLM_HIBIT >> 1;
}
bfd_put_32 (abfd, val, temp);
if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
return FALSE;
return TRUE;
}
#else
static bfd_boolean
nlm_powerpc_write_reloc (bfd *abfd,
asection *sec,
arelent *rel,
int indx)
{
struct nlm32_powerpc_external_reloc ext;
asection *code_sec, *data_sec, *bss_sec;
asymbol *sym;
asection *symsec;
unsigned long l_symndx;
int l_rtype;
int l_rsecnm;
reloc_howto_type *howto;
bfd_size_type address;
code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
sym = *rel->sym_ptr_ptr;
symsec = bfd_get_section (sym);
if (indx != -1)
{
BFD_ASSERT (bfd_is_und_section (symsec));
l_symndx = indx + 3;
}
else
{
if (symsec == code_sec)
l_symndx = 0;
else if (symsec == data_sec)
l_symndx = 1;
else if (symsec == bss_sec)
l_symndx = 2;
else
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
H_PUT_32 (abfd, l_symndx, ext.l_symndx);
for (howto = nlm_powerpc_howto_table;
howto < nlm_powerpc_howto_table + HOWTO_COUNT;
howto++)
{
if (howto->rightshift == rel->howto->rightshift
&& howto->size == rel->howto->size
&& howto->bitsize == rel->howto->bitsize
&& howto->pc_relative == rel->howto->pc_relative
&& howto->bitpos == rel->howto->bitpos
&& (howto->partial_inplace == rel->howto->partial_inplace
|| (! rel->howto->partial_inplace
&& rel->addend == 0))
&& (howto->src_mask == rel->howto->src_mask
|| (rel->howto->src_mask == 0
&& rel->addend == 0))
&& howto->dst_mask == rel->howto->dst_mask
&& howto->pcrel_offset == rel->howto->pcrel_offset)
break;
}
if (howto >= nlm_powerpc_howto_table + HOWTO_COUNT)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
l_rtype = howto->type;
if (howto->complain_on_overflow == complain_overflow_signed)
l_rtype |= 0x8000;
l_rtype |= (howto->bitsize - 1) << 8;
H_PUT_16 (abfd, l_rtype, ext.l_rtype);
address = rel->address;
if (sec == code_sec)
l_rsecnm = 0;
else if (sec == data_sec)
{
l_rsecnm = 1;
address += code_sec->size;
}
else
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
H_PUT_16 (abfd, l_rsecnm, ext.l_rsecnm);
H_PUT_32 (abfd, address, ext.l_vaddr);
if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
return FALSE;
return TRUE;
}
static bfd_boolean
nlm_powerpc_write_import (bfd * abfd, asection * sec, arelent * rel)
{
return nlm_powerpc_write_reloc (abfd, sec, rel, -1);
}
#endif
static bfd_boolean
nlm_powerpc_write_external (bfd *abfd,
bfd_size_type count,
asymbol *sym,
struct reloc_and_sec *relocs)
{
unsigned int i;
bfd_byte len;
unsigned char temp[NLM_TARGET_LONG_SIZE];
#ifdef OLDFORMAT
static int indx;
#endif
len = strlen (sym->name);
if ((bfd_bwrite (&len, (bfd_size_type) sizeof (bfd_byte), abfd)
!= sizeof (bfd_byte))
|| bfd_bwrite (sym->name, (bfd_size_type) len, abfd) != len)
return FALSE;
bfd_put_32 (abfd, count, temp);
if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
return FALSE;
for (i = 0; i < count; i++)
{
#ifndef OLDFORMAT
if (! nlm_powerpc_write_import (abfd, relocs[i].sec, relocs[i].rel))
return FALSE;
#else
if (! nlm_powerpc_write_reloc (abfd, relocs[i].sec,
relocs[i].rel, indx))
return FALSE;
#endif
}
#ifdef OLDFORMAT
++indx;
#endif
return TRUE;
}
#ifndef OLDFORMAT
static bfd_boolean
nlm_powerpc_set_public_section (bfd *abfd, nlmNAME (symbol_type) *sym)
{
if (sym->symbol.value & NLM_HIBIT)
{
sym->symbol.value &= ~NLM_HIBIT;
sym->symbol.flags |= BSF_FUNCTION;
sym->symbol.section =
bfd_get_section_by_name (abfd, NLM_CODE_NAME);
}
else
sym->symbol.section =
bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
sym->symbol.value <<= 2;
return TRUE;
}
static bfd_vma
nlm_powerpc_get_public_offset (bfd *abfd, asymbol *sym)
{
bfd_vma offset;
asection *sec;
offset = bfd_asymbol_value (sym);
sec = bfd_get_section (sym);
if (sec->flags & SEC_CODE)
{
offset -= nlm_get_text_low (abfd);
offset |= NLM_HIBIT;
}
else if (sec->flags & (SEC_DATA | SEC_ALLOC))
{
offset -= nlm_get_data_low (abfd);
}
else
{
bfd_set_error (bfd_error_invalid_operation);
abort ();
}
return offset;
}
#endif
#include "nlmswap.h"
static const struct nlm_backend_data nlm32_powerpc_backend =
{
"NetWare PowerPC Module \032",
sizeof (Nlm32_powerpc_External_Fixed_Header),
#ifndef OLDFORMAT
0,
#else
sizeof (struct nlm32_powerpc_external_prefix_header),
#endif
bfd_arch_powerpc,
0,
FALSE,
#ifndef OLDFORMAT
0,
0,
#else
nlm_powerpc_backend_object_p,
nlm_powerpc_write_prefix,
#endif
nlm_powerpc_read_reloc,
nlm_powerpc_mangle_relocs,
nlm_powerpc_read_import,
nlm_powerpc_write_import,
#ifndef OLDFORMAT
nlm_powerpc_set_public_section,
nlm_powerpc_get_public_offset,
#else
0,
0,
#endif
nlm_swap_fixed_header_in,
nlm_swap_fixed_header_out,
nlm_powerpc_write_external,
0,
};
#define TARGET_BIG_NAME "nlm32-powerpc"
#define TARGET_BIG_SYM nlmNAME (powerpc_vec)
#define TARGET_BACKEND_DATA & nlm32_powerpc_backend
#include "nlm-target.h"