This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
complex relocation fixes
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Wed, 26 Sep 2007 21:58:32 +0930
- Subject: complex relocation fixes
Even when symbols are cached, the complex relocation support code
needlessly reads the symbol table from disk and converts to internal
form just to have the luxury of finding symbols in a particular
buffer. This happens whether complex relocations are present or not.
On fixing this, I noticed that set_symbol_value wouldn't work unless
elf_bad_symtab was true (was this why MEP set it?). You'd get accesses
past the end of the array of local symbols.
* elflink.c (set_symbol_value): Add isymbuf and locsymcount
params. Change symidx to a size_t. Don't access past end
of symbol buffer.
(resolve_symbol): Add isymbuf param and use instead of
finfo->internal_syms.
(eval_symbol, evaluate_complex_relocation_symbols): Likewise.
(elf_link_input_bfd): Don't read symbols specially for
evaluate_complex_relocation_symbols.
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.278
diff -u -p -r1.278 elflink.c
--- bfd/elflink.c 18 Sep 2007 08:17:06 -0000 1.278
+++ bfd/elflink.c 26 Sep 2007 09:14:52 -0000
@@ -7230,38 +7230,43 @@ struct elf_outext_info
static void
set_symbol_value (bfd * bfd_with_globals,
- struct elf_final_link_info * finfo,
- int symidx,
+ Elf_Internal_Sym * isymbuf,
+ size_t locsymcount,
+ size_t symidx,
bfd_vma val)
{
- bfd_boolean is_local;
- Elf_Internal_Sym * sym;
- struct elf_link_hash_entry ** sym_hashes;
- struct elf_link_hash_entry * h;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry *h;
+ size_t extsymoff = locsymcount;
- sym_hashes = elf_sym_hashes (bfd_with_globals);
- sym = finfo->internal_syms + symidx;
- is_local = ELF_ST_BIND(sym->st_info) == STB_LOCAL;
-
- if (is_local)
+ if (symidx < locsymcount)
{
- /* It is a local symbol: move it to the
- "absolute" section and give it a value. */
- sym->st_shndx = SHN_ABS;
- sym->st_value = val;
- }
- else
- {
- /* It is a global symbol: set its link type
- to "defined" and give it a value. */
- h = sym_hashes [symidx];
- 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;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.value = val;
- h->root.u.def.section = bfd_abs_section_ptr;
+ Elf_Internal_Sym *sym;
+
+ sym = isymbuf + symidx;
+ if (ELF_ST_BIND (sym->st_info) == STB_LOCAL)
+ {
+ /* It is a local symbol: move it to the
+ "absolute" section and give it a value. */
+ sym->st_shndx = SHN_ABS;
+ sym->st_value = val;
+ return;
+ }
+ BFD_ASSERT (elf_bad_symtab (bfd_with_globals));
+ extsymoff = 0;
}
+
+ /* It is a global symbol: set its link type
+ to "defined" and give it a value. */
+
+ sym_hashes = elf_sym_hashes (bfd_with_globals);
+ h = sym_hashes [symidx - extsymoff];
+ 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;
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.value = val;
+ h->root.u.def.section = bfd_abs_section_ptr;
}
static bfd_boolean
@@ -7269,6 +7274,7 @@ resolve_symbol (const char *
bfd * input_bfd,
struct elf_final_link_info * finfo,
bfd_vma * result,
+ Elf_Internal_Sym * isymbuf,
size_t locsymcount)
{
Elf_Internal_Sym * sym;
@@ -7282,7 +7288,7 @@ resolve_symbol (const char *
for (i = 0; i < locsymcount; ++ i)
{
- sym = finfo->internal_syms + i;
+ sym = isymbuf + i;
sec = finfo->sections [i];
if (ELF_ST_BIND (sym->st_info) != STB_LOCAL)
@@ -7402,6 +7408,7 @@ eval_symbol (bfd_vma *
struct elf_final_link_info * finfo,
bfd_vma addr,
bfd_vma section_offset,
+ Elf_Internal_Sym * isymbuf,
size_t locsymcount,
int signed_p)
{
@@ -7459,8 +7466,9 @@ eval_symbol (bfd_vma *
if (symbol_is_section)
{
- if ((resolve_section (symbuf, finfo->output_bfd->sections, result) != TRUE)
- && (resolve_symbol (symbuf, input_bfd, finfo, result, locsymcount) != TRUE))
+ if (!resolve_section (symbuf, finfo->output_bfd->sections, result)
+ && !resolve_symbol (symbuf, input_bfd, finfo, result,
+ isymbuf, locsymcount))
{
undefined_reference ("section", symbuf);
return FALSE;
@@ -7468,9 +7476,10 @@ eval_symbol (bfd_vma *
}
else
{
- if ((resolve_symbol (symbuf, input_bfd, finfo, result, locsymcount) != TRUE)
- && (resolve_section (symbuf, finfo->output_bfd->sections,
- result) != TRUE))
+ if (!resolve_symbol (symbuf, input_bfd, finfo, result,
+ isymbuf, locsymcount)
+ && !resolve_section (symbuf, finfo->output_bfd->sections,
+ result))
{
undefined_reference ("symbol", symbuf);
return FALSE;
@@ -7487,9 +7496,9 @@ eval_symbol (bfd_vma *
sym += strlen (#op); \
if (* sym == ':') \
++ sym; \
- if (eval_symbol (& a, sym, & sym, input_bfd, finfo, addr, \
- section_offset, locsymcount, signed_p) \
- != TRUE) \
+ if (!eval_symbol (&a, sym, &sym, input_bfd, finfo, addr, \
+ section_offset, isymbuf, locsymcount, \
+ signed_p)) \
return FALSE; \
if (signed_p) \
* result = op ((signed)a); \
@@ -7505,14 +7514,14 @@ eval_symbol (bfd_vma *
sym += strlen (#op); \
if (* sym == ':') \
++ sym; \
- if (eval_symbol (& a, sym, & sym, input_bfd, finfo, addr, \
- section_offset, locsymcount, signed_p) \
- != TRUE) \
+ if (!eval_symbol (&a, sym, &sym, input_bfd, finfo, addr, \
+ section_offset, isymbuf, locsymcount, \
+ signed_p)) \
return FALSE; \
++ sym; \
- if (eval_symbol (& b, sym, & sym, input_bfd, finfo, addr, \
- section_offset, locsymcount, signed_p) \
- != TRUE) \
+ if (!eval_symbol (&b, sym, &sym, input_bfd, finfo, addr, \
+ section_offset, isymbuf, locsymcount, \
+ signed_p)) \
return FALSE; \
if (signed_p) \
* result = ((signed) a) op ((signed) b); \
@@ -7555,8 +7564,9 @@ eval_symbol (bfd_vma *
/* Entry point to evaluator, called from elf_link_input_bfd. */
static bfd_boolean
-evaluate_complex_relocation_symbols (bfd * input_bfd,
- struct elf_final_link_info * finfo,
+evaluate_complex_relocation_symbols (bfd *input_bfd,
+ struct elf_final_link_info *finfo,
+ Elf_Internal_Sym *isymbuf,
size_t locsymcount)
{
const struct elf_backend_data * bed;
@@ -7626,7 +7636,7 @@ evaluate_complex_relocation_symbols (bfd
if (index < locsymcount)
{
/* The symbol is local. */
- sym = finfo->internal_syms + index;
+ sym = isymbuf + index;
/* We're only processing STT_RELC or STT_SRELC type symbols. */
if ((ELF_ST_TYPE (sym->st_info) != STT_RELC) &&
@@ -7668,10 +7678,10 @@ evaluate_complex_relocation_symbols (bfd
printf (" Evaluating '%s' ...\n ", sym_name);
#endif
if (eval_symbol (& result, sym_name, & sym_name, input_bfd,
- finfo, addr, section_offset, locsymcount,
+ finfo, addr, section_offset, isymbuf, locsymcount,
signed_p))
/* Symbol evaluated OK. Update to absolute value. */
- set_symbol_value (input_bfd, finfo, index, result);
+ set_symbol_value (input_bfd, isymbuf, locsymcount, index, result);
else
result = FALSE;
@@ -9066,15 +9076,6 @@ elf_link_input_bfd (struct elf_final_lin
if (isymbuf == NULL)
return FALSE;
}
- /* evaluate_complex_relocation_symbols looks for symbols in
- finfo->internal_syms. */
- else if (isymbuf != NULL && locsymcount != 0)
- {
- bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
- finfo->internal_syms,
- finfo->external_syms,
- finfo->locsym_shndx);
- }
/* Find local symbol sections and adjust values of symbols in
SEC_MERGE sections. Write out those local symbols we know are
@@ -9212,7 +9213,8 @@ elf_link_input_bfd (struct elf_final_lin
return FALSE;
}
- if (! evaluate_complex_relocation_symbols (input_bfd, finfo, locsymcount))
+ if (! evaluate_complex_relocation_symbols (input_bfd, finfo, isymbuf,
+ locsymcount))
return FALSE;
/* Relocate the contents of each section. */
--
Alan Modra
Australia Development Lab, IBM