This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [patch][rfc] Complex Relocations gas and bfd
Alan Modra wrote:
gas should use a single BFD_RELOC_RELC. (The BFD_RELOC_* numbering is
internal to BFD.) This number could then be translated by each
backend bfd_reloc_type_lookup function to the appropriate howto.
Thanks again. Using this approach I now have an implementation for which
R_RELC is defined on a target by target basis, as desired. As you
suggested, I added R_RELC to the howto table for the target and it is
now obtained by each backend using bfd_reloc_type_lookup.
The other key change was that perform_complex_relocations in
bfd/elflink.c, which previously examined all relocs looking for complex
ones (and hence needed to know the value of R_RELC) has been renamed to
perform_complex_relocation and changed so that it only examines one
reloc, provided by the caller. Thus it can assume that the reloc is
complex and need not check for r_type == R_RELC. This function is now
called by the target specific code from <target>_elf_relocate_section as
each complex reloc is encountered.
Attached is a patch showing the changes. It must be applied after my
previous patch. Is that ok, or would you like a new overall patch?
Dave
Alternatively, you could do something clever in the generic code.
Store the target reloc in elf_backend_data, and stash that value into
a howto.
bfd/ChangeLog:
2007-01-25 Dave Brolley <brolley@redhat.com>
* elflink.c (evaluate_complex_relocation_symbols): Check for
STT_SRELC for global symbols.
(perform_complex_relocations): Renamed to
perform_complex_relocation and now examines only one relocation.
(elf_link_input_bfd): Don't call perform_complex_relocations.
* elf-bfd.h (bfd_elf_perform_complex_relocation_: New prototype.:
* elf32-mep.c (mep_elf_howto_table): Add R_RELC.
(OD,OS,OU): #undefs corrected to N, S and U repectively.
(mep_reloc_type_lookup): Handle BFD_RELOC_RELC.
(complex_reloc_installation_howto): Removed.
(mep_info_to_howto_rela): Remove special case for r_type==0xff.
(mep_elf_relocate_section): Call bfd_elf_perform_complex_relocation.
binutils/ChangeLog:
2007-01-25 Dave Brolley <brolley@redhat.com>
* readelf.c (dump_relocations): Don't check for
(rtype == NULL && type == R_RELC).
gas/ChangeLog:
2007-01-25 Dave Brolley <brolley@redhat.com>
* cgen.c (gas_cgen_install_complex_reloc): Removed.
(complex_reloc_installation_howto): Removed.
diff -cpr --exclude=CVS src-save/bfd/elf32-mep.c src/bfd/elf32-mep.c
*** src-save/bfd/elf32-mep.c 2007-01-19 13:17:24.000000000 -0500
--- src/bfd/elf32-mep.c 2007-01-24 14:51:04.000000000 -0500
*************** static reloc_howto_type mep_elf_howto_ta
*** 43,50 ****
{
/* type, size, bits, leftshift, rightshift, pcrel, OD/OS/OU, mask. */
MEPREL (R_MEP_NONE, 0, 0, 0, 0, 0, N, 0),
/* MEPRELOC:HOWTO */
! /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */
MEPREL (R_MEP_8, 0, 8, 0, 0, 0, U, 0xff),
MEPREL (R_MEP_16, 1, 16, 0, 0, 0, U, 0xffff),
MEPREL (R_MEP_32, 2, 32, 0, 0, 0, U, 0xffffffff),
--- 43,51 ----
{
/* type, size, bits, leftshift, rightshift, pcrel, OD/OS/OU, mask. */
MEPREL (R_MEP_NONE, 0, 0, 0, 0, 0, N, 0),
+ MEPREL (R_RELC, 0, 0, 0, 0, 0, N, 0),
/* MEPRELOC:HOWTO */
! /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */
MEPREL (R_MEP_8, 0, 8, 0, 0, 0, U, 0xff),
MEPREL (R_MEP_16, 1, 16, 0, 0, 0, U, 0xffff),
MEPREL (R_MEP_32, 2, 32, 0, 0, 0, U, 0xffffffff),
*************** static reloc_howto_type mep_elf_howto_ta
*** 71,80 ****
#define VALID_MEP_RELOC(N) ((N) >= 0 \
&& (N) < ARRAY_SIZE (mep_elf_howto_table)
! #undef OD
! #undef OS
! #undef OU
!
static bfd_reloc_status_type
mep_reloc
--- 72,80 ----
#define VALID_MEP_RELOC(N) ((N) >= 0 \
&& (N) < ARRAY_SIZE (mep_elf_howto_table)
! #undef N
! #undef S
! #undef U
static bfd_reloc_status_type
mep_reloc
*************** mep_reloc_type_lookup
*** 123,131 ****
case BFD_RELOC_VTABLE_INHERIT:
type = R_MEP_GNU_VTINHERIT;
break;
/* MEPRELOC:MAP */
! /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */
MAP(8);
MAP(16);
MAP(32);
--- 123,134 ----
case BFD_RELOC_VTABLE_INHERIT:
type = R_MEP_GNU_VTINHERIT;
break;
+ case BFD_RELOC_RELC:
+ type = R_RELC;
+ break;
/* MEPRELOC:MAP */
! /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */
MAP(8);
MAP(16);
MAP(32);
*************** mep_final_link_relocate
*** 262,268 ****
switch (howto->type)
{
/* MEPRELOC:APPLY */
! /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */
case R_MEP_8: /* 76543210 */
if (u > 255) r = bfd_reloc_overflow;
byte[0] = (u & 0xff);
--- 265,271 ----
switch (howto->type)
{
/* MEPRELOC:APPLY */
! /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */
case R_MEP_8: /* 76543210 */
if (u > 255) r = bfd_reloc_overflow;
byte[0] = (u & 0xff);
*************** mep_info_to_howto_rela
*** 379,392 ****
{
unsigned int r_type;
- static reloc_howto_type complex_reloc_installation_howto =
- HOWTO(R_RELC,0,0,0,0,0,complain_overflow_dont, 0, "RELOC_RELC",FALSE,0,0,0);
-
r_type = ELF32_R_TYPE (dst->r_info);
! if (r_type == 0xff)
! cache_ptr->howto = & complex_reloc_installation_howto;
! else
! cache_ptr->howto = & mep_elf_howto_table [r_type];
}
/* Look through the relocs for a section during the first phase.
--- 382,389 ----
{
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
! cache_ptr->howto = & mep_elf_howto_table [r_type];
}
/* Look through the relocs for a section during the first phase.
*************** mep_elf_relocate_section
*** 522,527 ****
--- 519,533 ----
continue;
}
+ /* Is this a complex relocation? */
+ if (ELF32_R_TYPE (rel->r_info) == R_RELC)
+ {
+ bfd_elf_perform_complex_relocation (output_bfd, info,
+ input_bfd, input_section, contents,
+ rel, local_syms, local_sections);
+ continue;
+ }
+
/* This is a final link. */
howto = mep_elf_howto_table + ELF32_R_TYPE (rel->r_info);
h = NULL;
diff -cpr --exclude=CVS src-save/bfd/elf-bfd.h src/bfd/elf-bfd.h
*** src-save/bfd/elf-bfd.h 2007-01-03 15:13:54.000000000 -0500
--- src/bfd/elf-bfd.h 2007-01-23 15:30:14.000000000 -0500
*************** extern bfd_boolean _bfd_elf_symbol_refs_
*** 1731,1736 ****
--- 1731,1746 ----
extern bfd_boolean bfd_elf_match_symbols_in_sections
(asection *, asection *, struct bfd_link_info *);
+ extern void bfd_elf_perform_complex_relocation
+ (bfd * output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info * info,
+ bfd * input_bfd,
+ asection * input_section,
+ bfd_byte * contents,
+ Elf_Internal_Rela * rel,
+ Elf_Internal_Sym * local_syms,
+ asection ** local_sections);
+
extern bfd_boolean _bfd_elf_setup_sections
(bfd *);
diff -cpr --exclude=CVS src-save/bfd/elflink.c src/bfd/elflink.c
*** src-save/bfd/elflink.c 2007-01-04 16:22:39.000000000 -0500
--- src/bfd/elflink.c 2007-01-23 15:55:12.000000000 -0500
*************** evaluate_complex_relocation_symbols (bfd
*** 6786,6792 ****
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
! if (h->type != STT_RELC)
continue;
signed_p = (h->type == STT_SRELC);
--- 6786,6792 ----
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
! if (h->type != STT_RELC && h->type != STT_SRELC)
continue;
signed_p = (h->type == STT_SRELC);
*************** decode_complex_addend
*** 6915,7079 ****
* trunc_p = (encoded >> 29) & 1;
}
! static void
! perform_complex_relocations
(bfd * output_bfd ATTRIBUTE_UNUSED,
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)
{
const struct elf_backend_data * bed;
! Elf_Internal_Rela * new_relocs;
! Elf_Internal_Rela * rel;
! Elf_Internal_Rela * relend;
! Elf_Internal_Shdr * symtab_hdr;
! struct elf_link_hash_entry ** sym_hashes;
! unsigned long non_complex_count = 0;
! if (info->relocatable)
! return;
- relend = relocs + input_section->reloc_count;
- sym_hashes = elf_sym_hashes (input_bfd);
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
! bed = get_elf_backend_data (input_bfd);
!
! new_relocs = xmalloc (input_section->reloc_count * sizeof (Elf_Internal_Rela));
! for (rel = relocs; rel < relend; rel ++)
{
! if (ELF32_R_TYPE (rel->r_info) != R_RELC)
! {
! /* Preserve this reloc for our caller; it is not complex. */
! memcpy (new_relocs + (non_complex_count++),
! rel, sizeof (Elf_Internal_Rela));
! }
! else
! {
! /* Perform this reloc, since it is complex
!
! (this is not to say that it necessarily refers to a complex
! symbol; merely that it is a self-describing CGEN based reloc.
! i.e. the addend has the complete reloc information (bit start, end,
! word size, etc) encoded within it.) */
! unsigned long start, oplen, len, wordsz,
! chunksz, lsb0_p, signed_p, trunc_p;
! Elf_Internal_Sym * sym = NULL;
! asection * sec = NULL;
! struct elf_link_hash_entry * h = NULL;
! bfd_vma relocation = 0, shift = 0, x = 0;
! unsigned long r_symndx;
! bfd_vma mask;
! r_symndx = ELF32_R_SYM (rel->r_info);
! if (bed->s->arch_size == 64)
! r_symndx >>= 24;
! #ifdef DEBUG
! printf ("Performing complex relocation %ld...\n", r_symndx);
! #endif
! if (r_symndx < symtab_hdr->sh_info)
! {
! /* The symbol is local. */
! sym = local_syms + r_symndx;
! sec = local_sections [r_symndx];
! relocation = sym->st_value;
! if (sym->st_shndx > SHN_UNDEF &&
! sym->st_shndx < SHN_LORESERVE)
! relocation += (sec->output_offset +
! sec->output_section->vma);
! }
! else
! {
! /* The symbol is global. */
! h = sym_hashes [r_symndx];
! 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)
! {
! sec = h->root.u.def.section;
! relocation = h->root.u.def.value;
! if (! bfd_is_abs_section (sec))
! relocation += (sec->output_section->vma
! + sec->output_offset);
! }
! if (h->root.type == bfd_link_hash_undefined
! && !((*info->callbacks->undefined_symbol)
! (info, h->root.root.string, input_bfd,
! input_section, rel->r_offset,
! info->unresolved_syms_in_objects == RM_GENERATE_ERROR
! || ELF_ST_VISIBILITY (h->other))))
! continue;
! }
! decode_complex_addend (& start, & oplen, & len, & wordsz,
! & chunksz, & lsb0_p, & signed_p,
! & trunc_p, rel->r_addend);
! mask = (((1L << (len - 1)) - 1) << 1) | 1;
! if (lsb0_p)
! shift = (start + 1) - len;
! else
! shift = (8 * wordsz) - (start + len);
! x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
#ifdef DEBUG
! printf ("Doing complex reloc: "
! "lsb0? %ld, signed? %ld, trunc? %ld, wordsz %ld, "
! "chunksz %ld, start %ld, len %ld, oplen %ld\n"
! " dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n",
! lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len,
! oplen, x, mask, relocation);
#endif
! if (! trunc_p)
! {
! /* Now do an overflow check. */
! if (bfd_check_overflow ((signed_p ?
! complain_overflow_signed :
! complain_overflow_unsigned),
! len, 0, (8 * wordsz),
! relocation) == bfd_reloc_overflow)
! (*_bfd_error_handler)
! ("%s (%s + 0x%lx): relocation overflow: 0x%lx %sdoes not fit "
! "within 0x%lx",
! input_bfd->filename, input_section->name, rel->r_offset,
! relocation, (signed_p ? "(signed) " : ""), mask);
! }
! /* Do the deed. */
! x = (x & ~(mask << shift)) | ((relocation & mask) << shift);
#ifdef DEBUG
! printf (" relocation: %8.8lx\n"
! " shifted mask: %8.8lx\n"
! " shifted/masked reloc: %8.8lx\n"
! " result: %8.8lx\n",
! relocation, (mask << shift),
! ((relocation & mask) << shift), x);
#endif
! put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
! }
! }
!
! /* Now copy back the remaining relocs. */
! if (non_complex_count != input_section->reloc_count)
! {
! memcpy (relocs, new_relocs, sizeof (Elf_Internal_Rela) * non_complex_count);
! input_section->reloc_count = non_complex_count;
! }
!
! free (new_relocs);
}
/* When performing a relocatable link, the input relocations are
--- 6915,7049 ----
* trunc_p = (encoded >> 29) & 1;
}
! void
! bfd_elf_perform_complex_relocation
(bfd * output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info * info,
bfd * input_bfd,
asection * input_section,
bfd_byte * contents,
! Elf_Internal_Rela * rel,
Elf_Internal_Sym * local_syms,
asection ** local_sections)
{
const struct elf_backend_data * bed;
! Elf_Internal_Shdr * symtab_hdr;
! asection * sec;
! bfd_vma relocation = 0, shift, x;
! unsigned long r_symndx;
! bfd_vma mask;
! unsigned long start, oplen, len, wordsz,
! chunksz, lsb0_p, signed_p, trunc_p;
!
! /* Perform this reloc, since it is complex.
! (this is not to say that it necessarily refers to a complex
! symbol; merely that it is a self-describing CGEN based reloc.
! i.e. the addend has the complete reloc information (bit start, end,
! word size, etc) encoded within it.). */
! r_symndx = ELF32_R_SYM (rel->r_info);
! bed = get_elf_backend_data (input_bfd);
! if (bed->s->arch_size == 64)
! r_symndx >>= 24;
! #ifdef DEBUG
! printf ("Performing complex relocation %ld...\n", r_symndx);
! #endif
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
! if (r_symndx < symtab_hdr->sh_info)
! {
! /* The symbol is local. */
! Elf_Internal_Sym * sym;
! sym = local_syms + r_symndx;
! sec = local_sections [r_symndx];
! relocation = sym->st_value;
! if (sym->st_shndx > SHN_UNDEF &&
! sym->st_shndx < SHN_LORESERVE)
! relocation += (sec->output_offset +
! sec->output_section->vma);
! }
! else
{
! /* The symbol is global. */
! struct elf_link_hash_entry **sym_hashes;
! struct elf_link_hash_entry * h;
! sym_hashes = elf_sym_hashes (input_bfd);
! h = sym_hashes [r_symndx];
! 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)
! {
! sec = h->root.u.def.section;
! relocation = h->root.u.def.value;
! if (! bfd_is_abs_section (sec))
! relocation += (sec->output_section->vma
! + sec->output_offset);
! }
! if (h->root.type == bfd_link_hash_undefined
! && !((*info->callbacks->undefined_symbol)
! (info, h->root.root.string, input_bfd,
! input_section, rel->r_offset,
! info->unresolved_syms_in_objects == RM_GENERATE_ERROR
! || ELF_ST_VISIBILITY (h->other))))
! return;
! }
! decode_complex_addend (& start, & oplen, & len, & wordsz,
! & chunksz, & lsb0_p, & signed_p,
! & trunc_p, rel->r_addend);
! mask = (((1L << (len - 1)) - 1) << 1) | 1;
! if (lsb0_p)
! shift = (start + 1) - len;
! else
! shift = (8 * wordsz) - (start + len);
! x = get_value (wordsz, chunksz, input_bfd, contents + rel->r_offset);
#ifdef DEBUG
! printf ("Doing complex reloc: "
! "lsb0? %ld, signed? %ld, trunc? %ld, wordsz %ld, "
! "chunksz %ld, start %ld, len %ld, oplen %ld\n"
! " dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n",
! lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len,
! oplen, x, mask, relocation);
#endif
! if (! trunc_p)
! {
! /* Now do an overflow check. */
! if (bfd_check_overflow ((signed_p ?
! complain_overflow_signed :
! complain_overflow_unsigned),
! len, 0, (8 * wordsz),
! relocation) == bfd_reloc_overflow)
! (*_bfd_error_handler)
! ("%s (%s + 0x%lx): relocation overflow: 0x%lx %sdoes not fit "
! "within 0x%lx",
! input_bfd->filename, input_section->name, rel->r_offset,
! relocation, (signed_p ? "(signed) " : ""), mask);
! }
! /* Do the deed. */
! x = (x & ~(mask << shift)) | ((relocation & mask) << shift);
#ifdef DEBUG
! printf (" relocation: %8.8lx\n"
! " shifted mask: %8.8lx\n"
! " shifted/masked reloc: %8.8lx\n"
! " result: %8.8lx\n",
! relocation, (mask << shift),
! ((relocation & mask) << shift), x);
#endif
! put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
}
/* When performing a relocatable link, the input relocations are
*************** elf_link_input_bfd (struct elf_final_lin
*** 8292,8305 ****
&& o->reloc_count > 0)
return FALSE;
- /* Perform any complex relocations in the internal_relocs array,
- remove them, and decrement o->reloc_count appropriately. */
- perform_complex_relocations (output_bfd, finfo->info,
- input_bfd, o, contents,
- internal_relocs,
- finfo->internal_syms,
- finfo->sections);
-
if (bed->s->arch_size == 32)
{
r_type_mask = 0xff;
--- 8262,8267 ----
diff -cpr --exclude=CVS src-save/binutils/readelf.c src/binutils/readelf.c
*** src-save/binutils/readelf.c 2007-01-15 11:45:07.000000000 -0500
--- src/binutils/readelf.c 2007-01-23 16:05:06.000000000 -0500
*************** dump_relocations (FILE *file,
*** 1175,1183 ****
break;
}
- if (rtype == NULL && type == R_RELC)
- rtype = "R_RELC";
-
if (rtype == NULL)
#ifdef _bfd_int64_low
printf (_("unrecognized: %-7lx"), _bfd_int64_low (type));
--- 1175,1180 ----
diff -cpr --exclude=CVS src-save/gas/cgen.c src/gas/cgen.c
*** src-save/gas/cgen.c 2007-01-04 16:07:27.000000000 -0500
--- src/gas/cgen.c 2007-01-24 14:52:12.000000000 -0500
*************** static unsigned long gas_cgen_encode_add
*** 38,46 ****
const unsigned long, const unsigned long, const unsigned long, \
const unsigned long);
- static bfd_reloc_status_type gas_cgen_install_complex_reloc
- (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
-
static char * weak_operand_overflow_check
(const expressionS *, const CGEN_OPERAND *);
--- 38,43 ----
*************** gas_cgen_md_apply_fix (fixP, valP, seg)
*** 1017,1036 ****
fixP->fx_addnumber = value;
}
- #ifdef OBJ_COMPLEX_RELC
-
- static bfd_reloc_status_type
- gas_cgen_install_complex_reloc (bfd * abfd ATTRIBUTE_UNUSED,
- arelent * reloc_entry ATTRIBUTE_UNUSED,
- asymbol * symbol ATTRIBUTE_UNUSED,
- PTR data ATTRIBUTE_UNUSED,
- asection * input_section ATTRIBUTE_UNUSED,
- bfd * output_bfd ATTRIBUTE_UNUSED,
- char ** error_message ATTRIBUTE_UNUSED)
- {
- return bfd_reloc_ok;
- }
- #endif
/* Translate internal representation of relocation info to BFD target format.
FIXME: To what extent can we get all relevant targets to use this? */
--- 1014,1019 ----
*************** gas_cgen_tc_gen_reloc (section, fixP)
*** 1041,1062 ****
fixS * fixP;
{
arelent *reloc;
- #ifdef OBJ_COMPLEX_RELC
- static reloc_howto_type complex_reloc_installation_howto =
- HOWTO (R_RELC, 0, 0, 0, 0, 0, complain_overflow_dont,
- gas_cgen_install_complex_reloc,
- "RELOC_RELC", FALSE, 0, 0, 0);
- #endif
-
reloc = (arelent *) xmalloc (sizeof (arelent));
- #ifdef OBJ_COMPLEX_RELC
- if (fixP->fx_r_type == BFD_RELOC_RELC)
- reloc->howto = &complex_reloc_installation_howto;
-
- else
- {
- #endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
if (reloc->howto == (reloc_howto_type *) NULL)
{
--- 1024,1031 ----
*************** gas_cgen_tc_gen_reloc (section, fixP)
*** 1066,1074 ****
}
assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
- #ifdef OBJ_COMPLEX_RELC
- }
- #endif
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
--- 1035,1040 ----