This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
powerpc64 opd edit
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sources dot redhat dot com
- Date: Mon, 8 Dec 2003 23:19:01 +1030
- Subject: powerpc64 opd edit
Current powerpc64 opd editing code leaves symbols defined in opd
unchanged when output, where they ought to be adjusted to reflect
changes caused by deleting entries. For nm, objdump etc. symbol table
dumps this is mostly just a nuisance level bug, but when ld -r is
involved we can generate bad code taking addresses of functions.
Fixing this without adding ppc64 specific code (or another hook) to the
generic code required an extra parameter on elf_link_output_sym, as the
ppc64 code needs some means to distinguish local symbols from globals.
Looking at sym->st_info for STB_LOCAL isn't sufficient because of forced
local symbols.
I suppose an extra hook called from elf_link_input_bfd in the same place
as _bfd_merged_section_offset might have been a neater way to solve the
problem of adjusting local symbol values, but I'd already written the
patch this way before I thought of that. :) Besides, passing the hash
entry allows a bug in elf64_hppa_link_output_symbol_hook to be fixed.
Since output_symbol_hook is called for local as well as global syms,
it was possible that the dyn_h lookup on a local sym might return
something for a global sym; Local syms in one input file can have the
same name as a global sym in another file.
* elf-bfd.h (struct elf_backend_data): Remove "bfd *" and add
"elflink_hash_entry *" param to elf_backend_link_output_symbol_hook.
Add "elflink_hash_entry *" param to elf_backend_output_arch_syms.
* elflink.h (elf_link_output_sym): Add "elflink_hash_entry *" param,
and pass to output_symbol_hook.
(elf_bfd_final_link): Adjust elf_link_output_sym calls.
(elf_link_output_extsym): Likewise.
(elf_link_input_bfd): Likewise.
* elf32-sh64.c (sh64_elf_link_output_symbol_hook): Adjust.
* elf32-v850.c (v850_elf_link_output_symbol_hook): Likewise.
* elf64-mmix.c (mmix_elf_link_output_symbol_hook): Likewise.
* elf64-sh64.c (sh64_elf64_link_output_symbol_hook): Likewise.
* elfxx-mips.c (_bfd_mips_elf_link_output_symbol_hook): Likewise.
* elfxx-mips.h (_bfd_mips_elf_link_output_symbol_hook): Likewise.
* elf64-sparc.c (sparc64_elf_output_arch_syms): Likewise.
* elf64-hppa.c (elf64_hppa_link_output_symbol_hook): Likewise.
Validate dynh->h against h.
* elf64-ppc.c (struct ppc_link_hash_entry): Add adjust_done bitfield.
(link_hash_newfunc): Init it.
(adjust_opd_syms): New function.
(ppc64_elf_edit_opd): Set adjust_done when global .opd sym adjusted.
Set opd.adjust for all .opd relocs. Call adjust_opd_syms.
(ppc64_elf_tls_optimize): Adjust possible .opd sym values here.
(ppc64_elf_relocate_section): Also adjust syms not a multiple of 24.
(ppc64_elf_output_symbol_hook): New function.
(elf_backend_link_output_symbol_hook): Define.
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.123
diff -u -p -r1.123 elf-bfd.h
--- bfd/elf-bfd.h 1 Dec 2003 06:28:23 -0000 1.123
+++ bfd/elf-bfd.h 8 Dec 2003 10:41:19 -0000
@@ -626,8 +626,8 @@ struct elf_backend_data
/* If this field is not NULL, it is called by the elf_link_output_sym
phase of a link for each symbol which will appear in the object file. */
bfd_boolean (*elf_backend_link_output_symbol_hook)
- (bfd *, struct bfd_link_info *info, const char *, Elf_Internal_Sym *,
- asection *);
+ (struct bfd_link_info *info, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *);
/* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend
linker the first time it encounters a dynamic object in the link.
@@ -793,7 +793,8 @@ struct elf_backend_data
not handled in the hash table. */
bfd_boolean (*elf_backend_output_arch_syms)
(bfd *, struct bfd_link_info *, void *,
- bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *));
+ bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *));
/* Copy any information related to dynamic linking from a pre-existing
symbol to a newly created symbol. Also called to copy flags and
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.249
diff -u -p -r1.249 elflink.h
--- bfd/elflink.h 1 Dec 2003 06:28:23 -0000 1.249
+++ bfd/elflink.h 8 Dec 2003 10:41:38 -0000
@@ -2833,7 +2833,8 @@ struct elf_final_link_info
};
static bfd_boolean elf_link_output_sym
- (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *);
+ (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
static bfd_boolean elf_link_flush_output_syms
(struct elf_final_link_info *);
static bfd_boolean elf_link_output_extsym
@@ -3407,7 +3408,8 @@ elf_bfd_final_link (bfd *abfd, struct bf
elfsym.st_info = 0;
elfsym.st_other = 0;
elfsym.st_shndx = SHN_UNDEF;
- if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr))
+ if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+ NULL))
goto error_return;
}
@@ -3423,7 +3425,7 @@ elf_bfd_final_link (bfd *abfd, struct bf
elfsym.st_other = 0;
elfsym.st_shndx = SHN_ABS;
if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd),
- &elfsym, bfd_abs_section_ptr))
+ &elfsym, bfd_abs_section_ptr, NULL))
goto error_return;
#endif
@@ -3448,7 +3450,7 @@ elf_bfd_final_link (bfd *abfd, struct bf
elfsym.st_value = 0;
else
elfsym.st_value = o->vma;
- if (! elf_link_output_sym (&finfo, NULL, &elfsym, o))
+ if (! elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
goto error_return;
if (i == SHN_LORESERVE - 1)
i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
@@ -3702,7 +3704,8 @@ elf_bfd_final_link (bfd *abfd, struct bf
if (bed->elf_backend_output_arch_syms)
{
typedef bfd_boolean (*out_sym_func)
- (void *, const char *, Elf_Internal_Sym *, asection *);
+ (void *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
if (! ((*bed->elf_backend_output_arch_syms)
(abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
@@ -4086,20 +4089,20 @@ static bfd_boolean
elf_link_output_sym (struct elf_final_link_info *finfo,
const char *name,
Elf_Internal_Sym *elfsym,
- asection *input_sec)
+ asection *input_sec,
+ struct elf_link_hash_entry *h)
{
Elf_External_Sym *dest;
Elf_External_Sym_Shndx *destshndx;
bfd_boolean (*output_symbol_hook)
- (bfd *, struct bfd_link_info *info, const char *,
- Elf_Internal_Sym *, asection *);
+ (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
elf_backend_link_output_symbol_hook;
if (output_symbol_hook != NULL)
{
- if (! ((*output_symbol_hook)
- (finfo->output_bfd, finfo->info, name, elfsym, input_sec)))
+ if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
return FALSE;
}
@@ -4640,7 +4643,7 @@ elf_link_output_extsym (struct elf_link_
h->indx = bfd_get_symcount (finfo->output_bfd);
- if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
+ if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h))
{
eoinfo->failed = TRUE;
return FALSE;
@@ -4845,7 +4848,7 @@ elf_link_input_bfd (struct elf_final_lin
}
}
- if (! elf_link_output_sym (finfo, name, &osym, isec))
+ if (! elf_link_output_sym (finfo, name, &osym, isec, NULL))
return FALSE;
}
@@ -5207,7 +5210,8 @@ elf_link_input_bfd (struct elf_final_lin
finfo->indices[r_symndx]
= bfd_get_symcount (output_bfd);
- if (! elf_link_output_sym (finfo, name, &sym, sec))
+ if (! elf_link_output_sym (finfo, name, &sym, sec,
+ NULL))
return FALSE;
}
Index: bfd/elf32-sh64.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-sh64.c,v
retrieving revision 1.21
diff -u -p -r1.21 elf32-sh64.c
--- bfd/elf32-sh64.c 1 Dec 2003 06:28:23 -0000 1.21
+++ bfd/elf32-sh64.c 8 Dec 2003 10:41:21 -0000
@@ -59,8 +59,8 @@ static bfd_boolean sh64_elf_add_symbol_h
(bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, const char **,
flagword *, asection **, bfd_vma *);
static bfd_boolean sh64_elf_link_output_symbol_hook
- (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
- asection *);
+ (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
static bfd_boolean sh64_backend_section_from_shdr
(bfd *, Elf_Internal_Shdr *, const char *);
static void sh64_elf_final_write_processing
@@ -470,11 +470,11 @@ sh64_elf_add_symbol_hook (bfd *abfd, str
DataLabel symbol. */
bfd_boolean
-sh64_elf_link_output_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info,
+sh64_elf_link_output_symbol_hook (struct bfd_link_info *info,
const char *cname,
Elf_Internal_Sym *sym,
- asection *input_sec ATTRIBUTE_UNUSED)
+ asection *input_sec ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
{
char *name = (char *) cname;
Index: bfd/elf32-v850.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-v850.c,v
retrieving revision 1.38
diff -u -p -r1.38 elf32-v850.c
--- bfd/elf32-v850.c 27 Nov 2003 18:49:38 -0000 1.38
+++ bfd/elf32-v850.c 8 Dec 2003 10:41:22 -0000
@@ -76,8 +76,8 @@ static bfd_boolean v850_elf_add_symbol_h
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
const char **, flagword *, asection **, bfd_vma *));
static bfd_boolean v850_elf_link_output_symbol_hook
- PARAMS ((bfd *, struct bfd_link_info *, const char *,
- Elf_Internal_Sym *, asection *));
+ PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *));
static bfd_boolean v850_elf_section_from_shdr
PARAMS ((bfd *, Elf_Internal_Shdr *, const char *));
static bfd_boolean v850_elf_gc_sweep_hook
@@ -2213,12 +2213,12 @@ v850_elf_add_symbol_hook (abfd, info, sy
}
static bfd_boolean
-v850_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
- bfd *abfd ATTRIBUTE_UNUSED;
+v850_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
struct bfd_link_info *info ATTRIBUTE_UNUSED;
const char *name ATTRIBUTE_UNUSED;
Elf_Internal_Sym *sym;
asection *input_sec;
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
{
/* If we see a common symbol, which implies a relocatable link, then
if a symbol was in a special common section in an input file, mark
Index: bfd/elf64-mmix.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-mmix.c,v
retrieving revision 1.28
diff -u -p -r1.28 elf64-mmix.c
--- bfd/elf64-mmix.c 27 Nov 2003 18:49:38 -0000 1.28
+++ bfd/elf64-mmix.c 8 Dec 2003 10:41:25 -0000
@@ -157,8 +157,8 @@ struct bpo_greg_section_info
};
static bfd_boolean mmix_elf_link_output_symbol_hook
- PARAMS ((bfd *, struct bfd_link_info *, const char *,
- Elf_Internal_Sym *, asection *));
+ PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *));
static bfd_reloc_status_type mmix_elf_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
@@ -2113,12 +2113,12 @@ _bfd_mmix_check_all_relocs (abfd, info)
number. */
static bfd_boolean
-mmix_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
- bfd *abfd ATTRIBUTE_UNUSED;
+mmix_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
struct bfd_link_info *info ATTRIBUTE_UNUSED;
const char *name ATTRIBUTE_UNUSED;
Elf_Internal_Sym *sym;
asection *input_sec;
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
{
if (input_sec != NULL
&& input_sec->name != NULL
Index: bfd/elf64-sh64.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-sh64.c,v
retrieving revision 1.41
diff -u -p -r1.41 elf64-sh64.c
--- bfd/elf64-sh64.c 1 Dec 2003 06:28:23 -0000 1.41
+++ bfd/elf64-sh64.c 8 Dec 2003 10:41:32 -0000
@@ -144,8 +144,8 @@ static bfd_boolean sh64_elf64_add_symbol
(bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, const char **,
flagword *, asection **, bfd_vma *);
static bfd_boolean sh64_elf64_link_output_symbol_hook
- (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
- asection *);
+ (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *);
static bfd_boolean sh64_elf64_fake_sections
(bfd *, Elf_Internal_Shdr *, asection *);
static void sh64_elf64_final_write_processing
@@ -2982,11 +2982,11 @@ sh64_elf64_add_symbol_hook (bfd *abfd, s
DataLabel symbol. */
static bfd_boolean
-sh64_elf64_link_output_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info,
+sh64_elf64_link_output_symbol_hook (struct bfd_link_info *info,
const char *cname,
Elf_Internal_Sym *sym,
- asection *input_sec ATTRIBUTE_UNUSED)
+ asection *input_sec ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
{
char *name = (char *) cname;
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.85
diff -u -p -r1.85 elfxx-mips.c
--- bfd/elfxx-mips.c 27 Nov 2003 18:49:39 -0000 1.85
+++ bfd/elfxx-mips.c 8 Dec 2003 10:41:43 -0000
@@ -4818,12 +4818,12 @@ _bfd_mips_elf_add_symbol_hook (abfd, inf
also where we undo the increment of the value for a mips16 symbol. */
bfd_boolean
-_bfd_mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
- bfd *abfd ATTRIBUTE_UNUSED;
+_bfd_mips_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
struct bfd_link_info *info ATTRIBUTE_UNUSED;
const char *name ATTRIBUTE_UNUSED;
Elf_Internal_Sym *sym;
asection *input_sec;
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
{
/* If we see a common symbol, which implies a relocatable link, then
if a symbol was small common in an input file, mark it as small
Index: bfd/elfxx-mips.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.h,v
retrieving revision 1.14
diff -u -p -r1.14 elfxx-mips.h
--- bfd/elfxx-mips.h 27 Nov 2003 16:43:25 -0000 1.14
+++ bfd/elfxx-mips.h 8 Dec 2003 10:41:43 -0000
@@ -36,8 +36,8 @@ extern bfd_boolean _bfd_mips_elf_add_sym
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
const char **, flagword *, asection **, bfd_vma *));
extern bfd_boolean _bfd_mips_elf_link_output_symbol_hook
- PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
- asection *));
+ PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *));
extern bfd_boolean _bfd_mips_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
extern bfd_boolean _bfd_mips_elf_check_relocs
Index: bfd/elf64-sparc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-sparc.c,v
retrieving revision 1.81
diff -u -p -r1.81 elf64-sparc.c
--- bfd/elf64-sparc.c 27 Nov 2003 18:49:38 -0000 1.81
+++ bfd/elf64-sparc.c 8 Dec 2003 10:41:34 -0000
@@ -65,7 +65,8 @@ static bfd_boolean sparc64_elf_add_symbo
const char **, flagword *, asection **, bfd_vma *));
static bfd_boolean sparc64_elf_output_arch_syms
PARAMS ((bfd *, struct bfd_link_info *, PTR,
- bfd_boolean (*) (PTR, const char *, Elf_Internal_Sym *, asection *)));
+ bfd_boolean (*) (PTR, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *)));
static void sparc64_elf_symbol_processing
PARAMS ((bfd *, asymbol *));
@@ -1511,7 +1512,8 @@ sparc64_elf_output_arch_syms (output_bfd
struct bfd_link_info *info;
PTR finfo;
bfd_boolean (*func)
- PARAMS ((PTR, const char *, Elf_Internal_Sym *, asection *));
+ PARAMS ((PTR, const char *, Elf_Internal_Sym *, asection *,
+ struct elf_link_hash_entry *));
{
int reg;
struct sparc64_elf_app_reg *app_regs =
@@ -1557,7 +1559,8 @@ sparc64_elf_output_arch_syms (output_bfd
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))
+ ? bfd_abs_section_ptr : bfd_und_section_ptr,
+ NULL))
return FALSE;
}
Index: bfd/elf64-hppa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-hppa.c,v
retrieving revision 1.43
diff -u -p -r1.43 elf64-hppa.c
--- bfd/elf64-hppa.c 27 Nov 2003 18:49:38 -0000 1.43
+++ bfd/elf64-hppa.c 8 Dec 2003 10:41:24 -0000
@@ -202,8 +202,8 @@ static bfd_boolean elf64_hppa_size_dynam
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean elf64_hppa_link_output_symbol_hook
- PARAMS ((bfd *abfd, struct bfd_link_info *, const char *,
- Elf_Internal_Sym *, asection *input_sec));
+ PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+ asection *, struct elf_link_hash_entry *));
static bfd_boolean elf64_hppa_finish_dynamic_symbol
PARAMS ((bfd *, struct bfd_link_info *,
@@ -1893,12 +1893,12 @@ elf64_hppa_size_dynamic_sections (output
table. Ick. */
static bfd_boolean
-elf64_hppa_link_output_symbol_hook (abfd, info, name, sym, input_sec)
- bfd *abfd ATTRIBUTE_UNUSED;
+elf64_hppa_link_output_symbol_hook (info, name, sym, input_sec, h)
struct bfd_link_info *info;
const char *name;
Elf_Internal_Sym *sym;
asection *input_sec ATTRIBUTE_UNUSED;
+ struct elf_link_hash_entry *h;
{
struct elf64_hppa_link_hash_table *hppa_info;
struct elf64_hppa_dyn_hash_entry *dyn_h;
@@ -1912,6 +1912,8 @@ elf64_hppa_link_output_symbol_hook (abfd
hppa_info = elf64_hppa_hash_table (info);
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
name, FALSE, FALSE);
+ if (dyn_h->h != h)
+ return TRUE;
/* Function symbols for which we created .opd entries *may* have been
munged by finish_dynamic_symbol and have to be un-munged here.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.141
diff -u -p -r1.141 elf64-ppc.c
--- bfd/elf64-ppc.c 27 Nov 2003 18:49:38 -0000 1.141
+++ bfd/elf64-ppc.c 8 Dec 2003 11:29:43 -0000
@@ -92,6 +92,7 @@ static bfd_reloc_status_type ppc64_elf_u
#define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol
#define elf_backend_reloc_type_class ppc64_elf_reloc_type_class
#define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections
+#define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook
#define elf_backend_special_sections ppc64_elf_special_sections
/* The name of the dynamic interpreter. This is put in the .interp
@@ -2762,6 +2763,9 @@ struct ppc_link_hash_entry
unsigned int is_func_descriptor:1;
unsigned int is_entry:1;
+ /* Whether global opd sym has been adjusted or not. */
+ unsigned int adjust_done:1;
+
/* Contexts in which symbol is used in the GOT (or TOC).
TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
corresponding relocs are encountered during check_relocs.
@@ -2971,6 +2975,7 @@ link_hash_newfunc (struct bfd_hash_entry
eh->is_func = 0;
eh->is_func_descriptor = 0;
eh->is_entry = 0;
+ eh->adjust_done = 0;
eh->tls_mask = 0;
}
@@ -4875,10 +4880,53 @@ get_tls_mask (char **tls_maskp, unsigned
return 1;
}
+/* Adjust all global syms defined in opd sections. In gcc generated
+ code these will already have been done, but I suppose we have to
+ cater for all sorts of hand written assembly. */
+
+static bfd_boolean
+adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+ struct ppc_link_hash_entry *eh;
+ asection *sym_sec;
+ long *opd_adjust;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
+ if (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)
+ return TRUE;
+
+ eh = (struct ppc_link_hash_entry *) h;
+ if (eh->adjust_done)
+ return TRUE;
+
+ sym_sec = eh->elf.root.u.def.section;
+ if (sym_sec != NULL
+ && elf_section_data (sym_sec) != NULL
+ && (opd_adjust = ppc64_elf_section_data (sym_sec)->opd.adjust) != NULL)
+ {
+ eh->elf.root.u.def.value += opd_adjust[eh->elf.root.u.def.value / 24];
+ eh->adjust_done = 1;
+ }
+ return TRUE;
+}
+
+/* Remove unused Official Procedure Descriptor entries. Currently we
+ only remove those associated with functions in discarded link-once
+ sections, or weakly defined functions that have been overridden. It
+ would be possible to remove many more entries for statically linked
+ applications. */
+
bfd_boolean
ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info)
{
bfd *ibfd;
+ bfd_boolean some_edited = FALSE;
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
@@ -5079,23 +5127,25 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
if (h != NULL)
{
- /* Redefine the function descriptor symbol
- to this location in the opd section.
- We've checked above that opd relocs are
- ordered. */
+ /* Redefine the function descriptor symbol to
+ this location in the opd section. It is
+ necessary to update the value here rather
+ than using an array of adjustments as we do
+ for local symbols, because various places
+ in the generic ELF code use the value
+ stored in u.def.value. */
fdh->elf.root.u.def.value = wptr - sec->contents;
- }
- else
- {
- /* Local syms are a bit tricky. We could
- tweak them as they can be cached, but
- we'd need to look through the local syms
- for the function descriptor sym which we
- don't have at the moment. So keep an
- array of adjustments. */
- adjust[rel->r_offset / 24] = wptr - rptr;
+ fdh->adjust_done = 1;
}
+ /* Local syms are a bit tricky. We could
+ tweak them as they can be cached, but
+ we'd need to look through the local syms
+ for the function descriptor sym which we
+ don't have at the moment. So keep an
+ array of adjustments. */
+ adjust[rel->r_offset / 24] = wptr - rptr;
+
if (wptr != rptr)
memcpy (wptr, rptr, 24);
wptr += 24;
@@ -5153,6 +5203,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
elf_section_data (sec)->rel_hdr.sh_size
= sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize;
BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL);
+ some_edited = TRUE;
}
else if (elf_section_data (sec)->relocs != relstart)
free (relstart);
@@ -5167,6 +5218,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
}
}
+ if (some_edited)
+ elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL);
+
return TRUE;
}
@@ -5262,7 +5316,17 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
value = h->root.u.def.value;
}
else
- value = sym->st_value;
+ {
+ value = sym->st_value;
+
+ if (elf_section_data (sym_sec) != NULL)
+ {
+ long *adjust;
+ adjust = ppc64_elf_section_data (sym_sec)->opd.adjust;
+ if (adjust != NULL)
+ value += adjust[value / 24];
+ }
+ }
ok_tprel = FALSE;
is_local = FALSE;
@@ -7402,7 +7466,7 @@ ppc64_elf_relocate_section (bfd *output_
long *opd_sym_adjust;
opd_sym_adjust = ppc64_elf_section_data (sec)->opd.adjust;
- if (opd_sym_adjust != NULL && sym->st_value % 24 == 0)
+ if (opd_sym_adjust != NULL)
relocation += opd_sym_adjust[sym->st_value / 24];
}
}
@@ -8671,6 +8735,32 @@ ppc64_elf_relocate_section (bfd *output_
}
return ret;
+}
+
+/* Adjust the value of any local symbols in opd sections. */
+
+static bfd_boolean
+ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
+ const char *name ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *elfsym,
+ asection *input_sec,
+ struct elf_link_hash_entry *h)
+{
+ long *adjust;
+ bfd_vma value;
+
+ if (h != NULL
+ || input_sec == NULL
+ || ppc64_elf_section_data (input_sec) == NULL
+ || (adjust = ppc64_elf_section_data (input_sec)->opd.adjust) == NULL)
+ return TRUE;
+
+ value = elfsym->st_value - input_sec->output_offset;
+ if (!info->relocatable)
+ value -= input_sec->output_section->vma;
+
+ elfsym->st_value += adjust[value / 24];
+ return TRUE;
}
/* Finish up dynamic symbol handling. We set the contents of various
--
Alan Modra
IBM OzLabs - Linux Technology Centre