xcoff: implement linker relaxation

bfd/ChangeLog:

	* coff-rs6000.c (xcoff_reloc_type_noop): Add info argument.
	(xcoff_reloc_type_fail): Likewise.
	(xcoff_reloc_type_pos): Likewise.
	(xcoff_reloc_type_neg): Likewise.
	(xcoff_reloc_type_rel): Likewise.
	(xcoff_reloc_type_toc): Likewise.
	(xcoff_reloc_type_ba): Likewise.
	(xcoff_reloc_type_crel): Likewise.
	(xcoff_reloc_type_tls): Likewise.
	(xcoff_reloc_type_br): Add stub handler.
	(xcoff_ppc_relocate_section): Add info to
	xcoff_calculate_relocation.
	(xcoff_stub_indirect_call_code): New constant.
	(xcoff_stub_shared_call_code): Likewise.
	(bfd_xcoff_backend_data): Add stub code fields.
	(bfd_pmac_xcoff_backend_data): Likewise.
	* coff64-rs6000.c (xcoff64_reloc_type_br): Add stub handler.
	(xcoff64_ppc_relocate_section): Add info to
	xcoff64_calculate_relocation.
	(xcoff64_stub_indirect_call_code): New constant.
	(xcoff64_stub_shared_call_code): Likewise.
	(bfd_xcoff_backend_data): Add stub code fields.
	(bfd_xcoff_aix5_backend_data): Likewise.
	* libxcoff.h (struct xcoff_backend_data_rec): Add stub fields.
	(bfd_xcoff_stub_indirect_call_code): New define.
	(bfd_xcoff_stub_indirect_call_size): New define.
	(bfd_xcoff_stub_shared_call_code): New define.
	(bfd_xcoff_stub_shared_call_size): New define.
	(xcoff_reloc_function): Add info argument.
	(enum xcoff_stub_type): New enum.
	(struct xcoff_stub_hash_entry): New structure.
	* xcofflink.c (struct xcoff_link_hash_table): Add stub hash
	table and params fields.
	(xcoff_stub_hash_entry): New define.
	(xcoff_stub_hash_lookup): New define.
	(stub_hash_newfunc): New function.
	(_bfd_xcoff_bfd_link_hash_table_free): Free the new stub hash
	table.
	(_bfd_xcoff_bfd_link_hash_table_create): Create the new stub
	hash table.
	(xcoff_link_add_symbols): Save rawsize for XTY_SD.
	(bfd_xcoff_link_init): New function.
	(xcoff_stub_csect_name): New function.
	(xcoff_stub_get_csect_in_range): New function.
	(xcoff_stub_name): New function.
	(bfd_xcoff_get_stub_entry): New function.
	(bfd_xcoff_type_of_stub): New function.
	(xcoff_add_stub): New function.
	(xcoff_build_one_stub): New function.
	(bfd_xcoff_size_stubs): New function.
	(bfd_xcoff_build_stubs): New function.
	(xcoff_stub_create_relocations): New function.
	(xcoff_link_input_bfd): Adapt relocations to stub.
	(xcoff_write_global_symbol): Adapt to new TOC entries generated
	for stubs.
	(_bfd_xcoff_bfd_final_link): Handle stub file.
	* xcofflink.h (struct bfd_xcoff_link_params): New structure.

ld/ChangeLog:

	* emultempl/aix.em (params): New variable.
	(stub_file): New variable.
	(xcoff_add_stub_section): New function.
	(xcoff_layout_sections_again): New function
	(hook_in_stub): New function.
	(_after_allocation): Add stub creation.
	(_create_output_section_statements): Allocate stub file and
	pass params to backend.
This commit is contained in:
Cl?ment Chigot
2022-04-20 15:11:47 +01:00
committed by Nick Clifton
parent 1876a54217
commit 2d23f9656c
8 changed files with 1413 additions and 33 deletions

View File

