This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
[PATCH] My current SPARC patches
On Thu, Jul 08, 1999 at 03:50:13PM -0700, Richard Henderson wrote:
> On Mon, Jul 05, 1999 at 05:47:29PM +0200, Jakub Jelinek wrote:
> > This patch adds support for R_SPARC_OLO10 relocation.
>
> I'm getting errors compiling this code.
>
> gcc -DHAVE_CONFIG_H -I. -I../../../binutils/bfd -I. -D_GNU_SOURCE -I. -I../../..
> /binutils/bfd -I../../../binutils/bfd/../include -I../../../binutils/bfd/../intl
> -I../intl -g -O2 -c ../../../binutils/bfd/elf64-sparc.c -o elf64-sparc.o
> .../elf64-sparc.c:2636: warning: initialization makes integer from pointer without a cast
> .../elf64-sparc.c:2636: initializer element is not computable at load time
That's because of the mips64 changes which went in two days ago after I
submited my patch. Below are all my current patches against current cvs
with the exception of the emulparams/elf64_sparc.sh.
>
> These bits I went ahead and put in.
Thanks.
elf64-sparc.c was not compiling because it used DT_SPARC_PLTFMT, which is
now removed. This is the Diff-pltfmt patch.
ELF64_R_TYPE_DATA is always used on the whole r_info, so the macro has to
mask out ELF64_R_TYPE bits. This is the second patch,
Diff-elf64-r-type-data.
Then there is a c-sparc.texi update and then STT_REGISTER and R_SPARC_OLO10
patches.
Cheers,
Jakub
___________________________________________________________________
Jakub Jelinek | jj@sunsite.mff.cuni.cz | http://sunsite.mff.cuni.cz
Administrator of SunSITE Czech Republic, MFF, Charles University
___________________________________________________________________
UltraLinux | http://ultra.linux.cz/ | http://ultra.penguin.cz/
Linux version 2.2.10 on a sparc64 machine (1343.49 BogoMips)
___________________________________________________________________
1999-07-09 Jakub Jelinek <jj@ultra.linux.cz>
* bfd/elf64-sparc.c (sparc64_elf_size_dynamic_sections): Remove
DT_SPARC_PLTFMT.
--- bfd/elf64-sparc.c.jj3 Fri Jul 9 13:36:00 1999
+++ bfd/elf64-sparc.c Fri Jul 9 13:48:07 1999
@@ -1762,9 +1762,7 @@ sparc64_elf_size_dynamic_sections (outpu
if (! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0)
|| ! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0)
|| ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
- || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_SPARC_PLTFMT,
- (info->shared != 0) + 1))
+ || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0))
return false;
}
1999-07-09 Jakub Jelinek <jj@ultra.linux.cz>
* sparc.h (ELF64_R_TYPE_DATA): Only use ELF64_R_TYPE bits, not
ELF64_R_SYM bits.
--- include/elf/sparc.h.jj Fri Jul 9 12:23:51 1999
+++ include/elf/sparc.h Fri Jul 9 14:16:50 1999
@@ -139,7 +139,7 @@ END_RELOC_NUMBERS
/* Relocation macros. */
#define ELF64_R_TYPE_DATA(info) \
- (((bfd_signed_vma)((info) >> 8) ^ 0x800000) - 0x800000)
+ (((bfd_signed_vma)(ELF64_R_TYPE(info) >> 8) ^ 0x800000) - 0x800000)
#define ELF64_R_TYPE_ID(info) \
((info) & 0xff)
#define ELF64_R_TYPE_INFO(data, type) \
1999-07-09 Jakub Jelinek <jj@ultra.linux.cz>
* gas/doc/c-sparc.texi: Document .register and .nword pseudo-ops.
--- ./gas/doc/c-sparc.texi.jj4 Mon May 3 09:28:45 1999
+++ ./gas/doc/c-sparc.texi Sat Jul 3 18:38:25 1999
@@ -145,11 +145,24 @@ syntax is different.
@item .half
This is functionally identical to @code{.short}.
+@cindex @code{nword} directive, SPARC
+@item .nword
+On the Sparc, the @code{.nword} directive produces native word sized value,
+ie. if assembling with -32 it is equivalent to @code{.word}, if assembling
+with -64 it is equivalent to @code{.xword}.
+
@cindex @code{proc} directive, SPARC
@item .proc
This directive is ignored. Any text following it on the same
line is also ignored.
+@cindex @code{register} directive, SPARC
+@item .register
+This directive declares use of a global application or system register.
+It must be followed by a register name %g2, %g3, %g6 or %g7, comma and
+the symbol name for that register or @code{#scratch} if it is a scratch
+register.
+
@cindex @code{reserve} directive, SPARC
@item .reserve
This must be followed by a symbol name, a positive number, and
@@ -176,4 +189,3 @@ instead of the 16 bit values it produces
On the Sparc V9 processor, the @code{.xword} directive produces
64 bit values.
@end table
-
1999-07-09 Jakub Jelinek <jj@ultra.linux.cz>
* bfd/elf-bfd.h (struct elf_backend_data): Add
print_symbol_all and output_arch_syms backend methods.
* bfd/elfxx-target.h: Likewise.
* bfd/elf64-sparc.c (sparc64_elf_bfd_link_hash_table_create,
sparc64_elf_add_symbol_hook, sparc64_elf_output_arch_syms,
sparc64_elf_get_symbol_type, sparc64_elf_symbol_processing): New
functions.
(sparc64_elf_size_dynamic_sections): Leave space for STT_REGISTER
symbols in .dynsym, add their names into .dynstr. Use generic
_bfd_elf_link_adjust_dynindx instead of sparc64_elf_adjust_dynindx).
(sparc64_elf_adjust_dynindx): Remove.
(sparc64_elf_finish_dynamic_sections): Output STT_REGISTER symbols
into .dynsym, fix up DT_SPARC_REGISTER pointers to them.
(sparc64_elf_print_symbol_all): New function.
* bfd/elf.c (bfd_elf_print_symbol): Allow special backend symbol
printing using the print_symbol_all hook.
* bfd/elflink.h (elf_bfd_final_link): Allow backend to emit some
global symbols which don't live in the symbol hash table.
* gas/config/tc-sparc.c (md_longopts): Add --no-undeclared-regs
option.
(sparc_ip): Warn if %g2 or %g3 register is used and not covered
by .register pseudo-op if -64 and --no-undeclared-regs.
(s_register, sparc_adjust_symtab): New functions.
* gas/config/tc-sparc.h (tc_adjust_symtab, sparc_adjust_symtab):
Declare sparc_adjust_symtab as tc_adjust_symtab.
--- ./bfd/elf-bfd.h.jj2 Fri Jul 9 12:17:32 1999
+++ ./bfd/elf-bfd.h Fri Jul 9 13:36:00 1999
@@ -550,6 +550,21 @@ struct elf_backend_data
void (*elf_backend_post_process_headers)
PARAMS ((bfd *, struct bfd_link_info *));
+ /* This function, if defined, prints a symbol to file and returns the
+ name of the symbol to be printed. It should return NULL to fall
+ back to default symbol printing. */
+ const char *(*elf_backend_print_symbol_all)
+ PARAMS ((bfd *, PTR, asymbol *));
+
+ /* This function, if defined, is called after all local symbols and
+ global symbols converted to locals are emited into the symtab
+ section. It allows the backend to emit special global symbols
+ not handled in the hash table. */
+ boolean (*elf_backend_output_arch_syms)
+ PARAMS ((struct bfd_link_info *, PTR,
+ boolean (*) PARAMS ((PTR, const char *,
+ Elf_Internal_Sym *, asection *))));
+
/* The swapping table to use when dealing with ECOFF information.
Used for the MIPS ELF .mdebug section. */
const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
--- ./bfd/elf64-sparc.c.jj2 Fri Jul 9 13:27:07 1999
+++ ./bfd/elf64-sparc.c Fri Jul 9 13:36:00 1999
@@ -32,6 +32,8 @@ Foundation, Inc., 59 Temple Place - Suit
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
#define MINUS_ONE (~ (bfd_vma) 0)
+static struct bfd_link_hash_table * sparc64_elf_bfd_link_hash_table_create
+ PARAMS((bfd *));
static reloc_howto_type *sparc64_elf_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void sparc64_elf_info_to_howto
@@ -51,8 +53,13 @@ static boolean sparc64_elf_adjust_dynami
PARAMS((struct bfd_link_info *, struct elf_link_hash_entry *));
static boolean sparc64_elf_size_dynamic_sections
PARAMS((bfd *, struct bfd_link_info *));
-static boolean sparc64_elf_adjust_dynindx
- PARAMS((struct elf_link_hash_entry *, PTR));
+static int sparc64_elf_get_symbol_type
+ PARAMS (( Elf_Internal_Sym *, int));
+static boolean sparc64_elf_add_symbol_hook
+ PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
+ const char **, flagword *, asection **, bfd_vma *));
+static void sparc64_elf_symbol_processing
+ PARAMS ((bfd *, asymbol *));
static boolean sparc64_elf_merge_private_bfd_data
PARAMS ((bfd *, bfd *));
@@ -598,6 +605,54 @@ sparc64_elf_write_relocs (abfd, sec, dat
}
}
+/* Sparc64 ELF linker hash table. */
+
+struct sparc64_elf_app_reg
+{
+ unsigned char bind;
+ unsigned short shndx;
+ bfd_size_type dynstr_index;
+ bfd *abfd;
+ char *name;
+};
+
+struct sparc64_elf_link_hash_table
+{
+ struct elf_link_hash_table root;
+
+ struct sparc64_elf_app_reg app_regs [4];
+ int dynindx_reg_base;
+};
+
+/* Get the Sparc64 ELF linker hash table from a link_info structure. */
+
+#define sparc64_elf_hash_table(p) \
+ ((struct sparc64_elf_link_hash_table *) ((p)->hash))
+
+/* Create a Sparc64 ELF linker hash table. */
+
+static struct bfd_link_hash_table *
+sparc64_elf_bfd_link_hash_table_create (abfd)
+ bfd *abfd;
+{
+ struct sparc64_elf_link_hash_table *ret;
+
+ ret = ((struct sparc64_elf_link_hash_table *)
+ bfd_zalloc (abfd, sizeof (struct sparc64_elf_link_hash_table)));
+ if (ret == (struct sparc64_elf_link_hash_table *) NULL)
+ return NULL;
+
+ if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
+ _bfd_elf_link_hash_newfunc))
+ {
+ bfd_release (abfd, ret);
+ return NULL;
+ }
+
+ return &ret->root.root;
+}
+
+
/* Utility for performing the standard initial work of an instruction
relocation.
*PRELOCATION will contain the relocated item.
@@ -1198,6 +1253,202 @@ sparc64_elf_check_relocs (abfd, info, se
return true;
}
+/* Hook called by the linker routine which adds symbols from an object
+ file. We use it for STT_REGISTER symbols. */
+
+static boolean
+sparc64_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ const Elf_Internal_Sym *sym;
+ const char **namep;
+ flagword *flagsp;
+ asection **secp;
+ bfd_vma *valp;
+{
+ static char *stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" };
+
+ if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER)
+ {
+ int reg;
+ struct sparc64_elf_app_reg *p;
+
+ reg = (int)sym->st_value;
+ switch (reg & ~1)
+ {
+ case 2: reg -= 2; break;
+ case 6: reg -= 4; break;
+ default:
+ (*_bfd_error_handler)
+ (_("%s: Only registers %%g[2367] can be declared using STT_REGISTER"),
+ bfd_get_filename (abfd));
+ return false;
+ }
+
+ if (info->hash->creator != abfd->xvec
+ || (abfd->flags & DYNAMIC) != 0)
+ {
+ /* STT_REGISTER only works when linking an elf64_sparc object.
+ If STT_REGISTER comes from a dynamic object, don't put it into
+ the output bfd. The dynamic linker will recheck it. */
+ *namep = NULL;
+ return true;
+ }
+
+ p = sparc64_elf_hash_table(info)->app_regs + reg;
+
+ if (p->name != NULL && strcmp (p->name, *namep))
+ {
+ (*_bfd_error_handler)
+ (_("Register %%g%d used incompatibly: "
+ "previously declared in %s to %s, in %s redefined to %s"),
+ (int)sym->st_value,
+ bfd_get_filename (p->abfd), *p->name ? p->name : "#scratch",
+ bfd_get_filename (abfd), **namep ? *namep : "#scratch");
+ return false;
+ }
+
+ if (p->name == NULL)
+ {
+ if (**namep)
+ {
+ struct elf_link_hash_entry *h;
+
+ h = (struct elf_link_hash_entry *)
+ bfd_link_hash_lookup (info->hash, *namep, false, false, false);
+
+ if (h != NULL)
+ {
+ unsigned char type = h->type;
+
+ if (type > STT_FUNC) type = 0;
+ (*_bfd_error_handler)
+ (_("Symbol `%s' has differing types: "
+ "previously %s, REGISTER in %s"),
+ *namep, stt_types [type], bfd_get_filename (abfd));
+ return false;
+ }
+
+ p->name = bfd_hash_allocate (&info->hash->table,
+ strlen (*namep) + 1);
+ if (!p->name)
+ return false;
+
+ strcpy (p->name, *namep);
+ }
+ else
+ p->name = "";
+ p->bind = ELF_ST_BIND (sym->st_info);
+ p->abfd = abfd;
+ p->shndx = sym->st_shndx;
+ }
+ else
+ {
+ if (p->bind == STB_WEAK
+ && ELF_ST_BIND (sym->st_info) == STB_GLOBAL)
+ {
+ p->bind = STB_GLOBAL;
+ p->abfd = abfd;
+ }
+ }
+ *namep = NULL;
+ return true;
+ }
+ else if (! *namep || ! **namep)
+ return true;
+ else
+ {
+ int i;
+ struct sparc64_elf_app_reg *p;
+
+ p = sparc64_elf_hash_table(info)->app_regs;
+ for (i = 0; i < 4; i++, p++)
+ if (p->name != NULL && ! strcmp (p->name, *namep))
+ {
+ unsigned char type = ELF_ST_TYPE (sym->st_info);
+
+ if (type > STT_FUNC) type = 0;
+ (*_bfd_error_handler)
+ (_("Symbol `%s' has differing types: "
+ "REGISTER in %s, %s in %s"),
+ *namep, bfd_get_filename (p->abfd), stt_types [type],
+ bfd_get_filename (abfd));
+ return false;
+ }
+ }
+ return true;
+}
+
+/* This function takes care of emmiting STT_REGISTER symbols
+ which we cannot easily keep in the symbol hash table. */
+
+static boolean
+sparc64_elf_output_arch_syms (info, finfo, func)
+ struct bfd_link_info *info;
+ PTR finfo;
+ boolean (*func) PARAMS ((PTR, const char *,
+ Elf_Internal_Sym *, asection *));
+{
+ int reg;
+ struct sparc64_elf_app_reg *app_regs =
+ sparc64_elf_hash_table(info)->app_regs;
+ Elf_Internal_Sym sym;
+
+ if (info->strip == strip_all)
+ return true;
+
+ for (reg = 0; reg < 4; reg++)
+ if (app_regs [reg].name != NULL)
+ {
+ if (info->strip == strip_some
+ && bfd_hash_lookup (info->keep_hash,
+ app_regs [reg].name,
+ false, false) == NULL)
+ continue;
+
+ sym.st_value = reg < 2 ? reg + 2 : reg + 4;
+ sym.st_size = 0;
+ sym.st_other = 0;
+ sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER);
+ sym.st_shndx = app_regs [reg].shndx;
+ if (! (*func) (finfo, app_regs [reg].name, &sym,
+ sym.st_shndx == SHN_ABS
+ ? bfd_abs_section_ptr : bfd_und_section_ptr))
+ return false;
+ }
+
+ return true;
+}
+
+static int
+sparc64_elf_get_symbol_type (elf_sym, type)
+ Elf_Internal_Sym * elf_sym;
+ int type;
+{
+ if (ELF_ST_TYPE (elf_sym->st_info) == STT_REGISTER)
+ return STT_REGISTER;
+ else
+ return type;
+}
+
+/* A STB_GLOBAL,STT_REGISTER symbol should be BSF_GLOBAL
+ even in SHN_UNDEF section. */
+
+static void
+sparc64_elf_symbol_processing (abfd, asym)
+ bfd *abfd;
+ asymbol *asym;
+{
+ elf_symbol_type *elfsym;
+
+ elfsym = (elf_symbol_type *) asym;
+ if (elfsym->internal_elf_sym.st_info
+ == ELF_ST_INFO (STB_GLOBAL, STT_REGISTER))
+ {
+ asym->flags |= BSF_GLOBAL;
+ }
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
@@ -1497,6 +1748,9 @@ sparc64_elf_size_dynamic_sections (outpu
must add the entries now so that we get the correct size for
the .dynamic section. The DT_DEBUG entry is filled in by the
dynamic linker and used by the debugger. */
+ int i, c;
+ struct sparc64_elf_app_reg * app_regs;
+
if (! info->shared)
{
if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0))
@@ -1525,6 +1779,44 @@ sparc64_elf_size_dynamic_sections (outpu
if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
return false;
}
+
+ /* Add dynamic STT_REGISTER symbols and corresponding DT_SPARC_REGISTER
+ entries if needed. */
+ app_regs = sparc64_elf_hash_table (info)->app_regs;
+ c = 0;
+ for (i = 0; i < 4; i++)
+ if (app_regs [i].name != NULL)
+ {
+ if (! bfd_elf64_add_dynamic_entry (info, DT_SPARC_REGISTER, 0))
+ return false;
+ c++;
+ }
+
+ if (c)
+ {
+ struct bfd_strtab_hash *dynstr;
+
+ dynstr = elf_hash_table (info)->dynstr;
+ BFD_ASSERT (dynstr != NULL);
+
+ elf_link_hash_traverse (elf_hash_table (info),
+ _bfd_elf_link_adjust_dynindx,
+ (PTR) &c);
+ elf_hash_table (info)->dynsymcount += c;
+
+ for (i = 0; i < 4; i++)
+ if (app_regs [i].name != NULL
+ && *app_regs [i].name != '\0')
+ {
+ app_regs [i].dynstr_index =
+ _bfd_stringtab_add (dynstr, app_regs [i].name, true, false);
+ if (app_regs [i].dynstr_index == (bfd_size_type) -1)
+ return false;
+ }
+
+ /* The first symbol in .dynsym is a dummy. */
+ sparc64_elf_hash_table (info)->dynindx_reg_base = 1;
+ }
}
/* If we are generating a shared library, we generate a section
@@ -1552,29 +1844,15 @@ sparc64_elf_size_dynamic_sections (outpu
}
elf_link_hash_traverse (elf_hash_table (info),
- sparc64_elf_adjust_dynindx,
+ _bfd_elf_link_adjust_dynindx,
(PTR) &c);
elf_hash_table (info)->dynsymcount += c;
+ sparc64_elf_hash_table (info)->dynindx_reg_base += c;
}
return true;
}
-/* Increment the index of a dynamic symbol by a given amount. Called
- via elf_link_hash_traverse. */
-
-static boolean
-sparc64_elf_adjust_dynindx (h, cparg)
- struct elf_link_hash_entry *h;
- PTR cparg;
-{
- int *cp = (int *) cparg;
-
- if (h->dynindx != -1)
- h->dynindx += *cp;
- return true;
-}
-
/* Relocate a SPARC64 ELF section. */
@@ -2398,6 +2676,7 @@ sparc64_elf_finish_dynamic_sections (out
bfd *dynobj;
asection *sdyn;
asection *sgot;
+ Elf64_External_Dyn *dt_register_dyn = NULL;
dynobj = elf_hash_table (info)->dynobj;
@@ -2426,6 +2705,10 @@ sparc64_elf_finish_dynamic_sections (out
case DT_PLTGOT: name = ".plt"; size = false; break;
case DT_PLTRELSZ: name = ".rela.plt"; size = true; break;
case DT_JMPREL: name = ".rela.plt"; size = false; break;
+ case DT_SPARC_REGISTER:
+ if (dt_register_dyn == NULL)
+ dt_register_dyn = dyncon;
+ /* fallthrough */
default: name = NULL; size = false; break;
}
@@ -2523,6 +2806,53 @@ sparc64_elf_finish_dynamic_sections (out
elf_section_data (sdynsym->output_section)->this_hdr.sh_info = c + 1;
}
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ int reg;
+ struct sparc64_elf_app_reg *app_regs =
+ sparc64_elf_hash_table(info)->app_regs;
+ asection *sdynsym;
+ Elf_Internal_Sym sym;
+ Elf_Internal_Dyn dyn;
+ int c = sparc64_elf_hash_table (info)->dynindx_reg_base;
+
+ /* Set up the STT_REGISTER dynamic symbols. */
+
+ sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
+ BFD_ASSERT (sdynsym != NULL);
+
+ sym.st_size = 0;
+ sym.st_other = 0;
+
+ for (reg = 0; reg < 4; reg++)
+ if (app_regs [reg].name != NULL)
+ {
+ sym.st_value = reg < 2 ? reg + 2 : reg + 4;
+ sym.st_size = 0;
+ sym.st_name = app_regs [reg].dynstr_index;
+ sym.st_other = 0;
+ sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER);
+ sym.st_shndx = app_regs [reg].shndx;
+ bfd_elf64_swap_symbol_out (output_bfd, &sym,
+ (PTR) (((Elf64_External_Sym *)
+ sdynsym->contents)
+ + c));
+ if (dt_register_dyn == NULL)
+ return false;
+
+ bfd_elf64_swap_dyn_in (dynobj, dt_register_dyn, &dyn);
+
+ if (dyn.d_tag != DT_SPARC_REGISTER)
+ return false;
+
+ dyn.d_un.d_val = c;
+ bfd_elf64_swap_dyn_out (output_bfd, &dyn, dt_register_dyn);
+
+ ++dt_register_dyn;
+ ++c;
+ }
+ }
+
return true;
}
@@ -2599,7 +2929,34 @@ sparc64_elf_merge_private_bfd_data (ibfd
}
return true;
}
+
+/* Print a STT_REGISTER symbol to file FILE. */
+static const char *
+sparc64_elf_print_symbol_all (abfd, filep, symbol)
+ bfd *abfd;
+ PTR filep;
+ asymbol *symbol;
+{
+ FILE *file = (FILE *) filep;
+ int reg, type;
+
+ if (ELF_ST_TYPE (((elf_symbol_type *) symbol)->internal_elf_sym.st_info)
+ != STT_REGISTER)
+ return NULL;
+
+ reg = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
+ type = symbol->flags;
+ fprintf (file, "REG_%c%c%11s%c%c R", "GOLI" [reg / 8], '0' + (reg & 7), "",
+ ((type & BSF_LOCAL)
+ ? (type & BSF_GLOBAL) ? '!' : 'l'
+ : (type & BSF_GLOBAL) ? 'g' : ' '),
+ (type & BSF_WEAK) ? 'w' : ' ');
+ if (symbol->name == NULL || symbol->name [0] == '\0')
+ return "#scratch";
+ else
+ return symbol->name;
+}
/* Set the right machine number for a SPARC64 ELF file. */
@@ -2664,6 +3021,9 @@ const struct elf_size_info sparc64_elf_s
/* This is the value that we used before the ABI was released. */
#define ELF_MACHINE_ALT1 EM_OLD_SPARCV9
+#define bfd_elf64_bfd_link_hash_table_create \
+ sparc64_elf_bfd_link_hash_table_create
+
#define elf_info_to_howto \
sparc64_elf_info_to_howto
#define bfd_elf64_get_reloc_upper_bound \
@@ -2677,6 +3037,12 @@ const struct elf_size_info sparc64_elf_s
#define elf_backend_create_dynamic_sections \
_bfd_elf_create_dynamic_sections
+#define elf_backend_add_symbol_hook \
+ sparc64_elf_add_symbol_hook
+#define elf_backend_get_symbol_type \
+ sparc64_elf_get_symbol_type
+#define elf_backend_symbol_processing \
+ sparc64_elf_symbol_processing
#define elf_backend_check_relocs \
sparc64_elf_check_relocs
#define elf_backend_adjust_dynamic_symbol \
@@ -2689,6 +3055,10 @@ const struct elf_size_info sparc64_elf_s
sparc64_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
sparc64_elf_finish_dynamic_sections
+#define elf_backend_print_symbol_all \
+ sparc64_elf_print_symbol_all
+#define elf_backend_output_arch_syms \
+ sparc64_elf_output_arch_syms
#define bfd_elf64_bfd_merge_private_bfd_data \
sparc64_elf_merge_private_bfd_data
--- ./bfd/elf.c.jj2 Fri Jul 9 12:20:45 1999
+++ ./bfd/elf.c Fri Jul 9 13:36:00 1999
@@ -756,8 +756,21 @@ bfd_elf_print_symbol (abfd, filep, symbo
case bfd_print_symbol_all:
{
CONST char *section_name;
+ CONST char *name = NULL;
+ struct elf_backend_data *bed;
+
section_name = symbol->section ? symbol->section->name : "(*none*)";
- bfd_print_symbol_vandf ((PTR) file, symbol);
+
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_print_symbol_all)
+ name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol);
+
+ if (name == NULL)
+ {
+ name = symbol->name;
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ }
+
fprintf (file, " %s\t", section_name);
/* Print the "other" value for a symbol. For common symbols,
we've already printed the size; now print the alignment.
@@ -825,7 +838,7 @@ bfd_elf_print_symbol (abfd, filep, symbo
((unsigned int)
((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
- fprintf (file, " %s", symbol->name);
+ fprintf (file, " %s", name);
}
break;
}
--- ./bfd/elflink.h.jj2 Fri Jul 9 12:19:20 1999
+++ ./bfd/elflink.h Fri Jul 9 13:36:00 1999
@@ -4177,6 +4177,18 @@ elf_bfd_final_link (abfd, info)
if (eoinfo.failed)
return false;
+ /* If backend needs to output some symbols not present in the hash
+ table, do it now. */
+ if (bed->elf_backend_output_arch_syms)
+ {
+ if (! (*bed->elf_backend_output_arch_syms)
+ (info, (PTR) &finfo,
+ (boolean (*) PARAMS ((PTR, const char *,
+ Elf_Internal_Sym *, asection *)))
+ elf_link_output_sym))
+ return false;
+ }
+
/* Flush all symbols to the file. */
if (! elf_link_flush_output_syms (&finfo))
return false;
--- ./bfd/elfxx-target.h.jj2 Fri Jul 9 12:19:22 1999
+++ ./bfd/elfxx-target.h Fri Jul 9 13:36:00 1999
@@ -294,6 +294,12 @@ Foundation, Inc., 59 Temple Place - Suit
#ifndef elf_backend_post_process_headers
#define elf_backend_post_process_headers NULL
#endif
+#ifndef elf_backend_print_symbol_all
+#define elf_backend_print_symbol_all NULL
+#endif
+#ifndef elf_backend_output_arch_syms
+#define elf_backend_output_arch_syms NULL
+#endif
/* Previously, backends could only use SHT_REL or SHT_RELA relocation
sections, but not both. They defined USE_REL to indicate SHT_REL
@@ -366,6 +372,8 @@ static CONST struct elf_backend_data elf
elf_backend_gc_mark_hook,
elf_backend_gc_sweep_hook,
elf_backend_post_process_headers,
+ elf_backend_print_symbol_all,
+ elf_backend_output_arch_syms,
elf_backend_ecoff_debug_swap,
ELF_MACHINE_ALT1,
ELF_MACHINE_ALT2,
--- ./gas/config/tc-sparc.c.jj4 Wed Jul 7 09:41:46 1999
+++ ./gas/config/tc-sparc.c Wed Jul 7 13:36:13 1999
@@ -87,6 +87,10 @@ static int warn_on_bump;
architecture, issue a warning. */
static enum sparc_opcode_arch_val warn_after_architecture;
+/* Non-zero if as should generate error if an undeclared g[23] register
+ has been used in -64. */
+static int no_undeclared_regs;
+
/* Non-zero if we are generating PIC code. */
int sparc_pic_code;
@@ -97,6 +101,9 @@ extern int target_big_endian;
static int target_little_endian_data;
+/* Symbols for global registers on v9. */
+static symbolS *globals[8];
+
/* V9 and 86x have big and little endian data, but instructions are always big
endian. The sparclet has bi-endian support but both data and insns have
the same endianness. Global `target_big_endian' is used for data.
@@ -119,6 +126,7 @@ static void s_common PARAMS ((int));
static void s_empty PARAMS ((int));
static void s_uacons PARAMS ((int));
static void s_ncons PARAMS ((int));
+static void s_register PARAMS ((int));
const pseudo_typeS md_pseudo_table[] =
{
@@ -143,6 +151,7 @@ const pseudo_typeS md_pseudo_table[] =
{"2byte", s_uacons, 2},
{"4byte", s_uacons, 4},
{"8byte", s_uacons, 8},
+ {"register", s_register, 0},
#endif
{NULL, 0, 0},
};
@@ -400,6 +409,10 @@ struct option md_longopts[] = {
{"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA},
#define OPTION_LITTLE_ENDIAN_DATA (OPTION_MD_BASE + 11)
{"little-endian-data", no_argument, NULL, OPTION_LITTLE_ENDIAN_DATA},
+#ifdef OBJ_ELF
+#define OPTION_NO_UNDECLARED_REGS (OPTION_MD_BASE + 12)
+ {"no-undeclared-regs", no_argument, NULL, OPTION_NO_UNDECLARED_REGS},
+#endif
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof(md_longopts);
@@ -549,6 +562,10 @@ md_parse_option (c, arg)
else
sparc_pic_code = 1;
break;
+
+ case OPTION_NO_UNDECLARED_REGS:
+ no_undeclared_regs = 1;
+ break;
#endif
default:
@@ -1865,6 +1882,11 @@ sparc_ip (str, pinsn)
goto error;
}
+ if ((mask & ~1) == 2 && sparc_arch_size == 64
+ && no_undeclared_regs && ! globals [mask])
+ as_bad (_("detected global register use not "
+ "covered by .register pseudo-op"));
+
/* Got the register, now figure out where
it goes in the opcode. */
switch (*args)
@@ -3706,6 +3728,112 @@ s_ncons (bytes)
{
cons (sparc_arch_size == 32 ? 4 : 8);
}
+
+#ifdef OBJ_ELF
+/* Handle the SPARC ELF .register pseudo-op. This sets the binding of a
+ global register.
+ The syntax is:
+
+ .register %g[2367],{#scratch|symbolname}
+ */
+
+static void
+s_register (ignore)
+ int ignore;
+{
+ char c;
+ int reg;
+ int flags;
+ const char *regname;
+
+ if (input_line_pointer[0] != '%'
+ || input_line_pointer[1] != 'g'
+ || ((input_line_pointer[2] & ~1) != '2'
+ && (input_line_pointer[2] & ~1) != '6')
+ || input_line_pointer[3] != ',')
+ as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname}"));
+ reg = input_line_pointer[2] - '0';
+ input_line_pointer += 4;
+
+ if (*input_line_pointer == '#')
+ {
+ ++input_line_pointer;
+ regname = input_line_pointer;
+ c = get_symbol_end ();
+ if (strcmp (regname, "scratch"))
+ as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname}"));
+ regname = "";
+ }
+ else
+ {
+ regname = input_line_pointer;
+ c = get_symbol_end ();
+ }
+ if (sparc_arch_size == 64)
+ {
+ if (globals [reg])
+ {
+ if (strcmp (S_GET_NAME (globals [reg]), regname))
+ as_bad (_("redefinition of global register"));
+ }
+ else
+ {
+ if (*regname)
+ {
+ if (symbol_find (regname))
+ as_bad (_("Register symbol %s already defined."), regname);
+ }
+ globals [reg] = symbol_make (regname);
+ flags = symbol_get_bfdsym (globals [reg])->flags;
+ if (! *regname)
+ flags = flags & ~(BSF_GLOBAL|BSF_LOCAL|BSF_WEAK);
+ if (! (flags & (BSF_GLOBAL|BSF_LOCAL|BSF_WEAK)))
+ flags |= BSF_GLOBAL;
+ symbol_get_bfdsym (globals [reg])->flags = flags;
+ S_SET_VALUE (globals [reg], (valueT)reg);
+ S_SET_ALIGN (globals [reg], reg);
+ S_SET_SIZE (globals [reg], 0);
+ /* Although we actually want undefined_section here,
+ we have to use absolute_section, because otherwise
+ generic as code will make it a COM section.
+ We fix this up in sparc_adjust_symtab. */
+ S_SET_SEGMENT (globals [reg], absolute_section);
+ S_SET_OTHER (globals [reg], 0);
+ elf_symbol (symbol_get_bfdsym (globals [reg]))
+ ->internal_elf_sym.st_info =
+ ELF_ST_INFO(STB_GLOBAL, STT_REGISTER);
+ elf_symbol (symbol_get_bfdsym (globals [reg]))
+ ->internal_elf_sym.st_shndx = SHN_UNDEF;
+ }
+ }
+
+ *input_line_pointer = c;
+
+ demand_empty_rest_of_line ();
+}
+
+/* Adjust the symbol table. We set undefined sections for STT_REGISTER
+ symbols which need it. */
+
+void
+sparc_adjust_symtab ()
+{
+ symbolS *sym;
+
+ for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+ {
+ if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym))
+ ->internal_elf_sym.st_info) != STT_REGISTER)
+ continue;
+
+ if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym))
+ ->internal_elf_sym.st_shndx != SHN_UNDEF))
+ continue;
+
+ S_SET_SEGMENT (sym, undefined_section);
+ }
+}
+#endif
/* If the --enforce-aligned-data option is used, we require .word,
et. al., to be aligned correctly. We do it by setting up an
--- ./gas/config/tc-sparc.h.jj4 Mon Jul 5 14:15:17 1999
+++ ./gas/config/tc-sparc.h Wed Jul 7 13:35:50 1999
@@ -134,6 +134,10 @@ extern int elf32_sparc_force_relocation
== S_GET_SEGMENT ((FIX)->fx_addsy))) \
|| strchr (S_GET_NAME ((FIX)->fx_addsy), '\001') != NULL \
|| strchr (S_GET_NAME ((FIX)->fx_addsy), '\002') != NULL))
+
+/* Finish up the entire symtab. */
+#define tc_adjust_symtab() sparc_adjust_symtab ()
+extern void sparc_adjust_symtab PARAMS ((void));
#endif
#ifdef OBJ_AOUT
1999-07-09 Jakub Jelinek <jj@ultra.linux.cz>
* bfd/elf64-sparc.c (sparc64_elf_info_to_howto): Use ELF64_R_TYPE_ID.
(sparc64_elf_get_reloc_upper_bound,
sparc64_elf_get_dynamic_reloc_upper_bound,
sparc64_elf_slurp_one_reloc_table, sparc64_elf_slurp_reloc_table,
sparc64_elf_canonicalize_dynamic_reloc, sparc64_elf_write_relocs):
New functions.
(sparc64_elf_check_relocs, sparc64_elf_relocate_section): Use
ELF64_R_TYPE_ID/DATA where appropriate.
* gas/config/tc-sparc.c (sparc_ip): Allow OLO10 relocations
on -64 and not pic.
(output_insn): Put OLO10's secondary addend into tc_fix_data.
(md_apply_fix3): Handle BFD_RELOC_SPARC_OLO10.
(tc_gen_reloc): Return two relocs for OLO10, LO10 and SPARC13.
* gas/config/tc-sparc.h (RELOC_EXPANSION_POSSIBLE,
MAX_RELOC_EXPANSION): Define.
(TC_FIX_TYPE, TC_INIT_FIX_DATA, TC_FIX_DATA_PRINT): Likewise.
--- ./gas/config/tc-sparc.c.jj Sat Jul 3 18:31:35 1999
+++ ./gas/config/tc-sparc.c Mon Jul 5 14:31:44 1999
@@ -2248,7 +2248,7 @@ sparc_ip (str, pinsn)
}
else
{
- if (1 || old_reloc != BFD_RELOC_SPARC13
+ if (old_reloc != BFD_RELOC_SPARC13
|| the_insn.reloc != BFD_RELOC_LO10
|| sparc_arch_size != 64
|| sparc_pic_code)
@@ -2667,6 +2667,8 @@ output_insn (insn, the_insn)
the insn size is 4 and fixup_segment will signal an overflow for
large 8 byte quantities. */
fixP->fx_no_overflow = 1;
+ if (the_insn->reloc == BFD_RELOC_SPARC_OLO10)
+ fixP->tc_fix_data = the_insn->exp2.X_add_number;
}
last_insn = insn;
@@ -3001,6 +3003,11 @@ md_apply_fix3 (fixP, value, segment)
}
break;
+ case BFD_RELOC_SPARC_OLO10:
+ val &= 0x3ff;
+ val += fixP->tc_fix_data;
+ /* intentional fallthrough */
+
case BFD_RELOC_SPARC13:
if (! in_signed_range (val, 0x1fff))
as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -3070,15 +3077,17 @@ md_apply_fix3 (fixP, value, segment)
/* Translate internal representation of relocation info to BFD target
format. */
-arelent *
+arelent **
tc_gen_reloc (section, fixp)
asection *section;
fixS *fixp;
{
+ static arelent *relocs[3];
arelent *reloc;
bfd_reloc_code_real_type code;
- reloc = (arelent *) xmalloc (sizeof (arelent));
+ relocs[0] = reloc = (arelent *) xmalloc (sizeof (arelent));
+ relocs[1] = NULL;
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
@@ -3115,6 +3124,7 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_SPARC_HIX22:
case BFD_RELOC_SPARC_LOX10:
case BFD_RELOC_SPARC_REV32:
+ case BFD_RELOC_SPARC_OLO10:
case BFD_RELOC_VTABLE_ENTRY:
case BFD_RELOC_VTABLE_INHERIT:
code = fixp->fx_r_type;
@@ -3168,13 +3178,18 @@ tc_gen_reloc (section, fixp)
}
#endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */
- reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (code == BFD_RELOC_SPARC_OLO10)
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO10);
+ else
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
if (reloc->howto == 0)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("internal error: can't export reloc type %d (`%s')"),
fixp->fx_r_type, bfd_get_reloc_code_name (code));
- return 0;
+ xfree (reloc);
+ relocs[0] = NULL;
+ return relocs;
}
/* @@ Why fx_addnumber sometimes and fx_offset other times? */
@@ -3209,7 +3224,21 @@ tc_gen_reloc (section, fixp)
reloc->addend = fixp->fx_offset;
#endif
- return reloc;
+ /* We expand R_SPARC_OLO10 to R_SPARC_LO10 and R_SPARC_13
+ on the same location. */
+ if (code == BFD_RELOC_SPARC_OLO10)
+ {
+ relocs[1] = reloc = (arelent *) xmalloc (sizeof (arelent));
+ relocs[2] = NULL;
+
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (section_symbol (absolute_section));
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_SPARC13);
+ reloc->addend = fixp->tc_fix_data;
+ }
+
+ return relocs;
}
/* We have no need to default values of symbols. */
--- ./gas/config/tc-sparc.h.jj Tue Jun 29 10:49:38 1999
+++ ./gas/config/tc-sparc.h Mon Jul 5 14:15:17 1999
@@ -35,6 +35,9 @@ struct frag;
extern const char *sparc_target_format PARAMS ((void));
#define TARGET_FORMAT sparc_target_format ()
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 2
+
#if 0
#ifdef TE_SPARCAOUT
/* Bi-endian support may eventually be unconditional, but until things are
@@ -160,5 +163,22 @@ extern void sparc_md_end PARAMS ((void))
#define TC_CONS_FIX_NEW cons_fix_new_sparc
extern void cons_fix_new_sparc
PARAMS ((struct frag *, int, unsigned int, struct expressionS *));
+
+#define TC_FIX_TYPE valueT
+
+#define TC_INIT_FIX_DATA(X) \
+ do \
+ { \
+ (X)->tc_fix_data = 0; \
+ } \
+ while(0)
+
+#define TC_FIX_DATA_PRINT(FILE, FIXP) \
+ do \
+ { \
+ fprintf((FILE), "addend2=%ld\n", \
+ (unsigned long) (FIXP)->tc_fix_data); \
+ } \
+ while(0)
/* end of tc-sparc.h */
--- bfd/elf64-sparc.c.jj Fri Jul 9 12:18:56 1999
+++ bfd/elf64-sparc.c Fri Jul 9 13:27:07 1999
@@ -61,6 +61,15 @@
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static boolean sparc64_elf_object_p PARAMS ((bfd *));
+static long sparc64_elf_get_reloc_upper_bound PARAMS ((bfd *, asection *));
+static long sparc64_elf_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
+static boolean sparc64_elf_slurp_one_reloc_table
+ PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, asymbol **, boolean));
+static boolean sparc64_elf_slurp_reloc_table
+ PARAMS ((bfd *, asection *, asymbol **, boolean));
+static long sparc64_elf_canonicalize_dynamic_reloc
+ PARAMS ((bfd *, arelent **, asymbol **));
+static void sparc64_elf_write_relocs PARAMS ((bfd *, asection *, PTR));
/* The relocation "howto" table. */
@@ -213,8 +222,380 @@
arelent *cache_ptr;
Elf64_Internal_Rela *dst;
{
- BFD_ASSERT (ELF64_R_TYPE (dst->r_info) < (unsigned int) R_SPARC_max_std);
- cache_ptr->howto = &sparc64_elf_howto_table[ELF64_R_TYPE (dst->r_info)];
+ BFD_ASSERT (ELF64_R_TYPE_ID (dst->r_info) < (unsigned int) R_SPARC_max_std);
+ cache_ptr->howto = &sparc64_elf_howto_table[ELF64_R_TYPE_ID (dst->r_info)];
+}
+
+/* Due to the way how we handle R_SPARC_OLO10, each entry in a SHT_RELA
+ section can represent up to two relocs, we must tell the user to allocate
+ more space. */
+
+static long
+sparc64_elf_get_reloc_upper_bound (abfd, sec)
+ bfd *abfd;
+ asection *sec;
+{
+ return (sec->reloc_count * 2 + 1) * sizeof (arelent *);
+}
+
+static long
+sparc64_elf_get_dynamic_reloc_upper_bound (abfd)
+ bfd *abfd;
+{
+ return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 2;
+}
+
+/* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of
+ them. We cannot use generic elf routines for this, because R_SPARC_OLO10
+ has secondary addend in ELF64_R_TYPE_DATA. We handle it as two relocations
+ for the same location, R_SPARC_LO10 and R_SPARC_13. */
+
+static boolean
+sparc64_elf_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols, dynamic)
+ bfd *abfd;
+ asection *asect;
+ Elf_Internal_Shdr *rel_hdr;
+ asymbol **symbols;
+ boolean dynamic;
+{
+ struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+ PTR allocated = NULL;
+ bfd_byte *native_relocs;
+ arelent *relent;
+ unsigned int i;
+ int entsize;
+ bfd_size_type count;
+ arelent *relents;
+
+ allocated = (PTR) bfd_malloc ((size_t) rel_hdr->sh_size);
+ if (allocated == NULL)
+ goto error_return;
+
+ if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_read (allocated, 1, rel_hdr->sh_size, abfd)
+ != rel_hdr->sh_size))
+ goto error_return;
+
+ native_relocs = (bfd_byte *) allocated;
+
+ relents = asect->relocation + asect->reloc_count;
+
+ entsize = rel_hdr->sh_entsize;
+ BFD_ASSERT (entsize == sizeof (Elf64_External_Rela));
+
+ count = rel_hdr->sh_size / entsize;
+
+ for (i = 0, relent = relents; i < count;
+ i++, relent++, native_relocs += entsize)
+ {
+ Elf_Internal_Rela rela;
+
+ bfd_elf64_swap_reloca_in (abfd, (Elf64_External_Rela *) native_relocs, &rela);
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a normal BFD reloc is always section relative,
+ and the address of a dynamic reloc is absolute.. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic)
+ relent->address = rela.r_offset;
+ else
+ relent->address = rela.r_offset - asect->vma;
+
+ if (ELF64_R_SYM (rela.r_info) == 0)
+ relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ else
+ {
+ asymbol **ps, *s;
+
+ ps = symbols + ELF64_R_SYM (rela.r_info) - 1;
+ s = *ps;
+
+ /* Canonicalize ELF section symbols. FIXME: Why? */
+ if ((s->flags & BSF_SECTION_SYM) == 0)
+ relent->sym_ptr_ptr = ps;
+ else
+ relent->sym_ptr_ptr = s->section->symbol_ptr_ptr;
+ }
+
+ relent->addend = rela.r_addend;
+
+ BFD_ASSERT (ELF64_R_TYPE_ID (rela.r_info) < (unsigned int) R_SPARC_max_std);
+ if (ELF64_R_TYPE_ID (rela.r_info) == R_SPARC_OLO10)
+ {
+ relent->howto = &sparc64_elf_howto_table[R_SPARC_LO10];
+ relent[1].address = relent->address;
+ relent++;
+ relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ relent->addend = ELF64_R_TYPE_DATA (rela.r_info);
+ relent->howto = &sparc64_elf_howto_table[R_SPARC_13];
+ }
+ else
+ relent->howto = &sparc64_elf_howto_table[ELF64_R_TYPE_ID (rela.r_info)];
+ }
+
+ asect->reloc_count += relent - relents;
+
+ if (allocated != NULL)
+ free (allocated);
+
+ return true;
+
+ error_return:
+ if (allocated != NULL)
+ free (allocated);
+ return false;
+}
+
+/* Read in and swap the external relocs. */
+
+static boolean
+sparc64_elf_slurp_reloc_table (abfd, asect, symbols, dynamic)
+ bfd *abfd;
+ asection *asect;
+ asymbol **symbols;
+ boolean dynamic;
+{
+ struct bfd_elf_section_data * const d = elf_section_data (asect);
+ Elf_Internal_Shdr *rel_hdr;
+ Elf_Internal_Shdr *rel_hdr2;
+
+ if (asect->relocation != NULL)
+ return true;
+
+ if (! dynamic)
+ {
+ if ((asect->flags & SEC_RELOC) == 0
+ || asect->reloc_count == 0)
+ return true;
+
+ rel_hdr = &d->rel_hdr;
+ rel_hdr2 = d->rel_hdr2;
+
+ BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset
+ || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
+ }
+ else
+ {
+ /* Note that ASECT->RELOC_COUNT tends not to be accurate in this
+ case because relocations against this section may use the
+ dynamic symbol table, and in that case bfd_section_from_shdr
+ in elf.c does not update the RELOC_COUNT. */
+ if (asect->_raw_size == 0)
+ return true;
+
+ rel_hdr = &d->this_hdr;
+ asect->reloc_count = rel_hdr->sh_size / rel_hdr->sh_entsize;
+ rel_hdr2 = NULL;
+ }
+
+ asect->relocation = ((arelent *)
+ bfd_alloc (abfd,
+ asect->reloc_count * 2 * sizeof (arelent)));
+ if (asect->relocation == NULL)
+ return false;
+
+ /* The sparc64_elf_slurp_one_reloc_table routine increments reloc_count. */
+ asect->reloc_count = 0;
+
+ if (!sparc64_elf_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols,
+ dynamic))
+ return false;
+
+ if (rel_hdr2
+ && !sparc64_elf_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols,
+ dynamic))
+ return false;
+
+ return true;
+}
+
+/* Canonicalize the dynamic relocation entries. Note that we return
+ the dynamic relocations as a single block, although they are
+ actually associated with particular sections; the interface, which
+ was designed for SunOS style shared libraries, expects that there
+ is only one set of dynamic relocs. Any section that was actually
+ installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
+ the dynamic symbol table, is considered to be a dynamic reloc
+ section. */
+
+static long
+sparc64_elf_canonicalize_dynamic_reloc (abfd, storage, syms)
+ bfd *abfd;
+ arelent **storage;
+ asymbol **syms;
+{
+ asection *s;
+ long ret;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ ret = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ arelent *p;
+ long count, i;
+
+ if (! sparc64_elf_slurp_reloc_table (abfd, s, syms, true))
+ return -1;
+ count = s->reloc_count;
+ p = s->relocation;
+ for (i = 0; i < count; i++)
+ *storage++ = p++;
+ ret += count;
+ }
+ }
+
+ *storage = NULL;
+
+ return ret;
+}
+
+/* Write out the relocs. */
+
+static void
+sparc64_elf_write_relocs (abfd, sec, data)
+ bfd *abfd;
+ asection *sec;
+ PTR data;
+{
+ boolean *failedp = (boolean *) data;
+ Elf_Internal_Shdr *rela_hdr;
+ Elf64_External_Rela *outbound_relocas;
+ unsigned int idx, count;
+ asymbol *last_sym = 0;
+ int last_sym_idx = 0;
+
+ /* If we have already failed, don't do anything. */
+ if (*failedp)
+ return;
+
+ if ((sec->flags & SEC_RELOC) == 0)
+ return;
+
+ /* The linker backend writes the relocs out itself, and sets the
+ reloc_count field to zero to inhibit writing them here. Also,
+ sometimes the SEC_RELOC flag gets set even when there aren't any
+ relocs. */
+ if (sec->reloc_count == 0)
+ return;
+
+ /* We can combine two relocs that refer to the same address
+ into R_SPARC_OLO10 if first one is R_SPARC_LO10 and the
+ latter is R_SPARC_13 with no associated symbol. */
+ count = 0;
+ for (idx = 0; idx < sec->reloc_count; idx++)
+ {
+ bfd_vma addr;
+ unsigned int i;
+
+ ++count;
+
+ addr = sec->orelocation[idx]->address;
+ if (sec->orelocation[idx]->howto->type == R_SPARC_LO10
+ && idx < sec->reloc_count - 1)
+ {
+ arelent *r = sec->orelocation[idx + 1];
+
+ if (r->howto->type == R_SPARC_13
+ && r->address == addr
+ && bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
+ && (*r->sym_ptr_ptr)->value == 0)
+ ++idx;
+ }
+ }
+
+ rela_hdr = &elf_section_data (sec)->rel_hdr;
+
+ rela_hdr->sh_size = rela_hdr->sh_entsize * count;
+ rela_hdr->contents = (PTR) bfd_alloc (abfd, rela_hdr->sh_size);
+ if (rela_hdr->contents == NULL)
+ {
+ *failedp = true;
+ return;
+ }
+
+ /* Figure out whether the relocations are RELA or REL relocations. */
+ if (rela_hdr->sh_type != SHT_RELA)
+ abort ();
+
+ /* orelocation has the data, reloc_count has the count... */
+ outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents;
+
+ for (idx = 0; idx < sec->reloc_count; idx++)
+ {
+ Elf_Internal_Rela dst_rela;
+ Elf64_External_Rela *src_rela;
+ arelent *ptr;
+ asymbol *sym;
+ int n;
+
+ ptr = sec->orelocation[idx];
+ src_rela = outbound_relocas + idx;
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a BFD reloc is always section relative. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ dst_rela.r_offset = ptr->address;
+ else
+ dst_rela.r_offset = ptr->address + sec->vma;
+
+ sym = *ptr->sym_ptr_ptr;
+ if (sym == last_sym)
+ n = last_sym_idx;
+ else if (bfd_is_abs_section (sym->section) && sym->value == 0)
+ n = STN_UNDEF;
+ else
+ {
+ last_sym = sym;
+ n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
+ if (n < 0)
+ {
+ *failedp = true;
+ return;
+ }
+ last_sym_idx = n;
+ }
+
+ if ((*ptr->sym_ptr_ptr)->the_bfd != NULL
+ && (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
+ && ! _bfd_elf_validate_reloc (abfd, ptr))
+ {
+ *failedp = true;
+ return;
+ }
+
+ if (ptr->howto->type == R_SPARC_LO10
+ && idx < sec->reloc_count - 1)
+ {
+ arelent *r = sec->orelocation[idx + 1];
+
+ if (r->howto->type == R_SPARC_13
+ && r->address == ptr->address
+ && bfd_is_abs_section ((*r->sym_ptr_ptr)->section)
+ && (*r->sym_ptr_ptr)->value == 0)
+ {
+ idx++;
+ dst_rela.r_info
+ = ELF64_R_INFO (n, ELF64_R_TYPE_INFO (r->addend,
+ R_SPARC_OLO10));
+ }
+ else
+ dst_rela.r_info = ELF64_R_INFO (n, R_SPARC_LO10);
+ }
+ else
+ dst_rela.r_info = ELF64_R_INFO (n, ptr->howto->type);
+
+ dst_rela.r_addend = ptr->addend;
+ bfd_elf64_swap_reloca_out (abfd, &dst_rela, src_rela);
+ }
}
/* Utility for performing the standard initial work of an instruction
@@ -570,7 +951,7 @@
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- switch (ELF64_R_TYPE (rel->r_info))
+ switch (ELF64_R_TYPE_ID (rel->r_info))
{
case R_SPARC_GOT10:
case R_SPARC_GOT13:
@@ -809,7 +1190,7 @@
default:
(*_bfd_error_handler)(_("%s: check_relocs: unhandled reloc type %d"),
bfd_get_filename(abfd),
- ELF64_R_TYPE (rel->r_info));
+ ELF64_R_TYPE_ID (rel->r_info));
return false;
}
}
@@ -1245,7 +1626,7 @@
bfd_vma relocation;
bfd_reloc_status_type r;
- r_type = ELF64_R_TYPE (rel->r_info);
+ r_type = ELF64_R_TYPE_ID (rel->r_info);
if (r_type < 0 || r_type >= (int) R_SPARC_max_std)
{
bfd_set_error (bfd_error_bad_value);
@@ -1531,7 +1912,11 @@
& ELF_LINK_HASH_DEF_REGULAR) == 0))
{
BFD_ASSERT (h->dynindx != -1);
- outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
+ outrel.r_info
+ = ELF64_R_INFO (h->dynindx,
+ ELF64_R_TYPE_INFO (
+ ELF64_R_TYPE_DATA (rel->r_info),
+ r_type));
outrel.r_addend = rel->r_addend;
}
else
@@ -1581,7 +1966,11 @@
}
}
- outrel.r_info = ELF64_R_INFO (indx, r_type);
+ outrel.r_info
+ = ELF64_R_INFO (indx,
+ ELF64_R_TYPE_INFO (
+ ELF64_R_TYPE_DATA (rel->r_info),
+ r_type));
/* For non-RELATIVE dynamic relocations, we keep the
same symbol, and so generally the same addend. But
@@ -1605,7 +1994,7 @@
reloc in an unallocated section. */
if (skip
|| (input_section->flags & SEC_ALLOC) != 0
- || ELF64_R_TYPE (outrel.r_info) != R_SPARC_RELATIVE)
+ || ELF64_R_TYPE_ID (outrel.r_info) != R_SPARC_RELATIVE)
continue;
}
break;
@@ -2225,6 +2614,45 @@
return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, mach);
}
+/* Relocations in the 64 bit SPARC ELF ABI are more complex than in
+ standard ELF, because R_SPARC_OLO10 has secondary addend in
+ ELF64_R_TYPE_DATA field. This structure is used to redirect the
+ relocation handling routines. */
+
+const struct elf_size_info sparc64_elf_size_info =
+{
+ sizeof (Elf64_External_Ehdr),
+ sizeof (Elf64_External_Phdr),
+ sizeof (Elf64_External_Shdr),
+ sizeof (Elf64_External_Rel),
+ sizeof (Elf64_External_Rela),
+ sizeof (Elf64_External_Sym),
+ sizeof (Elf64_External_Dyn),
+ sizeof (Elf_External_Note),
+ 8, /* hash-table entry size */
+ /* internal relocations per external relocations.
+ For link purposes we use just 1 internal per
+ 1 external, for assembly and slurp symbol table
+ we use 2. */
+ 1,
+ 64, /* arch_size */
+ 8, /* file_align */
+ ELFCLASS64,
+ EV_CURRENT,
+ bfd_elf64_write_out_phdrs,
+ bfd_elf64_write_shdrs_and_ehdr,
+ sparc64_elf_write_relocs,
+ bfd_elf64_swap_symbol_out,
+ sparc64_elf_slurp_reloc_table,
+ bfd_elf64_slurp_symbol_table,
+ bfd_elf64_swap_dyn_in,
+ bfd_elf64_swap_dyn_out,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
#define TARGET_BIG_SYM bfd_elf64_sparc_vec
#define TARGET_BIG_NAME "elf64-sparc"
#define ELF_ARCH bfd_arch_sparc
@@ -2238,6 +2666,12 @@
#define elf_info_to_howto \
sparc64_elf_info_to_howto
+#define bfd_elf64_get_reloc_upper_bound \
+ sparc64_elf_get_reloc_upper_bound
+#define bfd_elf64_get_dynamic_reloc_upper_bound \
+ sparc64_elf_get_dynamic_reloc_upper_bound
+#define bfd_elf64_canonicalize_dynamic_reloc \
+ sparc64_elf_canonicalize_dynamic_reloc
#define bfd_elf64_bfd_reloc_type_lookup \
sparc64_elf_reloc_type_lookup
@@ -2259,6 +2693,8 @@
#define bfd_elf64_bfd_merge_private_bfd_data \
sparc64_elf_merge_private_bfd_data
+#define elf_backend_size_info \
+ sparc64_elf_size_info
#define elf_backend_object_p \
sparc64_elf_object_p