extern asection *_bfd_elf_is_start_stop
(const struct bfd_link_info *, struct elf_link_hash_entry *);
+extern void _bfd_elf_record_start_stop
+ (struct bfd_link_info *);
+
extern bfd_boolean bfd_elf_reloc_symbol_deleted_p
(bfd_vma, void *);
BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
bed->s->swap_reloc_out (abfd, rel, loc);
}
+
+/* A linked list of __start_<name> and __stop_<name> symbols */
+
+struct start_stop_symbol
+{
+ struct elf_link_hash_entry *h;
+ const char *sec_name;
+ struct start_stop_symbol *next;
+};
+
+struct start_stop_symbol_info
+{
+ struct start_stop_symbol *symbol_list;
+ bfd_boolean failed;
+};
+
+/* Collect __start_<name> and __stop_<name> symbols referenced by
+ regular objects. This is called via elf_link_hash_traverse. */
+
+static bfd_boolean
+elf_link_collect_start_stop (struct elf_link_hash_entry *h, void *data)
+{
+ if (!h->def_regular && h->ref_regular)
+ {
+ struct start_stop_symbol_info *info;
+ struct start_stop_symbol *p, **head;
+ const char *sec_name = h->root.root.string;
+
+ if (sec_name[0] == '_'
+ && sec_name[1] == '_'
+ && sec_name[2] == 's'
+ && sec_name[3] == 't')
+ sec_name += 4;
+ else
+ return TRUE;
+
+ if (sec_name[0] == 'a'
+ && sec_name[1] == 'r'
+ && sec_name[2] == 't')
+ sec_name += 3;
+ else if (sec_name[0] == 'o'
+ && sec_name[1] == 'p')
+ sec_name += 2;
+ else
+ return TRUE;
+
+ if (sec_name[0] == '_' && sec_name[1] != '\0')
+ sec_name += 1;
+ else
+ return TRUE;
+
+ info = (struct start_stop_symbol_info *) data;
+
+ p = (struct start_stop_symbol *) bfd_malloc (sizeof (*p));
+ if (p == NULL)
+ {
+ info->failed = TRUE;
+ return FALSE;
+ }
+
+ head = &info->symbol_list;
+ p->next = info->symbol_list;
+ p->h = h;
+ p->sec_name = sec_name;
+ *head = p;
+ }
+ return TRUE;
+}
+
+/* Record all __start_<name> and __stop_<name> symbols referenced by
+ regular objects. */
+
+void
+_bfd_elf_record_start_stop (struct bfd_link_info *info)
+{
+ struct start_stop_symbol_info symbols;
+
+ /* Collect start/stop symbols. Assuming there are fewer start/stop
+ symbols than input files, avoid scan over all input files for each
+ start/stop symbol. */
+ symbols.symbol_list = NULL;
+ symbols.failed = FALSE;
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_link_collect_start_stop, &symbols);
+
+ if (symbols.failed)
+ info->callbacks->einfo (_("%P%X: collect start/stop symbols: %E\n"));
+ else if (symbols.symbol_list)
+ {
+ bfd *i;
+
+ for (i = info->input_bfds; i != NULL; i = i->link.next)
+ if ((i->flags
+ & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+ {
+ /* Only check regular input files. */
+ struct start_stop_symbol *p, **pp;
+
+ for (pp = &symbols.symbol_list; (p = *pp) != NULL; )
+ if (bfd_get_section_by_name (i, p->sec_name) != NULL)
+ {
+ p->h->def_regular = 1;
+ p->h->type = STT_OBJECT;
+ /* If it is currently defined by a dynamic object, but
+ not by a regular object, then mark it as undefined
+ so that the generic linker will force the correct
+ value. */
+ if (p->h->def_dynamic)
+ {
+ p->h->root.type = bfd_link_hash_undefined;
+ p->h->root.u.undef.abfd
+ = p->h->root.u.def.section->owner;
+ }
+
+ /* Remove this from the list. */
+ *pp = p->next;
+ free (p);
+ }
+ else
+ pp = &p->next;
+
+ /* Stop when the list is empty. */
+ if (symbols.symbol_list == NULL)
+ break;
+ }
+ }
+}
NULL, /* recognized_file */
NULL, /* find potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
EOF
fi
+if test x"$LDEMUL_DO_ASSIGNMENTS" != xgld"$EMULATION_NAME"_do_assignments; then
fragment <<EOF
/* Look through an expression for an assignment statement. */
gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
}
+static struct elf_link_hash_entry *ehdr_start;
+static struct bfd_link_hash_entry ehdr_start_save;
+
+static void
+gld${EMULATION_NAME}_do_assignments (void)
+{
+ if (is_elf_hash_table (link_info.hash))
+ {
+ /* If we are going to make any variable assignments, we need to
+ let the ELF backend know about them in case the variables are
+ referred to by dynamic objects. */
+ lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
+
+ /* Also let the ELF backend know about __start_<name> and
+ __stop_<name> symbols. */
+ _bfd_elf_record_start_stop (&link_info);
+
+ /* Make __ehdr_start hidden if it has been referenced, to
+ prevent the symbol from being dynamic. */
+ if (!bfd_link_relocatable (&link_info))
+ {
+ struct elf_link_hash_entry *h
+ = elf_link_hash_lookup (elf_hash_table (&link_info),
+ "__ehdr_start", FALSE, FALSE, TRUE);
+
+ /* Only adjust the export class if the symbol was referenced
+ and not defined, otherwise leave it alone. def_regular is
+ set by the ELF backend if __ehdr_start is defined in linker
+ script. */
+ if (h != NULL
+ && !h->def_regular
+ && (h->root.type == bfd_link_hash_new
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_common))
+ {
+ _bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
+ if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+ /* Don't leave the symbol undefined. Undefined hidden
+ symbols typically won't have dynamic relocations, but
+ we most likely will need dynamic relocations for
+ __ehdr_start if we are building a PIE or shared
+ library. */
+ ehdr_start = h;
+ ehdr_start_save = h->root;
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = bfd_abs_section_ptr;
+ h->root.u.def.value = 0;
+ }
+ }
+ }
+}
+
+static void
+gld${EMULATION_NAME}_restore_ehdr_start (void)
+{
+ if (ehdr_start != NULL)
+ {
+ /* If we twiddled __ehdr_start to defined earlier, put it back
+ as it was. */
+ ehdr_start->root.type = ehdr_start_save.type;
+ ehdr_start->root.u = ehdr_start_save.u;
+ }
+}
+
+EOF
+else
+fragment <<EOF
+
+static
+gld${EMULATION_NAME}_restore_ehdr_start (void)
+{
+}
+
EOF
+fi
if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then
if test x"${ELF_INTERPRETER_NAME+set}" = xset; then
}
}
-#if defined(__GNUC__) && GCC_VERSION < 4006
- /* Work around a GCC uninitialized warning bug fixed in GCC 4.6. */
-static struct bfd_link_hash_entry ehdr_start_empty;
-#endif
-
/* This is called after the sections have been attached to output
sections, but before any sizes or addresses have been set. */
const char *rpath;
asection *sinterp;
bfd *abfd;
- struct elf_link_hash_entry *ehdr_start = NULL;
-#if defined(__GNUC__) && GCC_VERSION < 4006
- /* Work around a GCC uninitialized warning bug fixed in GCC 4.6. */
- struct bfd_link_hash_entry ehdr_start_save = ehdr_start_empty;
-#else
- struct bfd_link_hash_entry ehdr_start_save;
-#endif
if (is_elf_hash_table (link_info.hash))
- {
- _bfd_elf_tls_setup (link_info.output_bfd, &link_info);
-
- /* Make __ehdr_start hidden if it has been referenced, to
- prevent the symbol from being dynamic. */
- if (!bfd_link_relocatable (&link_info))
- {
- struct elf_link_hash_entry *h
- = elf_link_hash_lookup (elf_hash_table (&link_info), "__ehdr_start",
- FALSE, FALSE, TRUE);
-
- /* Only adjust the export class if the symbol was referenced
- and not defined, otherwise leave it alone. */
- if (h != NULL
- && (h->root.type == bfd_link_hash_new
- || h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_common))
- {
- _bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
- if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
- h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
- /* Don't leave the symbol undefined. Undefined hidden
- symbols typically won't have dynamic relocations, but
- we most likely will need dynamic relocations for
- __ehdr_start if we are building a PIE or shared
- library. */
- ehdr_start = h;
- ehdr_start_save = h->root;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = bfd_abs_section_ptr;
- h->root.u.def.value = 0;
- }
- }
-
- /* If we are going to make any variable assignments, we need to
- let the ELF backend know about them in case the variables are
- referred to by dynamic objects. */
- lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
- }
+ _bfd_elf_tls_setup (link_info.output_bfd, &link_info);
/* Let the ELF backend work out the sizes of any sections required
by dynamic linking. */
if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info))
einfo ("%P%F: failed to set dynamic section sizes: %E\n");
- if (ehdr_start != NULL)
- {
- /* If we twiddled __ehdr_start to defined earlier, put it back
- as it was. */
- ehdr_start->root.type = ehdr_start_save.type;
- ehdr_start->root.u = ehdr_start_save.u;
- }
+ gld${EMULATION_NAME}_restore_ehdr_start ();
}
EOF
${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
${LDEMUL_NEW_VERS_PATTERN-NULL},
- ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+ ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+ ${LDEMUL_DO_ASSIGNMENTS-gld${EMULATION_NAME}_do_assignments},
};
EOF
${LDEMUL_RECOGNIZED_FILE-NULL},
${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
${LDEMUL_NEW_VERS_PATTERN-NULL},
- ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+ ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+ ${LDEMUL_DO_ASSIGNMENTS-NULL}
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
${LDEMUL_RECOGNIZED_FILE-NULL},
${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
${LDEMUL_NEW_VERS_PATTERN-NULL},
- ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+ ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+ ${LDEMUL_DO_ASSIGNMENTS-NULL}
};
EOF
# \f
gld_${EMULATION_NAME}_recognized_file,
gld_${EMULATION_NAME}_find_potential_libraries,
NULL, /* new_vers_pattern. */
- NULL /* extra_map_file_text. */
+ NULL, /* extra_map_file_text. */
+ NULL /* do_assignments */
};
EOF
gld_${EMULATION_NAME}_recognized_file,
gld_${EMULATION_NAME}_find_potential_libraries,
NULL, /* new_vers_pattern. */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
NULL, /* recognized file */
NULL, /* find_potential_libraries */
NULL, /* new_vers_pattern */
- NULL /* extra_map_file_text */
+ NULL, /* extra_map_file_text */
+ NULL /* do_assignments */
};
EOF
if (ld_emulation->extra_map_file_text)
ld_emulation->extra_map_file_text (abfd, info, mapf);
}
+
+void
+ldemul_do_assignments (void)
+{
+ if (ld_emulation->do_assignments)
+ ld_emulation->do_assignments ();
+}
(struct bfd_elf_version_expr *);
extern void ldemul_extra_map_file_text
(bfd *, struct bfd_link_info *, FILE *);
+extern void ldemul_do_assignments
+ (void);
typedef struct ld_emulation_xfer_struct {
/* Run before parsing the command line and script file.
void (*extra_map_file_text)
(bfd *, struct bfd_link_info *, FILE *);
+ /* Called to do assignments. */
+ void (*do_assignments)
+ (void);
+
} ld_emulation_xfer_type;
typedef enum {
prefer_next_section = FALSE;
expld.phase = phase;
lang_statement_iteration++;
+ if (phase == lang_mark_phase_enum)
+ ldemul_do_assignments ();
lang_do_assignments_1 (statement_list.head,
abs_output_section, NULL, 0, &found_end);
}