binutils-gdb/bfd/elfxx-e2k.c

7817 lines
258 KiB
C

/* E2k-specific support for ELF
Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/e2k.h"
#include "elf/elcore.h"
#include "elfxx-e2k.h"
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
#define MINUS_ONE (0xffffffffffffffffULL)
#define ELF64_P(abfd) (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
#define ABI_PM_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_E2K_PM) == EF_E2K_PM)
#define ABI_64_P(abfd) (ELF64_P (abfd) && ! ABI_PM_P (abfd))
#define ELF_R_TYPE(abfd, i) \
(ELF64_P (abfd) ? ELF64_R_TYPE (i) : ELF32_R_TYPE (i))
#define ELF_R_SYM(abfd, i) \
(ELF64_P (abfd) ? ELF64_R_SYM (i) : ELF32_R_SYM (i))
/* REMINDER: this function has been originally implemented in commit
525c9ec6527259f0017dea91547b9ab0502ea30b to resolve issues related to LD
tests producing SREC output. However, it turns out to be that when invoked
from within e2k-linux-as it fills in literals with inappropriate for a RELA
target assembly-time symbol values, which makes it difficult to compare
relocatable objects produced by GAS and LAS. */
static bfd_reloc_status_type
_bfd_e2k_elf_64_abs_lit_reloc (bfd *abfd,
arelent *reloc_entry,
asymbol *symbol,
void *data,
asection *input_section ATTRIBUTE_UNUSED,
bfd *output_bfd ATTRIBUTE_UNUSED,
char **error_message ATTRIBUTE_UNUSED)
{
bfd_vma res;
res = (symbol->section->output_section->vma
+ symbol->section->output_offset
+ symbol->value
+ reloc_entry->addend);
res = ((res & 0xffffffffULL) << 32) + (res >> 32);
bfd_put_64 (abfd, res, (unsigned char *) data + reloc_entry->address);
return bfd_reloc_ok;
}
/* For non-ELF targets (e.g. srec) don't relocate anything, just return
`bfd_reloc_ok' so that generic code in reloc.c doesn't attempt to do this
itself and thus cause an overflow. */
static bfd_reloc_status_type
_bfd_e2k_elf_islocal_reloc (bfd *abfd ATTRIBUTE_UNUSED,
arelent *reloc_entry ATTRIBUTE_UNUSED,
asymbol *symbol ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED,
asection *input_section ATTRIBUTE_UNUSED,
bfd *output_bfd ATTRIBUTE_UNUSED,
char **error_message ATTRIBUTE_UNUSED)
{
return bfd_reloc_ok;
}
/* The underlying two functions have been implemented for the sake of GDB
compile command which uses them to handle `R_E2K_{GOT_OFF,64_PC_LIT}' in a
just compiled relocatable object file. A special treatment of these
relocations is required because _GLOBAL_OFFSET_TABLE_ remains undefined in
a compiled object file. Having taken into account that R_E2K_GOTOFF is 32-
bit by its nature, one can't use "default" zero value for GOT. Below I
believe that GOT is placed at the start of the first section relocated
against it. A reversed order of 32-bit literals within a 64-bit one is taken
into account when handling R_E2K_64_PC_LIT as well.
On i386 bfd_elf_generic_reloc () does the "right" thing when processing
analogous relocations because in 32-bit address space they may (silently) let
GOT be equal to zero without a subsequent relocation overflow. There's no
issue related to a special order of sub-literals as well. I wonder how
relocations of these types are processed on x86_64 though . . . */
static bfd_reloc_status_type
_bfd_e2k_elf_64_pc_lit_reloc (bfd *abfd,
arelent *reloc_entry,
asymbol *symbol,
void *data,
asection *input_section,
bfd *output_bfd,
char **error_message)
{
bfd_vma gp;
const char *name = bfd_asymbol_name (symbol);
bfd_vma res;
/* For now let them produce whatever they like for dummy cases I'm not
interested in. FIXME: can't I obtain R_E2K_64_PC_LIT against other symbols
via GDB's `compile'? Find out how the containing section of GOT turns out
to be ABS rather than UND. */
if (! bfd_is_abs_section (symbol->section)
|| strcmp (name, "_GLOBAL_OFFSET_TABLE_") != 0)
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
/* Use ABFD's GP (hopefully it's not used otherwise on E2K) to hold the
synthetic value of GOT, which is the start of the first section relocated
against it. FIXME: I should probably verify that this section belongs to
the address space of an inferior (i.e. isn't a debug section or something
like that) to avoid potential relocation overflows. At the same time what
should I do if the first section relocated against GOT turns out to be a
debug one? Where am I going to take address of GOT from in such a case?
Hopefully, this should be almost impossible . . . */
gp = _bfd_get_gp_value (abfd);
if (gp == 0)
{
gp = input_section->vma;
_bfd_set_gp_value (abfd, gp);
}
res = (gp + reloc_entry->addend
- (input_section->vma + reloc_entry->address));
res = ((res & 0xffffffffULL) << 32) + (res >> 32);
bfd_put_64 (abfd, res, (unsigned char *) data + reloc_entry->address);
return bfd_reloc_ok;
}
static bfd_reloc_status_type
_bfd_e2k_elf_got_off_reloc (bfd *abfd,
arelent *reloc_entry,
asymbol *symbol,
void *data,
asection *input_section,
bfd *output_bfd ATTRIBUTE_UNUSED,
char **error_message ATTRIBUTE_UNUSED)
{
bfd_vma gp;
bfd_vma res;
/* See the corresponding comment one function above. */
gp = _bfd_get_gp_value (abfd);
if (gp == 0)
{
gp = input_section->vma;
_bfd_set_gp_value (abfd, gp);
}
res = (symbol->section->output_section->vma
+ symbol->section->output_offset
+ symbol->value
+ reloc_entry->addend
- gp);
bfd_put_32 (abfd, res, (unsigned char *) data + reloc_entry->address);
return bfd_reloc_ok;
}
static reloc_howto_type _bfd_e2k_elf_howto_table[] =
{
[R_E2K_32_ABS] =
HOWTO (R_E2K_32_ABS, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_ABS", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_32_DYNOPT] =
HOWTO (R_E2K_32_DYNOPT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_DYNOPT", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_32_PC] =
HOWTO (R_E2K_32_PC, 0, 2, 32, TRUE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_PC", FALSE,
0x00000000, 0xffffffff, TRUE),
[R_E2K_AP_GOT] =
HOWTO (R_E2K_AP_GOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_AP_GOT", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_PL_GOT] =
HOWTO (R_E2K_PL_GOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_PL_GOT", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_64_ABS] =
HOWTO (R_E2K_64_ABS, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_ABS", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_DYNOPT] =
HOWTO (R_E2K_64_DYNOPT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_DYNOPT", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_ABS_LIT] =
HOWTO (R_E2K_64_ABS_LIT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
_bfd_e2k_elf_64_abs_lit_reloc, "R_E2K_64_ABS_LIT", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_PC_LIT] =
HOWTO (R_E2K_64_PC_LIT, 0, 4, 64,
/* Even though it _is_ really pc-relative we set pc_relative
to FALSE so that _bfd_final_link_relocate doesn't
attempt to subtract address from relocation value. */
FALSE,
0, complain_overflow_bitfield,
_bfd_e2k_elf_64_pc_lit_reloc, "R_E2K_64_PC_LIT", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_32_JMP_SLOT] =
HOWTO (R_E2K_32_JMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_JMP_SLOT", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_32_COPY] =
HOWTO (R_E2K_32_COPY, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_COPY", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_32_RELATIVE] =
HOWTO (R_E2K_32_RELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_RELATIVE", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_32_IRELATIVE] =
HOWTO (R_E2K_32_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_IRELATIVE", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_64_JMP_SLOT] =
HOWTO (R_E2K_64_JMP_SLOT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_JMP_SLOT", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_COPY] =
HOWTO (R_E2K_64_COPY, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_COPY", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_RELATIVE] =
HOWTO (R_E2K_64_RELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_RELATIVE", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_RELATIVE_LIT] =
HOWTO (R_E2K_64_RELATIVE_LIT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_RELATIVE_LIT", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_IRELATIVE] =
HOWTO (R_E2K_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_IRELATIVE", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_TLS_GDMOD] =
HOWTO (R_E2K_TLS_GDMOD, 0, 2, 32, FALSE, 0, complain_overflow_unsigned,
bfd_elf_generic_reloc, "R_E2K_TLS_GDMOD", FALSE, 0,
0xffffffff, FALSE),
[R_E2K_TLS_GDREL] =
HOWTO (R_E2K_TLS_GDREL, 0, 2, 32, FALSE, 0, complain_overflow_unsigned,
bfd_elf_generic_reloc, "R_E2K_TLS_GDREL", FALSE, 0,
0xffffffff, FALSE),
[R_E2K_TLS_IE] =
HOWTO (R_E2K_TLS_IE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_IE", FALSE, 0x00000000,
0xffffffff, FALSE),
[R_E2K_32_TLS_LE] =
HOWTO (R_E2K_32_TLS_LE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_32_TLS_LE", FALSE, 0x00000000,
0xffffffff, FALSE),
[R_E2K_64_TLS_LE] =
HOWTO (R_E2K_64_TLS_LE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_64_TLS_LE", FALSE, 0x0000000000000000ULL,
MINUS_ONE, FALSE),
/* The underlying two are normally emitted by LD but GAS may also produce them
when generating debug info for __thread variables. The latter is an actual
reason for putting them here. */
[R_E2K_TLS_32_DTPREL] =
HOWTO (R_E2K_TLS_32_DTPREL, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_32_DTPREL", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_TLS_64_DTPREL] =
HOWTO (R_E2K_TLS_64_DTPREL, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_64_DTPREL", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
/* These ones are not emitted by GAS but HOWTOs for them are required to
prevent GDB from barfing on them. */
[R_E2K_TLS_32_DTPMOD] =
HOWTO (R_E2K_TLS_32_DTPMOD, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_32_DTPMOD", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_TLS_64_DTPMOD] =
HOWTO (R_E2K_TLS_64_DTPMOD, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_64_DTPMOD", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_TLS_TPOFF32] =
HOWTO (R_E2K_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_TPOFF32", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_TLS_TPOFF64] =
HOWTO (R_E2K_TLS_TPOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_TLS_TPOFF64", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
/* The next two howtos aren't used by BFD in fact, except for producing
relocation dumps. Therefore, the fields are initialized in a rather random
manner. I wonder, how `{src,dst}_mask' fields can be expressed for 128-bit
items using the 64-bit `bfd_vma' type . . . */
/* Now that `struct reloc_howto_struct' has been packed and `size == 8'
(this value used to match `bfd_get_reloc_size () == 16') and `bitsize ==
128' can be no longer encoded, stupidly set these fileds to 0 for `R_E2K_
{AP,PL}' and get ready to process these relocations specially wherever
needed. */
[R_E2K_AP] =
HOWTO (R_E2K_AP, 0, 0, 0, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_AP", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_PL] =
HOWTO (R_E2K_PL, 0, 0, 0, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_PL", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_GOT] =
HOWTO (R_E2K_GOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_GOT", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_GOTOFF] =
HOWTO (R_E2K_GOTOFF, 0, 2, 32, FALSE, 0, complain_overflow_signed,
_bfd_e2k_elf_got_off_reloc, "R_E2K_GOTOFF", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_DISP] =
HOWTO (R_E2K_DISP, 3, 2, 32, TRUE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_DISP", FALSE,
0xf0000000, 0x0fffffff, TRUE),
/* This relocation is treated very specially by E2K backend. Set all useless
fields (i.e., those ones which don't get processed by the common code in
reloc.c) to FALSE. E.g., no matter that this relocation is PC_RELATIVE in
principle, the corresponding field is set to FALSE. */
[R_E2K_PREF] =
HOWTO (R_E2K_PREF, 7, 2, 32, FALSE, 4, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_DISP", FALSE,
0x00000000, 0x0ffffff0, FALSE),
[R_E2K_GOTPLT] =
HOWTO (R_E2K_GOTPLT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_GOTPLT", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_ISLOCAL] =
HOWTO (R_E2K_ISLOCAL, 0, 2, 1, FALSE, 16, complain_overflow_bitfield,
_bfd_e2k_elf_islocal_reloc, "R_E2K_ISLOCAL", FALSE,
0xff00ffff, 0x00ff0000, FALSE),
[R_E2K_ISLOCAL32] =
HOWTO (R_E2K_ISLOCAL32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_E2K_ISLOCAL32", FALSE,
0x00000000, 0xffffffff, FALSE),
[R_E2K_32_SIZE] =
HOWTO(R_E2K_32_SIZE, 0, 2, 32, FALSE, 0, complain_overflow_unsigned,
bfd_elf_generic_reloc, "R_E2K_32_SIZE", FALSE, 0xffffffff, 0xffffffff,
FALSE),
[R_E2K_64_SIZE] =
HOWTO(R_E2K_64_SIZE, 0, 4, 64, FALSE, 0, complain_overflow_unsigned,
bfd_elf_generic_reloc, "R_E2K_64_SIZE", FALSE, MINUS_ONE, MINUS_ONE,
FALSE),
[R_E2K_64_GOTOFF] =
HOWTO (R_E2K_64_GOTOFF, 0, 4, 64, FALSE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_E2K_64_GOTOFF", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
[R_E2K_64_GOTOFF_LIT] =
HOWTO (R_E2K_64_GOTOFF_LIT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
_bfd_e2k_elf_64_abs_lit_reloc, "R_E2K_64_GOTOFF_LIT", FALSE,
0x0000000000000000ULL, MINUS_ONE, FALSE),
/* Note that it's crucial for R_E2K_NONE to have `size == 3' so as to ensure
that `bfd_get_reloc_size ()' returns 0 for it. The latter is important
because R_E2K_NONE may be assigned an offset at the very end of the output
section during the relocatable link if the discarded input section to which
the original relocation was applied was located correspondingly. Otherwise,
processing R_E2K_NONE in such a case during the final link will result in
`bfd_reloc_outofrange'. */
[R_E2K_NONE] =
HOWTO (R_E2K_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_E2K_NONE", FALSE,
0, 0, FALSE),
#include "elfxx-elcore-howto.h"
};
reloc_howto_type *
_bfd_e2k_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
{
switch (code)
{
case BFD_RELOC_32:
return &_bfd_e2k_elf_howto_table[R_E2K_32_ABS];
case BFD_RELOC_64:
return &_bfd_e2k_elf_howto_table[R_E2K_64_ABS];
case BFD_RELOC_32_PCREL:
return &_bfd_e2k_elf_howto_table[R_E2K_32_PC];
case BFD_RELOC_64_PCREL:
return &_bfd_e2k_elf_howto_table[R_E2K_64_PC_LIT];
case BFD_RELOC_32_GOTOFF:
return &_bfd_e2k_elf_howto_table[R_E2K_GOTOFF];
case BFD_RELOC_E2K_64_ABS_LIT:
return &_bfd_e2k_elf_howto_table[R_E2K_64_ABS_LIT];
case BFD_RELOC_E2K_DISP:
/* Keep in mind that our DISP relocation is very different from
PCREL ones though at other architectures like i386 they may be
the same. That is the reason for having a separate
BFD_RELOC_E2K_DISP. */
return &_bfd_e2k_elf_howto_table[R_E2K_DISP];
case BFD_RELOC_E2K_PLT:
/* This one shouldn't be used by any of our components at present. */
return NULL;
case BFD_RELOC_E2K_GOTPLT:
return &_bfd_e2k_elf_howto_table[R_E2K_GOTPLT];
case BFD_RELOC_E2K_GOT:
return &_bfd_e2k_elf_howto_table[R_E2K_GOT];
case BFD_RELOC_E2K_TLS_GDMOD:
return &_bfd_e2k_elf_howto_table[R_E2K_TLS_GDMOD];
case BFD_RELOC_E2K_TLS_GDREL:
return &_bfd_e2k_elf_howto_table[R_E2K_TLS_GDREL];
case BFD_RELOC_E2K_TLS_IE:
return &_bfd_e2k_elf_howto_table[R_E2K_TLS_IE];
case BFD_RELOC_E2K_32_TLS_LE:
return &_bfd_e2k_elf_howto_table[R_E2K_32_TLS_LE];
case BFD_RELOC_E2K_64_TLS_LE:
return &_bfd_e2k_elf_howto_table[R_E2K_64_TLS_LE];
case BFD_RELOC_E2K_32_DTPREL:
return &_bfd_e2k_elf_howto_table[R_E2K_TLS_32_DTPREL];
case BFD_RELOC_E2K_64_DTPREL:
return &_bfd_e2k_elf_howto_table[R_E2K_TLS_64_DTPREL];
case BFD_RELOC_E2K_ISLOCAL:
return &_bfd_e2k_elf_howto_table[R_E2K_ISLOCAL];
case BFD_RELOC_E2K_ISLOCAL32:
return &_bfd_e2k_elf_howto_table[R_E2K_ISLOCAL32];
case BFD_RELOC_SIZE32:
return &_bfd_e2k_elf_howto_table[R_E2K_32_SIZE];
case BFD_RELOC_SIZE64:
return &_bfd_e2k_elf_howto_table[R_E2K_64_SIZE];
case BFD_RELOC_E2K_PREF:
return &_bfd_e2k_elf_howto_table[R_E2K_PREF];
case BFD_RELOC_E2K_GOTOFF64:
return &_bfd_e2k_elf_howto_table[R_E2K_64_GOTOFF];
case BFD_RELOC_E2K_GOTOFF64_LIT:
return &_bfd_e2k_elf_howto_table[R_E2K_64_GOTOFF_LIT];
case BFD_RELOC_E2K_AP_GOT:
return &_bfd_e2k_elf_howto_table[R_E2K_AP_GOT];
case BFD_RELOC_E2K_PL_GOT:
return &_bfd_e2k_elf_howto_table[R_E2K_PL_GOT];
case BFD_RELOC_E2K_AP:
return &_bfd_e2k_elf_howto_table[R_E2K_AP];
case BFD_RELOC_E2K_PL:
return &_bfd_e2k_elf_howto_table[R_E2K_PL];
case BFD_RELOC_E2K_DYNOPT64:
return &_bfd_e2k_elf_howto_table[R_E2K_64_DYNOPT];
case BFD_RELOC_E2K_DYNOPT32:
return &_bfd_e2k_elf_howto_table[R_E2K_32_DYNOPT];
default:
break;
}
return NULL;
}
reloc_howto_type *
_bfd_e2k_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
const char *r_name)
{
unsigned int i;
for (i = 0;
i < (sizeof (_bfd_e2k_elf_howto_table)
/ sizeof (_bfd_e2k_elf_howto_table[0]));
i++)
{
if (_bfd_e2k_elf_howto_table[i].name != NULL
&& strcasecmp (_bfd_e2k_elf_howto_table[i].name, r_name) == 0)
return &_bfd_e2k_elf_howto_table[i];
}
return NULL;
}
/* These ones are set to values of the respective options. See my comments
in `elfxx-e2k.h' on why they are not placed into e2k link hash table. */
static int e2k_ipd;
static int e2k_is_x86app;
static int e2k_is_4mpages;
static bfd_boolean arch_set_via_cmdline;
static bfd_boolean restrict_to_arch;
static bfd_boolean relaxed_e2k_machine_check;
static bfd_boolean output_new_e_machine = TRUE;
bfd_boolean simulating_mode;
static bfd_boolean pack_cud_gd;
static int link_mixed_eir_phase;
bfd_boolean e2k_dsp_linux_mode;
struct cud_gd_range
{
bfd_vma min;
bfd_vma max;
bfd_vma align;
bfd_signed_vma delta;
/* This field should be of no use except for during the initialization
of htab->ranges[]. Consider eliminating it. */
bfd_boolean in_cud;
};
static int
compare_cud_gd_ranges (const void *a, const void *b)
{
const struct cud_gd_range *first = (const struct cud_gd_range *) a;
const struct cud_gd_range *second = (const struct cud_gd_range *) b;
/* Taking into account that the ranges are not allowed to overlap (at least
at present) which is going to be checked during the initialization of
htab->ranges[] below, just use MIN field to order them. */
return first->min < second->min ? -1 : (first->min > second->min ? 1 : 0);
}
#ifdef HAVE_e2k_elf64_vec
bfd_vma
orig_offset_in_cud (struct bfd_link_info *info, bfd_vma offset)
{
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
if (! ABI_PM_P (htab->elf.dynobj)
|| htab->ranges == NULL)
return offset;
int i;
struct cud_gd_range *ranges = htab->ranges;
for (i = 0; i < htab->ranges_num; i++)
{
if (! ranges[i].in_cud)
continue;
bfd_vma orig_off = offset - ranges[i].delta;
if (orig_off >= ranges[i].min && orig_off < ranges[i].max)
return orig_off;
}
return offset;
}
#endif
#ifndef HAVE_e2k_elf64_vec
static
#endif
bfd_vma
adjust_offset_in_cud_gd (struct bfd_link_info *info, bfd_vma offset)
{
int i;
struct _bfd_e2k_elf_link_hash_table *htab;
struct cud_gd_range *ranges;
/* Zero offset corresponds to NULL both in CUD and GD. It's probably the
only valid offset not belonging to any of PT_LOAD segments. */
if (offset == 0)
return 0;
if (! pack_cud_gd)
return offset;
htab = _bfd_e2k_elf_hash_table (info);
if (! ABI_PM_P (htab->elf.dynobj))
return offset;
if (htab->ranges == NULL)
{
struct elf_segment_map *m;
Elf_Internal_Phdr *phdrs = elf_tdata (info->output_bfd)->phdr;
Elf_Internal_Phdr *p;
int num = 0;
bfd_vma max_page_aligned;
bfd_vma cud_size, gd_size;
for (m = elf_seg_map (info->output_bfd), p = phdrs; m != NULL;
m = m->next, p++)
{
if (p->p_type == PT_LOAD)
num++;
}
ranges = (struct cud_gd_range *) bfd_alloc (htab->elf.dynobj,
(sizeof (struct cud_gd_range)
* num));
/* FIXME ... */
if (ranges == NULL)
{
/* Hopefully this will make the linkage fail. */
_bfd_error_handler (_("allocation of address ranges for CUD and GD "
"failed"));
/* There's no point in trying anymore. */
pack_cud_gd = FALSE;
return offset;
}
for (m = elf_seg_map (info->output_bfd), p = phdrs, i = 0; m != NULL;
m = m->next, p++)
{
if (p->p_type == PT_LOAD)
{
if (p->p_align < 0x1000
|| ((p->p_vaddr - p->p_offset) & (p->p_align - 1)) != 0)
{
_bfd_error_handler (_("inappropriately aligned segments "
"cannot be packed"));
pack_cud_gd = FALSE;
return offset;
}
ranges[i].min = p->p_vaddr;
ranges[i].max = p->p_vaddr + p->p_memsz;
ranges[i].align = p->p_align;
ranges[i].in_cud = (p->p_flags & PF_X) ? TRUE : FALSE;
i++;
}
}
qsort (ranges, num, sizeof (struct cud_gd_range), compare_cud_gd_ranges);
cud_size = gd_size = 0;
max_page_aligned = 0;
for (i = 0; i < num; i++)
{
bfd_vma min_page_aligned = ranges[i].min & ~(ranges[i].align - 1);
bfd_vma b, r, pos;
/* MAX_PAGE_ALIGNED corresponds to the preceding segment in this
comparison, of course. */
if (min_page_aligned < max_page_aligned)
{
_bfd_error_handler (_("compactification of CUD/GD segments "
"with overlapping pages is not supported"));
pack_cud_gd = FALSE;
return offset;
}
max_page_aligned = (ranges[i].max + 0xfffULL) & ~(0xfffULL);
if (ranges[i].in_cud)
pos = cud_size;
else
pos = gd_size;
pos = (pos + 0xfffULL) & ~0xfffULL;
r = ranges[i].min & (ranges[i].align - 1);
b = (pos + ranges[i].align - (r + 1)) / ranges[i].align;
pos = b * ranges[i].align + r;
ranges[i].delta = pos - ranges[i].min;
pos += ranges[i].max - ranges[i].min;
if (ranges[i].in_cud)
cud_size = pos;
else
gd_size = pos;
}
htab->ranges_num = num;
htab->ranges = ranges;
}
else
ranges = htab->ranges;
/* FIXME: consider optimizing this search. */
for (i = 0; i < htab->ranges_num; i++)
{
if (offset < ranges[i].min)
break;
if (offset >= ranges[i].max)
continue;
return offset + ranges[i].delta;
}
/* Give a chance to an "_end"-like symbol formally lying one byte beyond
its range. */
int j;
j = htab->ranges_num - 1;
if (offset == ranges[j].max)
return offset + ranges[j].delta;
/* If the trailing address range in CUD (GD) didn't match look for another
trailing range GD (CUD) respectively. */
bfd_boolean in_cud = !ranges[j].in_cud;
for (i = j - 1; i >= 0; i--)
{
if (ranges[i].in_cud == in_cud)
{
if (offset == ranges[i].max)
return offset + ranges[i].delta;
else
/* No point in trying any longer as we have checked trailing ranges
both in CUD and GD. */
break;
}
}
/* FIXME: this may happen for ABS symbols. */
#if 0
_bfd_error_handler (_("address 0x%lx doesn't correspond to any "
"PT_LOAD segment and thus can't be reliably "
"compactified"), offset);
#endif /* 0 */
return offset;
}
#define WSZ(wsz) \
/* LTS0 */ (0x00000010 | (wsz << 5))
/* A pattern for Protected Mode self-init function header. */
static const unsigned int selfinit_header[] =
{
/* 0: */
/* HS */ 0x00008011,
/* CS1 */ 0x00000000, /* setwd wsz = 0x{4,8}, nfx = 0x1 */
/* LTS1 */ 0x00000000,
#ifndef NEW_PM_ABI
/* LTS0 */ WSZ (0x4)
#else /* defined NEW_PM_ABI */
/* LTS0 */ WSZ (0x8),
#endif /* defined NEW_PM_ABI */
};
/* A pattern for Protected Mode self-init function snippet performing an
initialization of AP. */
static const unsigned int selfinit_ap[] =
{
/* 0: */
/* HS */ 0x0c000012,
/* ALS0 */ 0x62f2d880, /* gdtoap,0 _f32s,_lts0 obj, %qr0 */
/* ALS1 */ 0x62f2d881,
/* LTS0 */ 0x00000000,
/* 10: */
/* HS */ 0x0c300022,
/* ALS0 */ 0x5180d880, /* aptoapb,0 %qr0, _f32s,_lts0 size, %qr0 */
/* ALS1 */ 0x5181d881,
/* ALES */ 0x01c001c0,
/* LTS1 */ 0x00000000,
/* LTS0 */ 0x00000000,
/* 28: */
/* HS */ 0x04000011,
/* ALS0 */ 0x1081d881, /* adds,0 %r1, _f32s,_lts0 addend, %r1 */
/* LTS1 */ 0x00000000,
/* LTS0 */ 0x00000000,
/* 38: */
/* HS */ 0x92400012,
/* ALS2 */ 0x39c0d880, /* stgdq,2 0x0, _f32s,_lts0 0x0, %qr0 */
/* ALS5 */ 0x39c0d881,
/* LTS0 */ 0x00000000
};
/* A pattern for Protected Mode self-init function snippet performing an
initialization of PL. */
static const unsigned int selfinit_pl[] =
{
/* 0: */
/* HS */ 0x04000001,
/* ALS0 */ 0x11c0c081, /* addd,0 0x0, 0x0, %dr1 */
/* 8: */
/* HS */ 0x04000011,
/* ALS0 */ 0x63f0d880, /* getpl,0 _f32s,_lts0 fn, %dr0 */
/* LTS1 */ 0x00000000,
/* LTS0 */ 0x00000000,
/* 18: */
/* HS */ 0x92400012,
/* ALS2 */ 0x39c0d880, /* stgdq,2 0x0, _f32s,_lts0 pos, %qr0 */
/* ALS5 */ 0x39c0d881,
/* LTS0 */ 0x00000000,
};
/* A pattern for Protected Mode self-init function tail. */
static const unsigned int selfinit_tail[] =
{
/* 0: */
/* HS */ 0x00004001,
/* CS0 */ 0xf0000000, /* return %ctpr3 */
/* 70: */
/* HS */ 0x00001001,
/* SS */ 0x80000c20, /* ct %ctpr3 */
/* ipd 2 */
};
static void
add_selfinit_header (struct bfd_link_info *info)
{
bfd *output_bfd = info->output_bfd;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
unsigned char *ptr = htab->selfinit->contents;
unsigned int i;
if (htab->selfinit_off != 0)
return;
for (i = 0; i < sizeof (selfinit_header) / 4; i++)
bfd_put_32 (output_bfd, selfinit_header[i], ptr + 4 * i);
htab->selfinit_off = sizeof (selfinit_header);
}
static void
add_selfinit_tail (struct bfd_link_info *info)
{
bfd *output_bfd = info->output_bfd;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
unsigned char *ptr = htab->selfinit->contents + htab->selfinit_off;
unsigned int i;
if (htab->selfinit_off + sizeof (selfinit_tail) != htab->selfinit->size)
return;
for (i = 0; i < sizeof (selfinit_tail) / 4; i++)
bfd_put_32 (output_bfd, selfinit_tail[i], ptr + 4 * i);
htab->selfinit_off += sizeof (selfinit_tail);
}
static void
add_selfinit_ap (struct bfd_link_info *info,
bfd_vma relocation,
bfd_vma size,
bfd_vma addend,
bfd_vma targ_off,
const char *name ATTRIBUTE_UNUSED)
{
bfd *output_bfd = info->output_bfd;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
unsigned char *ptr;
unsigned int i;
// printf ("%s: AP\n", name);
// fflush (NULL);
BFD_ASSERT (htab->selfinit_off + sizeof (selfinit_ap)
+ sizeof (selfinit_tail) <= htab->selfinit->size);
add_selfinit_header (info);
ptr = htab->selfinit->contents + htab->selfinit_off;
if (targ_off == (bfd_vma) -1 || targ_off == (bfd_vma) -2)
{
/* Fill it in with NOPs. */
for (i = 0; i < sizeof (selfinit_ap) / 4; i++)
bfd_put_32 (output_bfd, 0, ptr + 4 * i);
htab->selfinit_off += sizeof (selfinit_ap);
add_selfinit_tail (info);
return;
}
for (i = 0; i < sizeof (selfinit_ap) / 4; i++)
bfd_put_32 (output_bfd, selfinit_ap[i], ptr + 4 * i);
if (relocation == 0)
{
/* RELOCATION equal to zero can be probably considered as a sign of a weak
undefined symbol. Indeed, any symbol defined in the data segment is
sure to be placed _after_ the code segment containing `__selfinit ()'
in ELF address space. Stupidly replace GDTOAP with two `addd's setting
"%qr0" to a numerical zero (HS and a trailing LTS0 playing no role for
`addd 0x0, 0x0, %r{0,1}' remain unchanged). */
static const unsigned int addq[] =
{
/* ALS0 */ 0x11c0c080, /* addd,0 0x0, 0x0, %dr0 */
/* ALS1 */ 0x11c0c081, /* addd,1 0x0, 0x0, %dr1 */
};
for (i = 0; i < 2; i++)
bfd_put_32 (output_bfd, addq[i], ptr + 4 + 4 * i);
}
else
bfd_put_32 (output_bfd, adjust_offset_in_cud_gd (info, relocation),
ptr + 12);
if (relocation == 0 || size == 0)
{
/* If size can't be determined reliably, just insert three NOPs in place
of APTOAPB. It also makes no sense to perform APTOAPB on "NULL" `AP's
corresponding to undefined weak symbols. I wonder if the latter may
turn out to have non-zero size. */
for (i = 4; i < 10; i++)
bfd_put_32 (output_bfd, 0, ptr + 4 * i);
}
else
bfd_put_32 (output_bfd, size, ptr + 36);
/* Customize the addend to be added to the obtained %qr0. */
bfd_put_32 (output_bfd, addend, ptr + 52);
bfd_put_32 (output_bfd, adjust_offset_in_cud_gd (info, targ_off), ptr + 68);
htab->selfinit_off += sizeof (selfinit_ap);
add_selfinit_tail (info);
}
static void
add_selfinit_pl (struct bfd_link_info *info,
bfd_vma relocation,
bfd_vma targ_off,
const char *name ATTRIBUTE_UNUSED)
{
bfd *output_bfd = info->output_bfd;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
unsigned char *ptr;
unsigned int i;
// printf ("%s: PL\n", name);
// fflush (NULL);
BFD_ASSERT (htab->selfinit_off + sizeof (selfinit_pl)
+ sizeof (selfinit_tail) <= htab->selfinit->size);
add_selfinit_header (info);
ptr = htab->selfinit->contents + htab->selfinit_off;
if (targ_off == (bfd_vma) -1 || targ_off == (bfd_vma) -2)
{
/* Fill it in with NOPs. */
for (i = 0; i < sizeof (selfinit_pl) / 4; i++)
bfd_put_32 (output_bfd, 0, ptr + 4 * i);
htab->selfinit_off += sizeof (selfinit_pl);
add_selfinit_tail (info);
return;
}
for (i = 0; i < sizeof (selfinit_pl) / 4; i++)
bfd_put_32 (output_bfd, selfinit_pl[i], ptr + 4 * i);
if (relocation == 0)
{
/* RELOCATION equal to zero should correspond to an undefined weak
function. Indeed, any defined function should be placed after
`__selfinit ()' in ELF address space and thus is sure to have non-zero
address. Replace `GETPL . . , %r0' with ADDd in such a case. Note that
ADDd in the preceding wide instruction will do half of the job of
producing a NULL 128-bit long PL on all Elbrus architectures. */
static const unsigned int addd =
/* ALS0 */ 0x11c0c080; /* addd,0 0x0, 0x0, %dr0 */
bfd_put_32 (output_bfd, addd, ptr + 12);
}
else
{
bfd_put_32 (output_bfd, adjust_offset_in_cud_gd (info, relocation),
ptr + 20);
}
bfd_put_32 (output_bfd, adjust_offset_in_cud_gd (info, targ_off), ptr + 36);
htab->selfinit_off += sizeof (selfinit_pl);
add_selfinit_tail (info);
}
void
_bfd_e2k_elf_after_parse (int phase)
{
link_mixed_eir_phase = phase;
}
/* This function should be called from `after_open' rather than from
`after_parse' since a hash table should have already been allocated
by the time it gets called. */
void
_bfd_e2k_elf_after_open (int ipd,
int is_x86app,
int is_4mpages,
bfd_boolean arch_via_cmdline,
bfd_boolean restrict_to,
bfd_boolean machine_check,
bfd_boolean new_e_machine,
bfd_boolean simulate,
bfd_boolean pack_cg)
{
/* Note that in S-records test INFO->HTAB turns out to be zero somehow when
this function gets called . . . */
e2k_ipd = ipd;
e2k_is_x86app = is_x86app;
e2k_is_4mpages = is_4mpages;
arch_set_via_cmdline = arch_via_cmdline;
restrict_to_arch = restrict_to;
relaxed_e2k_machine_check = machine_check;
output_new_e_machine = new_e_machine;
simulating_mode = simulate;
pack_cud_gd = pack_cg;
}
static bfd_boolean
check_magic (bfd *abfd, asection *magic_sec)
{
char *magic = getenv ("MAGIC");
size_t magic_size;
char *data;
bfd_boolean res = FALSE;
BFD_ASSERT (magic);
magic_size = strlen (magic) + 1;
data = xmalloc (magic_sec->size);
if (! bfd_get_section_contents (abfd, magic_sec, data, 0, magic_sec->size))
{
_bfd_error_handler (_("%pB: cannot read contents of section %pA\n"),
abfd, magic_sec);
}
if (magic_sec->size == (12 + ((sizeof ("MCST") + 3) & 0xfffffffc)
+ ((magic_size + 3) & 0xfffffffc))
&& bfd_get_32 (abfd, data) == sizeof ("MCST")
&& bfd_get_32 (abfd, data + 4) == magic_size
&& bfd_get_32 (abfd, data + 8) == NT_MAGIC
&& data[12 + sizeof ("MCST") - 1] == '\0'
&& data[12 + ((sizeof ("MCST") + 3) & 0xfffffffc)
+ magic_size - 1] == '\0'
&& strncmp (data + 12, "MCST", sizeof ("MCST") - 1) == 0
&& strncmp (data + 12 + ((sizeof ("MCST") + 3) & 0xfffffffc), magic,
magic_size - 1) == 0)
res = TRUE;
free (data);
return res;
}
/* This function is used to produce neat error messages when merging BFDs
below. As for `bfd_printable_name ()', it's not quite perfect since it
contains redundant ":{32,64,pm}" info which is guaranteed to coincide by
the time `merge_private_bfd_data ()' is called. On the other hand, forward
incompatible `elbrus-v{2,3}' BFDs should be identified as `elbrus-{2c+,4c}'
specific respectively for now. The decorated names more or less match the
ones output by `readelf --headers'. */
static const char *
decorated_arch_name (bfd *abfd)
{
Elf_Internal_Ehdr *hdr = elf_elfheader (abfd);
/* FIXME: it's too early to check `hdr->e_machine == EM_MCST_ELBRUS' for
OBFD here, since it may have not been set up so far. */
bfd_boolean fi = (hdr->e_flags & EF_E2K_INCOMPAT) != 0;
unsigned long mach = abfd->arch_info->mach / 4;
switch (mach)
{
case bfd_mach_e2k_generic:
return fi ? "forward incompatible generic" : "generic";
case bfd_mach_e2k_ev1:
return fi ? "forward incompatible elbrus-v1" : "elbrus-v1";
case bfd_mach_e2k_ev2:
return fi ? "elbrus-2c+" : "elbrus-v2";
case bfd_mach_e2k_ev3:
return fi ? "elbrus-4c" : "elbrus-v3";
case bfd_mach_e2k_ev4:
return fi ? "forward incompatible elbrus-v4" : "elbrus-v4";
case bfd_mach_e2k_ev5:
return fi ? "elbrus-8c2" : "elbrus-v5";
case bfd_mach_e2k_ev6:
return fi ? "forward incompatible elbrus-v6" : "elbrus-v6";
case bfd_mach_e2k_8c:
return "elbrus-8c";
case bfd_mach_e2k_1cplus:
return "elbrus-1c+";
case bfd_mach_e2k_12c:
return "elbrus-12c";
case bfd_mach_e2k_16c:
return "elbrus-16c";
case bfd_mach_e2k_2c3:
return "elbrus-2c3";
default:
BFD_ASSERT (0);
return NULL;
}
}
static const char *
bitness (unsigned long mach)
{
static const char *names[] = {"64-bit", "32-bit", "PM", "any"};
return names[mach % 4];
}
bfd_boolean
_bfd_e2k_elf_merge_private_bfd_data_1 (bfd *ibfd, bfd *obfd,
bfd_boolean uclibc_output ATTRIBUTE_UNUSED)
{
unsigned long imach, omach;
int incompatible_input;
int incompatible_output;
Elf_Internal_Ehdr *ihdr;
Elf_Internal_Ehdr *ohdr;
/* This is used internally in this function to enumerate all currently
recognized E2K processor types when it comes to determining if `bfd_mach_
e2k_*' BFD can be executed on this or that processor. */
enum
{
ev1,
ev2,
ev3,
e8c,
e1cplus,
ev5,
e12c,
e16c,
e2c3,
/* The related bit in mask stands for "all future processor models". */
ev7
};
/* Specify P in the mask of processors at which the BFD under consideration
can be executed. */
#define AT(p) (1L << p)
#define AT_ev6 (AT (e12c) | AT (e16c) | AT (e2c3))
/* This is a machine compatibility table. It provides the mask of machines an
object file compiled (or linked) for a given machine (specified by the row)
can be executed on in either compatible (column 0) or incompatible (column
1) mode. Incompatible mode means that the object file contains code which
is incompatible with subsequent machines, which isn't usually the case. */
static const unsigned long mask[][2] =
{
[bfd_mach_e2k_generic] = {(AT (ev1) | AT (ev2) | AT (ev3) | AT (e8c)
| AT (e1cplus) | AT (ev5) | AT_ev6
| AT (ev7)),
(AT (ev1) | AT (ev2))},
[bfd_mach_e2k_ev1] = {AT (ev1),
AT (ev1)},
[bfd_mach_e2k_ev2] = {(AT (ev2) | AT (ev3) | AT (e8c) | AT (e1cplus)
| AT (ev5) | AT_ev6 | AT (ev7)),
(AT (ev2))},
[bfd_mach_e2k_ev3] = {(AT (ev3) | AT (e8c) | AT (e1cplus) | AT (ev5)
| AT_ev6 | AT (ev7)),
AT (ev3)},
[bfd_mach_e2k_ev4] = {(AT (e8c) | AT (e1cplus) | AT (ev5) | AT_ev6
| AT (ev7)),
(AT (e8c) | AT (e1cplus))},
[bfd_mach_e2k_ev5] = {(AT (ev5) | AT_ev6 | AT (ev7)),
AT (ev5)},
[bfd_mach_e2k_ev6] = {(AT_ev6 | AT (ev7)),
AT_ev6},
[bfd_mach_e2k_8c] = {AT (e8c),
AT (e8c)},
[bfd_mach_e2k_1cplus] = {AT (e1cplus),
AT (e1cplus)},
[bfd_mach_e2k_12c] = {AT (e12c),
AT (e12c)},
[bfd_mach_e2k_16c] = {AT (e16c),
AT (e16c)},
[bfd_mach_e2k_2c3] = {AT (e2c3),
AT (e2c3)}
};
{
static bfd_boolean first_ibfd_saved = TRUE;
bfd_boolean res = TRUE, first_ibfd = first_ibfd_saved;
int iuclibc =
elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU][Tag_GNU_E2K_UCLIBC].i;
/* Next time `first_ibfd' will be set to FALSE. */
first_ibfd_saved = FALSE;
if ((uclibc_output && iuclibc == 0)
|| (! uclibc_output && iuclibc != 0))
{
_bfd_error_handler (_("%s input object %pB is not compatible with "
"%s output"),
uclibc_output ? "GNU" : "uclibc",
ibfd,
uclibc_output ? "uclibc" : "GNU");
res = FALSE;
}
if (uclibc_output && first_ibfd)
bfd_elf_add_obj_attr_int (obfd, OBJ_ATTR_GNU, Tag_GNU_E2K_UCLIBC, 1);
if (! res)
return FALSE;
}
if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour && getenv ("MAGIC"))
{
asection *magic_sec;
static bfd_boolean first_ibfd_saved = TRUE;
bfd_boolean res, first_ibfd = first_ibfd_saved;
/* Next time `first_ibfd' will be set to FALSE. */
first_ibfd_saved = FALSE;
magic_sec = bfd_get_section_by_name (ibfd, ".magic");
if (magic_sec == NULL)
{
_bfd_error_handler (_("Input object %pB doesn't have a .magic "
"section"), ibfd);
return FALSE;
}
res = check_magic (ibfd, magic_sec);
/* Exclude this section from output no matter what `check_magic ()'
returned, though it's not absolutely necessary if it failed: we are
not going to have any output in this case. */
if (! first_ibfd)
{
magic_sec->flags |= SEC_EXCLUDE;
magic_sec->size = 0;
}
if (! res)
{
_bfd_error_handler (_("Input object %pB contains wrong MAGIC "),
ibfd);
return FALSE;
}
}
/* My further checks are meaningful if both input and output files are
ELFs only. Well, probably the check for `obfd' is redundant, because
this method is related to an ELF-specific backend. As for `ibfd' we
may very well have a binary here, e.g. when building the Kernel
(see Bug #58954).
P.S. This test has been borrowed from `elfxx-mips.c' and seems to be
OK for my purposes. Maybe, it can be replaced with the one from
`bfd_arch_get_compatible ()' in `archures.c' where a `binary' case
is considered explicitly. */
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
ihdr = elf_elfheader (ibfd);
ohdr = elf_elfheader (obfd);
imach = ibfd->arch_info->mach;
omach = obfd->arch_info->mach;
/* We shouldn't find ourselves here if `bfd_e2k_compatible ()' failed,
should we? */
if (imach % 4 != omach % 4)
{
_bfd_error_handler
(_("%s input file `%pB' is incompatible with %s output"),
bitness (imach), ibfd, bitness (omach));
return FALSE;
}
/* Input object file with "any bitness" mach should not appear in
principle. */
BFD_ASSERT (imach % 4 != 3);
if ((ihdr->e_ident[EI_OSABI] == ELFOSABI_KPDA
|| get_elf_backend_data (obfd)->elf_osabi == ELFOSABI_KPDA)
&& ihdr->e_ident[EI_OSABI] != get_elf_backend_data (obfd)->elf_osabi)
{
bfd_boolean kpda_input = ihdr->e_ident[EI_OSABI] == ELFOSABI_KPDA;
const char *linux_abi = "Linux";
const char *kpda_abi = "KPDA";
_bfd_error_handler
(_("%pB: input with `%s' ABI cannot be processed by `%s' target"),
ibfd, kpda_input ? kpda_abi : linux_abi,
kpda_input ? linux_abi : kpda_abi);
return FALSE;
}
/* Shared objects' machine shouldn't have an impact on the one eventually set
for OBFD as they can be very different from the ones used at runtime in
this respect. The above tests not allowing for the mixture of different
ABIs and GNU, Uclibc and KPDA object files seem to be reasonable because
the user should NOT allow for such mixtures at link-time. */
if ((ibfd->flags & DYNAMIC) != 0)
return TRUE;
/* Now that we are guaranteed that input and output bfds have the same mode,
migrate to e2k machine masks defined in `MCST E2K' section of
`bfd/archures.c'. */
imach /= 4;
omach /= 4;
/* Explicitly prohibit the linkage of "generic" and "elbrus-v1" input ELFs as
proposed in Bug #96498, Comment #11 so as to make it impossible in
principle. */
if (imach == bfd_mach_e2k_generic || imach == bfd_mach_e2k_ev1)
{
_bfd_error_handler
(_("%pB: link of `%s' input files is no longer supported"),
ibfd,
imach == bfd_mach_e2k_generic ? "generic" : "elbrus-v1");
return FALSE;
}
/* Further machine compatibility checks should not be performed in
`--relaxed-e2k-machine' mode. */
if (relaxed_e2k_machine_check)
return TRUE;
/* Is the currently considered input file incompatible? */
incompatible_input = (((ihdr->e_machine == EM_MCST_ELBRUS)
&& (ihdr->e_flags & EF_E2K_INCOMPAT))
? 1
: 0);
if (! output_new_e_machine)
{
if (incompatible_input )
{
_bfd_error_handler (_("New style object %pB with `EF_E2K_INCOMPAT' "
"flag set cannot be linked into an old "
"style %pB"), ibfd, obfd);
return FALSE;
}
/* If we are still alive here when producing an old style output,
we haven't come across a new style incompatible object file. */
incompatible_output = 0;
}
else
{
/* Have we already come across an incompatible object file which
resulted in an incompatible output? */
incompatible_output = (ohdr->e_flags & EF_E2K_INCOMPAT) ? 1 : 0;
}
/* Provided that `--restrict-to-arch OUTPUT_ARCH' has been specified, an
input file's architecture should exactly match OUTPUT_ARCH. */
if (restrict_to_arch && imach != omach)
{
_bfd_error_handler
(_("input file `%pB' of `%s' architecture does not match "
"`%s' specified via `--restrict-to-arch' option"),
ibfd, decorated_arch_name (ibfd), decorated_arch_name (obfd));
return FALSE;
}
/* Get masks of machines input and output files can be executed at. */
imach = mask[imach][incompatible_input];
/* VERIFY: hopefully `omach' is set to `bfd_mach_e2k_generic' via LD script
if it's not explicitly specified via `-A' by the user. This is crucial
for my scheme to work properly. */
omach = mask[omach][incompatible_output];
/* Update the mask for the output and see if it becomes incompatible after
the next input file has been brought into play. */
omach = omach & imach;
incompatible_output = (incompatible_input || incompatible_output);
/* If the output arch has been specified explicitly, fail if we get
something different (e.g. the user wants E3S while the combination
of input files makes us choose E2S). */
if (arch_set_via_cmdline
&& omach != mask[obfd->arch_info->mach / 4][incompatible_output])
omach = 0;
if (omach != 0)
{
unsigned int i;
if (output_new_e_machine && incompatible_input)
{
/* Don't care about this case when producing old style output. It
should be impossible (see call to bfd_error_handler above). */
ohdr->e_flags |= EF_E2K_INCOMPAT;
}
/* Get the machine number corresponding to the updated output mask. It
should be one of our candidates provided that I don't have a logical
error here. */
for (i = 0; i < sizeof (mask) / sizeof (mask[0]); i++)
{
if (omach == mask[i][incompatible_output])
break;
}
BFD_ASSERT (i < sizeof (mask) / sizeof (mask[0]));
i *= 4;
i += obfd->arch_info->mach % 4;
if (obfd->arch_info->mach != (unsigned long) i)
bfd_set_arch_mach (obfd, bfd_arch_e2k, (unsigned long) i);
return TRUE;
}
_bfd_error_handler
(_("input file `%pB' of `%s' architecture is incompatible "
"with `%s' output"),
ibfd, decorated_arch_name (ibfd), decorated_arch_name (obfd));
return FALSE;
}
#define is_e2k_elf(abfd) \
(bfd_get_flavour (abfd) == bfd_target_elf_flavour \
&& elf_tdata (abfd) != NULL \
&& elf_object_id (abfd) == E2K_ELF_DATA)
bfd_boolean
_bfd_e2k_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
return _bfd_e2k_elf_merge_private_bfd_data_1 (ibfd, info->output_bfd, FALSE);
}
/* I need this structure because of an extra TYPE field missing from `struct
elf_dyn_relocs' required to distinguish between references via `R_E2K_{AP,
PL}'. FIXME: eventually it should be derived from the latter. */
struct e2k_elf_dyn_relocs
{
struct e2k_elf_dyn_relocs *next;
/* The input section of the reloc. */
asection *sec;
/* Total number of relocs copied for the input section. */
bfd_size_type count;
/* Number of pc-relative relocs copied for the input section. */
bfd_size_type pc_count;
int type;
};
/* E2K ELF linker hash entry. */
struct _bfd_e2k_elf_link_hash_entry
{
struct elf_link_hash_entry elf;
/* Track dynamic relocs copied for this symbol. */
struct e2k_elf_dyn_relocs *dyn_relocs;
#define GOT_UNKNOWN 0
#define GOT_NORMAL 1
#define GOT_TLS_GDMOD 2
#define GOT_TLS_GDREL 4
#define GOT_TLS_IE 8
char tls_type;
union gotplt_union gdmod;
/* This is used to account for IE-related GOT entries. I need a separate
counter/offset field because a symbol may be accessed both via GD and IE
model. FIXME: find out whether the scheme employing GLIST field in h->got
can be used instead. */
union gotplt_union ie;
/* Offset of the entry within '.got.plt'. Used together with the
secondary PLT entry, but can remain alone if the corresponding function
can be resolved locally and no secondary entry is actually needed. */
bfd_vma gotplt_offset;
/* Information about the GOT PLT entry. Filled when there are both GOT and PLT
relocations against the same function. Once it's set, both `plt.offset' and
`secondary_plt.offset' should be set to `-1' since no one of them is needed
any longer. */
union gotplt_union plt_got;
/* TRUE if this symbol is defined within a DSP relocatable object file. */
bfd_boolean dsp_symbol;
char relgot_cntr;
/* Set to 1 if this symbol's value should be set to its PLT offset once it
can be determined reliably. */
char finalize_plt_offset;
/* Whether this symbol is accessed via `R_E2K_AP_GOT' or `R_E2K_PL_GOT' in
Protected Mode. */
char pm_got_type;
};
#define _bfd_e2k_elf_hash_entry(ent) ((struct _bfd_e2k_elf_link_hash_entry *)(ent))
struct plt_entry
{
union
{
bfd_signed_vma refcount;
bfd_vma idx;
} primary, secondary;
};
static bfd_boolean
positive_plt_refcount (struct elf_link_hash_entry *h)
{
if (h->plt.plist == NULL)
return FALSE;
BFD_ASSERT (h->plt.plist->secondary.refcount
>= h->plt.plist->primary.refcount);
if (h->plt.plist->primary.refcount > 0)
return TRUE;
return FALSE;
}
static bfd_boolean
positive_secondary_plt_refcount (struct elf_link_hash_entry *h)
{
if (h->plt.plist == NULL)
return FALSE;
if (h->plt.plist->secondary.refcount > 0)
return TRUE;
return FALSE;
}
static struct plt_entry *
make_plt_record (bfd *abfd)
{
struct plt_entry *entry;
entry = bfd_zalloc (abfd, sizeof (*entry));
return entry;
}
/* Implementation of this one as well as of 'decrease_plt_refcount ()' which
is not implemented yet requires additional consideration. */
static void
decrease_secondary_plt_refcount (struct elf_link_hash_entry *h)
{
if (h->plt.plist && h->plt.plist->secondary.refcount > 0)
h->plt.plist->secondary.refcount -= 1;
}
static void
discard_plt_refcount (struct elf_link_hash_entry *h)
{
BFD_ASSERT (h->plt.plist != NULL
&& h->plt.plist->primary.refcount > 0
&& (h->plt.plist->secondary.refcount
>= h->plt.plist->primary.refcount));
h->plt.plist->secondary.refcount -= h->plt.plist->primary.refcount;
h->plt.plist->primary.refcount = 0;
}
static bfd_boolean
increase_secondary_plt_refcount (bfd *abfd, struct elf_link_hash_entry *h)
{
if (h->plt.plist == NULL)
h->plt.plist = make_plt_record (abfd);
if (h->plt.plist == NULL)
return FALSE;
h->plt.plist->secondary.refcount += 1;
return TRUE;
}
static bfd_boolean
increase_plt_refcount (bfd *abfd, struct elf_link_hash_entry *h)
{
if (! increase_secondary_plt_refcount (abfd, h))
return FALSE;
h->plt.plist->primary.refcount += 1;
return TRUE;
}
static void
copy_plt_refcount (struct elf_link_hash_entry *dst,
struct elf_link_hash_entry *src)
{
if (src->plt.plist == NULL
|| (src->plt.plist->primary.refcount == 0
&& src->plt.plist->secondary.refcount == 0))
return;
if (dst->plt.plist == NULL)
dst->plt.plist = src->plt.plist;
else
{
dst->plt.plist->primary.refcount += src->plt.plist->primary.refcount;
dst->plt.plist->secondary.refcount += src->plt.plist->secondary.refcount;
}
}
static bfd_vma
secondary_plt_idx (struct elf_link_hash_entry *h)
{
if (h->plt.plist == NULL)
return (bfd_vma) -1;
return h->plt.plist->secondary.idx;
}
/* This should be called only if `secondary_plt_idx ()' returns an index
different from `-1'. */
static bfd_vma
secondary_plt_offset (struct elf_link_hash_entry *h,
struct _bfd_e2k_elf_link_hash_table *htab)
{
int idx;
BFD_ASSERT (h->plt.plist && h->plt.plist->secondary.idx != (bfd_vma) -1);
idx = h->plt.plist->secondary.idx;
return htab->plt_got_header_size + idx * htab->plt_got_secondary_entry_size;
}
static bfd_vma
plt_idx (struct elf_link_hash_entry *h)
{
if (h->plt.plist == NULL)
return (bfd_vma) -1;
return h->plt.plist->primary.idx;
}
/* This should be called only if `plt_idx ()' returns an index different
from `-1'. */
static bfd_vma
plt_offset (struct elf_link_hash_entry *h,
struct _bfd_e2k_elf_link_hash_table *htab)
{
int idx;
BFD_ASSERT (h->plt.plist && h->plt.plist->primary.idx != (bfd_vma) -1);
idx = h->plt.plist->primary.idx;
return (htab->plt_got_header_size
+ htab->secondary_plt_num * htab->plt_got_secondary_entry_size
+ idx * htab->plt_got_primary_entry_size);
}
/* Set the next available index for a secondary PLT entry. Pass NULL for HTAB
to specify that it should be set to -1. */
static void
set_secondary_plt_idx (struct elf_link_hash_entry *h,
struct _bfd_e2k_elf_link_hash_table *htab)
{
if (h->plt.plist == NULL && htab == NULL)
return;
BFD_ASSERT (h->plt.plist != NULL
&& (h->plt.plist->secondary.refcount > 0
|| htab == NULL));
h->plt.plist->secondary.idx = htab ? htab->secondary_plt_num++ : (bfd_vma) -1;
}
/* Set the next available index for a primary PLT entry. Pass NULL for HTAB
to specify that it should be set to -1. */
static void
set_plt_idx (struct elf_link_hash_entry *h,
struct _bfd_e2k_elf_link_hash_table *htab)
{
if (h->plt.plist == NULL && htab == NULL)
return;
BFD_ASSERT (h->plt.plist != NULL
&& (h->plt.plist->primary.refcount > 0
|| htab == NULL));
h->plt.plist->primary.idx = htab ? htab->primary_plt_num++ : (bfd_vma) -1;
}
struct _bfd_e2k_elf_obj_tdata
{
struct elf_obj_tdata root;
union
{
bfd_signed_vma *refcounts;
bfd_vma *offsets;
} local_ie;
/* tls_type for each local got entry. */
char *local_got_tls_type;
/* How many .rela.got entries have been reserved for each local symbol. */
char *local_relgot_cntr;
};
#define _bfd_e2k_elf_tdata(abfd) \
((struct _bfd_e2k_elf_obj_tdata *) (abfd)->tdata.any)
#define _bfd_e2k_elf_local_ie_refcounts(abfd) \
(_bfd_e2k_elf_tdata (abfd)->local_ie.refcounts)
#define _bfd_e2k_elf_local_ie_offsets(abfd) \
(_bfd_e2k_elf_tdata (abfd)->local_ie.offsets)
#define _bfd_e2k_elf_local_got_tls_type(abfd) \
(_bfd_e2k_elf_tdata (abfd)->local_got_tls_type)
#define _bfd_e2k_elf_local_relgot_cntr(abfd) \
(_bfd_e2k_elf_tdata (abfd)->local_relgot_cntr)
static void
e2k_put_word_32 (bfd *abfd, bfd_vma val, void *ptr)
{
bfd_put_32 (abfd, val, ptr);
}
static void
e2k_put_word_64 (bfd *abfd, bfd_vma val, void *ptr)
{
bfd_put_64 (abfd, val, ptr);
}
static bfd_vma
e2k_elf_r_info_32 (bfd_vma rel_index, bfd_vma type)
{
return ELF32_R_INFO (rel_index, type);
}
static bfd_vma
e2k_elf_r_info_64 (bfd_vma rel_index, bfd_vma type)
{
return ELF64_R_INFO (rel_index, type);
}
/* Patterns of 32-bit PLT entries and headers relying on '.got.plt'. */
static const unsigned int plt32_got_pic_header[] =
{
/* 0000<000000000000> HS */ 0x04100091, /* M_0: nop 1 */
/* ALS0 */ 0x3e81c088, /* rrs,0 %ip, %r8 */
/* ALES */ 0x01c00000,
/* LTS0 */ 0x00000000,
/* 0001<000000000010> HS */ 0x14500122, /* :nop 2 */
/* ALS0 */ 0x6688d888, /* ldgdw,0 [ %r8 + _f32s,_lts0 0x11111111 ], %r8 */
/* ALS2 */ 0x6688d98a, /* ldgdw,2 [ %r8 + _f32s,_lts1 0x22222222 ], %r10 */
/* ALES */ 0x01c00000,
/* LTS1 */ 0x22222222,
/* LTS0 */ 0x11111111,
/* 0002<000000000028> HS */ 0x04000001, /* : */
/* ALS0 */ 0x63f08ad1, /* getpl,0 %r10, %ctpr1 */
/* 0003<000000000030> HS */ 0x00009012, /* : */
/* SS */ 0x80000420, /* ipd 2 */
/* CS1 */ 0x50000004, /* call %ctpr1, wbs = 0x4 */
/* LTS0 */ 0x00000000,
/* 0004<000000000040> HS */ 0x04000001, /* : */
/* ALS0 */ 0x63f088d1, /* getpl,0 %r8, %ctpr1 */
/* 0005<000000000048> HS */ 0x00001001, /* : */
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT32_GOT_PIC_HEADER_NOP_OFFSET 0x10
#define PLT32_GOT_PIC_LINK_MAP_LD_OFFSET 0x24
#define PLT32_GOT_PIC_DL_FIXUP_LD_OFFSET 0x20
#define PLT32_GOT_PIC_HEADER_SIZE sizeof (plt32_got_pic_header)
static const unsigned int plt32_got_non_pic_header[] =
{
/* 0: */
/* HS */ 0x92400112, /* nop 2 */
/* ALS2 */ 0x66c0d888, /* ldgdw,2 0x0, _f32s,_lts0 0x76543210, %dr8 */
/* ALS5 */ 0x66c4d88a, /* ldgdw,5 0x4, _f32s,_lts0 0x76543210, %dr10 */
/* LTS0 */ 0x76543210,
/* 10: */
/* HS */ 0x04000001,
/* ALS0 */ 0x63f08ad1, /* getpl,0 %r10, %ctpr1 */
/* 18: */
/* HS */ 0x00009012,
/* SS */ 0x80000420,
/* ipd 2 */
/* CS1 */ 0x50000004, /* call %ctpr1, wbs = 0x4 */
/* LTS0 */ 0x00000000,
/* 28: */
/* HS */ 0x04000001,
/* ALS0 */ 0x63f088d1, /* getpl,0 %r8, %ctpr1 */
/* 30: */
/* HS */ 0x00001001,
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT32_GOT_NON_PIC_HEADER_NOP_OFFSET 0x0
#define PLT32_GOT_NON_PIC_LINK_MAP_LD_OFFSET 0xc
#define PLT32_GOT_NON_PIC_HEADER_SIZE sizeof (plt32_got_non_pic_header)
static const unsigned int plt32_got_pic_primary_entry[] =
{
/* 0008<000000000070> HS */ 0x041080a2, /* :nop 1 */
/* ALS0 */ 0x3e81c088, /* rrs,0 %ip, %r8 */
/* CS1 */ 0x00000000, /* setwd wsz = 0x8, nfx = 0x1 */
/* ALES */ 0x01c00000,
/* LTS1 */ 0x00000000,
/* LTS0 */ 0x00000110,
/* 0009<000000000088> HS */ 0x04100111, /* :nop 2 */
/* ALS0 */ 0x6688d888, /* ldgdw,0 [ %r8 + _f32s,_lts0 0x44444444 ], %r8 */
/* ALES */ 0x01c00000,
/* LTS0 */ 0x44444444,
/* 0010<000000000098> HS */ 0x04000001, /* : */
/* ALS0 */ 0x63f088d1, /* getpl,0 %r8, %ctpr1 */
/* 0011<0000000000a0> HS */ 0x00001001, /* : */
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT32_GOT_PIC_ENTRY_NOP_OFFSET 0x18
#define PLT32_GOT_PIC_TARGET_LD_OFFSET 0x24
#define PLT32_GOT_PIC_PRIMARY_ENTRY_SIZE sizeof (plt32_got_pic_primary_entry)
static const unsigned int plt32_got_non_pic_primary_entry[] =
{
/* 0: */
/* HS */ 0x10408122, /* nop 2 */
/* ALS2 */ 0x66c0d988, /* ldgdw,2 0x0, _f32s,_lts1 0x76543210, %dr8 */
/* CS1 */ 0x00000000, /* setwd wsz = 0x8, nfx = 0x1 */
/* LTS2 */ 0x00000000,
/* LTS1 */ 0x76543210,
/* LTS0 */ 0x00000110,
/* 18: */
/* HS */ 0x04000001,
/* ALS0 */ 0x63f088d1, /* getpl,0 %r8, %ctpr1 */
/* 20: */
/* HS */ 0x00001001,
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT32_GOT_NON_PIC_ENTRY_NOP_OFFSET 0x0
#define PLT32_GOT_NON_PIC_TARGET_LD_OFFSET 0x10
#define PLT32_GOT_NON_PIC_PRIMARY_ENTRY_SIZE sizeof (plt32_got_non_pic_primary_entry)
static void
build_plt_entry (struct bfd_link_info *info,
asection *splt,
bfd_vma offset,
bfd_vma gotplt_offset)
{
bfd *output_bfd = info->output_bfd;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
unsigned int i;
bfd_vma slot_addr;
asection *sgotplt = htab->elf.sgotplt;
unsigned char *plt_literal =
splt->contents + offset + htab->plt_got_target_ld_offset;
unsigned long omach = bfd_get_mach (output_bfd) / 4;;
/* Until support for specific elbrus-v6 machines has been added I can check
it this way. Note that `>= 6' can't be used here because specific machines
(say, elbrus-{8c,1c+} for elbrus-v4) are marked with numbers exceeding the
maximal possible iset version. */
/* Take into account that delay between load and its consumer has been
increased from 3 to 5 ticks starting from elbrus-v6 (see Bug #112004,
Comment #8). */
unsigned int nops = ((omach == bfd_mach_e2k_ev6
|| omach == bfd_mach_e2k_12c
|| omach == bfd_mach_e2k_16c
|| omach == bfd_mach_e2k_2c3) ? 4 : 2);
unsigned int hs_nop =
htab->plt_got_primary_entry[htab->plt_got_entry_nop_offset / 4];
for (i = 0; i < htab->plt_got_primary_entry_size / 4; i++)
bfd_put_32 (output_bfd, htab->plt_got_primary_entry[i],
(splt->contents + offset + 4 * i));
/* Adjust HS.nop according to the aforesaid. */
hs_nop = (hs_nop & 0xfffffc7fu) | (nops << 7);
bfd_put_32 (output_bfd, hs_nop,
(htab->elf.splt->contents
+ offset
+ htab->plt_got_entry_nop_offset));
slot_addr = adjust_offset_in_cud_gd (info,
(sgotplt->output_section->vma
+ sgotplt->output_offset
+ gotplt_offset));
if (! ABI_PM_P (htab->elf.dynobj) && bfd_link_pic (info))
{
/* Adjust primary PLT entry: write out 32-bit offset of the
corresponding '.got.plt' slot relative to it. It's involved in
`ld{,gd}w [%r8 == primary_entry_pc + CALCULATED_OFFSET], %r8'. */
bfd_put_32 (output_bfd,
(slot_addr
- (splt->output_section->vma
+ splt->output_offset
+ offset)),
plt_literal);
}
else
{
/* In non-PIC case it's just enough to encode the address of the
related '.got.plt' slot into PLT entry as a literal of an
appropriate size. */
if (ABI_64_P (output_bfd))
{
bfd_put_32 (output_bfd, slot_addr >> 32, plt_literal);
plt_literal += 4;
}
bfd_put_32 (output_bfd, slot_addr & 0xffffffff, plt_literal);
}
/* Relocation offset cannot be encoded within this function because unlike
e.g. Sparc we don't have a trivial correspondence between an index of
an entry in `.plt' and that of the corresponding relocation in
`.rela.plt' */
}
static void
build_secondary_plt_entry (struct bfd_link_info *info,
bfd_vma offset,
bfd_vma gotplt_offset,
bfd_vma *r_offset,
const char *name)
{
unsigned int i;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
bfd *output_bfd = info->output_bfd;
asection *splt = htab->elf.splt;
asection *sgotplt = htab->elf.sgotplt;
/* Set R_OFFSET of the run-time relocation which is to fix the above
'.got.plt' slot. */
*r_offset = (sgotplt->output_section->vma + sgotplt->output_offset
+ gotplt_offset);
if (htab->plt_got_secondary_entry_size == 0)
return;
for (i = 0; i < htab->plt_got_secondary_entry_size / 4; i++)
bfd_put_32 (output_bfd, htab->plt_got_secondary_entry[i],
splt->contents + offset + 4 * i);
/* Adjust secondary PLT entry: write out CS0 syllable of "ibranch to PLT
header". It seems to be the same both in 32 and 64-bit mode. */
bfd_put_32 (output_bfd, (((unsigned int) -offset) >> 3) & 0x0fffffff,
splt->contents + offset + htab->plt_got_disp_offset);
if (! ABI_PM_P (htab->elf.dynobj))
{
/* Adjust the corresponding `.got.plt' slot, which is to be lazily
relocated at run-time. Initially it should be set to the link-time
address of the just created secondary PLT entry. */
htab->put_word (output_bfd,
splt->output_section->vma + splt->output_offset + offset,
sgotplt->contents + gotplt_offset);
}
else
{
add_selfinit_pl (info,
(splt->output_section->vma
+ splt->output_offset + offset),
(sgotplt->output_section->vma + sgotplt->output_offset
+ gotplt_offset),
name);
}
}
/* FIXME: this function is to be unified with its 64-bit counterpart. */
static void
e2k32_plt_lazy_entry_adjust_reloc_offset (bfd *output_bfd,
struct _bfd_e2k_elf_link_hash_table *htab,
asection *splt,
bfd_vma offset,
bfd_vma dynrel_offset)
{
/* Adjust secondary PLT entry: write out the corresponding 32-bit offset
within `.rela.plt', which is the second parameter of `_dl_fixup (). */
bfd_put_32 (output_bfd, dynrel_offset,
splt->contents + offset + htab->plt_got_reloc_arg_offset);
}
static const unsigned int plt64_got_pic_header[] =
{
/* 0000<000000000000> HS */ 0x04100091, /* header: nop 1 */
/* ALS0 */ 0x3f81c088, /* rrd,0 %ip, %dr8 */
/* ALES */ 0x01c00000,
/* LTS0 */ 0x00000000,
/* 0001<000000000010> HS */ 0x14000122, /* :nop 2 */
/* ALS0 */ 0x6788d888, /* ldd,0 [ %dr8 + _f32s,_lts0 0x11111111 ], %dr8 */
/* ALS2 */ 0x6788d98a, /* ldd,2 [ %dr8 + _f32s,_lts1 0x22222222 ], %dr10 */
/* LTS2 */ 0x00000000,
/* LTS1 */ 0x22222222,
/* LTS0 */ 0x11111111,
/* 0002<000000000028> HS */ 0x04000001, /* : */
/* ALS0 */ 0x61c08ad1, /* movtd,0 %dr10, %ctpr1 */
/* 0003<000000000030> HS */ 0x00009012, /* : */
/* SS */ 0x80000420, /* ipd 2 */
/* CS1 */ 0x50000004, /* call %ctpr1, wbs = 0x4 */
/* LTS0 */ 0x00000000,
/* 0004<000000000040> HS */ 0x04000001, /* : */
/* ALS0 */ 0x61c088d1, /* movtd,0 %dr8, %ctpr1 */
/* 0005<000000000048> HS */ 0x00001001, /* : */
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT64_GOT_PIC_HEADER_NOP_OFFSET 0x10
#define PLT64_GOT_PIC_LINK_MAP_LD_OFFSET 0x24
#define PLT64_GOT_PIC_DL_FIXUP_LD_OFFSET 0x20
#define PLT64_GOT_PIC_HEADER_SIZE sizeof (plt64_got_pic_header)
static const unsigned int plt64_got_non_pic_header[] =
{
/* 0: */
/* HS */ 0x14000122, /* nop 2 */
/* ALS0 */ 0x67c0dc88, /* ldd,0 0x0, _f64,_lts0 0xfedcba9876543210, %dr8 */
/* ALS2 */ 0x67c8dc8a, /* ldd,2 0x8, _f64,_lts0 0xfedcba9876543210, %dr10 */
/* LTS2 */ 0x00000000,
/* LTS1 */ 0xfedcba98,
/* LTS0 */ 0x76543210,
/* 18: */
/* HS */ 0x04000001,
/* ALS0 */ 0x61c08ad1, /* movtd,0 %dr10, %ctpr1 */
/* 20: */
/* HS */ 0x00009012,
/* SS */ 0x80000420, /* ipd 2 */
/* CS1 */ 0x50000004, /* call %ctpr1, wbs = 0x4 */
/* LTS0 */ 0x00000000,
/* 30: */
/* HS */ 0x04000001,
/* ALS0 */ 0x61c088d1, /* movtd,0 %dr8, %ctpr1 */
/* 38: */
/* HS */ 0x00001001,
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT64_GOT_NON_PIC_HEADER_NOP_OFFSET 0x0
#define PLT64_GOT_NON_PIC_LINK_MAP_LD_OFFSET 0x10
#define PLT64_GOT_NON_PIC_HEADER_SIZE sizeof (plt64_got_non_pic_header)
static const unsigned int plt64_got_pic_primary_entry[] =
{
/* 0008<000000000070> HS */ 0x041080a2, /* :nop 1 */
/* ALS0 */ 0x3f81c088, /* rrd,0 %ip, %dr8 */
/* CS1 */ 0x00000000, /* setwd wsz = 0x8, nfx = 0x1 */
/* ALES */ 0x01c00000,
/* LTS1 */ 0x00000000,
/* LTS0 */ 0x00000110,
/* 0009<000000000088> HS */ 0x04000111, /* :nop 2 */
/* ALS0 */ 0x6788d888, /* ldd,0 [ %dr8 + _f32s,_lts0 0x44444444 ], %dr8 */
/* LTS1 */ 0x00000000,
/* LTS0 */ 0x44444444,
/* 0010<000000000098> HS */ 0x04000001, /* : */
/* ALS0 */ 0x61c088d1, /* movtd,0 %dr8, %ctpr1 */
/* 0011<0000000000a0> HS */ 0x00001001, /* : */
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT64_GOT_PIC_ENTRY_NOP_OFFSET 0x18
#define PLT64_GOT_PIC_TARGET_LD_OFFSET 0x24
#define PLT64_GOT_PIC_PRIMARY_ENTRY_SIZE sizeof (plt64_got_pic_primary_entry)
static const unsigned int plt64_got_non_pic_primary_entry[] =
{
/* 0: */
/* HS */ 0x04008122, /* nop 2 */
/* ALS0 */ 0x67c0dd88, /* ldd,0 0x0, _f64,_lts1 0xfedcba9876543210, %dr8 */
/* CS1 */ 0x00000000, /* setwd wsz = 0x8, nfx = 0x1 */
/* LTS2 */ 0xfedcba98,
/* LTS1 */ 0x76543210,
/* LTS0 */ 0x00000110,
/* 18: */
/* HS */ 0x04000001,
/* ALS0 */ 0x61c088d1, /* movtd,0 %dr8, %ctpr1 */
/* 20: */
/* HS */ 0x00001001,
/* SS */ 0x80000420, /* ct %ctpr1 */
/* ipd 2 */
};
#define PLT64_GOT_NON_PIC_ENTRY_NOP_OFFSET 0x0
#define PLT64_GOT_NON_PIC_TARGET_LD_OFFSET 0xc
#define PLT64_GOT_NON_PIC_PRIMARY_ENTRY_SIZE sizeof (plt64_got_non_pic_primary_entry)
#define MOVTD_TARGET(ind) \
/* HS */ 0x04000001, \
/* ALS0 */ (0x61c080d1 | (ind << 8)) /* movtd,0 %dr{ind}, %ctpr1 */
#define LOAD_LINK_MAP_DL_FIXUP(reg1, reg2) \
/* HS */ 0xb6d00034, \
/* ALS0 */ (0x79c0d880 | reg1), /* ldgdq,0 0x0, _f32s,_lts0 0x12345678, %qr{reg1} */ \
/* ALS2 */ (0x79c0d880 | (reg1 + 1)), \
/* ALS3 */ (0x79d0d880 | reg2), /* ldgdq,3 0x10, _f32s,_lts0 0x12345678, %qr{reg2} */ \
/* ALS5 */ (0x79d0d880 | (reg2 + 1)), \
/* ALES03*/ 0x01c001c0, \
/* LTS1 */ 0x00000000, \
/* LTS0 */ 0x12345678
#define MOVTQ_PAIR(src, dst) \
/* HS */ 0x6db00034, \
/* ALS0 */ (0x57c08080 | ((src + 0) << 8) | (dst + 0)), /* movtq,0 %qr{src}, %qr{dst} */ \
/* ALS1 */ (0x57c08080 | ((src + 1) << 8) | (dst + 1)), \
/* ALS3 */ (0x57c08080 | ((src + 2) << 8) | (dst + 2)), /* movtq,3 %qr{src+2}, %qr{dst+2} */ \
/* ALS4 */ (0x57c08080 | ((src + 3) << 8) | (dst + 3)), \
/* ALES */ 0x01c001c0, \
/* ALES */ 0x01c001c0, \
/* LTS0 */ 0x00000000
#define CALL_WBS(wbs) \
/* CS1 */ (0x50000000 | wbs) /* call %ctpr1, wbs = wbs */
static const unsigned int plt128_got_header[] =
{
LOAD_LINK_MAP_DL_FIXUP (
#ifndef NEW_PM_ABI
10, 14
#else /* defined NEW_PM_ABI */
18, 22
#endif
),
MOVTD_TARGET(
#ifndef NEW_PM_ABI
14
#else /* defined NEW_PM_ABI */
22
#endif /* defined NEW_PM_ABI */
),
/* 28: */
/* HS */ 0x00009012,
/* SS */ 0x80000420, /* ipd 2 */
/* CS1 */ CALL_WBS (
#ifndef NEW_PM_ABI
0x4
#else /* defined NEW_PM_ABI */
0x8
#endif /* defined NEW_PM_ABI */
),
/* LTS0 */ 0x00000000,
MOVTD_TARGET (
#ifndef NEW_PM_ABI
8
#else /* defined NEW_PM_ABI */
16
#endif /* defined NEW_PM_ABI */
),
#ifndef NEW_PM_ABI
MOVTQ_PAIR (0, 8),
MOVTQ_PAIR (4, 12),
#else /* defined NEW_PM_ABI */
MOVTQ_PAIR (0, 16),
MOVTQ_PAIR (4, 20),
MOVTQ_PAIR (8, 24),
MOVTQ_PAIR (12, 28),
#endif /* defined NEW_PM_ABI */
/* HS */ 0x00009012,
/* SS */ 0x80000420, /* ipd 2 */
/* CS1 */ CALL_WBS (
#ifndef NEW_PM_ABI
0x4
#else /* defined NEW_PM_ABI */
0x8
#endif /* defined NEW_PM_ABI */
),
/* LTS0 */ 0x00000000,
/* HS */ 0x00004001,
/* CS0 */ 0xf0000000, /* return %ctpr3 */
#ifndef NEW_PM_ABI
MOVTQ_PAIR (8, 0),
MOVTQ_PAIR (12, 4),
#else /* defined NEW_PM_ABI */
MOVTQ_PAIR (16, 0),
MOVTQ_PAIR (20, 4),
MOVTQ_PAIR (24, 8),
MOVTQ_PAIR (28, 12),
#endif /* defined NEW_PM_ABI */
/* HS */ 0x00001001,
/* SS */ 0x80000c20, /* ct %ctpr3 */
/* ipd 2 */
};
#define PLT128_GOT_HEADER_NOP_OFFSET 0x0
#define PLT128_GOT_LINK_MAP_LD_OFFSET 0x1c
#define PLT128_GOT_HEADER_SIZE sizeof (plt128_got_header);
#define LOAD_TARGET(ind) \
/* ALS0 */ (0x79c0d980 | ind), /* ldgdq,0 0x0, _f32s,_lts1 0x0, %qr{ind} */ \
/* ALS2 */ (0x79c0d980 | (ind + 1))
static const unsigned int plt128_got_primary_entry[] =
{
/* 0: */
/* HS */ 0x14508033,
/* ALS{0,2} */ LOAD_TARGET (
#ifndef NEW_PM_ABI
8
#else /* defined NEW_PM_ABI */
16
#endif /* defined NEW_PM_ABI */
),
/* CS1 */ 0x00000000, /* setwd wsz = 0x{8,10}, nfx = 0x1 */
/* ALES0 */ 0x01c00000,
/* LTS2 */ 0x00000000,
/* LTS1 */ 0x00000000,
/* LTS0 */ WSZ (
#ifndef NEW_PM_ABI
0x8
#else /* defined NEW_PM_ABI */
0x10
#endif /* defined NEW_PM_ABI */
),
#ifndef NEW_PM_ABI
MOVTD_TARGET (8),
MOVTQ_PAIR (0, 8),
MOVTQ_PAIR (4, 12),
#else /* defined NEW_PM_ABI */
MOVTD_TARGET (16),
MOVTQ_PAIR (0, 16),
MOVTQ_PAIR (4, 20),
MOVTQ_PAIR (8, 24),
MOVTQ_PAIR (12, 28),
#endif /* defined NEW_PM_ABI */
/* HS */ 0x00009012,
/* SS */ 0x80000420, /* ipd 2 */
/* CS1 */ CALL_WBS (
#ifndef NEW_PM_ABI
0x4
#else /* defined NEW_PM_ABI */
0x8
#endif /* defined NEW_PM_ABI */
),
/* LTS0 */ 0x00000000,
/* HS */ 0x00005012,
/* SS */ 0x80000000, /* ipd 2 */
/* CS0 */ 0xf0000000, /* return %ctpr3 */
/* LTS0 */ 0x00000000,
#ifndef NEW_PM_ABI
MOVTQ_PAIR (8, 0),
MOVTQ_PAIR (12, 4),
#else /* defined NEW_PM_ABI */
MOVTQ_PAIR (16, 0),
MOVTQ_PAIR (20, 4),
MOVTQ_PAIR (24, 8),
MOVTQ_PAIR (28, 12),
#endif /* defined NEW_PM_ABI */
/* HS */ 0x00001001,
/* SS */ 0x80000c20, /* ct %ctpr3 */
/* ipd 2 */
};
#define PLT128_GOT_ENTRY_NOP_OFFSET 0x0
#define PLT128_GOT_TARGET_LD_OFFSET 0x18
#define PLT128_GOT_PRIMARY_ENTRY_SIZE sizeof (plt128_got_primary_entry)
#define RELOC_ARG(ind) \
/* ALS0 */ (0x10c0d980 | ind) /* adds,0 0x0, _f32s,_lts1 0x12345678, %r{ind} */
static const unsigned int plt128_got_secondary_entry[] =
{
/* 0: */
/* HS */ 0x0400d034,
/* SS */ 0x80000020, /* ipd 2 */
/* ALS0 */ RELOC_ARG (
#ifndef NEW_PM_ABI
12
#else /* defined NEW_PM_ABI */
20
#endif /* defined NEW_PM_ABI */
),
/* CS0 */ 0x00000000, /* ibranch 0x0 */
/* CS1 */ 0x00000000, /* setwd wsz = 0x{8,10}, nfx = 0x1 */
/* LTS2 */ 0x00000000,
/* LTS1 */ 0x12345678,
/* LTS0 */ WSZ (
#ifndef NEW_PM_ABI
0x8
#else /* defined NEW_PM_ABI */
0x10
#endif /* defined NEW_PM_ABI */
)
};
#define PLT128_GOT_DISP_OFFSET 0xc
#define PLT128_GOT_RELOC_ARG_OFFSET 0x18
#define PLT128_GOT_SECONDARY_ENTRY_SIZE sizeof (plt128_got_secondary_entry)
static const unsigned int plt_got_secondary_entry[] =
{
/* 0: */
/* HS */ 0x0400d034,
/* SS */ 0x80000020, /* ipd 2 */
/* ALS0 */ 0x11c0d989, /* addd,0 0x0, _f32s,_lts1 0x76543210, %r9 */
/* CS0 */ 0x00000000, /* ibranch 0x0 */
/* CS1 */ 0x00000000, /* setwd wsz = 0x8, nfx = 0x1 */
/* LTS2 */ 0x00000000,
/* LTS1 */ 0x76543210,
/* LTS0 */ 0x00000110,
};
#define PLT_GOT_DISP_OFFSET 0xc
#define PLT_GOT_RELOC_ARG_OFFSET 0x18
#define PLT_GOT_SECONDARY_ENTRY_SIZE sizeof (plt_got_secondary_entry)
static void
e2k64_plt_lazy_entry_adjust_reloc_offset (bfd *output_bfd,
struct _bfd_e2k_elf_link_hash_table *htab,
asection *splt,
bfd_vma offset,
bfd_vma dynrel_offset)
{
/* Adjust secondary PLT entry: write out the corresponding 32-bit offset
within `.rela.plt', which is the second parameter of `_dl_fixup (). */
bfd_put_32 (output_bfd, dynrel_offset,
splt->contents + offset + htab->plt_got_reloc_arg_offset);
}
/* Create an entry in an E2k ELF linker hash table. */
static struct bfd_hash_entry *
_bfd_e2k_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
struct bfd_hash_table *table,
const char *string)
{
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (entry == NULL)
{
entry = bfd_hash_allocate (table,
sizeof (struct _bfd_e2k_elf_link_hash_entry));
if (entry == NULL)
return entry;
}
/* Call the allocation method of the superclass. */
entry = _bfd_elf_link_hash_newfunc (entry, table, string);
if (entry != NULL)
{
struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
struct _bfd_e2k_elf_link_hash_entry *eh;
eh = (struct _bfd_e2k_elf_link_hash_entry *) entry;
eh->dyn_relocs = NULL;
eh->tls_type = GOT_UNKNOWN;
eh->gdmod = htab->init_got_refcount;
eh->ie = htab->init_got_refcount;
eh->gotplt_offset = (bfd_vma) -1;
eh->plt_got = htab->init_got_refcount;
eh->dsp_symbol = FALSE;
/* Initially there are no .rela.got relocs required for this symbol. */
eh->relgot_cntr = 0;
eh->finalize_plt_offset = 0;
eh->pm_got_type = 0;
}
return entry;
}
static void
_bfd_e2k_elf_link_hash_table_finalize (struct bfd_link_info *info)
{
struct _bfd_e2k_elf_link_hash_table *htab;
htab = _bfd_e2k_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
/* Setup members related to the latest PLT implementation making use of
'.got.plt'. */
if (ABI_64_P (info->output_bfd))
{
if (bfd_link_pic (info))
{
htab->plt_got_header = plt64_got_pic_header;
htab->plt_got_header_nop_offset = PLT64_GOT_PIC_HEADER_NOP_OFFSET;
htab->plt_got_link_map_ld_offset = PLT64_GOT_PIC_LINK_MAP_LD_OFFSET;
htab->plt_got_dl_fixup_ld_offset = PLT64_GOT_PIC_DL_FIXUP_LD_OFFSET;
htab->plt_got_header_size = PLT64_GOT_PIC_HEADER_SIZE;
htab->plt_got_primary_entry = plt64_got_pic_primary_entry;
htab->plt_got_entry_nop_offset = PLT64_GOT_PIC_ENTRY_NOP_OFFSET;
htab->plt_got_target_ld_offset = PLT64_GOT_PIC_TARGET_LD_OFFSET;
htab->plt_got_primary_entry_size = PLT64_GOT_PIC_PRIMARY_ENTRY_SIZE;
}
else
{
htab->plt_got_header = plt64_got_non_pic_header;
htab->plt_got_header_nop_offset = PLT64_GOT_NON_PIC_HEADER_NOP_OFFSET;
htab->plt_got_link_map_ld_offset =
PLT64_GOT_NON_PIC_LINK_MAP_LD_OFFSET;
htab->plt_got_header_size = PLT64_GOT_NON_PIC_HEADER_SIZE;
htab->plt_got_primary_entry = plt64_got_non_pic_primary_entry;
htab->plt_got_entry_nop_offset = PLT64_GOT_NON_PIC_ENTRY_NOP_OFFSET;
htab->plt_got_target_ld_offset = PLT64_GOT_NON_PIC_TARGET_LD_OFFSET;
htab->plt_got_primary_entry_size =
PLT64_GOT_NON_PIC_PRIMARY_ENTRY_SIZE;
}
}
else if (! ABI_PM_P (info->output_bfd))
{
if (bfd_link_pic (info))
{
htab->plt_got_header = plt32_got_pic_header;
htab->plt_got_header_nop_offset = PLT32_GOT_PIC_HEADER_NOP_OFFSET;
htab->plt_got_link_map_ld_offset = PLT32_GOT_PIC_LINK_MAP_LD_OFFSET;
htab->plt_got_dl_fixup_ld_offset = PLT32_GOT_PIC_DL_FIXUP_LD_OFFSET;
htab->plt_got_header_size = PLT32_GOT_PIC_HEADER_SIZE;
htab->plt_got_primary_entry = plt32_got_pic_primary_entry;
htab->plt_got_entry_nop_offset = PLT32_GOT_PIC_ENTRY_NOP_OFFSET;
htab->plt_got_target_ld_offset = PLT32_GOT_PIC_TARGET_LD_OFFSET;
htab->plt_got_primary_entry_size = PLT32_GOT_PIC_PRIMARY_ENTRY_SIZE;
}
else
{
htab->plt_got_header = plt32_got_non_pic_header;
htab->plt_got_header_nop_offset = PLT32_GOT_NON_PIC_HEADER_NOP_OFFSET;
htab->plt_got_link_map_ld_offset =
PLT32_GOT_NON_PIC_LINK_MAP_LD_OFFSET;
htab->plt_got_header_size = PLT32_GOT_NON_PIC_HEADER_SIZE;
htab->plt_got_primary_entry = plt32_got_non_pic_primary_entry;
htab->plt_got_entry_nop_offset = PLT32_GOT_NON_PIC_ENTRY_NOP_OFFSET;
htab->plt_got_target_ld_offset = PLT32_GOT_NON_PIC_TARGET_LD_OFFSET;
htab->plt_got_primary_entry_size =
PLT32_GOT_NON_PIC_PRIMARY_ENTRY_SIZE;
}
}
if (! ABI_PM_P (htab->elf.dynobj))
{
/* This one could be set in `_bfd_e2k_elf_link_hash_table_create ()' since
the secondary entry is common in all modes. I setup it here just for
"symmetry". */
htab->plt_got_secondary_entry = plt_got_secondary_entry;
htab->plt_got_reloc_arg_offset = PLT_GOT_RELOC_ARG_OFFSET;
htab->plt_got_disp_offset = PLT_GOT_DISP_OFFSET;
htab->plt_got_secondary_entry_size = PLT_GOT_SECONDARY_ENTRY_SIZE;
}
else /* if (ABI_PM_P (info->output_bfd)) */
{
htab->plt_got_header = plt128_got_header;
htab->plt_got_header_nop_offset = PLT128_GOT_HEADER_NOP_OFFSET;
htab->plt_got_link_map_ld_offset = PLT128_GOT_LINK_MAP_LD_OFFSET;
htab->plt_got_header_size = PLT128_GOT_HEADER_SIZE;
htab->plt_got_primary_entry = plt128_got_primary_entry;
htab->plt_got_entry_nop_offset = PLT128_GOT_ENTRY_NOP_OFFSET;
htab->plt_got_target_ld_offset = PLT128_GOT_TARGET_LD_OFFSET;
htab->plt_got_primary_entry_size = PLT128_GOT_PRIMARY_ENTRY_SIZE;
htab->plt_got_secondary_entry = plt128_got_secondary_entry;
htab->plt_got_reloc_arg_offset = PLT128_GOT_RELOC_ARG_OFFSET;
htab->plt_got_disp_offset = PLT128_GOT_DISP_OFFSET;
htab->plt_got_secondary_entry_size = PLT128_GOT_SECONDARY_ENTRY_SIZE;
}
}
/* Ancient "semantics" values for 32 and 64-bit ABIs. I don't think
that it makes sense to make them public via `include/elf/e2k.h'.
Let them exist here hidden from the outside World. */
#define E2K_MPTR_32 1
#define E2K_MPTR_64 2
/* Create E2K ELF linker hash table. */
struct bfd_link_hash_table *
_bfd_e2k_elf_link_hash_table_create (bfd *abfd)
{
struct _bfd_e2k_elf_link_hash_table *ret;
bfd_size_type amt = sizeof (struct _bfd_e2k_elf_link_hash_table);
ret = (struct _bfd_e2k_elf_link_hash_table *) bfd_zmalloc (amt);
if (ret == NULL)
return NULL;
/* FIXME: this is a bit of a duplication of _bfd_e2k_elf_init_file_header_1
() which is likely to be called after all input files have been opened
which is too late for ABI_{64,PM}_P (OUTPUT_BFD) to work properly in all
places of interest. */
if (abfd->arch_info->mach % 4 == 2)
elf_elfheader (abfd)->e_flags |= EF_E2K_PM;
if (ELF64_P (abfd))
{
ret->r_info = e2k_elf_r_info_64;
ret->bytes_per_sym = sizeof (Elf64_External_Sym);
ret->bytes_per_rela = sizeof (Elf64_External_Rela);
ret->ancient_semantics = E2K_MPTR_64;
}
else
{
ret->r_info = e2k_elf_r_info_32;
ret->bytes_per_sym = sizeof (Elf32_External_Sym);
ret->bytes_per_rela = sizeof (Elf32_External_Rela);
ret->ancient_semantics = E2K_MPTR_32;
}
if (ABI_64_P (abfd))
{
ret->put_word = e2k_put_word_64;
ret->adjust_plt_lazy_entry_reloc_offset
= e2k64_plt_lazy_entry_adjust_reloc_offset;
ret->word_align_power = 3;
ret->bytes_per_word = 8;
ret->abs_reloc = R_E2K_64_ABS;
ret->abs_lit_reloc = R_E2K_64_ABS_LIT;
ret->copy_reloc = R_E2K_64_COPY;
ret->relative_reloc = R_E2K_64_RELATIVE;
ret->relative_lit_reloc = R_E2K_64_RELATIVE_LIT;
ret->dtpmod_reloc = R_E2K_TLS_64_DTPMOD;
ret->dtpoff_reloc = R_E2K_TLS_64_DTPREL;
ret->tpoff_reloc = R_E2K_TLS_TPOFF64;
ret->jmp_slot_reloc = R_E2K_64_JMP_SLOT;
ret->irelative_reloc = R_E2K_64_IRELATIVE;
}
else
{
ret->put_word = e2k_put_word_32;
ret->adjust_plt_lazy_entry_reloc_offset
= e2k32_plt_lazy_entry_adjust_reloc_offset;
ret->word_align_power = 2;
ret->bytes_per_word = 4;
ret->abs_reloc = R_E2K_32_ABS;
ret->abs_lit_reloc = R_E2K_32_ABS;
ret->copy_reloc = R_E2K_32_COPY;
ret->relative_reloc = R_E2K_32_RELATIVE;
ret->relative_lit_reloc = R_E2K_32_RELATIVE;
ret->dtpmod_reloc = R_E2K_TLS_32_DTPMOD;
ret->dtpoff_reloc = R_E2K_TLS_32_DTPREL;
ret->tpoff_reloc = R_E2K_TLS_TPOFF32;
ret->jmp_slot_reloc = R_E2K_32_JMP_SLOT;
ret->irelative_reloc = R_E2K_32_IRELATIVE;
}
ret->gdmod_zero_off = (bfd_vma) -1;
if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
_bfd_e2k_elf_link_hash_newfunc,
sizeof (struct _bfd_e2k_elf_link_hash_entry),
E2K_ELF_DATA))
{
free (ret);
return NULL;
}
/* Note that in the new scheme of dealing with PLT entries it should be enough
to set initial values for PLIST fields only. I set REFCOUNT and OFFSET as
well to take into account the case when they may turn out to be wider than
PLIST in order to make debug inspection of them look nicer. */
ret->elf.init_plt_refcount.refcount = 0;
ret->elf.init_plt_refcount.plist = NULL;
/* Note that `_bfd_elf_link_hash_table_init ()' sets initial OFFSET to
`-(bfd_vma) 1' which doesn't look compatible with the initial PLIST
value. */
ret->elf.init_plt_offset.offset = 0;
ret->elf.init_plt_offset.plist = NULL;
return &ret->elf.root;
}
/* Create .dynbss and .rela.bss sections in DYNOBJ required to support copy
relocations. Currently it's unlikely that some generic function will do this
for me. */
bfd_boolean
_bfd_e2k_elf_create_dynamic_sections (bfd *dynobj,
struct bfd_link_info *info)
{
struct _bfd_e2k_elf_link_hash_table *htab;
htab = _bfd_e2k_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
if (!_bfd_elf_create_dynamic_sections (dynobj, info))
return FALSE;
/* .got should be aligned to 2**4 in PM. */
if (ABI_PM_P (dynobj)
&& ! bfd_set_section_alignment (htab->elf.sgot, 4))
return FALSE;
htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
if (!htab->sdynbss)
abort ();
if (!bfd_link_pic (info))
{
htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
if (!htab->srelbss)
abort ();
}
return TRUE;
}
static bfd_boolean met_eir_section;
static bfd_boolean eir_in_this_bfd;
static void
search_eir (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj ATTRIBUTE_UNUSED)
{
if (strcmp (sect->name, ".pack_pure_eir") == 0
|| strcmp (sect->name, ".pack_mixed_eir") == 0)
{
met_eir_section = TRUE;
eir_in_this_bfd = TRUE;
}
}
static void
discard_unsuitable_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj ATTRIBUTE_UNUSED)
{
if ((link_mixed_eir_phase == 1 && met_eir_section)
|| (link_mixed_eir_phase == 3
&& (!(met_eir_section && !eir_in_this_bfd)
/* Don't include an archive member into an output file at the
third EIR linkage stage by analogy with Sparc. Now that we
massively use libraries without EIR when compiling in '-fwhole'
mode (e.g. libc.a) (at Sparc we've probably been having such a
situation for years) almost all archive members may be very
well collected into the third intermediate obect file, which
will cause conflicts during the final linkage, like the one
described in Bug #73608. So, let's prohibit this. */
|| abfd->my_archive)))
{
/* SEC_DEBUGGING is required to fool lang_gc_sections in ldlang.c */
sect->flags |= (SEC_EXCLUDE | SEC_DEBUGGING);
}
}
static void
search_pure_eir (bfd *abfd, asection *sec, void *no_pure_eir)
{
if (strcmp (sec->name, ".pack_pure_eir") == 0)
{
*((bfd_boolean *) no_pure_eir) = FALSE;
_bfd_error_handler ("%pB with '.pack_pure_eir' is illegal during "
"non-relocatable linkage", abfd);
bfd_set_error (bfd_error_wrong_format);
}
}
bfd_boolean
_bfd_e2k_elf_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
{
bfd_boolean ret;
/* Check for the absence of `.pack_pure_eir' sections during
non-relocatable linkage (see Bug #41413). */
if (bfd_get_format (abfd) == bfd_object && info && !bfd_link_relocatable (info))
{
bfd_boolean no_pure_eir = TRUE;
bfd_map_over_sections (abfd, search_pure_eir, &no_pure_eir);
if (! no_pure_eir)
return FALSE;
}
ret = bfd_elf_link_add_symbols (abfd, info);
/* COMMON sections are created while COMMON symbols are being
read rather than while parsing input file's section headers.
Therefore, a call to `bfd_elf_link_add_symbols ()' should
precede the following, provided that we need to be able to
discard COMMON sections. And we actually need this (see
Bug #57962). */
if ((link_mixed_eir_phase == 1
|| link_mixed_eir_phase == 3)
&& bfd_get_format (abfd) == bfd_object)
{
eir_in_this_bfd = FALSE;
bfd_map_over_sections (abfd, search_eir, NULL);
bfd_map_over_sections (abfd, discard_unsuitable_section, NULL);
}
return ret;
}
bfd_boolean
_bfd_e2k_elf_mkobject (bfd *abfd)
{
return bfd_elf_allocate_object (abfd, sizeof (struct _bfd_e2k_elf_obj_tdata),
E2K_ELF_DATA);
}
/* What's the point in this function provided that elf backend doesn't use
arelents? It turns out to be that when `elf_link_add_object_symbols ()' meets
a `.gnu.warning.SYMBOL' section it calls `_bfd_generic_link_add_one_symbol
()' which requires all this canonicalization. */
bfd_boolean
_bfd_e2k_elf_info_to_howto (bfd *abfd,
arelent *bfd_reloc,
Elf_Internal_Rela *elf_reloc)
{
unsigned int r_type;
r_type = ELF_R_TYPE (abfd, elf_reloc->r_info);
if (r_type < (sizeof (_bfd_e2k_elf_howto_table)
/ sizeof (_bfd_e2k_elf_howto_table[0])))
bfd_reloc->howto = &_bfd_e2k_elf_howto_table[r_type];
else
bfd_reloc->howto = NULL;
if (bfd_reloc->howto == NULL || bfd_reloc->howto->name == NULL)
{
_bfd_error_handler (_("%pB: unsupported relocation type %#x"),
abfd, r_type);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
return TRUE;
}
static asection *
create_magic_section (bfd *abfd, const char *magic)
{
asection *s;
bfd_byte *contents;
size_t name_size, name_size_aligned;
size_t magic_size, magic_size_aligned;
static const char name[] = "MCST";
s = bfd_make_section_anyway_with_flags (abfd, ".magic",
(SEC_LINKER_CREATED
| SEC_HAS_CONTENTS | SEC_READONLY));
if (s == NULL)
return NULL;
name_size = sizeof (name);
name_size_aligned = (name_size + 3) & 0xfffffffc;
magic_size = strlen (magic) + 1;
magic_size_aligned = (magic_size + 3) & 0xfffffffc;
s->size = 12 + name_size_aligned + magic_size_aligned;
s->contents = (bfd_byte *) bfd_zalloc (abfd, s->size);
if (s->contents == NULL)
return NULL;
contents = s->contents;
/* Follow the standard note section layout:
First write the length of the name string. */
bfd_put_32 (abfd, (bfd_vma) name_size, contents);
contents += 4;
/* Next comes the length of the "MAGIC" itself, i.e., the actual data. */
bfd_put_32 (abfd, (bfd_vma) magic_size, contents);
contents += 4;
/* Write the note NT_MAGIC type. */
bfd_put_32 (abfd, (bfd_vma) NT_MAGIC, contents);
contents += 4;
/* Write the name field. */
memcpy (contents, name, name_size);
contents += name_size_aligned;
/* Finally, write the descriptor. */
memcpy (contents, magic, magic_size);
return s;
}
static bfd_boolean
dummy_traverse (struct bfd_hash_entry *bh, void *data ATTRIBUTE_UNUSED)
{
struct _bfd_e2k_elf_link_hash_entry *eh;
eh = (struct _bfd_e2k_elf_link_hash_entry *) bh;
if (eh->relgot_cntr > 0)
{
static int here_we_are;
here_we_are++;
}
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_final_link (bfd *abfd, struct bfd_link_info *info)
{
char *magic;
asection *magic_sec = NULL;
/* There is nothing to be done here if we are going to output
a binary file when linking EIR (see Bug #59012, Comment # ). */
if (link_mixed_eir_phase == 2)
return TRUE;
/* There is no point in creating a `.magic' section in the OBFD if it has
already been borrowed from one of the IBFD's. Do we have the corresponding
output section at this stage? Fortunately, output sections have already
been assigned. */
if ((magic = getenv ("MAGIC")) != NULL
&& !bfd_get_section_by_name (abfd, ".magic"))
{
if ((magic_sec = create_magic_section (abfd, magic)) == NULL)
return FALSE;
}
if (! bfd_elf_final_link (abfd, info))
return FALSE;
bfd_hash_traverse (&info->hash->table, dummy_traverse, NULL);
if (magic_sec != NULL)
{
if (! bfd_set_section_contents (abfd, magic_sec, magic_sec->contents,
(bfd_vma) 0, magic_sec->size))
return FALSE;
}
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
Elf_Internal_Sym *sym,
const char **name ATTRIBUTE_UNUSED,
flagword *flags ATTRIBUTE_UNUSED,
asection **sec ATTRIBUTE_UNUSED,
bfd_vma *value ATTRIBUTE_UNUSED)
{
asection *ecomm;
char *dsp_common_sec_name;
if ((abfd->flags & DYNAMIC) == 0
&& bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour
&& (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
|| ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
elf_tdata (info->output_bfd)->has_gnu_osabi = TRUE;
/* When not linking EIR, special symbols related to sections containing EIR
should be ignored.
In my new external EIR linkage scheme these symbols are not employed
anymore, however this check is required in case someone links with
older libraries containing such symbols. */
if (!link_mixed_eir_phase && CONST_STRNEQ (*name, "#@EIR@#_"))
{
*name = NULL;
return TRUE;
}
/* This should be fixed somehow . . . */
switch (sym->st_shndx)
{
case SHN_DSP_COMMON_00:
dsp_common_sec_name = "DSP_COMMON00";
break;
case SHN_DSP_COMMON_01:
dsp_common_sec_name = "DSP_COMMON01";
break;
case SHN_DSP_COMMON_02:
dsp_common_sec_name = "DSP_COMMON02";
break;
case SHN_DSP_COMMON_03:
dsp_common_sec_name = "DSP_COMMON03";
break;
case SHN_DSP_COMMON_04:
dsp_common_sec_name = "DSP_COMMON04";
break;
case SHN_DSP_COMMON_05:
dsp_common_sec_name = "DSP_COMMON05";
break;
case SHN_DSP_COMMON_06:
dsp_common_sec_name = "DSP_COMMON06";
break;
case SHN_DSP_COMMON_07:
dsp_common_sec_name = "DSP_COMMON07";
break;
case SHN_DSP_COMMON_08:
dsp_common_sec_name = "DSP_COMMON08";
break;
case SHN_DSP_COMMON_09:
dsp_common_sec_name = "DSP_COMMON09";
break;
case SHN_DSP_COMMON_10:
dsp_common_sec_name = "DSP_COMMON10";
break;
case SHN_DSP_COMMON_11:
dsp_common_sec_name = "DSP_COMMON11";
break;
case SHN_DSP_COMMON_12:
dsp_common_sec_name = "DSP_COMMON12";
break;
case SHN_DSP_COMMON_13:
dsp_common_sec_name = "DSP_COMMON13";
break;
case SHN_DSP_COMMON_14:
dsp_common_sec_name = "DSP_COMMON14";
break;
case SHN_DSP_COMMON_15:
dsp_common_sec_name = "DSP_COMMON15";
break;
default:
return TRUE;
}
/* DSP_COMMONx section instructs LD to put related DSP common symbols to the
corresponding `.dsp_bssX' output section.
Ordinary (i.e. non-dsp) COMMON symbols are treated in the same way in
`_bfd_generic_link_add_one_symbol ()'. We get invoked from
`elf_link_add_object_symbols ()' before the aforementioned function is
called. We should not only create the `DSP_COMMONx' section but also
adjust `section' and `value' parameters which are later passed to
`_bfd_generic_link_add_one_symbol ()'. */
ecomm = bfd_get_section_by_name (abfd, dsp_common_sec_name);
if (ecomm == NULL)
{
ecomm = bfd_make_section_with_flags (abfd,
dsp_common_sec_name,
(SEC_ALLOC
| SEC_IS_COMMON
| SEC_LINKER_CREATED));
if (ecomm == NULL)
return FALSE;
}
*sec = ecomm;
*value = sym->st_size;
return TRUE;
}
/* This function is borrowed from `elfxx-sparc.c'. Why isn't the common
functionality implemented in `elf-ifunc.c' used there? Probably because
the latter deals with `.got.plt' which has no role at Sparc. Find out
if we can use this common functionality instead of stupidly duplicating
Sparc implementation. */
static bfd_boolean
create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab = elf_hash_table (info);
flagword flags, pltflags;
asection *s;
if (htab->irelifunc != NULL || htab->iplt != NULL)
return TRUE;
flags = bed->dynamic_sec_flags;
pltflags = flags | SEC_ALLOC | SEC_CODE | SEC_LOAD | SEC_READONLY;
s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
if (s == NULL
|| ! bfd_set_section_alignment (s, bed->plt_alignment))
return FALSE;
htab->iplt = s;
s = bfd_make_section_with_flags (abfd, ".rela.iplt",
flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->irelplt = s;
return TRUE;
}
void
_bfd_e2k_elf_copy_indirect_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *dir,
struct elf_link_hash_entry *ind)
{
struct _bfd_e2k_elf_link_hash_entry *edir, *eind;
struct elf_link_hash_table *htab;
union gotplt_union saved;
edir = (struct _bfd_e2k_elf_link_hash_entry *) dir;
eind = (struct _bfd_e2k_elf_link_hash_entry *) ind;
/* Once I started discarding dynamic relocs for non-dynamic symbols (see
allocate_dynrelocs ()) it became clear how important it is to copy
its reloc to its direct (versioned, i.e. having `@GLIBC_2. . .' in its
name) dynamic counterpart. Without that no space used to be allocated
for dynamic relocs against the direct symbol which lead to assertion
failure while swapping them out into the output file. */
if (eind->dyn_relocs != NULL)
{
if (edir->dyn_relocs != NULL)
{
struct e2k_elf_dyn_relocs **pp;
struct e2k_elf_dyn_relocs *p;
/* Add reloc counts against the indirect sym to the direct sym
list. Merge any entries against the same section. */
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
{
struct e2k_elf_dyn_relocs *q;
for (q = edir->dyn_relocs; q != NULL; q = q->next)
if (q->sec == p->sec)
{
q->pc_count += p->pc_count;
q->count += p->count;
*pp = p->next;
break;
}
if (q == NULL)
pp = &p->next;
}
*pp = edir->dyn_relocs;
}
edir->dyn_relocs = eind->dyn_relocs;
eind->dyn_relocs = NULL;
}
if (ind->root.type == bfd_link_hash_indirect
/* This function may be called several times with the same EDIR (e.g.
"errno@@GLIBC_PRIVATE") but different EINDs (e.g. "errno" and
"errno@GLIBC_PRIVATE"). Whereas the first EIND has `TLS_TYPE ==
GOT_TLS_IE', the second one turns out to be `GOT_UNKNOWN'. The
previously employed condition `dir->got.refcount <= 0' adopted from
sparc backend saved us from re-setting `EIND->TLS_TYPE' to
`GOT_UNKNOWN' provided that the first EIND had been really accessed
via GOT (i.e. had `GOT.REFCOUNT > 0'). Now that IE relocations are
tracked via a separate IE.REFCOUNT, this is not going to work. Try
to verify explicitly that EIND is not GOT_UNKNOWN instead. */
&& eind->tls_type != GOT_UNKNOWN)
{
edir->tls_type |= eind->tls_type;
/* Probably this may happen somehow if different EINDs having incompatible
TLS types are merged to the same EDIR. An error message should be used
then rather than ASSERT. */
BFD_ASSERT ((edir->tls_type & GOT_NORMAL) == 0
|| (edir->tls_type & (GOT_TLS_GDMOD | GOT_TLS_GDREL
| GOT_TLS_IE)) == 0);
/* There is analogous code in `_bfd_elf_link_hash_copy_indirect ()'
adjusting DIR->GOT.REFCOUNT. */
if ((eind->tls_type & GOT_TLS_GDMOD) != 0
&& eind->gdmod.refcount > 0)
{
edir->gdmod.refcount += eind->gdmod.refcount;
eind->gdmod.refcount = 0;
}
if ((eind->tls_type & GOT_TLS_IE) != 0
&& eind->ie.refcount > 0)
{
edir->ie.refcount += eind->ie.refcount;
eind->ie.refcount = 0;
}
eind->tls_type = GOT_UNKNOWN;
}
htab = elf_hash_table (info);
if (ind->plt.plist != NULL)
{
copy_plt_refcount (dir, ind);
ind->plt = htab->init_plt_refcount;
}
if (eind->relgot_cntr > 0)
{
edir->relgot_cntr += eind->relgot_cntr;
eind->relgot_cntr = 0;
}
/* Prevent `_bfd_elf_link_hash_copy_indirect ()' from manipulating `{dir,ind}
->plt.refcount'. It's obviously wrong now that these fields contain junk
while PLIST is actually used. I've already done this job a few lines above.
I wonder why they don't care about this in elfxx-mips.c and what they get
in the end if `ind->plt.refcount > htab->init_plt_refcount.refcount' turns
out to be TRUE . . .*/
saved = ind->plt;
ind->plt = htab->init_plt_refcount;
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
ind->plt = saved;
}
bfd_boolean
_bfd_e2k_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
asection *sec, const Elf_Internal_Rela *relocs)
{
struct _bfd_e2k_elf_link_hash_table *htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
if (bfd_link_relocatable (info))
return TRUE;
htab = _bfd_e2k_elf_hash_table (info);
if (htab == NULL)
return FALSE;
BFD_ASSERT (is_e2k_elf (abfd));
if (!create_ifunc_sections (htab->elf.dynobj, info))
return FALSE;
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
rel = relocs;
rel_end = relocs + sec->reloc_count;
for (; rel < rel_end; rel++)
{
unsigned int r_type;
unsigned int r_symndx;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *isym;
bfd_boolean size_reloc = FALSE;
r_type = ELF_R_TYPE (abfd, rel->r_info);
r_symndx = ELF_R_SYM (abfd, rel->r_info);
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
{
_bfd_error_handler (_("%pB: bad symbol index: %d"),
abfd, r_symndx);
return FALSE;
}
isym = NULL;
if (r_symndx < symtab_hdr->sh_info)
{
/* This is a local symbol. */
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
h = NULL;
}
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
/* This fragment is borrowed from `elfxx-sparc.c'. Forcing
`h->ref_regular' to be equal to one should be enough to satisfy the
outermost condition in `allocate_dynrelocs ()' and reserve space in
PLT. What's the point in setting `PLT.REFCOUNT'? Anyway, I don't
understand for sure what's the point in setting `REF_REGULAR'. Probably
this indicates that the symbol has been REFERED to, no matter that from
the same regular object where it's defined (for IFUNC only). */
if (h && h->type == STT_GNU_IFUNC)
{
if (h->def_regular)
{
h->ref_regular = 1;
if (! increase_plt_refcount (abfd, h))
return FALSE;
}
}
/* Fix the build of ld-plugin/pr15323 this way. */
if (h != NULL)
h->root.non_ir_ref_regular = 1;
switch (r_type)
{
case R_E2K_GOT:
case R_E2K_AP_GOT:
case R_E2K_PL_GOT:
case R_E2K_TLS_GDMOD:
case R_E2K_TLS_GDREL:
case R_E2K_TLS_IE:
/* This symbol requires a GOT entry. */
{
/* FIXME: gcc when compiling with `-O2' cannot determine that
TLS_TYPE is ALWAYS initialized below in fact . . . */
int tls_type = GOT_NORMAL;
int old_tls_type;
switch (r_type)
{
case R_E2K_GOT:
case R_E2K_AP_GOT:
case R_E2K_PL_GOT:
tls_type = GOT_NORMAL;
break;
case R_E2K_TLS_GDMOD:
tls_type = GOT_TLS_GDMOD;
break;
case R_E2K_TLS_GDREL:
tls_type = GOT_TLS_GDREL;
break;
case R_E2K_TLS_IE:
tls_type = GOT_TLS_IE;
break;
}
if (h != NULL)
{
if (r_type == R_E2K_TLS_IE)
_bfd_e2k_elf_hash_entry (h)->ie.refcount += 1;
else if (r_type == R_E2K_TLS_GDMOD)
_bfd_e2k_elf_hash_entry (h)->gdmod.refcount += 1;
else
{
char pm_got_type = 0;
struct _bfd_e2k_elf_link_hash_entry *eh
= _bfd_e2k_elf_hash_entry (h);
if (r_type == R_E2K_AP_GOT)
pm_got_type = 1;
else if (r_type == R_E2K_PL_GOT)
pm_got_type = 2;
if (pm_got_type)
{
if (eh->pm_got_type == 0)
eh->pm_got_type = pm_got_type;
else if (eh->pm_got_type != pm_got_type)
_bfd_error_handler
(_("a symbol is accessed both via "
"`R_E2K_{AP,PL}_GOT'"));
}
h->got.refcount += 1;
}
old_tls_type = _bfd_e2k_elf_hash_entry (h)->tls_type;
}
else
{
bfd_signed_vma *local_got_refcounts, *local_ie_refcounts;
local_got_refcounts = elf_local_got_refcounts (abfd);
if (local_got_refcounts == NULL)
{
bfd_size_type size;
size = symtab_hdr->sh_info;
size *= (2 * sizeof (bfd_signed_vma) + sizeof (char)
+ sizeof (unsigned char));
local_got_refcounts = (bfd_signed_vma *)
bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL)
return FALSE;
elf_local_got_refcounts (abfd) = local_got_refcounts;
_bfd_e2k_elf_local_ie_refcounts (abfd)
= local_got_refcounts + symtab_hdr->sh_info;
_bfd_e2k_elf_local_got_tls_type (abfd)
= (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
_bfd_e2k_elf_local_relgot_cntr (abfd)
= ((char *) _bfd_e2k_elf_local_got_tls_type (abfd)
+ symtab_hdr->sh_info);
}
local_ie_refcounts = _bfd_e2k_elf_local_ie_refcounts (abfd);
if (r_type == R_E2K_TLS_IE)
local_ie_refcounts[r_symndx] += 1;
else
local_got_refcounts[r_symndx] += 1;
old_tls_type = _bfd_e2k_elf_local_got_tls_type (abfd) [r_symndx];
}
if (old_tls_type != GOT_UNKNOWN
&& (tls_type & GOT_NORMAL) != (old_tls_type & GOT_NORMAL))
{
_bfd_error_handler
(_("%pB: `%s' accessed both as normal and thread local symbol"),
abfd, h ? h->root.root.string : "<local>");
return FALSE;
}
if (h != NULL)
_bfd_e2k_elf_hash_entry (h)->tls_type |= tls_type;
else
_bfd_e2k_elf_local_got_tls_type (abfd) [r_symndx] |= tls_type;
}
/* Fall through */
case R_E2K_GOTOFF:
case R_E2K_64_GOTOFF:
case R_E2K_64_GOTOFF_LIT:
create_got:
/* .got should be created here if create_dynamic_sections () isn't
called during the link, but there are relocations requiring it.
FIXME: consider moving this code to setup_gnu_properties () by
analogy with x86. */
if (htab->elf.sgot == NULL)
{
if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
return FALSE;
/* .got should be aligned to 2**4 in PM. */
if (ABI_PM_P (htab->elf.dynobj)
&& ! bfd_set_section_alignment (htab->elf.sgot, 4))
return FALSE;
}
break;
case R_E2K_GOTPLT:
if (h != NULL)
{
if (! increase_secondary_plt_refcount (abfd, h))
return FALSE;
/* This ensures that PLT related info won't be discarded in
`_bfd_elf_adjust_dynamic_symbol ()' if this call is resolved
locally. Without it I'll be unable to make a decision that this
symbol requires a .got entry in `allocate_dynrelocs ()' and may
very well get SIGSEGV later in relocate_section. */
h->needs_plt = 1;
}
goto create_got;
case R_E2K_DISP:
/* Sparc has `!bfd_link_pic (info)' in the condition below, while i386
uses `bfd_link_executable (info)'. Why shouldn't we increase PLT refcount
when linking a shared library??? Because both sparc and i386 have
a special reloc (e.g., R_386_PLT32) which instructs LD to jump via
a PLT entry in fPIC mode. */
if (h != NULL)
{
/* Ensure that `_bfd_e2k_elf_size_dynamic_sections' gets called
so that NEEDS_PLT and PLT.REFCOUNT are reset appropriately
in case a PLT entry isn't required for this symbol (see
`allocate_dynrelocs ()'. */
h->needs_plt = 1;
if (! increase_plt_refcount (abfd, h))
return FALSE;
}
break;
case R_E2K_32_SIZE:
case R_E2K_64_SIZE:
size_reloc = TRUE;
goto do_size;
case R_E2K_64_ABS_LIT:
case R_E2K_32_ABS:
case R_E2K_64_ABS:
case R_E2K_AP:
case R_E2K_PL:
if (h != NULL && !bfd_link_pic (info))
{
/* Set this flag for now until adjust_dynamic_symbol where it may
be cleared if there are no relocations related to this symbol
against readonly sections. Once again, the name of this flag
seems to be a misnomer. */
h->non_got_ref = 1;
/* h->non_got_ref is likely to be never cleared in adjust_dynamic
_symbol for functions, even if all `R_E2K_XX_ABS{,LIT}'
relocations against it are applied to RW-sections. Therefore,
no corresponding dynamic relocations are going to be generated
in relocate_section now that we set this flag. They should be
resolved to a primary PLT entry instead. */
if (! increase_plt_refcount (abfd, h))
return FALSE;
h->pointer_equality_needed = 1;
}
do_size:
if ((ABI_PM_P (abfd)
/* Relocations of these types should be always tracked in PM
even when linking a static executable. */
&& (r_type == R_E2K_AP || r_type == R_E2K_PL))
|| (bfd_link_pic (info)
&& (sec->flags & SEC_ALLOC) != 0)
/* Hopefully the following is going to help when we are dealing
with these relocations in dynamic executables without creating
copy relocs. */
|| (!bfd_link_pic (info)
&& (sec->flags & SEC_ALLOC) != 0
&& h != NULL
&& !h->def_regular))
{
struct e2k_elf_dyn_relocs *p;
struct e2k_elf_dyn_relocs **head;
/* Create a dynamic reloc section associated with the section
being considered. */
if (sreloc == NULL)
{
sreloc = _bfd_elf_make_dynamic_reloc_section
(sec, htab->elf.dynobj, htab->word_align_power,
abfd, TRUE);
if (sreloc == NULL)
return FALSE;
}
/* If this is a global symbol, we count the number of
relocations we need for this symbol. */
if (h != NULL)
head = &((struct _bfd_e2k_elf_link_hash_entry *) h)->dyn_relocs;
else
{
void **vpp;
/* S is a section which this local symbol is defined in. */
asection *s;
BFD_ASSERT (isym != NULL);
s = bfd_section_from_elf_index (abfd, isym->st_shndx);
/* Other backends set S to SEC in case the former turns out
to be NULL. I cannot imagine how this may happen and what
is the point in `s = sec'. These sections have different
relation to the symbol after all . . . */
BFD_ASSERT (s != NULL);
vpp = &elf_section_data (s)->local_dynrel;
head = (struct e2k_elf_dyn_relocs **) vpp;
}
p = *head;
if (p == NULL || p->sec != sec)
{
bfd_size_type amt = sizeof (*p);
p = ((struct e2k_elf_dyn_relocs *)
bfd_alloc (htab->elf.dynobj, amt));
if (p == NULL)
return FALSE;
p->next = *head;
*head = p;
p->sec = sec;
p->count = 0;
p->pc_count = 0;
p->type = 0;
}
p->count += 1;
/* Count size relocations as PC-relative relocations so as to make
it possible to discard them if the symbol is referenced
locally within a shared library. Funnily enough, PC-relative
relocations are not actually counted in this backend yet. */
if (size_reloc || (r_type == R_E2K_32_ABS && ABI_PM_P (abfd)))
p->pc_count += 1;
if (ABI_PM_P (abfd) && (r_type == R_E2K_AP || r_type == R_E2K_PL))
{
int type = (r_type == R_E2K_AP ? 1 : 2);
if (p->type == 0)
p->type = type;
else if (p->type != type)
_bfd_error_handler
(_("a symbol is accessed both via `R_E2K_{AP,PL}'"));
}
}
break;
}
}
return TRUE;
}
/* Update the got entry reference counts for the section being removed. */
bfd_boolean
_bfd_e2k_elf_gc_sweep_hook (bfd *abfd,
struct bfd_link_info *info,
asection *sec,
const Elf_Internal_Rela *relocs)
{
struct _bfd_e2k_elf_link_hash_table *htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_signed_vma *local_got_refcounts;
bfd_signed_vma *local_ie_refcounts;
const Elf_Internal_Rela *rel, *relend;
if (bfd_link_relocatable (info))
return TRUE;
htab = _bfd_e2k_elf_hash_table (info);
if (htab == NULL)
return FALSE;
elf_section_data (sec)->local_dynrel = NULL;
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
local_ie_refcounts = _bfd_e2k_elf_local_ie_refcounts (abfd);
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
{
unsigned long r_symndx;
unsigned int r_type;
struct elf_link_hash_entry *h = NULL;
r_symndx = ELF_R_SYM (abfd, rel->r_info);
if (r_symndx >= symtab_hdr->sh_info)
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
else
{
/* At i386 they handle the case of local STT_GNU_IFUNC symbol here
and obtain a hash entry for it! This is rather unusual. */
}
if (h)
{
struct _bfd_e2k_elf_link_hash_entry *eh;
struct e2k_elf_dyn_relocs **pp;
struct e2k_elf_dyn_relocs *p;
/* As far as I understand, the underlying code lets us get rid of
all dynamic relocations against H, applied to the section to be
removed. It doesn't matter whether they have any relation to the
currently considered REL or not. */
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
if (p->sec == sec)
{
/* Everything must go for SEC. */
*pp = p->next;
break;
}
}
else
{
Elf_Internal_Sym *isym;
asection *s;
struct e2k_elf_dyn_relocs **pp;
struct e2k_elf_dyn_relocs *p;
/* Take care of discarding dynamic relocations applied to a section
being garbage collected against local symbols (defined in other
sections). The failure to do so led to an assertion failure in Bug
#82835 due to redundant space in '.rela.data'. Interestingly
enough, I've not noticed analogous code for x86 . . . */
isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx);
/* S is the section the related local symbol comes from. */
s = bfd_section_from_elf_index (abfd, isym->st_shndx);
pp = (struct e2k_elf_dyn_relocs **) &elf_section_data (s)->local_dynrel;
for (; (p = *pp) != NULL; pp = &p->next)
if (p->sec == sec)
{
/* Everything must go for SEC. */
*pp = p->next;
break;
}
}
r_type = ELF32_R_TYPE (rel->r_info);
switch (r_type)
{
case R_E2K_GOT:
case R_E2K_AP_GOT:
case R_E2K_PL_GOT:
case R_E2K_TLS_GDREL:
if (h != NULL)
{
if (h->got.refcount > 0)
h->got.refcount -= 1;
}
else if (local_got_refcounts != NULL)
{
if (local_got_refcounts[r_symndx] > 0)
local_got_refcounts[r_symndx] -= 1;
}
break;
case R_E2K_GOTPLT:
BFD_ASSERT (h != NULL);
decrease_secondary_plt_refcount (h);
break;
case R_E2K_TLS_GDMOD:
/* Note that there's no point in tracing gdmod.refcount for local TLS
symbols. Thererefore, there is nothing to be decreased here in
this case. */
if (h != NULL)
{
struct _bfd_e2k_elf_link_hash_entry *eh;
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
if (eh->gdmod.refcount > 0)
eh->gdmod.refcount -= 1;
}
/* Fall through */
case R_E2K_TLS_IE:
if (h != NULL)
{
struct _bfd_e2k_elf_link_hash_entry *eh;
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
if (eh->ie.refcount > 0)
eh->ie.refcount -= 1;
}
else if (local_ie_refcounts != NULL)
{
if (local_ie_refcounts[r_symndx] > 0)
local_ie_refcounts[r_symndx] -= 1;
}
break;
/* Currently I don't tackle PLT refcounts and the case of ifuncs
because I've not got a clear understanding of these issues yet. */
}
}
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *h)
{
struct _bfd_e2k_elf_link_hash_table *htab;
struct e2k_elf_dyn_relocs *p;
struct _bfd_e2k_elf_link_hash_entry *eh;
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
if (h->type == STT_FUNC
|| h->type == STT_GNU_IFUNC
|| h->needs_plt)
{
if (SYMBOL_CALLS_LOCAL (info, h)
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak))
{
/* This case can occur if there is no point in building a PLT entry
for this symbol. For example, when making a function call within
an executable (either PIE or not). */
if (h->plt.plist)
{
if (h->plt.plist->primary.refcount == 0)
{
h->plt.plist->primary.idx = (bfd_vma) -1;
h->needs_plt = 0;
}
if (h->plt.plist->secondary.refcount == 0)
h->plt.plist->secondary.idx = (bfd_vma) -1;
}
}
return TRUE;
}
else
{
/* It's possible that we incorrectly decided a .plt reloc was needed for
a `R_E2K_XX_ABS{,_LIT}' to a non-function symbol in check_relocs. They
say that we can't decide accurately between function and non-function
symbols in check_relocs, so fix it now. */
set_plt_idx (h, NULL);
set_secondary_plt_idx (h, NULL);
}
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
if (h->is_weakalias)
{
struct elf_link_hash_entry *def = weakdef (h);
BFD_ASSERT (def->root.type == bfd_link_hash_defined);
h->root.u.def.section = def->root.u.def.section;
h->root.u.def.value = def->root.u.def.value;
h->non_got_ref = def->non_got_ref;
return TRUE;
}
/* This is a reference to a symbol defined by a dynamic object which
is not a function. */
/* If we are creating a shared library, we must presume that the
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
if (bfd_link_pic (info))
return TRUE;
/* If there are no references to this symbol that do not use the
GOT, we don't need to generate a copy reloc. */
if (!h->non_got_ref)
return TRUE;
/* If -z nocopyreloc was given, we won't generate them either. */
if (info->nocopyreloc)
{
h->non_got_ref = 0;
return TRUE;
}
htab = _bfd_e2k_elf_hash_table (info);
if (htab == NULL)
return FALSE;
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *s;
s = p->sec->output_section;
if (s != NULL && (s->flags & SEC_READONLY) != 0)
break;
}
/* If the underlying condition fulfills, a copy relocation won't be
created. */
if (p == NULL)
{
/* It turns out that this flag might be cleared in case there are actually
non-GOT relocations only in rw sections, mightn't it? Isn't it a
misnomer?
Later in `relocate_section ()' its zero value along with other
conditions instructs LD to create dynamic relocations against these
sections. */
h->non_got_ref = 0;
return TRUE;
}
/* I guess that if either of the two underlying conditions fails there is no
point in creating a copy relocation for the symbol. */
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
htab->srelbss->size += htab->bytes_per_rela;
h->needs_copy = 1;
}
return _bfd_elf_adjust_dynamic_copy (info, h, htab->sdynbss);
}
static void
reserve_space_for_selfinit (struct _bfd_e2k_elf_link_hash_table *htab,
size_t size_of_item,
size_t items,
const char *name ATTRIBUTE_UNUSED)
{
htab->selfinit->size += items * size_of_item;
// printf ("%s: %ld %s slots\n", name, items,
// size_of_item == sizeof (selfinit_ap) ? "AP" : "PL");
// fflush (NULL);
}
static bfd_boolean
allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info;
struct _bfd_e2k_elf_link_hash_table *htab;
struct _bfd_e2k_elf_link_hash_entry *eh;
struct e2k_elf_dyn_relocs *p;
int i;
info = (struct bfd_link_info *) inf;
htab = _bfd_e2k_elf_hash_table (info);
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
if ((htab->elf.dynamic_sections_created
&& positive_plt_refcount (h))
|| (h->type == STT_GNU_IFUNC
&& h->def_regular
&& h->ref_regular))
{
if (! SYMBOL_CALLS_LOCAL (info, h)
// WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)
|| (h->type == STT_GNU_IFUNC
&& h->def_regular))
{
asection *s;
s = htab->elf.splt;
if (s == NULL)
s = htab->elf.iplt;
if (s->size == 0)
{
/* FIXME: this way I setup hash table members related to PLT
trampolines which coudn't be set in `_bfd_e2k_elf_link_hash_
table_create ()' because of the unavailability of INFO. */
_bfd_e2k_elf_link_hash_table_finalize (info);
s->size = htab->plt_got_header_size;
}
if (positive_plt_refcount (h))
{
set_plt_idx (h, htab);
/* Make room for this primary PLT entry. */
s->size += htab->plt_got_primary_entry_size;
}
/* 1. Other backends also have a `! bfd_link_pic (info)' condition which I
don't quite understand yet.
2. What if this symbol is defined in a regular object? Should we
substitute it with its PLT entry then?
3. Keep in mind that other architectures have a special
fPIC-specific variant of R_E2K_DISP, which lets them calculate an
offset to the corresponding PLT entry in `relocate_section ()' in
addition to the underlying hack. */
if (!bfd_link_pic (info)
&& !h->def_regular)
{
h->root.u.def.section = s;
/* Primary offset in .plt can't be determined reliably now that
primary entries are allocated after secondary ones because not
all symbols have been assigned their secondary PLT offsets so
far. Mark this symbol as requiring its value to be set to its
primary PLT offset once it can be determined. */
eh->finalize_plt_offset = 1;
}
}
else
{
/* Provided that a primary PLT entry is not required to call this
function it shouldn't contribute into the corresponding secondary
PLT entry refcount. Note, that the secondary entry may still be
needed on its own because of the code making use of so-called
inlined PLT entries (i.e. `@GOTPLT' relocations). */
if (positive_plt_refcount (h))
discard_plt_refcount (h);
set_plt_idx (h, NULL);
h->needs_plt = 0;
}
}
else
{
if (positive_plt_refcount (h))
discard_plt_refcount (h);
set_plt_idx (h, NULL);
}
/* We may need to allocate a few other entries under the following
circumstances:
R_E2K_DISP can't be resolved at linktime and an accompanying secondary PLT
entry is required along with entries in `.got.plt' and `.rela.plt'.
The very same entries may be required because R_E2K_GOTPLT can't be
resolved at linktime on its own.
*/
if (positive_secondary_plt_refcount (h))
{
bfd_boolean dyn = htab->elf.dynamic_sections_created;
/* Ensure that an undefined weak symbol becomes dynamic (it may remain
non-dynamic when linking an executable in fact) so that `WILL_CALL_
FINISH_DYNAMIC_SYMBOL ()' below could return true for it. It's really
necessary since undefined weak symbols aren't considered to be resolved
locally within an executable.
Currently this is the only case I'm aware of when a symbol should be
explicitly recorded as dynamic. At the same time I'd like to avoid the
trouble of recording all symbols accessed this way as dynamic (consider
the case when a PIC object is linked into an executable). Therefore,
unlike other backends I explicitly check for the type of a symbol. */
if (dyn
&& h->dynindx == -1
&& !h->forced_local
&& h->root.type == bfd_link_hash_undefweak)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
/* If the address of this function is accessed via GOT, we don't need
any other entries. */
if (h->got.refcount > 0 && !h->pointer_equality_needed)
set_secondary_plt_idx (h, NULL);
else if ((SYMBOL_CALLS_LOCAL (info, h)
&& h->type != STT_GNU_IFUNC)
/* How can this rather special case be treated in a more regular
way? */
|| (!dyn && h->root.type == bfd_link_hash_undefweak))
{
/* This function is called locally within an executable via a load
from GOT. Therefore, it requires a '.got' entry the value of which
should be known at link-time. */
set_secondary_plt_idx (h, NULL);
BFD_ASSERT (eh->tls_type == GOT_UNKNOWN
|| eh->tls_type == GOT_NORMAL);
eh->tls_type = GOT_NORMAL;
h->got.refcount = 1;
}
else if (dyn
|| h->type == STT_GNU_IFUNC)
#if 0
if (bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
#endif /* 0 */
{
/* The function will be resolved at run-time. Allocate the secondary
PLT entry and the corresponding entries in '.got.plt' and '.rela
.got.plt'. */
asection *srela;
asection *s = htab->elf.splt;
if (s != NULL)
srela = htab->elf.srelplt;
else
{
s = htab->elf.iplt;
srela = htab->elf.irelplt;
}
if (s->size == 0)
{
/* FIXME: this way I setup hash table members related to PLT
trampolines which coudn't be set in `_bfd_e2k_elf_link_hash_
table_create ()' because of the unavailability of INFO. */
_bfd_e2k_elf_link_hash_table_finalize (info);
s->size = htab->plt_got_header_size;
}
set_secondary_plt_idx (h, htab);
s->size += htab->plt_got_secondary_entry_size;
eh->gotplt_offset = htab->elf.sgotplt->size;
htab->elf.sgotplt->size
+= ABI_PM_P (htab->elf.dynobj) ? 16 : htab->bytes_per_word;
srela->size += htab->bytes_per_rela;
/* In Protected Mode one needs to reserve space for code to lazily
"self-initialize" the secondary PLT entry. The code will be emitted
in `build_secondary_plt_entry ()'. */
if (ABI_PM_P (htab->elf.dynobj))
reserve_space_for_selfinit (htab, sizeof (selfinit_pl), 1,
h->root.root.string);
}
/* We may find ourselves here, for example, if the symbol is not defined
anywhere. What should be done then? */
}
else
set_secondary_plt_idx (h, NULL);
for (i = 0; i < 4; i++)
{
static const int types[] = {GOT_NORMAL, GOT_TLS_GDMOD, GOT_TLS_GDREL,
GOT_TLS_IE};
union gotplt_union *pgot;
if ((eh->tls_type & types[i]) == 0)
continue;
if (types[i] == GOT_TLS_GDMOD)
pgot = &eh->gdmod;
else if (types[i] == GOT_TLS_IE)
pgot = &eh->ie;
else
pgot = &h->got;
if (pgot->refcount > 0)
{
bfd_boolean dyn;
dyn = htab->elf.dynamic_sections_created;
/* What a hack it is! Don't forget to find out why undefined weak
symbols are not marked as dynamic without it. This awful hack
is present in almost all backends.
What's the point in having dynamic symbols if we are doing a static
link though? */
if (dyn
&& h->root.type == bfd_link_hash_undefweak
&& h->dynindx == -1
&& !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
pgot->offset = htab->elf.sgot->size;
htab->elf.sgot->size
+= ABI_PM_P (htab->elf.dynobj) ? 16 : htab->bytes_per_word;
if ((types[i] == GOT_NORMAL || types[i] == GOT_TLS_IE)
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& ((WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
/* This way I stupidly ensure that no space is allocated in
.rela.got for a meaningless relative dynamic relocation
against a locally resolved symbol in PM shared(?)
OBFD. */
&& ! (ABI_PM_P (htab->elf.dynobj)
/* In a PM shared library runtime relocation can be
avoided for a locally symbol only via GOT_NORMAL,
not via GOT_TLS_IE, of course. The latter case is
quite analogous to ordinary modes since the offset
of the symbol in the static TLS block is unknown at
link-time whichever mode the library is intended
for. */
&& types[i] == GOT_NORMAL
&& SYMBOL_REFERENCES_LOCAL (info, h)))
|| (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h)
&& ! ABI_PM_P (htab->elf.dynobj))))
{
htab->elf.srelgot->size += htab->bytes_per_rela;
eh->relgot_cntr += 1;
}
else if (types[i] == GOT_TLS_GDMOD || types[i] == GOT_TLS_GDREL)
{
if (h->dynindx != -1)
{
htab->elf.srelgot->size += htab->bytes_per_rela;
eh->relgot_cntr += 1;
}
else if (types[i] == GOT_TLS_GDMOD)
{
if (htab->gdmod_zero_off == (bfd_vma) -1)
{
htab->gdmod_zero_off = htab->elf.sgot->size;
htab->elf.sgot->size
+= (ABI_PM_P (htab->elf.dynobj)
? 16 : htab->bytes_per_word);
if (bfd_link_pic (info))
htab->elf.srelgot->size += htab->bytes_per_rela;
}
}
}
else if (ABI_PM_P (htab->elf.dynobj))
{
if (eh->pm_got_type == 1)
reserve_space_for_selfinit (htab, sizeof (selfinit_ap), 1,
h->root.root.string);
else if (eh->pm_got_type == 2)
reserve_space_for_selfinit (htab, sizeof (selfinit_pl), 1,
h->root.root.string);
}
}
else
pgot->offset = -1;
}
if ((eh->tls_type & (GOT_NORMAL | GOT_TLS_GDREL)) == 0)
h->got.offset = (bfd_vma) -1;
if ((eh->tls_type & GOT_TLS_IE) == 0)
eh->ie.offset = (bfd_vma) -1;
if (eh->dyn_relocs == NULL)
return TRUE;
/* See if we can discard the previously allocated dynamic relocs. */
if (bfd_link_pic (info))
{
/* Ensure that place isn't reserved for excessive dynamic SIZE relocations
against locally referenced symbols in a shared library. Note that they
aren't created in this case as well as PC-relative relocations. This
doesn't relate to ABS relocations, of course. */
if (SYMBOL_CALLS_LOCAL (info, h))
{
struct e2k_elf_dyn_relocs **pp;
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
{
p->count -= p->pc_count;
p->pc_count = 0;
if (p->count == 0)
*pp = p->next;
else
pp = &p->next;
}
}
/* Discard relocs on undefined weak syms with non-default visibility. */
if (eh->dyn_relocs != NULL
&& h->root.type == bfd_link_hash_undefweak)
{
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
eh->dyn_relocs = NULL;
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
else if (h->dynindx == -1
&& !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
}
/* There's no point in dynamic relocations against symbols with hidden
visibility in PM shared libraries. Note that symbols with other non-
default visibilities nonetheless require "absolute" relocations to
tune to the related PLT entry or the copy in the main executable for
comparison of pointers between the main executable and shared library
to work properly. */
if (ABI_PM_P (htab->elf.dynobj)
&& (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
|| SYMBOL_REFERENCES_LOCAL (info, h)
|| h->forced_local)
&& eh->dyn_relocs != NULL)
goto discard_dyn_relocs;
}
else
{
/* For the non-shared case, discard space for relocs against symbols
which turn out to need copy relocs or are not dynamic.
The beginning of this comment has been borrowed from `elf32-i386.c'.
In fact below we also get rid of relocs against dynamic symbols unless
they are defined by a shared library taking part in the link. */
if (!h->non_got_ref
&& ((h->def_dynamic
&& !h->def_regular)
|| (htab->elf.dynamic_sections_created
&& (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_undefined))))
{
/* Here should be a machinery for making symbol dynamic in case it
hasn't been made before, see `elf32-i386.c'. By the way, they say
that undefined weak symbols `won't yet be marked as dynamic'.
Let's skip it for now and implement when we have an appropriate
test to understand this in detail . . . */
if (h->dynindx != -1)
goto keep;
}
discard_dyn_relocs:
if (ABI_PM_P (htab->elf.dynobj))
{
for (p = eh->dyn_relocs; p != NULL; p = p->next)
reserve_space_for_selfinit (htab,
(p->type == 1
? sizeof (selfinit_ap)
: sizeof (selfinit_pl)),
p->count - p->pc_count,
h->root.root.string);
}
eh->dyn_relocs = NULL;
keep: ;
}
/* Allocate space for various `.rela. . . ' dynamic relocation sections. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
sreloc->size += p->count * htab->bytes_per_rela;
}
return TRUE;
}
static bfd_boolean
finalize_plt_offsets (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
struct _bfd_e2k_elf_link_hash_table *htab
= _bfd_e2k_elf_hash_table (info);
struct _bfd_e2k_elf_link_hash_entry *eh
= (struct _bfd_e2k_elf_link_hash_entry *) h;
/* In Protected Mode we need to make PL accessible by ld.so if this is either
a dynamic function defined in OBFD or its PLT entry should be visible from
the outside for the sake of pointer comparison between PIC and non-PIC
code. */
if (ABI_PM_P (htab->elf.dynobj)
&& ((h->def_regular && h->type == STT_FUNC && h->dynindx != -1)
|| (h->pointer_equality_needed && eh->finalize_plt_offset)))
{
struct export_pl_list *next = htab->export_pl_list;
htab->export_pl->size += 16;
reserve_space_for_selfinit (htab, sizeof (selfinit_pl), 1,
h->root.root.string);
htab->export_pl_list
= ((struct export_pl_list *) bfd_alloc
(htab->elf.dynobj, sizeof (struct export_pl_list)));
htab->export_pl_list->next = next;
htab->export_pl_list->h = h;
}
if (eh->finalize_plt_offset)
{
h->root.u.def.value = plt_offset (h, htab);
eh->finalize_plt_offset = 0;
}
return TRUE;
}
/* Find any dynamic relocs that apply to read-only sections. */
static bfd_boolean
readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
{
struct _bfd_e2k_elf_link_hash_entry *eh;
struct e2k_elf_dyn_relocs *p;
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *s = p->sec->output_section;
if (s != NULL && (s->flags & SEC_READONLY) != 0)
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
info->flags |= DF_TEXTREL;
if (bfd_link_textrel_check (info))
info->callbacks->einfo (_("%P: %pB: warning: relocation against `%s' "
"in readonly section `%pA'.\n"),
p->sec->owner, h->root.root.string,
p->sec);
/* Not an error, just cut short the traversal. */
return FALSE;
}
}
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info *info)
{
struct _bfd_e2k_elf_link_hash_table *htab;
bfd *dynobj;
bfd *ibfd;
asection *s;
htab = _bfd_e2k_elf_hash_table (info);
if (htab == NULL)
return FALSE;
dynobj = htab->elf.dynobj;
if (dynobj == NULL)
abort ();
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
bfd_signed_vma *local_got, *local_ie;
bfd_signed_vma *end_local_got;
char *local_tls_type;
char *local_relgot_cntr;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
if (! is_e2k_elf (ibfd))
continue;
for (s = ibfd->sections; s != NULL; s = s->next)
{
struct e2k_elf_dyn_relocs *p;
for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
{
/* Local symbols shouldn't require an entry in `.rela.xxx' when
referenced via a SIZE relocation. */
p->count -= p->pc_count;
p->pc_count = 0;
if (p->count != 0)
{
if (! ABI_PM_P (dynobj))
{
srel = elf_section_data (p->sec)->sreloc;
srel->size += p->count * htab->bytes_per_rela;
if ((p->sec->output_section->flags & SEC_READONLY) != 0
&& (info->flags & DF_TEXTREL) == 0)
{
info->flags |= DF_TEXTREL;
if (bfd_link_textrel_check (info))
info->callbacks->einfo
(_("%P: %pB: warning: relocation in readonly "
"section `%pA'.\n"), p->sec->owner, p->sec);
}
}
else
{
/* Under no circumstances (i.e. no matter whether a static
or dynamic executable or a shared library is linked)
should one require dynamic relocations against local
symbols in Protected Mode. */
BFD_ASSERT (p->type == 1 || p->type == 2);
reserve_space_for_selfinit (htab,
(p->type == 1
? sizeof (selfinit_ap)
: sizeof (selfinit_pl)),
p->count, s->name);
}
}
}
}
local_got = elf_local_got_refcounts (ibfd);
if (local_got == NULL)
continue;
/* These ones are always allocated right after local_got in
check_relocs (), therefore I don't compare them with NULL. */
local_ie = _bfd_e2k_elf_local_ie_refcounts (ibfd);
/* An array containing a number of '.rela.got' entries related to each
local symbol. */
local_relgot_cntr = _bfd_e2k_elf_local_relgot_cntr (ibfd);
symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
local_tls_type = _bfd_e2k_elf_local_got_tls_type (ibfd);
s = htab->elf.sgot;
srel = htab->elf.srelgot;
for (; local_got < end_local_got;
++local_got, ++local_ie, ++local_tls_type, ++local_relgot_cntr)
{
int i;
static const int types[] = {GOT_NORMAL, GOT_TLS_GDMOD, GOT_TLS_GDREL,
GOT_TLS_IE};
for (i = 0; i < 4; i++)
{
bfd_signed_vma *entry;
if ((*local_tls_type & types[i]) == 0)
continue;
if (types[i] == GOT_TLS_IE)
entry = local_ie;
else
entry = local_got;
/* See if there are any references related to the type of access
under consideration. */
if (*entry > 0)
{
/* For local symbols we need one GOT entry to store the result
of R_E2K_TLS_XX_DTPMOD processing against a dynamic symbol
with zero index. Certainly, when linking a shared library
we need one entry in .rela.got for the mentioned dynamic
relocation as well. Note that since this symbol turns out
to be LOCAL the result of this relocation's processing by
ld.so is a runtime index of the containing dynamic object.
For an executable it's known at linktime and turns out to
be equal to 1 (see processing of R_E2K_TLS_GDMOD in
`relocate_section ()'). */
if (types[i] == GOT_TLS_GDMOD
&& htab->gdmod_zero_off == (bfd_vma) -1)
{
htab->gdmod_zero_off = s->size;
s->size += ABI_PM_P (dynobj) ? 16 : htab->bytes_per_word;
if (bfd_link_pic (info))
srel->size += htab->bytes_per_rela;
/* I don't increase *local_relgot_cntr here intentionally
since this relocation may be shared among multiple
local symbols. */
}
/* We need one GOT entry to store a symbol's runtime offset
(in case of IE and GDREL) or address (in case of
GOT_NORMAL) related to the type of access under
consideration. */
if (types[i] != GOT_TLS_GDMOD)
{
*entry = s->size;
s->size += ABI_PM_P (dynobj) ? 16 : htab->bytes_per_word;
}
/* Allocate space for the corresponding entry in .rela.got
required to produce a valid runtime offset (address). This
value can't be determined at linktime in GOT_{NORMAL,
TLS_IE} cases only when producing a shared library. */
if (bfd_link_pic (info)
&& (types[i] == GOT_NORMAL
|| types[i] == GOT_TLS_IE))
{
srel->size += htab->bytes_per_rela;
*local_relgot_cntr += 1;
}
}
}
}
}
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
/* Now that space has been allocated for all primary and secondary PLT
entries it should be possible to set values to final primary PLT offsets
for symbols requiring this. */
elf_link_hash_traverse (&htab->elf, finalize_plt_offsets, info);
/* When linking an executable allocate space for `_start ()' both in
`.data.export_pl' and `.text.selfinit'. FIXME: this way redundant space
is allocated even when creating a static executable. */
if (ABI_PM_P (htab->elf.dynobj) && bfd_link_executable (info))
{
htab->export_pl->size += 16;
reserve_space_for_selfinit (htab, sizeof (selfinit_pl), 1, "_start");
}
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
for (s = dynobj->sections; s != NULL; s = s->next)
{
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
if (CONST_STRNEQ (bfd_section_name (s), ".rela"))
{
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
s->reloc_count = 0;
}
else if (s != htab->elf.sgot
&& s != htab->elf.sgotplt
&& s != htab->elf.splt
&& s != htab->elf.iplt)
{
/* It's not one of our sections, so don't allocate space. */
continue;
}
if (s->size == 0)
{
/* This lets me get rid of such sections as `.rela.iplt' in case they
are not really needed. The failure to do so may result in an empty
`.rela.dyn' section in the output BFD: it won't be excluded because
of its input sections (e.g., the aforementioned `.rela.iplt')
without SEC_EXCLUDE flag set. */
s->flags |= SEC_EXCLUDE;
continue;
}
if ((s->flags & SEC_HAS_CONTENTS) == 0)
continue;
/* Allocate memory for the section contents. We use bfd_zalloc
here in case unused entries are not reclaimed before the
section's contents are written out. This should not happen,
but this way if it does, we get a R_E2K_NONE reloc instead
of garbage. */
s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size);
if (s->contents == NULL)
return FALSE;
}
if (ABI_PM_P (dynobj)
&& (s = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
{
const struct elf_backend_data *bed;
bfd_byte *dyncon, *dynconend;
size_t dynsize;
bed = get_elf_backend_data (dynobj);
dynsize = bed->s->sizeof_dyn;
dynconend = s->contents + s->size;
/* See if `D_{INIT,FINI}' were created by `bfd_elf_size_dynamic_sections
()' and take care of allocating space for the related PLs and selfinit
code in case they were. */
for (dyncon = s->contents; dyncon < dynconend; dyncon += dynsize)
{
Elf_Internal_Dyn dyn;
bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
if (dyn.d_tag == DT_INIT || dyn.d_tag == DT_FINI)
{
htab->export_pl->size += 16;
reserve_space_for_selfinit (htab, sizeof (selfinit_pl), 1,
(dyn.d_tag == DT_INIT
? "_init" : "_fini"));
}
}
}
if (htab->selfinit)
htab->selfinit->contents
= (unsigned char *) bfd_zalloc (dynobj, htab->selfinit->size);
if (htab->export_pl)
htab->export_pl->contents
= (unsigned char *) bfd_zalloc (dynobj, htab->export_pl->size);
if (htab->elf.dynamic_sections_created)
{
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
if (bfd_link_executable (info))
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
}
if (!add_dynamic_entry (DT_RELA, 0)
|| !add_dynamic_entry (DT_RELASZ, 0)
|| !add_dynamic_entry (DT_RELAENT, htab->bytes_per_rela))
return FALSE;
/* If any dynamic relocs apply to a read-only section,
then we need a DF_TEXTREL flag. */
if ((info->flags & DF_TEXTREL) == 0)
elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info);
/* Finally the presence of a DF_TEXTREL flag leads to the creation
of a DT_TEXTREL entry. As far as I understand, this is needed
since new dynamic tags are not created by default (see a description
of the `--enable-new-dtags' option). Are we going to obtain both
DT_FLAGS and DT_TEXTREL in case the aforementioned option is set? */
if (info->flags & DF_TEXTREL)
{
if (!add_dynamic_entry (DT_TEXTREL, 0))
return FALSE;
}
if (htab->elf.srelplt->size > 0)
{
if (! add_dynamic_entry (DT_E2K_LAZY_GOT, 0))
return FALSE;
}
if (htab->elf.srelplt->size > 0
/* In Protected Mode DT_PLTGOT has a special meaning unrelated to
`.plt', therefore, it should be always present. */
|| ABI_PM_P (htab->elf.dynobj))
{
if (! add_dynamic_entry (DT_PLTGOT, 0))
return FALSE;
}
if (htab->elf.srelplt->size > 0
&& ABI_PM_P (htab->elf.dynobj))
{
/* However, we do need the real DT_PLTGOT too if we are to implement
lazy binding in PM. */
if (! add_dynamic_entry (DT_REAL_PLTGOT, 0))
return FALSE;
}
if (htab->elf.srelplt->size > 0)
{
if (! add_dynamic_entry (DT_PLTRELSZ, 0)
|| ! add_dynamic_entry (DT_PLTREL, DT_RELA)
|| ! add_dynamic_entry (DT_JMPREL, 0))
return FALSE;
}
/* These ones are purely PM-specific. */
if (ABI_PM_P (htab->elf.dynobj))
{
if (! add_dynamic_entry (DT_PLTGOTSZ, 0)
|| ! add_dynamic_entry (DT_INIT_GOT, 0)
|| ! add_dynamic_entry (DT_EXPORT_PL, 0)
|| ! add_dynamic_entry (DT_EXPORT_PLSZ, 0))
return FALSE;
}
}
return TRUE;
}
unsigned int
_bfd_e2k_elf_action_discarded (asection *sec)
{
if (strcmp (".mcst.parallelism", sec->name) == 0)
return PRETEND;
return _bfd_elf_default_action_discarded (sec);
}
/* Return the base VMA address which should be subtracted from real addresses
when resolving @dtpoff relocation.
This is PT_TLS segment p_vaddr. */
static bfd_vma
_bfd_e2k_elf_dtpoff_base (struct bfd_link_info *info)
{
/* If tls_sec is NULL, we should have signalled an error already. */
if (elf_hash_table (info)->tls_sec == NULL)
return 0;
return elf_hash_table (info)->tls_sec->vma;
}
/* Return the base VMA address which should be subtracted from real addresses
when resolving @tprel() relocation.
Main program TLS (whose template starts at PT_TLS p_vaddr)
is assigned offset round(sizeof tcbhead_t) == 2 * size_of_pointer,
PT_TLS p_align). */
static bfd_vma
_bfd_e2k_elf_tpoff_base (struct bfd_link_info *info,
bfd_boolean protected_mode)
{
struct _bfd_e2k_elf_link_hash_table *htab;
asection *tls_sec;
htab = _bfd_e2k_elf_hash_table (info);
tls_sec = elf_hash_table (info)->tls_sec;
/* FIXME: this may happen if we have no TLS data in any of the input BFDs but
some of them contain references to such variables via the Local Exec TLS
model. Such an invalid situation happens within libm.so compiled with my
rudimentary `e2k-linux-gcc': there are no `__thread'-variables defined
within it but there are numerous references to `errno'. To let the linkage
succeed and not crash here just return something . . . */
if (tls_sec == NULL)
return 0;
return (tls_sec->vma
- align_power ((protected_mode
/* This somehow takes into account that 2 Array
Pointers are likely to be allocated at the start
of __thread area at runtime in Protected Mode. */
? 2 * 16
: (bfd_vma) 2 * htab->bytes_per_word),
tls_sec->alignment_power));
}
int
simulate_relocate_section (bfd *input_bfd,
asection *input_section,
bfd_byte *contents,
Elf_Internal_Rela *relocs)
{
Elf_Internal_Rela *rel = relocs;
Elf_Internal_Rela *relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
bfd_vma relocation = 0;
unsigned int r_type = ELF_R_TYPE (input_bfd, rel->r_info);
reloc_howto_type *howto = _bfd_e2k_elf_howto_table + r_type;
/* FIXME? LAS seems to be incapable of treating "preprocessed" expressions
(i.e. those ones produced by `e2k-linux-as --preprocess') like
`$inmask-2' properly (i.e. as a sum of `inmask' symbol and `-2'
addend). It emits a relocation against `inmask-2' symbol instead with
zero addend. To eliminate divergences in linked files due to such a
stupid behaviour of LAS, the actual relocation's addend is replaced
with zero below. */
_bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation,
rel->r_addend);
}
return TRUE;
}
/* The definition comes below with other DSP-specific hooks. */
static unsigned int get_dsp_data_section_idx (const char *sec_name);
int
_bfd_e2k_elf_relocate_section (bfd *output_bfd,
struct bfd_link_info *info,
bfd *input_bfd,
asection *input_section,
bfd_byte *contents,
Elf_Internal_Rela *relocs,
Elf_Internal_Sym *local_syms,
asection **local_sections)
{
struct _bfd_e2k_elf_link_hash_table *htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets, *local_ie_offsets;
char *local_relgot_cntr;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
BFD_ASSERT (is_e2k_elf (input_bfd));
htab = _bfd_e2k_elf_hash_table (info);
if (htab == NULL)
return FALSE;
if (simulating_mode)
return simulate_relocate_section (input_bfd, input_section, contents,
relocs);
symtab_hdr = &elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
local_ie_offsets = _bfd_e2k_elf_local_ie_offsets (input_bfd);
local_relgot_cntr = _bfd_e2k_elf_local_relgot_cntr (input_bfd);
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
unsigned int r_type;
reloc_howto_type *howto;
unsigned long r_symndx;
asection *sec;
bfd_vma relocation;
bfd_boolean unresolved_reloc;
struct elf_link_hash_entry *h;
struct _bfd_e2k_elf_link_hash_entry *eh;
Elf_Internal_Sym *sym;
bfd_vma r_addend;
bfd_vma off;
bfd_vma st_size;
bfd_reloc_status_type r;
r_type = ELF_R_TYPE (input_bfd, rel->r_info);
switch (r_type)
{
case R_E2K_32_ABS:
case R_E2K_32_PC:
case R_E2K_64_ABS:
case R_E2K_64_ABS_LIT:
case R_E2K_64_PC_LIT:
case R_E2K_TLS_GDMOD:
case R_E2K_TLS_GDREL:
case R_E2K_TLS_IE:
case R_E2K_32_TLS_LE:
case R_E2K_64_TLS_LE:
case R_E2K_TLS_32_DTPMOD:
case R_E2K_TLS_32_DTPREL:
case R_E2K_TLS_64_DTPMOD:
case R_E2K_TLS_64_DTPREL:
case R_E2K_GOT:
case R_E2K_AP_GOT:
case R_E2K_PL_GOT:
case R_E2K_GOTPLT:
case R_E2K_GOTOFF:
case R_E2K_64_GOTOFF:
case R_E2K_64_GOTOFF_LIT:
case R_E2K_DISP:
case R_E2K_PREF:
case R_E2K_ISLOCAL:
case R_E2K_ISLOCAL32:
case R_E2K_32_SIZE:
case R_E2K_64_SIZE:
case R_E2K_AP:
case R_E2K_PL:
case R_ELCORE_NONE:
case R_ELCORE_I5:
case R_ELCORE_I16:
case R_ELCORE_I16PC:
case R_ELCORE_S16:
case R_ELCORE_S16PC:
case R_ELCORE_I32:
case R_ELCORE_I5_FAKE:
case R_ELCORE_I16_FAKE:
case R_ELCORE_I16PC_FAKE:
case R_ELCORE_S16_FAKE:
case R_ELCORE_S16PC_FAKE:
case R_ELCORE_I32_FAKE:
case R_E2K_NONE:
case R_E2K_64_DYNOPT:
case R_E2K_32_DYNOPT:
break;
default:
_bfd_error_handler
(_("%pB: unrecognized relocation (0x%x) in section `%pA'"),
input_bfd, r_type, input_section);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
howto = _bfd_e2k_elf_howto_table + r_type;
r_symndx = ELF_R_SYM (input_bfd, rel->r_info);
h = NULL;
eh = NULL;
sym = NULL;
sec = NULL;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
/* Keep in mind that rel->r_addend may very well change after this
call if we migrate to a new MERGED section. Therefore, set our
local R_ADDEND variable below. */
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
st_size = sym->st_size;
}
else
{
bfd_boolean warned ATTRIBUTE_UNUSED;
bfd_boolean ignored ATTRIBUTE_UNUSED;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
h, sec, relocation,
unresolved_reloc, warned, ignored);
if (strcmp (h[0].root.root.string, "ASN1_ANY_it") == 0)
{
static int cntr;
cntr++;
}
st_size = h->size;
/* The following checks probably make sense for relocations against
global symbols only. Otherwise, it's a compiler's responsibility
to verify that local symbols are accessed properly. Moreover, at
present we cannot mix non-dsp and dsp code in one object file.
Therefore, such problems for local symbols seem to be illusive.
However, think about appending a `dsp_symbol' sign to local
symbols . . .*/
/* If I used `_bfd_error_handler ()' below than the only
opportunity to fail would be to `return FALSE'. That would
probably mean to return immediately after the very first
error. However, I'd like to see all of them, therefore
I use LD's einfo ("%X . . .") instead. That guarantees
that no object output will be created (see `ldmisc.c'). */
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
/* DSP relocations against non-DSP symbols are not supported. */
if (r_type >= R_ELCORE_NONE && r_type <= R_ELCORE_I32_FAKE
/* We cannot be sure that it's a non-DSP symbol if it's not
defined anywhere. */
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common)
&& !eh->dsp_symbol)
{
info->callbacks->einfo
(_("%XReferencing non-DSP symbol `%s' from DSP object `%pB'\n"),
h->root.root.string, input_bfd);
/* return FALSE; */
}
/* DSP symbols may be accessed either from DSP relocatable objects
via DSP-specific relocations or from E2k objects via R_E2K_32_ABS
and R_E2K_64_ABS_LIT. Direct DSP function calls are not permitted
(see Bug #40364) as well as other types of access (e.g. via GOT)
as long as we don't support dynamic binding with DSP modules. */
else if (eh->dsp_symbol
&& !(r_type >= R_ELCORE_NONE && r_type <= R_ELCORE_I32_FAKE)
&& !(r_type == R_E2K_32_ABS || r_type == R_E2K_64_ABS
|| r_type == R_E2K_64_ABS_LIT ))
{
info->callbacks->einfo
(_("%XReferencing DSP symbol `%s' from non-DSP object `%pB' "
"via `%s' relocation. \n"), h->root.root.string, input_bfd,
howto->name);
/* return FALSE; */
}
}
/* It turns out that relocs against symbols coming from discarded
sections should either be removed (as it happens when doing a
relocatable link and input section contains debugging info)
or their `r_{info,addend}' zeroed out. The corresponding contents
in INPUT_SECTION is cleared as well. Unfortunately at E2K
`R_E2K_32_ABS is 0' and because of this zeroing out `r_info' is a
bad idea. In order to set up R_E2K_NONE instead, I need the underlying
hack with an additional loop (see also an implementation of
RELOC_AGAINS_DISCARDED_SECTION in elf-bfd.h). Funny enough, METAG has
the same trouble as we do, but they use their own version of this
macro. */
if (sec != NULL && discarded_section (sec))
{
int i;
Elf_Internal_Rela *prev_rel = rel;
for (i = 0; i < 1; i++)
{
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
rel, 1, relend, howto, 0, contents);
}
if (rel >= prev_rel)
{
/* This means that the relocation was not removed, its
`r_{info,addend}' were zeroed out instead. */
prev_rel->r_info = htab->r_info (0, R_E2K_NONE);
}
/* Really continue now rather than inside
RELOC_AGAINST_DISCARDED_SECTION */
continue;
}
if (bfd_link_relocatable (info))
continue;
/* I suppose, I may set R_ADDEND now. */
r_addend = rel->r_addend;
if (h != NULL
&& h->type == STT_GNU_IFUNC
&& h->def_regular)
{
asection *plt_sec;
plt_sec = htab->elf.splt;
if (plt_sec == NULL)
plt_sec = htab->elf.iplt;
switch (r_type)
{
/* Indirect functions should be never considered local in
fact. */
case R_E2K_ISLOCAL:
relocation = 0xc0;
goto do_relocation;
case R_E2K_ISLOCAL32:
relocation = 0x0;
goto do_relocation;
case R_E2K_GOT:
case R_E2K_AP_GOT:
case R_E2K_PL_GOT:
case R_E2K_GOTPLT:
break;
case R_E2K_64_ABS:
case R_E2K_64_ABS_LIT:
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset
+ plt_offset (h, htab));
if (r_type == R_E2K_64_ABS_LIT)
goto process_r_e2k_64_abs_lit;
else
goto common_processing;
/* The usage of R_E2K_GOTOFF against IFUNC symbols shouldn't
cause any problems on E2K unlike i386: one can just use the
related PLT entry to resolve it. On i386 that's impossible
since `%ebx' should be specially initialized when performing a
CALL via PLT. */
case R_E2K_GOTOFF:
case R_E2K_64_GOTOFF:
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset
+ plt_offset (h, htab)
- htab->elf.sgotplt->output_section->vma
- htab->elf.sgotplt->output_offset);
if (r_type == R_E2K_64_GOTOFF)
{
relocation += r_addend;
r_addend = 0;
relocation = ((relocation >> 32)
| ((relocation & 0xffffffff) << 32));
}
goto do_relocation;
case R_E2K_DISP:
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset + plt_offset (h, htab));
goto do_relocation;
default:
/* FIXME: perform some output here and call `bfd_set_error ()'.
Otherwise LD will finish without a meaningful error message.
Moreover, it'll output something like "final link failed:
bfd_errmsgs[coresponding_to_a_stale_bfd_error]". */
return FALSE;
}
}
switch (r_type)
{
case R_E2K_GOT:
case R_E2K_AP_GOT:
case R_E2K_PL_GOT:
case R_E2K_GOTPLT:
/* Relocation is to the entry for this symbol in the global
offset table. */
if (htab->elf.sgot == NULL)
abort ();
if (h != NULL)
{
bfd_boolean dyn;
bfd_boolean entry_created = FALSE;
if (r_type == R_E2K_GOTPLT
&& secondary_plt_idx (h) != (bfd_vma) -1)
off = eh->gotplt_offset;
else
off = h->got.offset;
if (off == (bfd_vma) -1)
break;
dyn = elf_hash_table (info)->dynamic_sections_created;
if (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)
&& ! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h))
{
if ((off & 1) != 0)
off &= ~1;
else
{
asection *s;
Elf_Internal_Rela outrel;
/* We need to generate a R_E2K_XX_RELATIVE reloc
for the dynamic linker. */
s = htab->elf.srelgot;
BFD_ASSERT (s != NULL);
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
outrel.r_info = htab->r_info (0, htab->relative_reloc);
outrel.r_addend = relocation;
relocation = 0;
BFD_ASSERT (--eh->relgot_cntr >= 0);
elf_append_rela (output_bfd, s, &outrel);
entry_created = TRUE;
}
}
else if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
/* Stupidly generate code in `__selfinit ()' for a
locally resolved symbol in PM. What's the point in
postponing it until finish_dynamic_symbol even if it's
called in the end? */
|| ((r_type == R_E2K_AP_GOT || r_type == R_E2K_PL_GOT)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
{
if ((off & 1) != 0)
off &= ~1;
else
{
unsigned char *got_contents;
if (r_type == R_E2K_GOTPLT
&& secondary_plt_idx (h) != (bfd_vma) -1)
got_contents = htab->elf.sgotplt->contents;
else
got_contents = htab->elf.sgot->contents;
htab->put_word (output_bfd,
((r_type == R_E2K_AP_GOT
|| r_type == R_E2K_PL_GOT)
? 0
: relocation),
got_contents + off);
if (r_type == R_E2K_AP_GOT)
add_selfinit_ap (info, relocation, st_size, r_addend,
(htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off),
h->root.root.string);
else if (r_type == R_E2K_PL_GOT)
add_selfinit_pl (info, relocation + r_addend,
(htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off),
h->root.root.string);
entry_created = TRUE;
}
}
if (entry_created)
{
if (r_type == R_E2K_GOTPLT
&& secondary_plt_idx (h) != (bfd_vma) -1)
eh->gotplt_offset |= 1;
else
h->got.offset |= 1;
}
}
else
{
if (local_got_offsets == NULL)
abort ();
off = local_got_offsets[r_symndx];
if ((off & 1) != 0)
off &= ~1;
else
{
if (bfd_link_pic (info))
{
asection *s;
Elf_Internal_Rela outrel;
/* We need to generate a R_E2K_XX_RELATIVE reloc
for the dynamic linker. */
s = htab->elf.srelgot;
BFD_ASSERT (s != NULL);
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
outrel.r_info = htab->r_info (0, htab->relative_reloc);
outrel.r_addend = relocation;
relocation = 0;
BFD_ASSERT (--local_relgot_cntr[r_symndx] >= 0);
elf_append_rela (output_bfd, s, &outrel);
}
htab->put_word (output_bfd, relocation,
htab->elf.sgot->contents + off);
local_got_offsets[r_symndx] |= 1;
}
}
/* In Protected Mode a GOT entry is accessed directly via its address
in the data segment. */
if (r_type == R_E2K_AP_GOT || r_type == R_E2K_PL_GOT)
relocation = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
/* Offset with respect to '_GLOBAL_OFFSET_TABLE' symbol should be
substituted during the link process in non-protected modes. */
else
relocation = ((r_type == R_E2K_GOT
|| secondary_plt_idx (h) == (bfd_vma) -1)
? (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off
- htab->elf.sgotplt->output_section->vma
- htab->elf.sgotplt->output_offset)
: off);
break;
case R_E2K_GOTOFF:
case R_E2K_64_GOTOFF:
case R_E2K_64_GOTOFF_LIT:
/* Relocation is relative to the start of the global offset
table. */
/* Check to make sure it isn't a protected function or data
symbol for shared library since it may not be local when
used as function address or with copy relocation. We also
need to make sure that a symbol is referenced locally. */
if (!bfd_link_executable (info) && h)
{
if (!h->def_regular)
{
const char *v;
switch (ELF_ST_VISIBILITY (h->other))
{
case STV_HIDDEN:
v = _("hidden symbol");
break;
case STV_INTERNAL:
v = _("internal symbol");
break;
case STV_PROTECTED:
v = _("protected symbol");
break;
default:
v = _("symbol");
break;
}
_bfd_error_handler
(_("%pB: relocation `%s' against undefined %s `%s' can not be used when making a shared object"),
input_bfd, howto->name, v, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
else if (!SYMBOL_REFERENCES_LOCAL (info, h)
&& (h->type == STT_FUNC
|| h->type == STT_OBJECT)
&& ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
{
_bfd_error_handler
(_("%pB: relocation `%s' against protected %s `%s' can not be used when making a shared object"),
input_bfd,
howto->name,
h->type == STT_FUNC ? "function" : "data",
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
relocation -= (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset);
if (r_type == R_E2K_64_GOTOFF_LIT)
{
relocation += r_addend;
r_addend = 0;
relocation = ((relocation >> 32)
| ((relocation & 0xffffffff) << 32));
}
break;
case R_E2K_DISP:
if (h != NULL && plt_idx (h) != (bfd_vma) -1)
{
relocation = (htab->elf.splt->output_section->vma
+ htab->elf.splt->output_offset
+ plt_offset (h, htab));
}
break;
case R_E2K_PREF:
{
bfd_vma hline_mask = ~0x7f;
bfd_vma wc_offs;
/* Get the contents of PDISP field which should contain the offset
of this syllable within the current wide command. By convention
it's stored within the `pdisp' field (see Bug #68612,
Comment #24). */
wc_offs = bfd_get_32 (input_bfd, contents + rel->r_offset);
wc_offs &= 0x0ffffff0;
wc_offs >>= 4;
relocation = (((relocation
+ r_addend)
& hline_mask)
- ((input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset
- wc_offs)
& hline_mask));
}
/* This relocation may become too peculiar to process it via
`_bfd_final_link_relocate ()', though at present it's almost
possible (see the formula in Bug #68612, Comment #0). Anyway, it
may be a better idea to call `_bfd_relocate_contents ()' rather
than to set `r_addend' to zero as I used to do . . . */
_bfd_relocate_contents (howto, input_bfd, relocation,
contents + rel->r_offset);
continue;
case R_E2K_32_SIZE:
case R_E2K_64_SIZE:
/* Set to symbol size. */
relocation = st_size;
goto common_processing;
/* Prevent _bfd_final_link_relocate from its usual actions
when dealing with bogus LIT-relocs. We are going to pass
it a swapped value which shouldn't be modified. That's
why we take care of these things ourselves. */
case R_E2K_64_PC_LIT:
relocation -= (input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset);
/* Fall through */
case R_E2K_64_ABS_LIT:
process_r_e2k_64_abs_lit:
relocation += r_addend;
relocation = (relocation >> 32) | ((relocation & 0xffffffff) << 32);
/* Don't zero `R_ADDEND' out unconditionally because its initial
value may be required while creating a dynamic relocation
corresponding to R_E2K_64_ABS_LIT. */
if (r_type == R_E2K_64_PC_LIT)
{
r_addend = 0;
break;
}
/* Fall through */
case R_E2K_32_ABS:
case R_E2K_64_ABS:
case R_E2K_AP:
case R_E2K_PL:
common_processing:
/* This check is borrowed from elf32-i386.c . It's needed because
for some reason we don't create sreloc section for an unallocated
section (see check_relocs). Shouldn't we relocate sections
containing debug info at all? */
if ((input_section->flags & SEC_ALLOC) == 0)
break;
if ((bfd_link_pic (info)
&& (h == NULL
/* Weak undefined symbols with non-default visibility are
hidden from dynamic linker, i.e. they are explicitly
marked as non-dynamic in `_bfd_elf_fix_symbol_flags'.
Creating a relative reloc against such a symbol definitely
leads to erroneous result: one is going to obtain library
base address instead of zero. As an example, consider a
`visibility (hidden_weak) (non PIC)' test. */
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& ((r_type != R_E2K_32_SIZE && r_type != R_E2K_64_SIZE)
|| !SYMBOL_CALLS_LOCAL(info, h)))
|| (!bfd_link_pic (info)
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
&& h->def_dynamic
&& !h->def_regular))
{
Elf_Internal_Rela outrel;
bfd_boolean skip;
bfd_boolean relocate;
asection *sreloc;
skip = FALSE;
relocate = FALSE;
/* Take into account that the initial relocation offset may have
changed for "adjusted" sections like '.eh_frame' (see
_bfd_elf_discard_section_eh_frame () in elf-eh-frame.c for an
example). Alternatively the relocatable contents corresponding
to the current relocation may have been removed, in which case
it returns -1. There's also the third case, which I don't quite
understand yet, when -2 is returned. The i386 backend just
outputs a zeroed-out dynamic relocation then.
It's possible that `outrel.r_offset' should be calculated this
way not only here. */
outrel.r_offset =
_bfd_elf_section_offset (output_bfd, info, input_section,
rel->r_offset);
if (outrel.r_offset == (bfd_vma) -1)
skip = TRUE;
else if (outrel.r_offset == (bfd_vma) -2)
skip = TRUE, relocate = TRUE;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
/* Stupidly avoid creating meaningless relative relocation in
Protected Mode this way . . . */
if (ABI_PM_P (input_bfd)
&& (h == NULL
|| h->dynindx == -1
/* SYMBOLIC_BIND itself does NOT imply the presence
of the symbol's definition required to build self-
initialization code. If the symbol was NOT defined in
an input object file space for its self-init code might
not have been allocated before, which would trigger an
assertion failure if one tried to emit this code here
(Bug #127084). Note that h->def_regular is likely to be
set for COMMON and defined weak symbols as well, but is
NOT set for undefined weaks not(?) requiring self-
initialization in dynamic case (ld.so is capable of
creating NULL itself). */
|| (SYMBOLIC_BIND (info, h)
&& h->def_regular)))
{
/* What could be a useless (in case `skip == 1') selfinit
code sequence, used instead of a relative relocaton in PM,
replaced with? Presumably, it could be replaced with
`nop's, but this hasn't been implemented yet. Therefore,
let it be emitted. FIXME: this is probably going to result
in run-time failure if the location in `.eh_frame' it was
originally supposed to initialize no longer exists. If this
was absolutely impossible, one could avoid the need to
replace "original" dynamic relocations with `R_E2K_NONE's
applied to zero VMA. */
if (r_type == R_E2K_AP || r_type == R_E2K_PL)
goto do_selfinit;
/* Let "skip" replace some other relocation with R_E2K_NONE.
Is such situation possible at all? */
else if (! skip)
break;
}
if (skip)
{
outrel.r_offset = 0;
outrel.r_info = htab->r_info (0, R_E2K_NONE);
outrel.r_addend = 0;
}
else if (h != NULL
&& h->dynindx != -1
&& (! SYMBOLIC_BIND (info, h)
/* SYMBOLIC_BIND may very well return 1 for a symbol
mkssing from the shared library being linked with,
say, `-Bsymbolic-functions'. This will result in a
defective relative relocation against its base
(i.e. zero link-time address) as it happened in
Bug #100946. This extra check borrowed from
`COPY_INPUT_RELOC_P()' in `bfd/elfxx-x86.h' lets
me prevent this from happening. */
|| ! h->def_regular))
{
outrel.r_info = htab->r_info (h->dynindx, r_type);
outrel.r_addend = r_addend;
}
else
{
if (r_type != R_E2K_64_ABS_LIT)
{
outrel.r_info = htab->r_info (0, htab->relative_reloc);
outrel.r_addend = relocation + r_addend;
}
else
{
outrel.r_info = htab->r_info (0,
htab->relative_lit_reloc);
/* This relocation value is not to be output into a pair
of literal syllables, therefore undo our preparations
a few dozens of lines above. Keep in mind that
R_ADDEND has already been taken into account during
these preparations. */
outrel.r_addend = ((relocation >> 32)
| ((relocation & 0xffffffff) << 32));
}
}
/* Keep in mind that sreloc belongs to htab->dynobj, rather than
to output_bfd. It's created in `check_relocs ()'. */
sreloc = elf_section_data (input_section)->sreloc;
elf_append_rela (output_bfd, sreloc, &outrel);
/* There's no point in relocating if `_bfd_elf_section_offset ()'
returned `-1'. However, we should have output R_E2K_NONE
dynamic relocation above to avoid assertion failures due to
redundant space for dynamic relocations later. */
if (skip && !relocate)
continue;
/* TODO: find out what's going to be output to this position in
the output section after we perform a subsequent BREAK. I
guess that it's `RELOCATION + R_ADDEND'. Shouldn't we zero
them out here? Anyway, this value is to be replaced by LDSO
at runtime. */
/* `_bfd_elf_eh_frame_section_offset ()' returns `-2', in which
case we set SKIP above, if it thinks that we don't need a run-
time relocation against '.eh_frame' section (e.g. FDE's initial
_location field). In this case perform a link-time relocation
"somehow" (currently I don't know what should be done with its
result at run-time). To obtain sensible results we shouldn't
zero out RELOCATION and R_ADDEND, otherwise we'll definitely
fail when checking for FDEs' potential overlaps in
`_bfd_elf_write_section_eh_frame_hdr ()'. */
if (!skip)
{
relocation = 0;
r_addend = 0;
}
}
else if (ABI_PM_P (input_bfd) && r_type != R_E2K_32_ABS)
{
bfd_vma targ_off;
do_selfinit:
targ_off = _bfd_elf_section_offset (output_bfd, info,
input_section,
rel->r_offset);
if (targ_off != (bfd_vma) -1 && targ_off != (bfd_vma) -2)
targ_off += (input_section->output_section->vma
+ input_section->output_offset);
if (r_type == R_E2K_AP)
add_selfinit_ap (info, relocation, st_size, r_addend, targ_off,
h ? h->root.root.string : sec->name);
else
{
BFD_ASSERT (r_type == R_E2K_PL);
add_selfinit_pl (info, relocation + r_addend, targ_off,
h ? h->root.root.string : sec->name);
}
}
else if (r_type == R_E2K_64_ABS_LIT)
/* It's time to zero R_ADDEND out for this sort of relocation.
Otherwise, it'll be taken into account twice. */
r_addend = 0;
break;
case R_E2K_TLS_GDMOD:
case R_E2K_TLS_GDREL:
case R_E2K_TLS_IE:
{
long indx;
bfd_vma *poff;
Elf_Internal_Rela outrel;
char *prelgot_cntr
= h ? &eh->relgot_cntr : &local_relgot_cntr[r_symndx];
asection *sreloc = htab->elf.srelgot;
indx = h && h->dynindx != -1 ? h->dynindx : 0;
/* FIXME: stupid GCC doesn't see that OFF is sure to be initialized
within switch below. */
off = 0;
switch (r_type)
{
case R_E2K_TLS_GDMOD:
poff = indx != 0 ? &eh->gdmod.offset : &htab->gdmod_zero_off;
off = *poff;
BFD_ASSERT (off != (bfd_vma) -1);
if ((off & 1) != 0)
{
off &= ~1;
break;
}
/* For a local symbol within an executable substitute the known
at linktime module index. Otherwise, emit DTPMOD reloc.
FIXME: I guess the former can be done for any symbol defined
within an executable. */
if (indx == 0 && ! bfd_link_pic (info))
htab->put_word (output_bfd, 1,
htab->elf.sgot->contents + off);
else
{
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
outrel.r_addend = 0;
outrel.r_info = htab->r_info (indx, htab->dtpmod_reloc);
/* Keep in mind that gdmod_zero GOT entry isn't associated
with any particular local symbol, but is shared among all
of them. Therefore, I don't increase any symbol's relgot
_cntr in size_dynamic_sections () to account for the
underlying dynamic relocation. */
if (indx != 0)
BFD_ASSERT (--*prelgot_cntr >= 0);
elf_append_rela (output_bfd, sreloc, &outrel);
}
*poff |= 1;
break;
case R_E2K_TLS_GDREL:
poff = h ? &h->got.offset : &local_got_offsets[r_symndx];
off = *poff;
if ((off & 1) != 0)
{
off &= ~1;
break;
}
/* For a locally-defined symbol its offset with respect to the
beginning of PT_TLS segment (that one provided as the second
argument to __tls_getaddr () can be determined at link time.
Otherwise output a DTPOFF reloc. */
if (indx == 0)
htab->put_word (output_bfd,
relocation - _bfd_e2k_elf_dtpoff_base (info),
htab->elf.sgot->contents + off);
else
{
outrel.r_addend = 0;
outrel.r_info = htab->r_info (indx, htab->dtpoff_reloc);
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
BFD_ASSERT (--*prelgot_cntr >= 0);
elf_append_rela (output_bfd, sreloc, &outrel);
}
*poff |= 1;
break;
case R_E2K_TLS_IE:
poff = h ? &eh->ie.offset : &local_ie_offsets[r_symndx];
off = *poff;
if ((off & 1) != 0)
{
off &= ~1;
break;
}
/* FIXME: to be revisited . . . */
if (bfd_link_pic (info) || indx != 0)
{
if (indx == 0)
outrel.r_addend = (relocation
- _bfd_e2k_elf_dtpoff_base (info));
else
outrel.r_addend = 0;
outrel.r_info = htab->r_info (indx, htab->tpoff_reloc);
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
BFD_ASSERT (--*prelgot_cntr >= 0);
elf_append_rela (output_bfd, sreloc, &outrel);
}
else
{
bfd_vma recalc
= (relocation
- _bfd_e2k_elf_tpoff_base (info, ABI_PM_P (input_bfd)));
htab->put_word (output_bfd, recalc,
htab->elf.sgot->contents + off);
}
*poff |= 1;
break;
}
/* Finally, calculate the value to be substituted in place the
processed relocation is pointing to. Note that it's an offset with
respect to '_GLOBAL_OFFSET_TABLE' symbol. */
relocation = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off
- (ABI_PM_P (input_bfd)
? 0
: (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset)));
}
break;
case R_E2K_32_TLS_LE:
case R_E2K_64_TLS_LE:
relocation -= _bfd_e2k_elf_tpoff_base (info, ABI_PM_P (input_bfd));
/* Ensure that `_bfd_final_link_relocate ()' isn't going to
interfere with us in 64-bit case. */
if (r_type == R_E2K_64_TLS_LE)
{
relocation += r_addend;
r_addend = 0;
relocation = ((relocation >> 32)
| ((relocation & 0xffffffff) << 32));
}
break;
case R_E2K_TLS_32_DTPREL:
case R_E2K_TLS_64_DTPREL:
relocation -= _bfd_e2k_elf_dtpoff_base (info);
break;
case R_E2K_ISLOCAL:
/* For `0xc0' see encoding of 5-bit values within ALS in 6.3.1 of
iset.single. */
relocation = 0xc0 | (SYMBOL_CALLS_LOCAL (info, h) ? 0x1 : 0x0);
break;
case R_E2K_ISLOCAL32:
relocation = SYMBOL_CALLS_LOCAL (info, h) ? 0x1 : 0x0;
break;
case R_E2K_32_DYNOPT:
case R_E2K_64_DYNOPT:
/* According to the purpose of @DYNOPT expressed in Bug #117734,
Comment #11 leave relocation intact for local ELF symbols and
those global ones which are sure to be defined in the same
compilation unit, otherwise zero it out. */
if (h != NULL
&& (h->root.type != bfd_link_hash_defined
|| h->root.u.def.section->owner != input_bfd))
relocation = 0;
break;
case R_ELCORE_NONE:
case R_ELCORE_I5:
case R_ELCORE_I16:
case R_ELCORE_I16PC:
case R_ELCORE_S16:
case R_ELCORE_S16PC:
case R_ELCORE_I32:
case R_ELCORE_I5_FAKE:
case R_ELCORE_I16_FAKE:
case R_ELCORE_I16PC_FAKE:
case R_ELCORE_S16_FAKE:
case R_ELCORE_S16PC_FAKE:
case R_ELCORE_I32_FAKE:
/* Sec will be NULL for an undefined DSP symbol (see Bug #73562).
"Correctness" of the resulting relocation value in such a case
isn't important. */
if (!howto->pc_relative && sec != NULL)
{
/* The base address of the segment onto which the output section
is mapped should be subtracted from the value of a non-pc-
relative relocation to obtain the offset DSP uses to access
memory within the segment. */
struct elf_segment_map *crnt_map;
/* Take into account that XY-RAM is common to the whole group of
4 DSP Kernels. That's why a DSP Kernel's "own" data address
space starts from non-zero address unless its index is a multiple
of four. If `i >= 16' this means that we have a relocation against
a `.dsp_textXX' section. */
unsigned int i
= get_dsp_data_section_idx (sec->output_section->name);
if (i != (unsigned int) -1)
relocation += 4 * (i % 4) * 0x8000;
/* Otherwise we should probably warn that we cannot determine a DSP section
index, shouldn't we? */
for (crnt_map = elf_tdata (output_bfd)->o->seg_map, i = 0;
crnt_map;
crnt_map = crnt_map->next, i++)
{
unsigned j;
for (j = 0; j < crnt_map->count; j++)
{
if (crnt_map->sections[j] == sec->output_section)
break;
}
if (j < crnt_map->count)
break;
}
BFD_ASSERT (crnt_map != NULL);
relocation -= elf_tdata (output_bfd)->phdr[i].p_vaddr;
}
}
do_relocation:
if (r_type == R_E2K_AP || r_type == R_E2K_PL)
continue;
bfd_boolean restore_output_section_vma = FALSE;
bfd_vma saved_output_section_vma;
/* Do not adjust relocations having other meanings than offset by
mistake. Are all of them taken into account below? */
if (ABI_PM_P (input_bfd)
&& (input_section->flags & SEC_ALLOC) != 0 /* ??? */
/* What else relocations operate on offsets in CUD and GD? */
&& (((r_type == R_E2K_32_ABS
|| r_type == R_E2K_DISP)
&& ! (h != NULL
&& h->root.type == bfd_link_hash_defined
&& bfd_is_abs_section (h->root.u.def.section)))
/* For these relocations the offset (i.e. with respect to GD.base)
of a .got entry is evaluated here. It obviously needs to be
adjusted no matter if the target symbol is absolute or not. */
|| r_type == R_E2K_AP_GOT
|| r_type == R_E2K_PL_GOT
|| r_type == R_E2K_TLS_IE
|| r_type == R_E2K_TLS_GDMOD
|| r_type == R_E2K_TLS_GDREL
|| r_type == R_E2K_32_PC))
{
/* All this idiotism is required for PC-relative relocations to be
performed properly in "packed mode". */
saved_output_section_vma = input_section->output_section->vma;
input_section->output_section->vma
= adjust_offset_in_cud_gd (info, saved_output_section_vma);
restore_output_section_vma = TRUE;
relocation = adjust_offset_in_cud_gd (info, relocation);
}
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, r_addend);
if (restore_output_section_vma)
input_section->output_section->vma = saved_output_section_vma;
if (r != bfd_reloc_ok)
{
const char *name;
if (h != NULL)
name = h->root.root.string;
else
{
name = bfd_elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym->st_name);
if (name == NULL)
return FALSE;
if (*name == '\0')
name = bfd_section_name (sec);
}
if (r == bfd_reloc_overflow)
{
(*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), name, howto->name,
(bfd_vma) 0, input_bfd, input_section,
rel->r_offset);
}
else
{
_bfd_error_handler
(_("%pB(%pA+0x%lx): reloc against `%s': error %d"),
input_bfd, input_section,
(long) rel->r_offset, name, (int) r);
return FALSE;
}
}
}
return 1;
}
bfd_boolean
_bfd_e2k_elf_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
struct _bfd_e2k_elf_link_hash_table *htab;
struct _bfd_e2k_elf_link_hash_entry *eh;
Elf_Internal_Rela rela;
/* FIXME: find out if there is actually any risk of using an uninitialized
variable below. */
bfd_vma gotplt_offset = 0;
asection *splt;
asection *srela;
bfd_boolean ifunc = FALSE;
htab = _bfd_e2k_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
if (secondary_plt_idx (h) != (bfd_vma) -1)
gotplt_offset = eh->gotplt_offset & ~(bfd_vma) 1;
if (htab->elf.splt != NULL)
{
splt = htab->elf.splt;
srela = htab->elf.srelplt;
}
else
{
splt = htab->elf.iplt;
srela = htab->elf.irelplt;
}
if (plt_idx (h) != (bfd_vma) -1)
{
if (h->type == STT_GNU_IFUNC)
ifunc = TRUE;
if (secondary_plt_idx (h) == (bfd_vma) -1)
gotplt_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ (h->got.offset & ~(bfd_vma) 1)
- (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset));
build_plt_entry (info, splt, plt_offset (h, htab), gotplt_offset);
if (!h->def_regular)
{
/* In case this symbol is swapped out to the symbol table as defined
in `.plt' (see the code where I set `h->root.u.def.section' to
`.plt' in `allocate_dynrelocs ()'), the dynamic linker will bind
the corresponding PLT entry to itself. */
sym->st_shndx = SHN_UNDEF;
if (!h->pointer_equality_needed)
sym->st_value = 0;
}
}
if (secondary_plt_idx (h) != (bfd_vma) -1)
{
build_secondary_plt_entry (info, secondary_plt_offset (h, htab),
gotplt_offset, &rela.r_offset,
h->root.root.string);
}
if (secondary_plt_idx (h) != (bfd_vma) -1)
{
if (ifunc && SYMBOL_CALLS_LOCAL (info, h))
{
rela.r_addend = (h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset
+ h->root.u.def.value);
rela.r_info = htab->r_info (0, htab->irelative_reloc);
}
else if (bfd_link_pic (info) && SYMBOL_CALLS_LOCAL (info, h))
/* One shouldn't find himself here . . . */
abort ();
else if (h->dynindx != -1)
{
rela.r_addend = 0;
rela.r_info = htab->r_info (h->dynindx, htab->jmp_slot_reloc);
}
else
abort ();
/* Why don't other backends use elf_append_rela here? They prefer to
explicitly call swap_reloca_out instead. This is probably because they
need to guarantee that an entry in `PLT' and the corresponding
relocation in `.RELA.PLT' have the same index (maybe plus/minus some
constant). This correspondence is used when calculating the relocation
offset (relative to the value stored in DT_JMPREL) which is to be
encoded in the PLT entry for lazy binding to work. At present I don't
know whether I can guarantee such a correspondence for E2K at all,
therefore the relocation offset should be encoded separately after it
has been appended to `.RELA.PLT'. */
/* The underlying assert keeps track of relocations in .rela.got, not in
.{i,}rela.plt sections. Therefore, it's not appropriate here.
REMINDER: probably it makes sense to implement dedicated counters for
the latter relocation sections as well. */
/* BFD_ASSERT (--eh->relgot_cntr >= 0); */
elf_append_rela (output_bfd, srela, &rela);
/* FIXME: in order to get rid of the need to adjust PLT entries, I should
guarantee that the same index matches related entries within '.plt',
'.rela.plt' (and '.got.plt' in case it's required in the current PLT
implementation) sections. I've forgotten the reason, because of which
I can't be sure that this condition holds right now (see my comment
above). */
/* The secondary entry is not currently used in Protected Mode which is
made clear by setting its size to 0. */
if (htab->plt_got_secondary_entry_size)
{
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
bfd_vma dynrel_offset
= (srela->reloc_count - 1) * bed->s->sizeof_rela;
htab->adjust_plt_lazy_entry_reloc_offset
(output_bfd, htab, splt, secondary_plt_offset (h, htab),
dynrel_offset);
}
}
if (h->got.offset != (bfd_vma) -1 && eh->tls_type == GOT_NORMAL
/* Everything (i.e. generation of selfinit code) should have already
been done in relocate_section for locally-resolved symbols in PM.
Creating dynamic relative relocations against them makes absolutely
no sense. */
&& ! (ABI_PM_P (htab->elf.dynobj)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
{
if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL)
abort ();
rela.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ (h->got.offset & ~(bfd_vma) 1));
if (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
/* FIXME: improve your checks in `relocate_section ()' so as to ensure
that we don't do the same work twice. Aren't we going to overflow
`.rela.got' with duplicating relative relocations? */
/* BFD_ASSERT((h->got.offset & 1) != 0); */
rela.r_info = htab->r_info (0, htab->relative_reloc);
/* Note that we may find ourselves here in case the linkage is going
to fail due to the fact that the symbol under consideration turns
out to be undefined. This problem is present in elfxx-sparc.c and
probably in some other rela-specific (rather than rel) backends.
Don't bother about setting appropriate addend than, but avoid a
possible SIGSEGV. */
if (h->def_regular)
{
asection *sec = h->root.u.def.section;
rela.r_addend = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
else
rela.r_addend = 0;
}
else
{
int reloc = htab->abs_reloc;
if (eh->pm_got_type == 1)
reloc = R_E2K_AP;
else if (eh->pm_got_type == 2)
reloc = R_E2K_PL;
BFD_ASSERT((h->got.offset & 1) == 0);
rela.r_info = htab->r_info (h->dynindx, reloc);
rela.r_addend = 0;
}
/* Keep in mind that `got.offset' may still contain `1' in its least
significant bit. Otherwise you may very well spoil a subsequent
section! */
htab->put_word (output_bfd, (bfd_vma) 0,
htab->elf.sgot->contents
+ (h->got.offset & ~(bfd_vma) 1));
BFD_ASSERT (--eh->relgot_cntr >= 0);
elf_append_rela (output_bfd, htab->elf.srelgot, &rela);
}
if (h->needs_copy)
{
/* This symbol needs a copy reloc. Set it up. */
if (h->dynindx == -1
|| (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak)
|| htab->srelbss == NULL)
abort ();
rela.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rela.r_info = htab->r_info (h->dynindx, htab->copy_reloc);
rela.r_addend = 0;
elf_append_rela (output_bfd, htab->srelbss, &rela);
}
return TRUE;
}
/* Finish up `.dynamic' section. */
static bfd_boolean
e2k_finish_dyn (bfd *output_bfd, struct bfd_link_info *info,
bfd *dynobj, asection *sdyn,
asection *splt ATTRIBUTE_UNUSED,
bfd_vma *export_pl_off)
{
struct _bfd_e2k_elf_link_hash_table *htab;
const struct elf_backend_data *bed;
bfd_byte *dyncon, *dynconend;
size_t dynsize;
htab = _bfd_e2k_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
bed = get_elf_backend_data (output_bfd);
dynsize = bed->s->sizeof_dyn;
dynconend = sdyn->contents + sdyn->size;
for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize)
{
Elf_Internal_Dyn dyn;
const char *name;
bfd_boolean size;
bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
case DT_PLTGOT:
case DT_REAL_PLTGOT:
if (! ABI_PM_P (htab->elf.dynobj)
|| dyn.d_tag == DT_REAL_PLTGOT)
{
/* In non-PM case this entry is setup in the standard way.
As far as I understand, OUTPUT_BFD may very well have no
'.got.plt' section in case it's linked into '.got'.
Therefore, treat this case specially. FIXME: shouldn't I
implement all other cases by analogy with this one? */
asection *s = htab->elf.sgotplt;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
}
else
{
/* In Protected Mode the purpose of this entry is to fool the
Kernel so as to make it provide AP describing the whole
OBFD's GD to ld.so. To achieve that it contains "zero offset
from the start of GD". */
dyn.d_un.d_ptr = 0;
}
bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
/* Ensure that this entry isn't reset once again below. */
name = NULL;
break;
case DT_PLTGOTSZ:
{
struct elf_link_hash_entry *h;
h = elf_link_hash_lookup (elf_hash_table (info), "_end", FALSE,
FALSE, TRUE);
if (h != NULL
&& h->def_regular
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
{
asection *o = h->root.u.def.section;
dyn.d_un.d_val
= (adjust_offset_in_cud_gd (info,
(h->root.u.def.value
+ o->output_section->vma
+ o->output_offset
/* Ensures that address of "_end"
fits within the range. */
- 1))
/* Account for -1 hack above. */
+ 1);
bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
}
else
{
_bfd_error_handler (_(" The value of `DT_PLTGOTSZ' cannot be "
"determined"));
return FALSE;
}
}
name = NULL;
break;
case DT_INIT_GOT:
dyn.d_un.d_val = (htab->selfinit->output_section->vma
+ htab->selfinit->output_offset);
bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
name = NULL;
break;
case DT_EXPORT_PL:
dyn.d_un.d_val = (htab->export_pl->output_section->vma
+ htab->export_pl->output_offset);
bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
name = NULL;
break;
case DT_EXPORT_PLSZ:
dyn.d_un.d_val = htab->export_pl->size;
bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
name = NULL;
break;
case DT_PLTRELSZ:
name = ".rela.plt";
size = TRUE;
break;
case DT_JMPREL:
name = ".rela.plt";
size = FALSE;
break;
case DT_INIT:
case DT_FINI:
/* One needs to provide PLs for these entries via `.data.export_pl'
explicitly since the related `_{init,fini} ()' functions may turn
out to be non-dynamic in the end as it happens in glibc shared
libraries. FIXME: however, this may result in duplicating PLs if
`_{init,fini} ()' symbols turn out to be dynamic as in libmcst
shared libraries. */
if (ABI_PM_P (dynobj))
{
add_selfinit_pl (info, dyn.d_un.d_ptr, *export_pl_off,
dyn.d_tag == DT_INIT ? "_init" : "_fini");
*export_pl_off += 16;
}
/* Fall through */
default:
name = NULL;
size = FALSE;
break;
}
if (name != NULL)
{
asection *s;
s = bfd_get_section_by_name (output_bfd, name);
if (s == NULL)
dyn.d_un.d_val = 0;
else
{
if (! size)
dyn.d_un.d_ptr = s->vma;
else
dyn.d_un.d_val = s->size;
}
bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
}
}
return TRUE;
}
/* Used to decide how to sort relocs in an optimal manner for the
dynamic linker, before writing them out. */
enum elf_reloc_type_class
_bfd_e2k_elf_reloc_type_class (const struct bfd_link_info *info,
const asection *rel_sec ATTRIBUTE_UNUSED,
const Elf_Internal_Rela *rela)
{
bfd *abfd = info->output_bfd;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
if (htab->elf.dynsym != NULL
&& htab->elf.dynsym->contents != NULL)
{
/* Check relocation against STT_GNU_IFUNC symbol if there are
dynamic symbols. */
unsigned long r_symndx = ELF_R_SYM (abfd, rela->r_info);
if (r_symndx != STN_UNDEF)
{
Elf_Internal_Sym sym;
if (!bed->s->swap_symbol_in (abfd,
(htab->elf.dynsym->contents
+ r_symndx * htab->bytes_per_sym),
0, &sym))
abort ();
/* It's crucial to ensure that relocations against IFUNC symbols
which depend on invocation of resolve functions are processed after
the ones which may be required for the proper functioning of the
resolvers. See `ld_ifunc/pr18841{b,c}' tests for such a
situation. */
if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
return reloc_class_ifunc;
}
}
/* I wonder if it makes sense to sort other classes of relocations . . . */
return reloc_class_normal;
}
bfd_boolean
_bfd_e2k_elf_finish_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
bfd *dynobj;
asection *sdyn;
struct _bfd_e2k_elf_link_hash_table *htab;
bfd_vma targ_off = 0;
htab = _bfd_e2k_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
dynobj = htab->elf.dynobj;
/* Offset of the start of `.data.export_pl' section in GD. It'll be advanced
as new selfinit entries creating PLs in this section are added. */
if (ABI_PM_P (dynobj))
targ_off = (htab->export_pl->output_section->vma
+ htab->export_pl->output_offset);
/* May we look for this section in OUTPUT_BFD rather than in DYNOBJ? It
seems that the corresponding output_section has the SEC_LINKER_CREATED
flag as well. */
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
if (elf_hash_table (info)->dynamic_sections_created)
{
asection *splt;
splt = htab->elf.splt;
BFD_ASSERT (splt != NULL && sdyn != NULL);
if (!e2k_finish_dyn (output_bfd, info, dynobj, sdyn, splt, &targ_off))
return FALSE;
}
/* Setup PLT header required for lazy binding support. */
if (htab->elf.splt
&& htab->elf.splt->size > 0)
{
unsigned i;
for (i = 0; i < htab->plt_got_header_size / 4; i++)
bfd_put_32 (output_bfd, htab->plt_got_header[i],
htab->elf.splt->contents + 4 * i);
}
/* Customize the PLT header in case it's actually used. Note that in Protected
Mode lacking support for lazy binding it's not needed which is made clear
by setting its size to zero. */
if (htab->elf.splt
&& htab->elf.splt->size > 0
&& htab->plt_got_header_size > 0)
{
asection *splt;
asection *sgotplt;
unsigned long omach = bfd_get_mach (output_bfd) / 4;;
/* Until support for specific elbrus-v6 machines has been added I can
check it this way. Note that `>= 6' can't be used here because
specific machines (say, elbrus-{8c,1c+} for elbrus-v4) are marked
with numbers exceeding the maximal possible iset version. */
/* Take into account that delay between load and its consumer has been
increased from 3 to 5 ticks starting from elbrus-v6 (see Bug #112004,
Comment #8). */
unsigned int nops = ((omach == bfd_mach_e2k_ev6
|| omach == bfd_mach_e2k_12c
|| omach == bfd_mach_e2k_16c
|| omach == bfd_mach_e2k_2c3) ? 4 : 2);
unsigned int hs_nop =
htab->plt_got_header[htab->plt_got_header_nop_offset / 4];
/* Adjust HS.nop according to the aforesaid. */
hs_nop = (hs_nop & 0xfffffc7fu) | (nops << 7);
bfd_put_32 (output_bfd, hs_nop,
htab->elf.splt->contents + htab->plt_got_header_nop_offset);
// BFD_ASSERT (htab->elf.splt->size >= htab->plt_lazy_header_size);
splt = htab->elf.splt;
sgotplt = htab->elf.sgotplt;
if (bfd_link_pic (info) && ! ABI_PM_P (dynobj))
{
/* Offset to the start of .gotplt from 'RR %ip' insn in PLT
header. */
bfd_vma off = (sgotplt->output_section->vma + sgotplt->output_offset
- splt->output_section->vma - splt->output_offset);
/* This puts an offset to the entry in .got.plt containing the run-
time address of the link map corresponding to the output
object. */
bfd_put_32 (output_bfd, off + htab->bytes_per_word,
splt->contents + htab->plt_got_link_map_ld_offset);
/* This puts an offset to the entry, containing the run-time address
of `_dl_fixup ()'. */
bfd_put_32 (output_bfd, off + 2 * htab->bytes_per_word,
splt->contents + htab->plt_got_dl_fixup_ld_offset);
}
else
{
int starting_got_entry_size
= (ABI_PM_P (dynobj) ? 16 : htab->bytes_per_word);
/* In non-PIC and PM cases it's just enough to write the address of
`.got.plt' entry number 1 containing `struct link_map *'. The
address of the next entry containing `&_dl_fixup' is accessed by
means of specifying `size_of_PLT_entry' for SRC1 and the same
32-bit LTS for SRC2 for another load within the same wide
instruction. */
bfd_vma addr = adjust_offset_in_cud_gd (info,
(sgotplt->output_section->vma
+ sgotplt->output_offset
+ starting_got_entry_size));
unsigned int ld_offset = htab->plt_got_link_map_ld_offset;
if (ABI_64_P (output_bfd))
{
bfd_put_32 (output_bfd, addr >> 32, splt->contents + ld_offset);
ld_offset += 4;
}
bfd_put_32 (output_bfd, addr & 0xffffffff,
splt->contents + ld_offset);
}
}
/* Set the first entry in the global offset table to the address of
the dynamic section. */
if (htab->elf.sgotplt && htab->elf.sgotplt->size > 0)
{
int i;
bfd_vma val;
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
BFD_ASSERT (htab->elf.sgotplt->size >= bed->got_header_size);
val = (sdyn
? adjust_offset_in_cud_gd (info,
(sdyn->output_section->vma
+ sdyn->output_offset))
: 0);
htab->put_word (output_bfd, val, htab->elf.sgotplt->contents);
/* The second and the third entries will be filled in by ld.so with the
address of the map and that of '_dl_fixup ()' respectively. */
for (i = 0; i < 2; i++)
htab->put_word (output_bfd, 0,
(htab->elf.sgotplt->contents
+ htab->bytes_per_word * (i + 1)));
}
if (ABI_PM_P (htab->elf.dynobj))
{
if (htab->export_pl->size != 0)
{
struct export_pl_list *e;
for (e = htab->export_pl_list; e != NULL; e = e->next)
{
asection *s = e->h->root.u.def.section;
bfd_vma addr = (s->output_section->vma
+ s->output_offset
+ e->h->root.u.def.value);
add_selfinit_pl (info, addr, targ_off, e->h->root.root.string);
targ_off += 16;
}
/* Initialize PL for `_start ()' in `.data.export_pl' when linking an
executable. FIXME: this way a redundant PL is output for a static
executable. */
if (bfd_link_executable (info))
add_selfinit_pl (info, bfd_get_start_address (output_bfd),
targ_off, "_start");
}
}
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_object_p_1 (bfd *abfd,
bfd_boolean protected_mode)
{
Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
int elf_osabi = get_elf_backend_data (abfd)->elf_osabi;
unsigned int mach;
bfd_boolean res;
int pm = 0;
/* Prevent KPDA target from recognizing non-KPDA input file and vice
versa. */
if (elf_osabi != i_ehdrp->e_ident[EI_OSABI]
&& (elf_osabi == ELFOSABI_KPDA
|| i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_KPDA))
return FALSE;
if (i_ehdrp->e_machine == EM_E2K_OLD)
{
/* Check code semantics for old Elf files. */
if (!protected_mode)
{
if (ABI_64_P (abfd))
{
if (i_ehdrp->e_ident[7] != E2K_MPTR_64)
return FALSE;
}
else
{
if (i_ehdrp->e_ident[7] != E2K_MPTR_32)
return FALSE;
}
}
else
{
if (i_ehdrp->e_ident[7] != 5)
return FALSE;
}
mach = EF_E2K_OLD_FLAG_TO_MACH (i_ehdrp->e_flags);
}
else
{
if ((!protected_mode && (i_ehdrp->e_flags & EF_E2K_PM) != 0)
|| (protected_mode && (i_ehdrp->e_flags & EF_E2K_PM) != EF_E2K_PM))
return FALSE;
pm = (i_ehdrp->e_flags & EF_E2K_PM) == EF_E2K_PM;
mach = EF_E2K_FLAG_TO_MACH (i_ehdrp->e_flags);
}
/* Information about ABI is encoded into machine number nowadays. */
mach *= 4;
if (pm)
mach += 2;
else if (! ABI_64_P (abfd))
mach += 1;
/* I suppose that `bfd_default_set_arch_mach ()' should be used instead
of `bfd_set_arch_mach ()', when setting ARCH for an IBFD. The latter
expands into a call a target-specific hook, which is
`_bfd_elf_set_arch_mach ()' for most of ELF targets. This hook performs a
number of checks, which probably don't make much sense right now, prior to
calling `bfd_default_set_arch_mach ()'
If we correct MACH of the OBFD later, e.g. when merging private bfd data,
then `bfd_set_arch_mach ()' should be used. */
res = bfd_default_set_arch_mach (abfd, bfd_arch_e2k, mach);
return res;
}
bfd_boolean
_bfd_e2k_elf_object_p (bfd *abfd)
{
return _bfd_e2k_elf_object_p_1 (abfd, FALSE);
}
bfd *
_bfd_e2k_elf_link_setup_gnu_properties (struct bfd_link_info *info)
{
bfd *pbfd;
struct _bfd_e2k_elf_link_hash_table *htab;
htab = _bfd_e2k_elf_hash_table (info);
pbfd = _bfd_elf_link_setup_gnu_properties (info);
if (htab == NULL
|| bfd_link_relocatable (info))
return pbfd;
/* DYNOBJ may have already been set up in generic ELF code, for example, in
`_bfd_elf_link_create_dynstrtab ()'. */
if (htab->elf.dynobj == NULL)
{
if (pbfd != NULL)
htab->elf.dynobj = pbfd;
else
{
bfd *abfd;
/* Find a normal input file to hold linker created
sections. */
for (abfd = info->input_bfds;
abfd != NULL;
abfd = abfd->link.next)
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
&& (abfd->flags
& (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
{
htab->elf.dynobj = abfd;
break;
}
}
}
/* Hopefully this is the right place for creation of PM-specific subsidiary
`.text.selfinit' and `.data.export_pl' sections. */
if (htab->elf.dynobj && ABI_PM_P (htab->elf.dynobj))
{
/* Now that "_end" is defined conditionally (i.e. via PROVIDE ()) in
shared libraries we need to refer to it so as not to be left without
its definition when it comes to setting the value of DT_PLTGOTSZ. Note
that it seems to be too late to take care of that both in `{size,
finish}_dynamic_sections ()', but quite OK to do this here. */
if (bfd_link_dll (info)
/* This should prevent us from creating a reference if "_end" has
already been referred to from an input relocatable object. FIXME:
can't this happen after we create a reference here? Aren't the two
references going to interfere in some unpredictable way? */
&& elf_link_hash_lookup (elf_hash_table (info), "_end", FALSE,
FALSE, TRUE) == NULL)
{
if (! _bfd_generic_link_add_one_symbol (info, htab->elf.dynobj,
"_end", 0,
bfd_und_section_ptr, 0,
NULL, FALSE, FALSE,
NULL))
return FALSE;
}
/* FIXME: the use of `bfd_make_section ()' here results in a section
filled in with zeroes despite the fact that I allocate its contents
and set it up appropriately. */
htab->selfinit = bfd_make_section_anyway_with_flags
(htab->elf.dynobj, ".text.selfinit",
(SEC_LINKER_CREATED | SEC_HAS_CONTENTS));
htab->selfinit->size = sizeof (selfinit_header)
+ sizeof (selfinit_tail);
htab->export_pl = bfd_make_section_anyway_with_flags
(htab->elf.dynobj, ".data.export_pl",
(SEC_LINKER_CREATED | SEC_HAS_CONTENTS));
/* Ensure that ".data.export_pl" is appropriately aligned in PM. */
if (!bfd_set_section_alignment (htab->export_pl, 4))
info->callbacks->einfo (_("%F%pA: failed to align section\n"),
htab->export_pl);
htab->export_pl->size = 0;
}
return pbfd;
}
struct plt_symbol_indices
{
int *rel_indices;
};
static bfd_vma *
_bfd_e2k_elf_plt_sym_val (bfd *abfd,
asymbol **dynsyms,
asection *plt,
asection *relplt,
int kind,
void *dummy)
{
bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
asection *got = NULL;
bfd_byte *got_contents = NULL;
bfd_byte *plt_contents = plt->contents;
long i, count;
long j;
bfd_vma *plt_sym_val;
Elf_Internal_Shdr *hdr;
bfd_vma off;
bfd_boolean abi64 = ABI_64_P (plt->owner);
bfd_vma addr_in_got;
int max_plt_entries_num;
int *plt_rel_idx;
arelent *rel = relplt->relocation;
if (plt_contents == NULL)
{
plt_contents = (bfd_byte *) bfd_malloc (plt->size);
if (plt_contents == NULL)
return NULL;
/* FIXME: find out why we are passed PLT as `const asection *' while
`asection *' is required to get its contents. */
if (! bfd_get_section_contents (plt->owner, (asection *) plt,
plt_contents, 0, plt->size))
{
free (plt_contents);
return NULL;
}
/* FIXME: how do you like changing the field in a const object? Verify if
it's constant in fact or is just presented this way to us. */
((asection *) plt)->contents = plt_contents;
}
if (kind == 1)
{
/* .got is required only for calculation of "@secondary_plt" synthetic
symbols. */
got = bfd_get_section_by_name (abfd, ".got");
got_contents = got->contents;
if (got_contents == NULL)
{
got_contents = (bfd_byte *) bfd_malloc (got->size);
if (got_contents == NULL)
return NULL;
if (! bfd_get_section_contents (got->owner, got, got_contents, 0,
got->size))
{
free (got_contents);
return NULL;
}
got->contents = got_contents;
}
}
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
return NULL;
hdr = &elf_section_data (relplt)->this_hdr;
/* The number of relocations in .rela.plt for `kind == {0,1}' and in
.rela.dyn for `kind == 2'. */
count = relplt->size / hdr->sh_entsize;
plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count);
if (plt_sym_val == NULL)
return NULL;
if (kind == 0)
{
/* Allocate array storing relocation indices matching primary PLT entries
in the assumption that there are at most 8 entries for now. It'll be
reallocated later if needed. */
max_plt_entries_num = 8;
plt_rel_idx = (int *) bfd_malloc (max_plt_entries_num * sizeof (int));
if (plt_rel_idx == NULL)
{
free (plt_sym_val);
return NULL;
}
}
else
{
/* Use the array prepared during invocation with KIND == 0. */
struct plt_symbol_indices *plt_inds
= (struct plt_symbol_indices *) dummy;
plt_rel_idx = plt_inds->rel_indices;
}
/* -1 means that no symbol of KIND matching the i-th relocation entry has
been found. */
for (i = 0; i < count; i++)
plt_sym_val[i] = -1;
for (off = 0, j = 0; off < plt->size;)
{
bfd_vma next_off;
bfd_vma hs = H_GET_32 (plt->owner, plt_contents + off);
/* Secondary PLT entries are shared between 32/64-bit modes. Skip a
new-style secondary PLT entry. */
if (hs == plt_got_secondary_entry[0])
{
off += 0x20;
continue;
}
/* Skip an old-style secondary PLT entry. It's not used within this
backend anywhere except for this point, therefore an immediate
value for it is used in the comparison below. */
else if (hs == 0x0400c023)
{
off += 0x20;
continue;
}
else if (abi64)
{
/* Skip PIC and non-PIC PLT headers. */
if (hs == plt64_got_non_pic_header[0])
{
off += sizeof (plt64_got_non_pic_header);
continue;
}
else if ((hs & 0xfffffc7f)
== (plt64_got_pic_header[0] & 0xfffffc7f))
{
off += sizeof (plt64_got_pic_header);
continue;
}
/* This is a primary PLT entry which the address of the related entry
in .got may be extracted from and thereby the correspondence with
the dynamic relocation be established. */
else if (hs == plt64_got_non_pic_primary_entry[0]
|| ((hs & 0xfffffc7f)
== (plt64_got_pic_primary_entry[0] & 0xfffffc7f)))
{
/* Handle non-PIC primary PLT entry. */
if (hs == plt64_got_non_pic_primary_entry[0])
{
addr_in_got = ((H_GET_32 (plt->owner,
plt_contents + off + 12) << 32)
+ H_GET_32 (plt->owner,
plt_contents + off + 16));
next_off = off + sizeof (plt64_got_non_pic_primary_entry);
}
else
/* Process PIC one. */
{
addr_in_got = plt->vma + off;
addr_in_got += (int) H_GET_32 (plt->owner,
plt_contents + off + 36);
next_off = off + sizeof (plt64_got_pic_primary_entry);
}
}
/* PLT is damaged and can't be parsed to the end. Let the caller
benefit from partial results of our job. Note that for subsequent
KINDs we should break here as well, which is why there is no risk
of violating plt_rel_idx[] boundaries. */
else
return plt_sym_val;
}
else /* if (!abi64) */
{
/* Skip PIC and non-PIC PLT headers. */
if (hs == plt32_got_non_pic_header[0])
{
off += sizeof (plt32_got_non_pic_header);
continue;
}
else if ((hs & 0xfffffc7f)
== (plt32_got_pic_header[0] & 0xfffffc7f))
{
off += sizeof (plt32_got_pic_header);
continue;
}
/* This is a primary PLT entry which the address of the related entry
in .got may be extracted from and thereby the correspondence with
the dynamic relocation be established. */
else if (hs == plt32_got_non_pic_primary_entry[0]
|| ((hs & 0xfffffc7f)
== (plt32_got_pic_primary_entry[0] & 0xfffffc7f)))
{
/* Handle non-PIC primary PLT entry. */
if (hs == plt32_got_non_pic_primary_entry[0])
{
addr_in_got = H_GET_32 (plt->owner,
plt_contents + off + 16);
next_off = off + sizeof (plt32_got_non_pic_primary_entry);
}
/* Process PIC one. */
else
{
addr_in_got = plt->vma + off;
addr_in_got += (int) H_GET_32 (plt->owner,
plt_contents + off + 36);
next_off = off + sizeof (plt32_got_pic_primary_entry);
}
}
/* PLT is damaged and can't be parsed to the end. Let the caller
benefit from partial results of our job. Note that for subsequent
KINDs we should break here as well, which is why there is no risk
of violating plt_rel_idx[] boundaries. */
else
return plt_sym_val;
}
/* We are looking for either "@plt" or "@plt.got" symbol matching the
currently processed primary PLT entry. Searching the latter makes
sense only if the former hasn't been found, since there should be no
.rela.dyn and .rela.plt dynamic relocations corresponding to the same
primary PLT entry. This saves one the trouble of iterating through a
potentially huge .rela.dyn for most hopeless primary PLT entries.*/
if (kind == 0
|| (kind == 2
/* If there's .rela.dyn but no .rela.plt in ABFD this function
may be called with KIND == 2 only, in which case there's no
`plt_rel_idx[]'. */
&& (plt_rel_idx == NULL
|| plt_rel_idx[j] == -1)))
{
if (kind == 0 && j == max_plt_entries_num)
{
/* There are more primary PLT entries than one supposed. */
max_plt_entries_num *= 2;
plt_rel_idx = bfd_realloc (plt_rel_idx,
max_plt_entries_num * sizeof (int));
if (plt_rel_idx == NULL)
{
free (plt_sym_val);
return NULL;
}
}
/* Look for the matching dynamic relocation in `.rela.{plt,dyn}'
starting from the index next to the previous hit in hope that
primary PLT entries have more or less the same order as their
matching relocations. */
for (i = 0; i < count; i++, rel++)
{
/* Resume from the beginning if the upper boundary has been
crossed. */
if (rel == relplt->relocation + count)
rel = relplt->relocation;
if (addr_in_got == rel->address)
{
int k = rel - relplt->relocation;
plt_sym_val[k] = plt->vma + off;
/* Save the index of the matching .rela.plt entry. There's no
point in doing so when processing .rela.dyn as there'll be
no subsequent invocations. */
if (kind == 0)
plt_rel_idx[j] = k;
/* Ensure that the search for the relocation matching the
next primary PLT entry starts from the next one in
`.rela.{plt,dyn}'. */
rel++;
break;
}
}
/* No .rela.plt relocation matching this primary PLT entry has
been found. Make it clear that one may hope to find the one
in .rela.dyn. */
if (kind == 0 && i == count)
plt_rel_idx[j] = -1;
}
/* "@secondary_plt" symbol may exist only if the related "@plt"
one does. */
else if (kind == 1 && plt_rel_idx[j] != -1)
{
/* There is no point in looking for its relocation index as it
coincides with the one of the "@plt" one. As for its address
it's read from .got. */
if (addr_in_got >= got->vma
&& addr_in_got < got->vma + got->size)
{
bfd_vma secondary_plt_vma;
#define H_GET_XX(o, p) abi64 ? H_GET_64 (o, p) : H_GET_32 (o, p)
secondary_plt_vma
= H_GET_XX (got->owner,
got_contents + addr_in_got - got->vma);
#undef H_GET_XX
/* Ensure that the obtained "@secondary_plt" symbol's address
does actually belong to .plt to be on the safe side. */
if (secondary_plt_vma >= plt->vma
&& secondary_plt_vma < plt->vma + plt->size)
plt_sym_val[plt_rel_idx[j]] = secondary_plt_vma;
}
}
/* Proceed to the next J'th anticipated primary PLT entry which may be
located at NEXT_OFF or further. */
j++;
off = next_off;
}
/* Save plt_rel_idx[] for subsequent invocations. */
if (kind == 0)
{
struct plt_symbol_indices *plt_inds
= (struct plt_symbol_indices *) dummy;
plt_inds->rel_indices = plt_rel_idx;
}
return plt_sym_val;
}
/* Similar to _bfd_elf_get_synthetic_symtab. */
long
_bfd_e2k_elf_get_synthetic_symtab (bfd *abfd,
long symcount,
asymbol **syms,
long dynsymcount,
asymbol **dynsyms,
asymbol **ret)
{
int i;
asection *plt = bfd_get_section_by_name (abfd, ".plt");
long l, res[3];
asymbol *s, *sarr[3];
size_t size;
char *names;
long n;
struct plt_symbol_indices plt_sym_ind;
/* This may remain uninitialized if `_bfd_e2k_elf_plt_sym_val ()' is not
called, for example, if there's no PLT in the disassembled file. */
plt_sym_ind.rel_indices = NULL;
for (i = 0; i < 3; i++)
{
res[i] = _bfd_elf_ifunc_get_synthetic_symtab
(abfd, symcount, syms, dynsymcount, dynsyms,
&sarr[i], plt,
/* Primary or secondary PLT entry or `plt.got' entry. */
i,
&plt_sym_ind,
& _bfd_e2k_elf_plt_sym_val);
}
/* Free it only if it has really been allocated. */
if (plt_sym_ind.rel_indices)
free (plt_sym_ind.rel_indices);
if (res[0] == -1 && res[1] == -1 && res[2] == -1)
return -1;
size = 0;
for (i = 0; i < 3; i++)
{
/* If one of `get_synthetic_symtab ()' has failed just don't take
its result into account. */
if (res[i] != -1)
size += res[i] * sizeof (asymbol);
for (l = 0; l < res[i]; l++)
size += strlen (sarr[i][l].name) + 1;
}
s = *ret = (asymbol *) bfd_malloc (size);
names = (char *) s;
for (i = 0; i < 3; i++)
names += (res[i] != -1 ? res[i] : 0) * sizeof (asymbol);
n = 0;
for (i = 0; i < 3; i++)
{
for (l = 0; l < res[i]; l++)
{
size_t len;
len = strlen (sarr[i][l].name) + 1;
memcpy (names, sarr[i][l].name, len);
s[n] = sarr[i][l];
s[n].name = names;
n++;
names += len;
}
/* Free the intermediate array now that its contents has been copied to
the unified one. */
if (res[i] != -1)
free (sarr[i]);
else
/* Ensure that the bogus intermediate result doesn't spoil the
final one. */
res[i] = 0;
}
return res[0] + res[1] + res[2];
}
bfd_boolean
_bfd_e2k_elf_init_file_header (bfd *abfd,
struct bfd_link_info *info)
{
Elf_Internal_Ehdr *i_ehdrp;
unsigned int mach;
i_ehdrp = elf_elfheader (abfd);
/* Filter out info concerning ABI. */
mach = bfd_get_mach (abfd) / 4;
/* Presumably this function is useless when called either by OBJCOPY or
STRIP because all `e_flags' should be converted via the `copy_private
_bfd_data ()' hook. To avoid duplication, just return in such a case. */
if (info == NULL)
{
/* Ensure that `e_ident[EI_OSABI]' is set properly when GAS produces
output with the new `e_machine' in ELF header. Isn't it going to
introduce unfounded differences between input and output when this
function is invoked on behalf of OBJCOPY or STRIP? */
if (output_new_e_machine)
goto set_elf_osabi;
return TRUE;
}
/* These flags are the same both for EM_E2K_OLD and EM_MCST_ELBRUS. I guess
that they shouldn't be set explicitly here when an output bfd is produced
via OBJCOPY or STRIP. Also see a note concerning semantics below. */
if (_bfd_e2k_elf_hash_table (info))
i_ehdrp->e_flags |= (e2k_ipd
| (e2k_is_x86app ? EF_E2K_X86APP : 0)
| (e2k_is_4mpages ? EF_E2K_4MB_PAGES : 0));
if (! output_new_e_machine)
{
/* `e_machine' should be set explicitly to the old "alternative"
value now that we have the right one which isn't supported
anywhere yet. */
i_ehdrp->e_machine = EM_E2K_OLD;
/* Keep in mind that this function also gets called by OBJCOPY and STRIP
with `info == NULL'. At present I don't remember a true reason for
that. In that case "semantics" (and probably `e_flags') gets copied via
`bfd_e2k_elf_copy_private_bfd_data ()' and one shouldn't attempt to
set it up here (see Bugs #31435, #33851).
FIXME: this check is going to work both for non-PM and PM modes
provided that the corresponding hash tables have the same
`HASH_TABLE_ID's equal to `E2K_ELF_DATA'. */
if (_bfd_e2k_elf_hash_table (info))
{
/* In protected mode set an ancient PM semantic == 5. */
if (abfd->arch_info->mach % 4 == 2)
i_ehdrp->e_ident[7] = 5;
else
{
struct _bfd_e2k_elf_link_hash_table *htab;
htab = _bfd_e2k_elf_hash_table (info);
i_ehdrp->e_ident[7] = htab->ancient_semantics;
}
}
i_ehdrp->e_flags |= EF_E2K_MACH_TO_OLD_FLAG (mach);
/* Find out what this `0x80000000' is needed for. */
i_ehdrp->e_flags |= 0x80000000;
}
else
{
set_elf_osabi:
i_ehdrp->e_flags |= EF_E2K_MACH_TO_FLAG (mach);
if (abfd->arch_info->mach % 4 == 2)
{
i_ehdrp->e_flags |= EF_E2K_PM;
if (pack_cud_gd)
i_ehdrp->e_flags |= EF_E2K_PACK_SEGMENTS;
}
/* This sets e_ident[EI_OSABI == 7] in ELF header only. Nevertheless I
wonder how I managed to do without it when creating new-style ELFs
via binutils-2.18. Probably it worked because ELFOSABI_NONE, which is
set by default, equals to zero. */
if (! _bfd_elf_init_file_header (abfd, info))
return FALSE;
}
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_copy_private_bfd_data_1 (bfd *ibfd, bfd *obfd,
bfd_boolean protected_mode)
{
if (! _bfd_elf_copy_private_bfd_data (ibfd, obfd))
return FALSE;
if (elf_elfheader (obfd)->e_machine == EM_E2K_OLD)
{
/* Nobody is going to set `e_ident[7]' for us no matter whether we
are copying from an old-style (e_machine == EM_E2K_OLD) object
where it is already set or converting a new-style one. */
if (!protected_mode)
elf_elfheader (obfd)->e_ident[7]
= ABI_64_P (obfd) ? E2K_MPTR_64 : E2K_MPTR_32;
else
/* Currently PM objects with C++ hardware support turned off are
assumed. There is no point in copying this value from an input
file even if it is an old-style one. */
elf_elfheader (obfd)->e_ident[7] = 5;
/* The `e_flags' field has already been copied by
`_bfd_elf_copy_private_bfd_data', however when converting to an
old-styled object it should be converted as well. */
if (elf_elfheader (ibfd)->e_machine == EM_MCST_ELBRUS)
{
unsigned long iflags = elf_elfheader (ibfd)->e_flags;
unsigned long mach = EF_E2K_FLAG_TO_MACH (iflags);
/* `EF_E2K_INCOMPAT'-specific behaviour should not be supported
for old-styled objects and executables, since it requires
changes to the Kernel which are to be done simultaneously
with support for new-styled executables. */
if (iflags & EF_E2K_INCOMPAT)
{
_bfd_error_handler
(_("New style object %pB with `EF_E2K_INCOMPAT' flag cannot be "
"converted to an old style %pB"), ibfd, obfd);
return FALSE;
}
elf_elfheader (obfd)->e_flags
= (EF_E2K_MACH_TO_OLD_FLAG (mach) | (iflags & 0xf));
}
}
/* We find ourselves here only if `obfd->e_machine == EM_MCST_ELBRUS'. */
else if (elf_elfheader (ibfd)->e_machine == EM_E2K_OLD)
{
unsigned long iflags = elf_elfheader (ibfd)->e_flags;
unsigned long mach = EF_E2K_OLD_FLAG_TO_MACH (iflags);
/* When converting old objects, `EF_E2K_INCOMPAT' should definitely
not be set. */
elf_elfheader (obfd)->e_flags
= (EF_E2K_MACH_TO_FLAG (mach) | (protected_mode ? EF_E2K_PM : 0)
| (iflags & 0xf));
}
/* Otherwise a straightforward replication of `e_flags' performed by
`_bfd_elf_copy_private_bfd_data' will do. */
return TRUE;
}
bfd_boolean
_bfd_e2k_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
{
return _bfd_e2k_elf_copy_private_bfd_data_1 (ibfd, obfd, FALSE);
}
bfd_boolean
_bfd_e2k_elf_ignore_discarded_relocs (asection *sec)
{
bfd *abfd;
size_t locsymcount;
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *internal_relocs;
Elf_Internal_Rela *rel, *relend;
struct elf_link_hash_entry **sym_hashes;
const struct elf_backend_data *bed;
int r_sym_shift;
if (link_mixed_eir_phase != 1
&& link_mixed_eir_phase !=3)
return FALSE;
abfd = sec->owner;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info;
bed = get_elf_backend_data (abfd);
internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, FALSE);
rel = internal_relocs;
relend = rel + sec->reloc_count * bed->s->int_rels_per_ext_rel;
r_sym_shift = (bed->s->arch_size == 32) ? 8 : 32;
sym_hashes = elf_sym_hashes (abfd);
for ( ; rel < relend; rel++)
{
unsigned long r_symndx = rel->r_info >> r_sym_shift;
struct elf_link_hash_entry *h = NULL;
if (r_symndx == STN_UNDEF)
continue;
if (r_symndx >= locsymcount)
{
h = sym_hashes[r_symndx - locsymcount];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
if (((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& discarded_section (h->root.u.def.section))
/* Don't forget about common symbols. Their sections may
very well be discarded as well. */
|| (h->root.type == bfd_link_hash_common
&& discarded_section (h->root.u.c.p->section)))
#if 0
/* I don't have legal access to this (link) info . . . */
&& (h->root.u.def.next || . . .)
#endif /* 0 */
{
/* Stupidly make it undefined. Is it going to work? */
h->root.type = bfd_link_hash_undefined;
}
}
}
/* free (internal_relocs); */
return TRUE;
}
void
_bfd_e2k_elf_hide_symbol_1 (struct bfd_link_info *info,
struct elf_link_hash_entry *h,
bfd_boolean force_local,
bfd_boolean protected_mode)
{
/* I don't want to hide (make local) symbols from unsuitable
(SEC_EXCLUDE | SEC_DEBUGGING) sections
(see discard_unsuitable_section () before) in EIR linkage
mode. Prevent the code in `elf_link_add_object_symbols ()'
from achieving this. Interestingly enough, there is no attempt
to hide these symbols in binutils-2.21. */
if (link_mixed_eir_phase != 1 && link_mixed_eir_phase != 3)
{
/* Take care that space in .got is reserved for this symbol for the sake
of processing R_E2K_GOTPLT against it in relocate_section before any
mention of its PLT entries is destroyed in `_bfd_elf_link_hash_hide_
symbol ()' below. */
if (!protected_mode && h->type != STT_GNU_IFUNC)
{
if (positive_plt_refcount (h))
discard_plt_refcount (h);
if (positive_secondary_plt_refcount (h))
{
struct _bfd_e2k_elf_link_hash_entry *eh;
eh = (struct _bfd_e2k_elf_link_hash_entry *) h;
BFD_ASSERT (eh->tls_type == GOT_UNKNOWN
|| eh->tls_type == GOT_NORMAL);
h->got.refcount = 1;
eh->tls_type = GOT_NORMAL;
}
}
_bfd_elf_link_hash_hide_symbol (info, h, force_local);
}
}
void
_bfd_e2k_elf_hide_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *h,
bfd_boolean force_local)
{
_bfd_e2k_elf_hide_symbol_1 (info, h, force_local, FALSE);
}
struct write_eir_info
{
bfd_size_type max_size;
bfd_byte *contents;
/* This is set to FALSE if `_bfd_e2k_write_eir_contens ()' fails
for any section. */
bfd_boolean res;
};
static void
_bfd_e2k_write_eir_contents (bfd *abfd ATTRIBUTE_UNUSED,
asection *s,
void *param)
{
static bfd_vma s_offset;
bfd_vma next_s_offset;
bfd_vma mask;
struct bfd_link_order *p;
struct write_eir_info *wei;
/* There is nothing to do for non-EIR sections. */
if (strcmp (s->name, ".pack_pure_eir") != 0
&& strcmp (s->name, ".pack_mixed_eir") != 0)
return;
wei = (struct write_eir_info *) param;
/* If we've already failed, there is no point in continuing. */
if (wei->res == FALSE)
return;
mask = (1 << s->alignment_power) - 1;
s_offset = (s_offset + mask) & ~mask;
next_s_offset = s_offset;
for (p = s->map_head.link_order; p != NULL; p = p->next)
{
asection *i;
if (p->type != bfd_indirect_link_order)
continue;
i = p->u.indirect.section;
if (i->size > 0)
{
if (i->size > wei->max_size)
{
wei->max_size = i->size;
wei->contents = (bfd_byte *) bfd_realloc (wei->contents,
wei->max_size);
}
if (s_offset + i->output_offset + i->size > next_s_offset)
next_s_offset = s_offset + i->output_offset + i->size;
if (! bfd_get_section_contents (i->owner, i, wei->contents,
0, i->size)
|| bfd_seek (abfd, s_offset + i->output_offset, SEEK_SET) != 0
|| bfd_bwrite (wei->contents, i->size, abfd) != i->size)
{
wei->res = FALSE;
return;
}
}
}
/* Setting initial `s_offset' value for the next invocation. */
s_offset = next_s_offset;
}
/* This function gets called when BFD is being closed. Avoid calling
an ELF-specific method (which outputs strtab, . . .) when a raw
binary for EIR is required. */
bfd_boolean
_bfd_e2k_elf_write_object_contents (bfd *abfd)
{
struct write_eir_info wei;
if (link_mixed_eir_phase != 2)
return _bfd_elf_write_object_contents (abfd);
wei.max_size = 0;
wei.contents = NULL;
wei.res = TRUE;
/* Calculating positions of EIR sections and setting their contents. */
bfd_map_over_sections (abfd, _bfd_e2k_write_eir_contents, &wei);
if (wei.contents)
free (wei.contents);
return wei.res;
}
/* Here come DSP-related hooks. */
static void
_bfd_e2k_look_for_dsp_input (bfd *abfd ATTRIBUTE_UNUSED, asection *s,
void *inf)
{
int is_data = 0;
int is_rodata = 0;
struct bfd_link_info *info = (struct bfd_link_info *) inf;
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
if ((CONST_STRNEQ (s->name, ".dsp_text")
|| (CONST_STRNEQ (s->name, ".dsp_data") && (is_data = 1))
|| (CONST_STRNEQ (s->name, ".dsp_rodata") && (is_rodata = 1))
|| CONST_STRNEQ (s->name, "DSP_COMMON"))
&& s->size > 0)
{
htab->have_dsp_output = TRUE;
if (is_data)
{
int data_idx = atoi (&s->name[9]);
BFD_ASSERT (data_idx >= 0 && data_idx <= 15);
htab->dsp_non_empty_data[data_idx] = TRUE;
}
else if (is_rodata)
{
int rodata_idx = atoi (&s->name[11]);
BFD_ASSERT (rodata_idx >= 0 && rodata_idx <= 15);
htab->dsp_non_empty_rodata[rodata_idx] = TRUE;
}
}
}
/* As far as I understand, this function is to be called for each input BFD
which takes part in link. Therefore, it seems to be appropriate to determine
here whether we have non-empty input DSP sections.
It was an error to do this in `_bfd_e2k_elf_object_p ()' method which may be
called for the first member of `.a'-library. Imagine that this object file
isn't actually pulled into the link later but contains non-empty `.dsp_data'.
A faulty `dsp_non_empty_data[]' may be set in this case. This used to be a
reason for the problem described in the external Bug #477, Comment #5).
Probably, it's possible to do this in `_bfd_e2k_merge_private_bfd_data ()'
as well, but this function seems to be more appropriate, doesn't it? */
bfd_boolean
_bfd_e2k_elf_check_directives (bfd *abfd, struct bfd_link_info *info)
{
/* Do I really need to duplicate this in my hash table? */
struct _bfd_e2k_elf_link_hash_table *htab = _bfd_e2k_elf_hash_table (info);
if (e2k_dsp_linux_mode)
{
bfd_boolean prior = htab->have_dsp_output;
bfd_map_over_sections (abfd, _bfd_e2k_look_for_dsp_input, info);
/* May I create a section at the expense of this bfd here? */
if (!prior && htab->have_dsp_output)
{
asection *s;
/* What flags should be specified here? */
s = bfd_make_section_with_flags (abfd, ".dsp_mem", SEC_ALLOC);
bfd_set_section_alignment (s, 12);
s->size = 2560 * 1024;
}
}
return TRUE;
}
/* It's such a bore that I determine a dsp section index here based
on its name. */
static unsigned int
get_dsp_data_section_idx (const char *sec_name)
{
static const char *dsp_tpls[] = {".dsp_data", ".dsp_rodata", ".dsp_bss"};
int i;
for (i = 0; i < 3; i++)
{
unsigned long idx;
char *endptr;
size_t dsp_tpl_len = strlen (dsp_tpls[i]);
if (strncmp (sec_name, dsp_tpls[i], dsp_tpl_len) != 0
|| sec_name[dsp_tpl_len + 2] != '\0')
continue;
idx = strtoul (&sec_name[dsp_tpl_len], &endptr, 10);
if (endptr != &sec_name[dsp_tpl_len + 2] || idx > 15)
return (unsigned int) -1;
return (unsigned int) idx;
}
return -1;
}
const struct bfd_elf_special_section
_bfd_e2k_elf_special_sections[]=
{
{ STRING_COMMA_LEN (".dsp_bss00"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss01"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss02"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss03"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss04"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss05"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss06"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss07"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss08"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss09"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss10"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss11"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss12"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss13"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss14"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".dsp_bss15"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".magic"), 0, SHT_NOTE, 0 },
{ NULL, 0, 0, 0, 0 }
};
bfd_boolean
_bfd_e2k_elf_common_definition (Elf_Internal_Sym *sym)
{
if (sym->st_shndx >= SHN_DSP_COMMON_00
&& sym->st_shndx <= SHN_DSP_COMMON_15)
return TRUE;
return _bfd_elf_common_definition (sym);
}
void
_bfd_e2k_elf_merge_symbol_attribute
(struct elf_link_hash_entry *h,
const Elf_Internal_Sym *isym ATTRIBUTE_UNUSED,
bfd_boolean definition ATTRIBUTE_UNUSED,
bfd_boolean dynamic ATTRIBUTE_UNUSED)
{
/* FIXME: should it be determined whether a symbol is DSP by its
nature or not when reading input files? Probably it'd be better
to do this during the relocation process. In the latter case
there would probably be no trouble with common symbols. */
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
const char *sec_name = h->root.u.def.section->name;
if (CONST_STRNEQ (sec_name, ".dsp_text")
|| (get_dsp_data_section_idx (sec_name) != (unsigned int) -1))
{
struct _bfd_e2k_elf_link_hash_entry *eh
= (struct _bfd_e2k_elf_link_hash_entry *) h;
eh->dsp_symbol = TRUE;
}
}
/* Common symbols spoil our life. */
else if (h->root.type == bfd_link_hash_common)
{
if (CONST_STRNEQ (h->root.u.c.p->section->name, "DSP_COMMON"))
{
struct _bfd_e2k_elf_link_hash_entry *eh
= (struct _bfd_e2k_elf_link_hash_entry *) h;
eh->dsp_symbol = TRUE;
}
}
}
/* Support for core dump NOTE sections. */
bfd_boolean
_bfd_e2k_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
{
/* pr_cursig */
elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
/* Get pr_pid field. */
elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32);
/* Make a ".reg/999" section.
FIXME: get rid of hardcoded numerical values for size and offset. */
return _bfd_elfcore_make_pseudosection
(abfd, ".reg", note->descsz - 120, note->descpos + 112);
}
char *
_bfd_e2k_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz,
int note_type, ...)
{
switch (note_type)
{
default:
return NULL;
case NT_PRPSINFO:
{
/* `sizeof (struct elf_prpsinfo) == 136' within the Kernel. */
char data[136];
va_list ap;
va_start (ap, note_type);
memset (data, 0, sizeof (data));
/* Set `char pr_fname[16]' located at offset 40 within `struct
elf_prpsinfo'. */
strncpy (data + 40, va_arg (ap, const char *), 16);
/* Set `char pr_psargs[80]' located at offset 56 within `struct
elf_prpsinfo'. */
strncpy (data + 56, va_arg (ap, const char *), 80);
va_end (ap);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", note_type, data, sizeof (data));
}
case NT_PRSTATUS:
{
/* This is the `sizeof (struct elf_prstatus)' within the Kernel:
`4864 == (sizeof (user_regs_struct) == 4744) + 120 bytes distributed
over a few other fields'. */
char data[4864];
va_list ap;
long pid;
int cursig;
const void *greg;
va_start (ap, note_type);
memset (data, 0, sizeof (data));
/* Set `pr_pid' 32-bit field located at offset 32 within `struct
elf_prstatus'. */
pid = va_arg (ap, long);
bfd_put_32 (abfd, pid, data + 32);
/* Set `pr_cursig' 16-bit field located at offset 12 within `struct
elf_prstatus'. */
cursig = va_arg (ap, int);
bfd_put_16 (abfd, cursig, data + 12);
/* Set `elf_gregset_t pr_reg' field (it has a type of `user_regs_struct'
in fact occupying 4744 bytes at offset 12 within `struct elf_
prstatus'. */
greg = va_arg (ap, const void *);
memcpy (data + 112, greg, 4744);
va_end (ap);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", note_type, data, sizeof (data));
}
}
}