@ -1,3 +1,63 @@
2022-04-20 Clément Chigot <clement.chigot@atos.net>
* coff-rs6000.c (xcoff_reloc_type_noop): Add info argument.
(xcoff_reloc_type_fail): Likewise.
(xcoff_reloc_type_pos): Likewise.
(xcoff_reloc_type_neg): Likewise.
(xcoff_reloc_type_rel): Likewise.
(xcoff_reloc_type_toc): Likewise.
(xcoff_reloc_type_ba): Likewise.
(xcoff_reloc_type_crel): Likewise.
(xcoff_reloc_type_tls): Likewise.
(xcoff_reloc_type_br): Add stub handler.
(xcoff_ppc_relocate_section): Add info to
xcoff_calculate_relocation.
(xcoff_stub_indirect_call_code): New constant.
(xcoff_stub_shared_call_code): Likewise.
(bfd_xcoff_backend_data): Add stub code fields.
(bfd_pmac_xcoff_backend_data): Likewise.
* coff64-rs6000.c (xcoff64_reloc_type_br): Add stub handler.
(xcoff64_ppc_relocate_section): Add info to
xcoff64_calculate_relocation.
(xcoff64_stub_indirect_call_code): New constant.
(xcoff64_stub_shared_call_code): Likewise.
(bfd_xcoff_backend_data): Add stub code fields.
(bfd_xcoff_aix5_backend_data): Likewise.
* libxcoff.h (struct xcoff_backend_data_rec): Add stub fields.
(bfd_xcoff_stub_indirect_call_code): New define.
(bfd_xcoff_stub_indirect_call_size): New define.
(bfd_xcoff_stub_shared_call_code): New define.
(bfd_xcoff_stub_shared_call_size): New define.
(xcoff_reloc_function): Add info argument.
(enum xcoff_stub_type): New enum.
(struct xcoff_stub_hash_entry): New structure.
* xcofflink.c (struct xcoff_link_hash_table): Add stub hash
table and params fields.
(xcoff_stub_hash_entry): New define.
(xcoff_stub_hash_lookup): New define.
(stub_hash_newfunc): New function.
(_bfd_xcoff_bfd_link_hash_table_free): Free the new stub hash
table.
(_bfd_xcoff_bfd_link_hash_table_create): Create the new stub
hash table.
(xcoff_link_add_symbols): Save rawsize for XTY_SD.
(bfd_xcoff_link_init): New function.
(xcoff_stub_csect_name): New function.
(xcoff_stub_get_csect_in_range): New function.
(xcoff_stub_name): New function.
(bfd_xcoff_get_stub_entry): New function.
(bfd_xcoff_type_of_stub): New function.
(xcoff_add_stub): New function.
(xcoff_build_one_stub): New function.
(bfd_xcoff_size_stubs): New function.
(bfd_xcoff_build_stubs): New function.
(xcoff_stub_create_relocations): New function.
(xcoff_link_input_bfd): Adapt relocations to stub.
(xcoff_write_global_symbol): Adapt to new TOC entries generated
for stubs.
(_bfd_xcoff_bfd_final_link): Handle stub file.
* xcofflink.h (struct bfd_xcoff_link_params): New structure.
2022-04-20 Clément Chigot <clement.chigot@atos.net>
* coff-rs6000.c (_bfd_xcoff_put_ldsymbol_name): Write len in

View File

