mach-o: use a per-target reloc canonicalize function.

bfd/
	* mach-o.h (bfd_mach_o_swap_in_non_scattered_reloc)
	(bfd_mach_o_canonicalize_non_scattered_reloc)
	(bfd_mach_o_pre_canonicalize_one_reloc): Declare.
	(bfd_mach_o_backend_data): Rename field
	_bfd_mach_o_swap_reloc_in to _bfd_mach_o_canonicalize_one_reloc.
	* mach-o.c (bfd_mach_o_swap_in_non_scattered_reloc): Now public.
	(bfd_mach_o_canonicalize_non_scattered_reloc): Renames from
	bfd_mach_o_canonicalize_one_reloc.
	(bfd_mach_o_pre_canonicalize_one_reloc): New function.
	(bfd_mach_o_canonicalize_relocs): Adjust.
	(bfd_mach_o_canonicalize_relocs): Rename define from
	bfd_mach_o_swap_reloc_in.
	* mach-o-target.c (TARGET_NAME_BACKEND): Use
	bfd_mach_o_canonicalize_one_reloc instead of
	bfd_mach_o_swap_reloc_in.
	* mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc): Renames
	from bfd_mach_o_i386_swap_reloc_in and adjust.
	(bfd_mach_o_canonicalize_one_reloc): Renames from
	bfd_mach_o_i386_canonicalize_one_reloc.
	* mach-o-x86_64.c (bfd_mach_o_x86_64_canonicalize_one_reloc): Renames
	from bfd_mach_o_x86_64_swap_reloc_in and adjust.
	(bfd_mach_o_canonicalize_one_reloc): Renames from
	bfd_mach_o_x86_64_canonicalize_one_reloc.
This commit is contained in:
Tristan Gingold 2015-11-18 15:43:27 +01:00
parent 1798301e20
commit bcb51645d3
6 changed files with 176 additions and 107 deletions

View File

@ -5,6 +5,32 @@
backward file movement via "negative" sizes.
* coff-alpha.c (alpha_ecoff_openr_next_archived_file): Likewise.
2015-11-18 Tristan Gingold <gingold@adacore.com>
* mach-o.h (bfd_mach_o_swap_in_non_scattered_reloc)
(bfd_mach_o_canonicalize_non_scattered_reloc)
(bfd_mach_o_pre_canonicalize_one_reloc): Declare.
(bfd_mach_o_backend_data): Rename field
_bfd_mach_o_swap_reloc_in to _bfd_mach_o_canonicalize_one_reloc.
* mach-o.c (bfd_mach_o_swap_in_non_scattered_reloc): Now public.
(bfd_mach_o_canonicalize_non_scattered_reloc): Renames from
bfd_mach_o_canonicalize_one_reloc.
(bfd_mach_o_pre_canonicalize_one_reloc): New function.
(bfd_mach_o_canonicalize_relocs): Adjust.
(bfd_mach_o_canonicalize_relocs): Rename define from
bfd_mach_o_swap_reloc_in.
* mach-o-target.c (TARGET_NAME_BACKEND): Use
bfd_mach_o_canonicalize_one_reloc instead of
bfd_mach_o_swap_reloc_in.
* mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc): Renames
from bfd_mach_o_i386_swap_reloc_in and adjust.
(bfd_mach_o_canonicalize_one_reloc): Renames from
bfd_mach_o_i386_canonicalize_one_reloc.
* mach-o-x86_64.c (bfd_mach_o_x86_64_canonicalize_one_reloc): Renames
from bfd_mach_o_x86_64_swap_reloc_in and adjust.
(bfd_mach_o_canonicalize_one_reloc): Renames from
bfd_mach_o_x86_64_canonicalize_one_reloc.
2015-11-18 Tristan Gingold <gingold@adacore.com>
* mach-o.h (struct mach_o_data_struct): Add hdr_offset field.

View File

