#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#define ARCH_SIZE 32
#include "nlm/alpha-ext.h"
#define Nlm_External_Fixed_Header Nlm32_alpha_External_Fixed_Header
#include "libnlm.h"
static bfd_boolean
nlm_alpha_backend_object_p (bfd *abfd)
{
struct nlm32_alpha_external_prefix_header s;
file_ptr size;
if (bfd_bread (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
return FALSE;
if (H_GET_32 (abfd, s.magic) != NLM32_ALPHA_MAGIC)
return FALSE;
size = H_GET_32 (abfd, s.size);
if (bfd_seek (abfd, size, SEEK_SET) != 0)
return FALSE;
return TRUE;
}
static bfd_boolean
nlm_alpha_write_prefix (bfd *abfd)
{
struct nlm32_alpha_external_prefix_header s;
memset (&s, 0, sizeof s);
H_PUT_32 (abfd, NLM32_ALPHA_MAGIC, s.magic);
H_PUT_32 (abfd, 2, s.format);
H_PUT_32 (abfd, sizeof s, s.size);
if (bfd_bwrite (&s, (bfd_size_type) sizeof s, abfd) != sizeof s)
return FALSE;
return TRUE;
}
#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
static reloc_howto_type nlm32_alpha_howto_table[] =
{
HOWTO (ALPHA_R_IGNORE,
0,
0,
8,
FALSE,
0,
complain_overflow_dont,
0,
"IGNORE",
FALSE,
0,
0,
FALSE),
HOWTO (ALPHA_R_REFLONG,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"REFLONG",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (ALPHA_R_REFQUAD,
0,
4,
64,
FALSE,
0,
complain_overflow_bitfield,
0,
"REFQUAD",
TRUE,
ONES (64),
ONES (64),
FALSE),
HOWTO (ALPHA_R_GPREL32,
0,
2,
32,
FALSE,
0,
complain_overflow_bitfield,
0,
"GPREL32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (ALPHA_R_LITERAL,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
0,
"LITERAL",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (ALPHA_R_LITUSE,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
0,
"LITUSE",
FALSE,
0,
0,
FALSE),
HOWTO (ALPHA_R_GPDISP,
16,
2,
16,
TRUE,
0,
complain_overflow_dont,
0,
"GPDISP",
TRUE,
0xffff,
0xffff,
TRUE),
HOWTO (ALPHA_R_BRADDR,
2,
2,
21,
TRUE,
0,
complain_overflow_signed,
0,
"BRADDR",
FALSE,
0,
0x1fffff,
FALSE),
HOWTO (ALPHA_R_HINT,
2,
2,
14,
FALSE,
0,
complain_overflow_dont,
0,
"HINT",
TRUE,
0x3fff,
0x3fff,
FALSE),
HOWTO (ALPHA_R_SREL16,
0,
1,
16,
TRUE,
0,
complain_overflow_signed,
0,
"SREL16",
TRUE,
0xffff,
0xffff,
FALSE),
HOWTO (ALPHA_R_SREL32,
0,
2,
32,
TRUE,
0,
complain_overflow_signed,
0,
"SREL32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (ALPHA_R_SREL64,
0,
4,
64,
TRUE,
0,
complain_overflow_signed,
0,
"SREL64",
TRUE,
ONES (64),
ONES (64),
FALSE),
HOWTO (ALPHA_R_OP_PUSH,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
0,
"OP_PUSH",
FALSE,
0,
0,
FALSE),
HOWTO (ALPHA_R_OP_STORE,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
0,
"OP_STORE",
FALSE,
0,
ONES (64),
FALSE),
HOWTO (ALPHA_R_OP_PSUB,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
0,
"OP_PSUB",
FALSE,
0,
0,
FALSE),
HOWTO (ALPHA_R_OP_PRSHIFT,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
0,
"OP_PRSHIFT",
FALSE,
0,
0,
FALSE),
HOWTO (ALPHA_R_GPVALUE,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
0,
"GPVALUE",
FALSE,
0,
0,
FALSE)
};
static reloc_howto_type nlm32_alpha_nw_howto =
HOWTO (ALPHA_R_NW_RELOC,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
0,
"NW_RELOC",
FALSE,
0,
0,
FALSE);
static bfd_boolean
nlm_alpha_read_reloc (bfd *abfd,
nlmNAME (symbol_type) *sym,
asection **secp,
arelent *rel)
{
static bfd_vma gp_value;
static bfd_vma lita_address;
struct nlm32_alpha_external_reloc ext;
bfd_vma r_vaddr;
long r_symndx;
int r_type, r_extern, r_offset, r_size;
asection *code_sec, *data_sec;
if (bfd_bread (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
return FALSE;
r_vaddr = H_GET_64 (abfd, ext.r_vaddr);
r_symndx = H_GET_32 (abfd, ext.r_symndx);
BFD_ASSERT (bfd_little_endian (abfd));
r_type = ((ext.r_bits[0] & RELOC_BITS0_TYPE_LITTLE)
>> RELOC_BITS0_TYPE_SH_LITTLE);
r_extern = (ext.r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0;
r_offset = ((ext.r_bits[1] & RELOC_BITS1_OFFSET_LITTLE)
>> RELOC_BITS1_OFFSET_SH_LITTLE);
r_size = ((ext.r_bits[3] & RELOC_BITS3_SIZE_LITTLE)
>> RELOC_BITS3_SIZE_SH_LITTLE);
code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
if (r_extern)
{
BFD_ASSERT (sym != NULL);
rel->sym_ptr_ptr = NULL;
rel->addend = 0;
}
else
{
BFD_ASSERT (r_type == ALPHA_R_NW_RELOC || sym == NULL);
if (r_type == ALPHA_R_NW_RELOC
|| r_type == ALPHA_R_GPDISP
|| r_type == ALPHA_R_IGNORE)
{
rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
rel->addend = 0;
}
else if (r_symndx == ALPHA_RELOC_SECTION_TEXT)
{
rel->sym_ptr_ptr = code_sec->symbol_ptr_ptr;
BFD_ASSERT (bfd_get_section_vma (abfd, code_sec) == 0);
rel->addend = 0;
}
else if (r_symndx == ALPHA_RELOC_SECTION_DATA)
{
rel->sym_ptr_ptr = data_sec->symbol_ptr_ptr;
rel->addend = - bfd_get_section_vma (abfd, data_sec);
}
else
{
BFD_ASSERT (0);
rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
rel->addend = 0;
}
}
if (r_type == ALPHA_R_NW_RELOC
|| r_vaddr < code_sec->size)
{
*secp = code_sec;
rel->address = r_vaddr;
}
else
{
*secp = data_sec;
rel->address = r_vaddr - code_sec->size;
}
BFD_ASSERT ((r_type >= 0 && r_type <= ALPHA_R_GPVALUE)
|| r_type == ALPHA_R_NW_RELOC);
switch (r_type)
{
case ALPHA_R_BRADDR:
case ALPHA_R_SREL16:
case ALPHA_R_SREL32:
case ALPHA_R_SREL64:
rel->addend = 0;
break;
case ALPHA_R_GPREL32:
if (! r_extern)
rel->addend += gp_value;
break;
case ALPHA_R_LITERAL:
BFD_ASSERT (! r_extern);
rel->addend += lita_address;
break;
case ALPHA_R_LITUSE:
case ALPHA_R_GPDISP:
rel->addend = r_symndx;
rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
break;
case ALPHA_R_OP_STORE:
BFD_ASSERT (r_offset < 256 && r_size < 256);
rel->addend = (r_offset << 8) + r_size;
break;
case ALPHA_R_OP_PUSH:
case ALPHA_R_OP_PSUB:
case ALPHA_R_OP_PRSHIFT:
rel->addend = r_vaddr;
break;
case ALPHA_R_GPVALUE:
gp_value += r_symndx;
rel->addend = gp_value;
break;
case ALPHA_R_IGNORE:
rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
rel->address = r_vaddr;
rel->addend = gp_value;
break;
case ALPHA_R_NW_RELOC:
if (r_size == ALPHA_R_NW_RELOC_SETGP)
{
gp_value = r_vaddr;
rel->addend = 0;
}
else if (r_size == ALPHA_R_NW_RELOC_LITA)
{
lita_address = r_vaddr;
rel->addend = r_symndx + 1;
}
else
BFD_ASSERT (0);
rel->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
break;
default:
break;
}
if (r_type == ALPHA_R_NW_RELOC)
rel->howto = &nlm32_alpha_nw_howto;
else
rel->howto = &nlm32_alpha_howto_table[r_type];
return TRUE;
}
static bfd_boolean
nlm_alpha_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_alpha_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;
bfd_size_type amt;
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);
amt = rcount * sizeof (struct nlm_relent);
nlm_relocs = bfd_alloc (abfd, amt);
if (!nlm_relocs)
return FALSE;
sym -> relocs = nlm_relocs;
sym -> rcnt = 0;
while (sym -> rcnt < rcount)
{
asection *section;
if (! nlm_alpha_read_reloc (abfd, sym, §ion, &nlm_relocs -> reloc))
return FALSE;
nlm_relocs -> section = section;
nlm_relocs++;
sym -> rcnt++;
}
return TRUE;
}
static bfd_boolean
nlm_alpha_write_import (bfd * abfd, asection * sec, arelent * rel)
{
asymbol *sym;
bfd_vma r_vaddr;
long r_symndx;
int r_type, r_extern, r_offset, r_size;
struct nlm32_alpha_external_reloc ext;
sym = *rel->sym_ptr_ptr;
r_type = rel->howto->type;
if (r_type != ALPHA_R_NW_RELOC)
{
r_vaddr = bfd_get_section_vma (abfd, sec) + rel->address;
if ((sec->flags & SEC_CODE) == 0)
r_vaddr += bfd_get_section_by_name (abfd, NLM_CODE_NAME) -> size;
if (bfd_is_und_section (bfd_get_section (sym)))
{
r_extern = 1;
r_symndx = 0;
}
else
{
r_extern = 0;
if (bfd_get_section_flags (abfd, bfd_get_section (sym)) & SEC_CODE)
r_symndx = ALPHA_RELOC_SECTION_TEXT;
else
r_symndx = ALPHA_RELOC_SECTION_DATA;
}
r_offset = 0;
r_size = 0;
switch (r_type)
{
case ALPHA_R_LITUSE:
case ALPHA_R_GPDISP:
r_symndx = rel->addend;
break;
case ALPHA_R_OP_STORE:
r_size = rel->addend & 0xff;
r_offset = (rel->addend >> 8) & 0xff;
break;
case ALPHA_R_OP_PUSH:
case ALPHA_R_OP_PSUB:
case ALPHA_R_OP_PRSHIFT:
r_vaddr = rel->addend;
break;
case ALPHA_R_IGNORE:
r_vaddr = rel->address;
break;
default:
break;
}
}
else
{
r_vaddr = rel->address;
if (rel->addend == 0)
{
r_symndx = 0;
r_size = ALPHA_R_NW_RELOC_SETGP;
}
else
{
r_symndx = rel->addend - 1;
r_size = ALPHA_R_NW_RELOC_LITA;
}
r_extern = 0;
r_offset = 0;
}
H_PUT_64 (abfd, r_vaddr, ext.r_vaddr);
H_PUT_32 (abfd, r_symndx, ext.r_symndx);
BFD_ASSERT (bfd_little_endian (abfd));
ext.r_bits[0] = ((r_type << RELOC_BITS0_TYPE_SH_LITTLE)
& RELOC_BITS0_TYPE_LITTLE);
ext.r_bits[1] = ((r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0)
| ((r_offset << RELOC_BITS1_OFFSET_SH_LITTLE)
& RELOC_BITS1_OFFSET_LITTLE));
ext.r_bits[2] = 0;
ext.r_bits[3] = ((r_size << RELOC_BITS3_SIZE_SH_LITTLE)
& RELOC_BITS3_SIZE_LITTLE);
if (bfd_bwrite (&ext, (bfd_size_type) sizeof ext, abfd) != sizeof ext)
return FALSE;
return TRUE;
}
static bfd_boolean
nlm_alpha_set_public_section (bfd * abfd, nlmNAME (symbol_type) * sym)
{
asection *code_sec, *data_sec;
code_sec = bfd_get_section_by_name (abfd, NLM_CODE_NAME);
data_sec = bfd_get_section_by_name (abfd, NLM_INITIALIZED_DATA_NAME);
if (sym->symbol.value < code_sec->size)
{
sym->symbol.section = code_sec;
sym->symbol.flags |= BSF_FUNCTION;
}
else
{
sym->symbol.section = data_sec;
sym->symbol.value -= code_sec->size;
BFD_ASSERT ((code_sec->size & 0xf) == 0);
}
return TRUE;
}
static bfd_vma
nlm_alpha_get_public_offset (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
{
return bfd_asymbol_value (sym);
}
static bfd_boolean
nlm_alpha_write_external (bfd *abfd,
bfd_size_type count,
asymbol *sym,
struct reloc_and_sec *relocs)
{
bfd_size_type i;
bfd_byte len;
unsigned char temp[NLM_TARGET_LONG_SIZE];
arelent r;
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 + 2, temp);
if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), abfd) != sizeof (temp))
return FALSE;
r.sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
r.howto = &nlm32_alpha_nw_howto;
r.address = nlm_alpha_backend_data (abfd)->lita_address;
r.addend = nlm_alpha_backend_data (abfd)->lita_size + 1;
if (! nlm_alpha_write_import (abfd, NULL, &r))
return FALSE;
r.address = nlm_alpha_backend_data (abfd)->gp;
r.addend = 0;
if (! nlm_alpha_write_import (abfd, NULL, &r))
return FALSE;
for (i = 0; i < count; i++)
if (! nlm_alpha_write_import (abfd, relocs[i].sec, relocs[i].rel))
return FALSE;
return TRUE;
}
#include "nlmswap.h"
static const struct nlm_backend_data nlm32_alpha_backend =
{
"NetWare Alpha Module \032",
sizeof (Nlm32_alpha_External_Fixed_Header),
sizeof (struct nlm32_alpha_external_prefix_header),
bfd_arch_alpha,
0,
TRUE,
nlm_alpha_backend_object_p,
nlm_alpha_write_prefix,
nlm_alpha_read_reloc,
nlm_alpha_mangle_relocs,
nlm_alpha_read_import,
nlm_alpha_write_import,
nlm_alpha_set_public_section,
nlm_alpha_get_public_offset,
nlm_swap_fixed_header_in,
nlm_swap_fixed_header_out,
nlm_alpha_write_external,
0,
};
#define TARGET_LITTLE_NAME "nlm32-alpha"
#define TARGET_LITTLE_SYM nlmNAME (alpha_vec)
#define TARGET_BACKEND_DATA & nlm32_alpha_backend
#include "nlm-target.h"