@ -2937,7 +2937,8 @@ xcoff_reloc_type_noop (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val ATTRIBUTE_UNUSED,
bfd_vma addend ATTRIBUTE_UNUSED,
bfd_vma *relocation ATTRIBUTE_UNUSED,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
return true;
}
@ -2952,7 +2953,8 @@ xcoff_reloc_type_fail (bfd *input_bfd,
bfd_vma val ATTRIBUTE_UNUSED,
bfd_vma addend ATTRIBUTE_UNUSED,
bfd_vma *relocation ATTRIBUTE_UNUSED,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
_bfd_error_handler
/* xgettext: c-format */
@ -2972,7 +2974,8 @@ xcoff_reloc_type_pos (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
*relocation = val + addend;
return true;
@ -2988,7 +2991,8 @@ xcoff_reloc_type_neg (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
*relocation = - val - addend;
return true;
@ -3004,7 +3008,8 @@ xcoff_reloc_type_rel (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
howto->pc_relative = true;
@ -3027,7 +3032,8 @@ xcoff_reloc_type_toc (bfd *input_bfd,
bfd_vma val,
bfd_vma addend ATTRIBUTE_UNUSED,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
struct xcoff_link_hash_entry *h;
@ -3076,7 +3082,8 @@ xcoff_reloc_type_ba (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
howto->src_mask &= ~3;
howto->dst_mask = howto->src_mask;
@ -3096,10 +3103,13 @@ xcoff_reloc_type_br (bfd *input_bfd,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents)
bfd_byte *contents,
struct bfd_link_info *info)
{
struct xcoff_link_hash_entry *h;
bfd_vma section_offset;
struct xcoff_stub_hash_entry *stub_entry = NULL;
enum xcoff_stub_type stub_type;
if (0 > rel->r_symndx)
return false;
@ -3153,6 +3163,27 @@ xcoff_reloc_type_br (bfd *input_bfd,
howto->complain_on_overflow = complain_overflow_dont;
}
/* Check if a stub is needed. */
stub_type = bfd_xcoff_type_of_stub (input_section, rel, val, h);
if (stub_type != xcoff_stub_none)
{
asection *stub_csect;
stub_entry = bfd_xcoff_get_stub_entry (input_section, h, info);
if (stub_entry == NULL)
{
_bfd_error_handler (_("Unable to find the stub entry targeting %s"),
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return false;
}
stub_csect = stub_entry->hcsect->root.u.def.section;
val = (stub_entry->stub_offset
+ stub_csect->output_section->vma
+ stub_csect->output_offset);
}
/* The original PC-relative relocation is biased by -r_vaddr, so adding
the value below will give the absolute target address. */
*relocation = val + addend + rel->r_vaddr;
@ -3202,7 +3233,8 @@ xcoff_reloc_type_crel (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val ATTRIBUTE_UNUSED,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
howto->pc_relative = true;
howto->src_mask &= ~3;
@ -3227,7 +3259,8 @@ xcoff_reloc_type_tls (bfd *input_bfd ATTRIBUTE_UNUSED,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents ATTRIBUTE_UNUSED)
bfd_byte *contents ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
struct xcoff_link_hash_entry *h;
@ -3763,7 +3796,7 @@ xcoff_ppc_relocate_section (bfd *output_bfd,
if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
|| !((*xcoff_calculate_relocation[rel->r_type])
(input_bfd, input_section, output_bfd, rel, sym, &howto, val,
addend, &relocation, contents)))
addend, &relocation, contents, info)))
return false;
/* address */
@ -4281,6 +4314,34 @@ HOWTO (0, /* type */
0xffffffff, /* dst_mask */
false); /* pcrel_offset */
/* Indirect call stub
The first word of the code must be modified by filling in
the correct TOC offset. */
static const unsigned long xcoff_stub_indirect_call_code[4] =
{
0x81820000, /* lwz r12,0(r2) */
0x800c0000, /* lwz r0,0(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
};
/* Shared call stub
The first word of the code must be modified by filling in
the correct TOC offset.
This is exactly as the glink code but without the traceback,
as it won't be an independent function. */
static const unsigned long xcoff_stub_shared_call_code[6] =
{
0x81820000, /* lwz r12,0(r2) */
0x90410014, /* stw r2,20(r1) */
0x800c0000, /* lwz r0,0(r12) */
0x804c0004, /* lwz r2,4(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
};
/* glink
The first word of global linkage code must be modified by filling in
@ -4497,6 +4558,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
/* rtinit */
64, /* _xcoff_rtinit_size */
xcoff_generate_rtinit,
/* Stub indirect call. */
&xcoff_stub_indirect_call_code[0],
16, /* _xcoff_stub_indirect_call_size */
/* Stub shared call. */
&xcoff_stub_shared_call_code[0],
24, /* _xcoff_stub_shared_call_size */
};
/* The transfer vector that leads the outside world to all of the above. */
@ -4679,6 +4748,14 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data =
/* rtinit */
0, /* _xcoff_rtinit_size */
xcoff_generate_rtinit,
/* Stub indirect call. */
&xcoff_stub_indirect_call_code[0],
16, /* _xcoff_stub_indirect_call_size */
/* Stub shared call. */
&xcoff_stub_shared_call_code[0],
24, /* _xcoff_stub_shared_call_size */
};
/* The transfer vector that leads the outside world to all of the above. */

View File

@ -778,10 +778,13 @@ xcoff64_reloc_type_br (bfd *input_bfd,
bfd_vma val,
bfd_vma addend,
bfd_vma *relocation,
bfd_byte *contents)
bfd_byte *contents,
struct bfd_link_info *info)
{
struct xcoff_link_hash_entry *h;
bfd_vma section_offset;
struct xcoff_stub_hash_entry *stub_entry = NULL;
enum xcoff_stub_type stub_type;
if (0 > rel->r_symndx)
return false;
@ -833,6 +836,27 @@ xcoff64_reloc_type_br (bfd *input_bfd,
howto->complain_on_overflow = complain_overflow_dont;
}
/* Check if a stub is needed. */
stub_type = bfd_xcoff_type_of_stub (input_section, rel, val, h);
if (stub_type != xcoff_stub_none)
{
asection *stub_csect;
stub_entry = bfd_xcoff_get_stub_entry (input_section, h, info);
if (stub_entry == NULL)
{
_bfd_error_handler (_("Unable to find the stub entry targeting %s"),
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return false;
}
stub_csect = stub_entry->hcsect->root.u.def.section;
val = (stub_entry->stub_offset
+ stub_csect->output_section->vma
+ stub_csect->output_offset);
}
/* The original PC-relative relocation is biased by -r_vaddr, so adding
the value below will give the absolute target address. */
*relocation = val + addend + rel->r_vaddr;
@ -1645,7 +1669,7 @@ xcoff64_ppc_relocate_section (bfd *output_bfd,
if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
|| !((*xcoff64_calculate_relocation[rel->r_type])
(input_bfd, input_section, output_bfd, rel, sym, &howto, val,
addend, &relocation, contents)))
addend, &relocation, contents, info)))
return false;
/* address */
@ -2386,12 +2410,32 @@ HOWTO (0, /* type */
MINUS_ONE, /* dst_mask */
false); /* pcrel_offset */
/* Indirect call stub */
static const unsigned long xcoff64_stub_indirect_call_code[4] =
{
0xe9820000, /* ld r12,0(r2) */
0xe80c0000, /* ld r0,0(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
};
/* Shared call stub */
static const unsigned long xcoff64_stub_shared_call_code[6] =
{
0xe9820000, /* ld r12,0(r2) */
0xf8410028, /* std r2,40(r1) */
0xe80c0000, /* ld r0,0(r12) */
0xe84c0008, /* ld r2,8(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
};
static const unsigned long xcoff64_glink_code[10] =
{
0xe9820000, /* ld r12,0(r2) */
0xf8410028, /* std r2,40(r1) */
0xe80c0000, /* ld r0,0(r12) */
0xe84c0008, /* ld r0,8(r12) */
0xe84c0008, /* ld r2,8(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
0x00000000, /* start of traceback table */
@ -2495,6 +2539,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
/* rtinit. */
88, /* _xcoff_rtinit_size */
xcoff64_generate_rtinit,
/* Stub indirect call. */
&xcoff64_stub_indirect_call_code[0],
16, /* _xcoff_stub_indirect_call_size */
/* Stub shared call. */
&xcoff64_stub_shared_call_code[0],
24, /* _xcoff_stub_shared_call_size */
};
/* The transfer vector that leads the outside world to all of the above. */
@ -2759,6 +2811,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_aix5_backend_data =
/* rtinit. */
88, /* _xcoff_rtinit_size */
xcoff64_generate_rtinit,
/* Stub indirect call. */
&xcoff64_stub_indirect_call_code[0],
16, /* _xcoff_stub_indirect_call_size */
/* Stub shared call. */
&xcoff64_stub_shared_call_code[0],
24, /* _xcoff_stub_shared_call_size */
};
/* The transfer vector that leads the outside world to all of the above. */

View File

@ -99,6 +99,15 @@ struct xcoff_backend_data_rec
unsigned int _xcoff_rtinit_size;
bool (*_xcoff_generate_rtinit)
(bfd *, const char *, const char *, bool);
/* Stubs code generation.
The code part is an array which might need to be modified by
some relocations.
The size is in bytes. */
const unsigned long *_xcoff_stub_indirect_call_code;
unsigned long _xcoff_stub_indirect_call_size;
const unsigned long *_xcoff_stub_shared_call_code;
unsigned long _xcoff_stub_shared_call_size;
};
/* Look up an entry in an XCOFF link hash table. */
@ -185,6 +194,11 @@ struct xcoff_backend_data_rec
#define bfd_xcoff_glink_code(a, b) ((xcoff_backend (a)->_xcoff_glink_code[(b)]))
#define bfd_xcoff_glink_code_size(a) ((xcoff_backend (a)->_xcoff_glink_size))
#define bfd_xcoff_stub_indirect_call_code(a, b) ((xcoff_backend (a)->_xcoff_stub_indirect_call_code[(b)]))
#define bfd_xcoff_stub_indirect_call_size(a) ((xcoff_backend (a)->_xcoff_stub_indirect_call_size))
#define bfd_xcoff_stub_shared_call_code(a, b) ((xcoff_backend (a)->_xcoff_stub_shared_call_code[(b)]))
#define bfd_xcoff_stub_shared_call_size(a) ((xcoff_backend (a)->_xcoff_stub_shared_call_size))
/* Check for the magic number U803XTOCMAGIC or U64_TOCMAGIC for 64 bit
targets. */
#define bfd_xcoff_is_xcoff64(a) \
@ -211,11 +225,12 @@ struct xcoff_backend_data_rec
#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)
typedef bool xcoff_reloc_function (bfd *, asection *, bfd *,
struct internal_reloc *,
struct internal_syment *,
struct reloc_howto_struct *,
bfd_vma, bfd_vma,
bfd_vma *, bfd_byte *);
struct internal_reloc *,
struct internal_syment *,
struct reloc_howto_struct *,
bfd_vma, bfd_vma,
bfd_vma *, bfd_byte *,
struct bfd_link_info *);
typedef bool xcoff_complain_function (bfd *, bfd_vma, bfd_vma,
struct reloc_howto_struct *);
@ -261,4 +276,42 @@ struct xcoff_dwsect_name {
extern const struct xcoff_dwsect_name
xcoff_dwsect_names[XCOFF_DWSECT_NBR_NAMES];
/* Structure and functions needed by backend in order to handle
stubs created in xcofflink.c. */
enum xcoff_stub_type
{
xcoff_stub_none,
xcoff_stub_indirect_call,
xcoff_stub_shared_call
};
struct xcoff_stub_hash_entry
{
/* Base hash table entry structure. */
struct bfd_hash_entry root;
enum xcoff_stub_type stub_type;
/* The hash table entry of the stub's csect. */
struct xcoff_link_hash_entry *hcsect;
/* Offset in the stub's csect. */
bfd_vma stub_offset;
/* The target's section. */
asection *target_section;
/* The target's hash table entry. */
struct xcoff_link_hash_entry *htarget;
};
extern enum xcoff_stub_type bfd_xcoff_type_of_stub
(asection *, const struct internal_reloc *, bfd_vma,
struct xcoff_link_hash_entry *);
extern struct xcoff_stub_hash_entry *bfd_xcoff_get_stub_entry
(asection *, struct xcoff_link_hash_entry *, struct bfd_link_info *);
#endif /* LIBXCOFF_H */

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,17 @@
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Used to pass info between ld and bfd. */
struct bfd_xcoff_link_params
{
/* Linker stub bfd. */
bfd *stub_bfd;
/* Linker call-backs. */
asection * (*add_stub_section) (const char *, asection *);
void (*layout_sections_again) (void);
};
extern bool bfd_xcoff_split_import_path
(bfd *, const char *, const char **, const char **);
extern bool bfd_xcoff_set_archive_import_path
@ -41,3 +52,9 @@ extern bool bfd_xcoff_build_dynamic_sections
(bfd *, struct bfd_link_info *);
extern bool bfd_xcoff_link_generate_rtinit
(bfd *, const char *, const char *, bool);
extern bool bfd_xcoff_link_init
(struct bfd_link_info *, struct bfd_xcoff_link_params *);
extern bool bfd_xcoff_size_stubs
(struct bfd_link_info *info);
extern bool bfd_xcoff_build_stubs
(struct bfd_link_info *info);

View File

@ -1,3 +1,14 @@
2022-04-20 Clément Chigot <clement.chigot@atos.net>
* emultempl/aix.em (params): New variable.
(stub_file): New variable.
(xcoff_add_stub_section): New function.
(xcoff_layout_sections_again): New function
(hook_in_stub): New function.
(_after_allocation): Add stub creation.
(_create_output_section_statements): Allocate stub file and
pass params to backend.
2022-04-20 Clément Chigot <clement.chigot@atos.net>
* emultempl/aix.em (_after_allocation): New function.

View File

@ -63,6 +63,15 @@ static void gld${EMULATION_NAME}_free (void *);
static void gld${EMULATION_NAME}_find_relocs (lang_statement_union_type *);
static void gld${EMULATION_NAME}_find_exp_assignment (etree_type *);
static asection *xcoff_add_stub_section (const char *, asection *);
static void xcoff_layout_sections_again (void);
static struct bfd_xcoff_link_params params = {
NULL,
&xcoff_add_stub_section,
&xcoff_layout_sections_again
};
/* The file alignment required for each section. */
static unsigned long file_align;
@ -138,6 +147,9 @@ static int rtld;
/* Explicit command line library path, -blibpath */
static char *command_line_blibpath = NULL;
/* Fake input file for stubs. */
static lang_input_statement_type *stub_file;
/* This routine is called before anything else is done. */
static void
@ -154,6 +166,7 @@ gld${EMULATION_NAME}_before_parse (void)
link_info.init_function = NULL;
link_info.fini_function = NULL;
}
/* Handle AIX specific options. */
@ -1009,12 +1022,157 @@ gld${EMULATION_NAME}_before_allocation (void)
before_allocation_default ();
}
struct hook_stub_info
{
lang_statement_list_type add;
asection *input_section;
};
/* Traverse the linker tree to find the spot where the stub goes. */
static bool
hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
{
lang_statement_union_type *l;
bool ret;
for (; (l = *lp) != NULL; lp = &l->header.next)
{
switch (l->header.type)
{
case lang_constructors_statement_enum:
ret = hook_in_stub (info, &constructor_list.head);
if (ret)
return ret;
break;
case lang_output_section_statement_enum:
ret = hook_in_stub (info,
&l->output_section_statement.children.head);
if (ret)
return ret;
break;
case lang_wild_statement_enum:
ret = hook_in_stub (info, &l->wild_statement.children.head);
if (ret)
return ret;
break;
case lang_group_statement_enum:
ret = hook_in_stub (info, &l->group_statement.children.head);
if (ret)
return ret;
break;
case lang_input_section_enum:
if (l->input_section.section == info->input_section)
{
/* We've found our section. Insert the stub immediately
after its associated input section. */
*(info->add.tail) = l->header.next;
l->header.next = info->add.head;
return true;
}
break;
case lang_data_statement_enum:
case lang_reloc_statement_enum:
case lang_object_symbols_statement_enum:
case lang_output_statement_enum:
case lang_target_statement_enum:
case lang_input_statement_enum:
case lang_assignment_statement_enum:
case lang_padding_statement_enum:
case lang_address_statement_enum:
case lang_fill_statement_enum:
break;
default:
FAIL ();
break;
}
}
return false;
}
/* Call-back for bfd_xcoff_link_relocations.
Create a new stub section, and arrange for it to be linked
immediately before INPUT_SECTION. */
static asection *
xcoff_add_stub_section (const char *stub_sec_name, asection *input_section)
{
asection *stub_sec;
flagword flags;
asection *output_section;
lang_output_section_statement_type *os;
struct hook_stub_info info;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP);
stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
stub_sec_name, flags);
if (stub_sec == NULL)
goto err_ret;
output_section = input_section->output_section;
os = lang_output_section_get (output_section);
info.input_section = input_section;
lang_list_init (&info.add);
lang_add_section (&info.add, stub_sec, NULL, NULL, os);
if (info.add.head == NULL)
goto err_ret;
if (hook_in_stub (&info, &os->children.head))
return stub_sec;
err_ret:
einfo (_("%X%P: can not make stub section: %E\n"));
return NULL;
}
/* Another call-back for bfd_xcoff_link_relocations. */
static void
xcoff_layout_sections_again (void)
{
/* If we have changed sizes of the stub sections, then we need
to recalculate all the section offsets. This may mean we need to
add even more stubs. */
lang_relax_sections (true);
}
/* Call the back-end to verify relocations. */
static void
gld${EMULATION_NAME}_after_allocation (void)
{
/* If generating a relocatable output file, then we don't have any
stubs. */
if (stub_file != NULL && !bfd_link_relocatable (&link_info))
{
/* Call into the BFD backend to do the real work. */
if (!bfd_xcoff_size_stubs (&link_info))
einfo (_("%X%P: can not size stub sections: %E\n"));
}
/* Now that everything is in place, finalize the dynamic sections. */
if (!bfd_xcoff_build_dynamic_sections (link_info.output_bfd, &link_info))
einfo (_("%F%P: failed to layout dynamic sections: %E\n"));
if (!bfd_link_relocatable (&link_info))
{
/* Now build the linker stubs. */
if (stub_file != NULL && stub_file->the_bfd->sections != NULL)
{
if (! bfd_xcoff_build_stubs (&link_info))
einfo (_("%X%P: can not build stubs: %E\n"));
}
}
}
static char *
@ -1503,11 +1661,35 @@ fragment <<EOF
static void
gld${EMULATION_NAME}_create_output_section_statements (void)
{
if ((bfd_get_flavour (link_info.output_bfd) != bfd_target_xcoff_flavour))
return;
/* Stub file */
stub_file = lang_add_input_file ("linker stubs",
lang_input_file_is_fake_enum,
NULL);
stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
if (stub_file->the_bfd == NULL
|| !bfd_set_arch_mach (stub_file->the_bfd,
bfd_get_arch (link_info.output_bfd),
bfd_get_mach (link_info.output_bfd)))
{
einfo (_("%F%P: can not create stub BFD: %E\n"));
return;
}
stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
ldlang_add_file (stub_file);
params.stub_bfd = stub_file->the_bfd;
/* Pass linker params to the back-end. */
if (!bfd_xcoff_link_init (&link_info, &params))
einfo (_("%F%P: can not init BFD: %E\n"));
/* __rtinit */
if ((bfd_get_flavour (link_info.output_bfd) == bfd_target_xcoff_flavour)
&& (link_info.init_function != NULL
|| link_info.fini_function != NULL
|| rtld))
if (link_info.init_function != NULL
|| link_info.fini_function != NULL
|| rtld)
{
initfini_file = lang_add_input_file ("initfini",
lang_input_file_is_file_enum,