@ -112,20 +112,27 @@ static reloc_howto_type i386_howto_table[]=
};
static bfd_boolean
bfd_mach_o_i386_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd,
struct mach_o_reloc_info_external *raw,
arelent *res, asymbol **syms)
{
if (reloc->r_scattered)
bfd_mach_o_reloc_info reloc;
if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms))
return FALSE;
if (reloc.r_scattered)
{
switch (reloc->r_type)
switch (reloc.r_type)
{
case BFD_MACH_O_GENERIC_RELOC_PAIR:
if (reloc->r_length == 2)
if (reloc.r_length == 2)
{
res->howto = &i386_howto_table[7];
res->address = res[-1].address;
return TRUE;
}
else if (reloc->r_length == 1)
else if (reloc.r_length == 1)
{
res->howto = &i386_howto_table[10];
res->address = res[-1].address;
@ -133,24 +140,24 @@ bfd_mach_o_i386_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
}
return FALSE;
case BFD_MACH_O_GENERIC_RELOC_SECTDIFF:
if (reloc->r_length == 2)
if (reloc.r_length == 2)
{
res->howto = &i386_howto_table[5];
return TRUE;
}
else if (reloc->r_length == 1)
else if (reloc.r_length == 1)
{
res->howto = &i386_howto_table[8];
return TRUE;
}
return FALSE;
case BFD_MACH_O_GENERIC_RELOC_LOCAL_SECTDIFF:
if (reloc->r_length == 2)
if (reloc.r_length == 2)
{
res->howto = &i386_howto_table[6];
return TRUE;
}
else if (reloc->r_length == 1)
else if (reloc.r_length == 1)
{
res->howto = &i386_howto_table[9];
return TRUE;
@ -162,10 +169,10 @@ bfd_mach_o_i386_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
}
else
{
switch (reloc->r_type)
switch (reloc.r_type)
{
case BFD_MACH_O_GENERIC_RELOC_VANILLA:
switch ((reloc->r_length << 1) | reloc->r_pcrel)
switch ((reloc.r_length << 1) | reloc.r_pcrel)
{
case 0: /* len = 0, pcrel = 0 */
res->howto = &i386_howto_table[2];
@ -384,7 +391,7 @@ const mach_o_segment_name_xlat mach_o_i386_segsec_names_xlat[] =
{ NULL, NULL }
};
#define bfd_mach_o_swap_reloc_in bfd_mach_o_i386_swap_reloc_in
#define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_i386_canonicalize_one_reloc
#define bfd_mach_o_swap_reloc_out bfd_mach_o_i386_swap_reloc_out
#define bfd_mach_o_print_thread bfd_mach_o_i386_print_thread

View File

@ -104,7 +104,7 @@ static const bfd_mach_o_backend_data TARGET_NAME_BACKEND =
{
TARGET_ARCHITECTURE,
TARGET_PAGESIZE,
bfd_mach_o_swap_reloc_in,
bfd_mach_o_canonicalize_one_reloc,
bfd_mach_o_swap_reloc_out,
bfd_mach_o_print_thread,
bfd_mach_o_tgt_seg_table,

View File

@ -120,18 +120,25 @@ static reloc_howto_type x86_64_howto_table[]=
};
static bfd_boolean
bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
bfd_mach_o_x86_64_canonicalize_one_reloc (bfd *abfd,
struct mach_o_reloc_info_external *raw,
arelent *res, asymbol **syms)
{
/* On x86-64, scattered relocs are not used. */
if (reloc->r_scattered)
bfd_mach_o_reloc_info reloc;
if (!bfd_mach_o_pre_canonicalize_one_reloc (abfd, raw, &reloc, res, syms))
return FALSE;
switch (reloc->r_type)
/* On x86-64, scattered relocs are not used. */
if (reloc.r_scattered)
return FALSE;
switch (reloc.r_type)
{
case BFD_MACH_O_X86_64_RELOC_UNSIGNED:
if (reloc->r_pcrel)
if (reloc.r_pcrel)
return FALSE;
switch (reloc->r_length)
switch (reloc.r_length)
{
case 2:
res->howto = &x86_64_howto_table[1];
@ -143,16 +150,16 @@ bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
return FALSE;
}
case BFD_MACH_O_X86_64_RELOC_SIGNED:
if (reloc->r_length == 2 && reloc->r_pcrel)
if (reloc.r_length == 2 && reloc.r_pcrel)
{
res->howto = &x86_64_howto_table[2];
return TRUE;
}
break;
case BFD_MACH_O_X86_64_RELOC_BRANCH:
if (!reloc->r_pcrel)
if (!reloc.r_pcrel)
return FALSE;
switch (reloc->r_length)
switch (reloc.r_length)
{
case 2:
res->howto = &x86_64_howto_table[6];
@ -162,23 +169,23 @@ bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
}
break;
case BFD_MACH_O_X86_64_RELOC_GOT_LOAD:
if (reloc->r_length == 2 && reloc->r_pcrel && reloc->r_extern)
if (reloc.r_length == 2 && reloc.r_pcrel && reloc.r_extern)
{
res->howto = &x86_64_howto_table[7];
return TRUE;
}
break;
case BFD_MACH_O_X86_64_RELOC_GOT:
if (reloc->r_length == 2 && reloc->r_pcrel && reloc->r_extern)
if (reloc.r_length == 2 && reloc.r_pcrel && reloc.r_extern)
{
res->howto = &x86_64_howto_table[10];
return TRUE;
}
break;
case BFD_MACH_O_X86_64_RELOC_SUBTRACTOR:
if (reloc->r_pcrel)
if (reloc.r_pcrel)
return FALSE;
switch (reloc->r_length)
switch (reloc.r_length)
{
case 2:
res->howto = &x86_64_howto_table[8];
@ -191,21 +198,21 @@ bfd_mach_o_x86_64_swap_reloc_in (arelent *res, bfd_mach_o_reloc_info *reloc)
}
break;
case BFD_MACH_O_X86_64_RELOC_SIGNED_1:
if (reloc->r_length == 2 && reloc->r_pcrel)
if (reloc.r_length == 2 && reloc.r_pcrel)
{
res->howto = &x86_64_howto_table[3];
return TRUE;
}
break;
case BFD_MACH_O_X86_64_RELOC_SIGNED_2:
if (reloc->r_length == 2 && reloc->r_pcrel)
if (reloc.r_length == 2 && reloc.r_pcrel)
{
res->howto = &x86_64_howto_table[4];
return TRUE;
}
break;
case BFD_MACH_O_X86_64_RELOC_SIGNED_4:
if (reloc->r_length == 2 && reloc->r_pcrel)
if (reloc.r_length == 2 && reloc.r_pcrel)
{
res->howto = &x86_64_howto_table[5];
return TRUE;
@ -344,7 +351,7 @@ const mach_o_segment_name_xlat mach_o_x86_64_segsec_names_xlat[] =
{ NULL, NULL }
};
#define bfd_mach_o_swap_reloc_in bfd_mach_o_x86_64_swap_reloc_in
#define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_x86_64_canonicalize_one_reloc
#define bfd_mach_o_swap_reloc_out bfd_mach_o_x86_64_swap_reloc_out
#define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_x86_64_bfd_reloc_type_lookup

View File

@ -1299,7 +1299,7 @@ bfd_mach_o_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED,
/* In addition to the need to byte-swap the symbol number, the bit positions
of the fields in the relocation information vary per target endian-ness. */
static void
void
bfd_mach_o_swap_in_non_scattered_reloc (bfd *abfd, bfd_mach_o_reloc_info *rel,
unsigned char *fields)
{
@ -1325,17 +1325,87 @@ bfd_mach_o_swap_in_non_scattered_reloc (bfd *abfd, bfd_mach_o_reloc_info *rel,
}
}
static int
bfd_mach_o_canonicalize_one_reloc (bfd *abfd,
struct mach_o_reloc_info_external *raw,
arelent *res, asymbol **syms)
/* Set syms_ptr_ptr and addend of RES. */
bfd_boolean
bfd_mach_o_canonicalize_non_scattered_reloc (bfd *abfd,
bfd_mach_o_reloc_info *reloc,
arelent *res, asymbol **syms)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
bfd_mach_o_backend_data *bed = bfd_mach_o_get_backend_data (abfd);
bfd_mach_o_reloc_info reloc;
bfd_vma addr;
unsigned int num;
asymbol **sym;
/* Non-scattered relocation. */
reloc->r_scattered = 0;
res->addend = 0;
num = reloc->r_value;
if (reloc->r_extern)
{
/* PR 17512: file: 8396-1185-0.004. */
if (num >= (unsigned) bfd_mach_o_count_symbols (abfd))
sym = bfd_und_section_ptr->symbol_ptr_ptr;
else if (syms == NULL)
sym = bfd_und_section_ptr->symbol_ptr_ptr;
else
/* An external symbol number. */
sym = syms + num;
}
else if (num == 0x00ffffff || num == 0)
{
/* The 'symnum' in a non-scattered PAIR is 0x00ffffff. But as this
is generic code, we don't know wether this is really a PAIR.
This value is almost certainly not a valid section number, hence
this specific case to avoid an assertion failure.
Target specific swap_reloc_in routine should adjust that. */
sym = bfd_abs_section_ptr->symbol_ptr_ptr;
}
else
{
/* PR 17512: file: 006-2964-0.004. */
if (num > mdata->nsects)
return FALSE;
/* A section number. */
sym = mdata->sections[num - 1]->bfdsection->symbol_ptr_ptr;
/* For a symbol defined in section S, the addend (stored in the
binary) contains the address of the section. To comply with
bfd convention, subtract the section address.
Use the address from the header, so that the user can modify
the vma of the section. */
res->addend = -mdata->sections[num - 1]->addr;
}
/* Note: Pairs for PPC LO/HI/HA are not scattered, but contain the offset
in the lower 16bits of the address value. So we have to find the
'symbol' from the preceding reloc. We do this even though the
section symbol is probably not needed here, because NULL symbol
values cause an assert in generic BFD code. This must be done in
the PPC swap_reloc_in routine. */
res->sym_ptr_ptr = sym;
return TRUE;
}
/* Do most of the work for canonicalize_relocs on RAW: create internal
representation RELOC and set most fields of RES using symbol table SYMS.
Each target still has to set the howto of RES and possibly adjust other
fields.
Previously the Mach-O hook point was simply swap_in, but some targets
(like arm64) don't follow the generic rules (symnum is a value for the
non-scattered relocation ADDEND). */
bfd_boolean
bfd_mach_o_pre_canonicalize_one_reloc (bfd *abfd,
struct mach_o_reloc_info_external *raw,
bfd_mach_o_reloc_info *reloc,
arelent *res, asymbol **syms)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
bfd_vma addr;
addr = bfd_get_32 (abfd, raw->r_address);
res->sym_ptr_ptr = NULL;
res->addend = 0;
@ -1346,11 +1416,11 @@ bfd_mach_o_canonicalize_one_reloc (bfd *abfd,
bfd_vma symnum = bfd_get_32 (abfd, raw->r_symbolnum);
/* Scattered relocation, can't be extern. */
reloc.r_scattered = 1;
reloc.r_extern = 0;
reloc->r_scattered = 1;
reloc->r_extern = 0;
/* Extract section and offset from r_value (symnum). */
reloc.r_value = symnum;
reloc->r_value = symnum;
/* FIXME: This breaks when a symbol in a reloc exactly follows the
end of the data for the section (e.g. in a calculation of section
data length). At present, the symbol will end up associated with
@ -1368,81 +1438,33 @@ bfd_mach_o_canonicalize_one_reloc (bfd *abfd,
}
/* Extract the info and address fields from r_address. */
reloc.r_type = BFD_MACH_O_GET_SR_TYPE (addr);
reloc.r_length = BFD_MACH_O_GET_SR_LENGTH (addr);
reloc.r_pcrel = addr & BFD_MACH_O_SR_PCREL;
reloc.r_address = BFD_MACH_O_GET_SR_TYPE (addr);
reloc->r_type = BFD_MACH_O_GET_SR_TYPE (addr);
reloc->r_length = BFD_MACH_O_GET_SR_LENGTH (addr);
reloc->r_pcrel = addr & BFD_MACH_O_SR_PCREL;
reloc->r_address = BFD_MACH_O_GET_SR_TYPE (addr);
res->address = BFD_MACH_O_GET_SR_ADDRESS (addr);
}
else
{
unsigned int num;
/* Non-scattered relocation. */
reloc.r_scattered = 0;
reloc->r_scattered = 0;
reloc->r_address = addr;
res->address = addr;
/* The value and info fields have to be extracted dependent on target
endian-ness. */
bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum);
num = reloc.r_value;
bfd_mach_o_swap_in_non_scattered_reloc (abfd, reloc, raw->r_symbolnum);
if (reloc.r_extern)
{
/* PR 17512: file: 8396-1185-0.004. */
if (num >= (unsigned) bfd_mach_o_count_symbols (abfd))
sym = bfd_und_section_ptr->symbol_ptr_ptr;
else if (syms == NULL)
sym = bfd_und_section_ptr->symbol_ptr_ptr;
else
/* An external symbol number. */
sym = syms + num;
}
else if (num == 0x00ffffff || num == 0)
{
/* The 'symnum' in a non-scattered PAIR is 0x00ffffff. But as this
is generic code, we don't know wether this is really a PAIR.
This value is almost certainly not a valid section number, hence
this specific case to avoid an assertion failure.
Target specific swap_reloc_in routine should adjust that. */
sym = bfd_abs_section_ptr->symbol_ptr_ptr;
}
else
{
/* PR 17512: file: 006-2964-0.004. */
if (num > mdata->nsects)
return -1;
/* A section number. */
sym = mdata->sections[num - 1]->bfdsection->symbol_ptr_ptr;
/* For a symbol defined in section S, the addend (stored in the
binary) contains the address of the section. To comply with
bfd convention, subtract the section address.
Use the address from the header, so that the user can modify
the vma of the section. */
res->addend = -mdata->sections[num - 1]->addr;
}
/* Note: Pairs for PPC LO/HI/HA are not scattered, but contain the offset
in the lower 16bits of the address value. So we have to find the
'symbol' from the preceding reloc. We do this even though the
section symbol is probably not needed here, because NULL symbol
values cause an assert in generic BFD code. This must be done in
the PPC swap_reloc_in routine. */
res->sym_ptr_ptr = sym;
/* The 'address' is just r_address.
??? maybe this should be masked with 0xffffff for safety. */
res->address = addr;
reloc.r_address = addr;
if (!bfd_mach_o_canonicalize_non_scattered_reloc (abfd, reloc,
res, syms))
return FALSE;
}
/* We have set up a reloc with all the information present, so the swapper
can modify address, value and addend fields, if necessary, to convey
information in the generic BFD reloc that is mach-o specific. */
if (!(*bed->_bfd_mach_o_swap_reloc_in)(res, &reloc))
return -1;
return 0;
return TRUE;
}
static int
@ -1450,6 +1472,7 @@ bfd_mach_o_canonicalize_relocs (bfd *abfd, unsigned long filepos,
unsigned long count,
arelent *res, asymbol **syms)
{
bfd_mach_o_backend_data *bed = bfd_mach_o_get_backend_data (abfd);
unsigned long i;
struct mach_o_reloc_info_external *native_relocs;
bfd_size_type native_size;
@ -1472,8 +1495,8 @@ bfd_mach_o_canonicalize_relocs (bfd *abfd, unsigned long filepos,
for (i = 0; i < count; i++)
{
if (bfd_mach_o_canonicalize_one_reloc (abfd, &native_relocs[i],
&res[i], syms) < 0)
if (!(*bed->_bfd_mach_o_canonicalize_one_reloc)(abfd, &native_relocs[i],
&res[i], syms))
goto err;
}
free (native_relocs);
@ -1495,7 +1518,7 @@ bfd_mach_o_canonicalize_reloc (bfd *abfd, asection *asect,
return 0;
/* No need to go further if we don't know how to read relocs. */
if (bed->_bfd_mach_o_swap_reloc_in == NULL)
if (bed->_bfd_mach_o_canonicalize_one_reloc == NULL)
return 0;
if (asect->relocation == NULL)
@ -1550,7 +1573,7 @@ bfd_mach_o_canonicalize_dynamic_reloc (bfd *abfd, arelent **rels,
return 0;
/* No need to go further if we don't know how to read relocs. */
if (bed->_bfd_mach_o_swap_reloc_in == NULL)
if (bed->_bfd_mach_o_canonicalize_one_reloc == NULL)
return 0;
if (mdata->dyn_reloc_cache == NULL)
@ -5807,7 +5830,7 @@ bfd_boolean bfd_mach_o_free_cached_info (bfd *abfd)
#define bfd_mach_o_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
#define bfd_mach_o_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup
#define bfd_mach_o_swap_reloc_in NULL
#define bfd_mach_o_canonicalize_one_reloc NULL
#define bfd_mach_o_swap_reloc_out NULL
#define bfd_mach_o_print_thread NULL
#define bfd_mach_o_tgt_seg_table NULL

View File

@ -704,6 +704,11 @@ bfd_boolean bfd_mach_o_read_symtab_strtab (bfd *abfd);
bfd_vma bfd_mach_o_get_base_address (bfd *);
void bfd_mach_o_swap_in_non_scattered_reloc (bfd *, bfd_mach_o_reloc_info *,
unsigned char *);
bfd_boolean bfd_mach_o_canonicalize_non_scattered_reloc (bfd *, bfd_mach_o_reloc_info *, arelent *, asymbol **);
bfd_boolean bfd_mach_o_pre_canonicalize_one_reloc (bfd *, struct mach_o_reloc_info_external *, bfd_mach_o_reloc_info *, arelent *, asymbol **);
/* A placeholder in case we need to suppress emitting the dysymtab for some
reason (e.g. compatibility with older system versions). */
#define bfd_mach_o_should_emit_dysymtab(x) TRUE
@ -740,7 +745,8 @@ typedef struct bfd_mach_o_backend_data
{
enum bfd_architecture arch;
bfd_vma page_size;
bfd_boolean (*_bfd_mach_o_swap_reloc_in)(arelent *, bfd_mach_o_reloc_info *);
bfd_boolean (*_bfd_mach_o_canonicalize_one_reloc)
(bfd *, struct mach_o_reloc_info_external *, arelent *, asymbol **);
bfd_boolean (*_bfd_mach_o_swap_reloc_out)(arelent *, bfd_mach_o_reloc_info *);
bfd_boolean (*_bfd_mach_o_print_thread)(bfd *, bfd_mach_o_thread_flavour *,
void *, char *);