shnum = elf_numsections (abfd);
num_group = 0;
-#define IS_VALID_GROUP_SECTION_HEADER(shdr) \
+#define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize) \
( (shdr)->sh_type == SHT_GROUP \
- && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE) \
+ && (shdr)->sh_size >= minsize \
&& (shdr)->sh_entsize == GRP_ENTRY_SIZE \
&& ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0)
{
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
- if (IS_VALID_GROUP_SECTION_HEADER (shdr))
+ if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
num_group += 1;
}
{
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
- if (IS_VALID_GROUP_SECTION_HEADER (shdr))
+ if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
{
unsigned char *src;
Elf_Internal_Group *dest;
else
{
/* Normal section. Check if we should compress. */
- if ((abfd->flags & BFD_COMPRESS))
+ if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0)
action = compress;
}
if (!bfd_init_section_compress_status (abfd, newsect))
{
(*_bfd_error_handler)
- (_("%B: unable to initialize commpress status for section %s"),
+ (_("%B: unable to initialize compress status for section %s"),
abfd, name);
return FALSE;
}
if (!bfd_init_section_decompress_status (abfd, newsect))
{
(*_bfd_error_handler)
- (_("%B: unable to initialize decommpress status for section %s"),
+ (_("%B: unable to initialize decompress status for section %s"),
abfd, name);
return FALSE;
}
if (hdr->sh_entsize != bed->s->sizeof_sym)
return FALSE;
if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
- return FALSE;
+ {
+ if (hdr->sh_size != 0)
+ return FALSE;
+ /* Some assemblers erroneously set sh_info to one with a
+ zero sh_size. ld sees this as a global symbol count
+ of (unsigned) -1. Fix it here. */
+ hdr->sh_info = 0;
+ return TRUE;
+ }
BFD_ASSERT (elf_onesymtab (abfd) == 0);
elf_onesymtab (abfd) = shindex;
elf_tdata (abfd)->symtab_hdr = *hdr;
if (hdr->sh_entsize != bed->s->sizeof_sym)
return FALSE;
+ if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
+ {
+ if (hdr->sh_size != 0)
+ return FALSE;
+ /* Some linkers erroneously set sh_info to one with a
+ zero sh_size. ld sees this as a global symbol count
+ of (unsigned) -1. Fix it here. */
+ hdr->sh_info = 0;
+ return TRUE;
+ }
BFD_ASSERT (elf_dynsymtab (abfd) == 0);
elf_dynsymtab (abfd) = shindex;
elf_tdata (abfd)->dynsymtab_hdr = *hdr;
return TRUE;
case SHT_GROUP:
- if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
+ if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE))
return FALSE;
if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
return FALSE;
_bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
}
+ if (section_number >= SHN_LORESERVE)
+ {
+ _bfd_error_handler (_("%B: too many sections: %u"),
+ abfd, section_number);
+ return FALSE;
+ }
+
_bfd_elf_strtab_finalize (elf_shstrtab (abfd));
t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
return TRUE;
}
-/* Map symbol from it's internal number to the external number, moving
- all local symbols to be at the head of the list. */
-
static bfd_boolean
sym_is_global (bfd *abfd, asymbol *sym)
{
}
/* Don't output section symbols for sections that are not going to be
- output. */
+ output, that are duplicates or there is no BFD section. */
static bfd_boolean
ignore_section_sym (bfd *abfd, asymbol *sym)
{
- return ((sym->flags & BSF_SECTION_SYM) != 0
- && !(sym->section->owner == abfd
+ elf_symbol_type *type_ptr;
+
+ if ((sym->flags & BSF_SECTION_SYM) == 0)
+ return FALSE;
+
+ type_ptr = elf_symbol_from (abfd, sym);
+ return ((type_ptr != NULL
+ && type_ptr->internal_elf_sym.st_shndx != 0
+ && bfd_is_abs_section (sym->section))
+ || !(sym->section->owner == abfd
|| (sym->section->output_section->owner == abfd
- && sym->section->output_offset == 0)));
+ && sym->section->output_offset == 0)
+ || bfd_is_abs_section (sym->section)));
}
+/* Map symbol from it's internal number to the external number, moving
+ all local symbols to be at the head of the list. */
+
static bfd_boolean
elf_map_symbols (bfd *abfd)
{
if ((sym->flags & BSF_SECTION_SYM) != 0
&& sym->value == 0
- && !ignore_section_sym (abfd, sym))
+ && !ignore_section_sym (abfd, sym)
+ && !bfd_is_abs_section (sym->section))
{
asection *sec = sym->section;
/* Classify all of the symbols. */
for (idx = 0; idx < symcount; idx++)
{
- if (ignore_section_sym (abfd, syms[idx]))
- continue;
- if (!sym_is_global (abfd, syms[idx]))
- num_locals++;
- else
+ if (sym_is_global (abfd, syms[idx]))
num_globals++;
+ else if (!ignore_section_sym (abfd, syms[idx]))
+ num_locals++;
}
/* We will be adding a section symbol for each normal BFD section. Most
asymbol *sym = syms[idx];
unsigned int i;
- if (ignore_section_sym (abfd, sym))
- continue;
- if (!sym_is_global (abfd, sym))
+ if (sym_is_global (abfd, sym))
+ i = num_locals + num_globals2++;
+ else if (!ignore_section_sym (abfd, sym))
i = num_locals2++;
else
- i = num_locals + num_globals2++;
+ continue;
new_syms[i] = sym;
sym->udata.i = i + 1;
}
{
for (m = mfirst; m != NULL; m = m->next)
{
- if (m->p_type == PT_LOAD)
+ if (m->p_type == PT_LOAD
+ && m->count != 0
+ && m->sections[0]->vma >= info->relro_start
+ && m->sections[0]->vma < info->relro_end)
{
- asection *last = m->sections[m->count - 1];
- bfd_vma vaddr = m->sections[0]->vma;
- bfd_vma filesz = last->vma - vaddr + last->size;
+ i = m->count;
+ while (--i != (unsigned) -1)
+ if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS))
+ == (SEC_LOAD | SEC_HAS_CONTENTS))
+ break;
+
+ if (i == (unsigned) -1)
+ continue;
- if (vaddr < info->relro_end
- && vaddr >= info->relro_start
- && (vaddr + filesz) >= info->relro_end)
+ if (m->sections[i]->vma + m->sections[i]->size
+ >= info->relro_end)
break;
}
- }
+ }
/* Make a PT_GNU_RELRO segment only when it isn't empty. */
if (m != NULL)
p->p_memsz = bed->s->sizeof_ehdr;
if (m->count > 0)
{
- BFD_ASSERT (p->p_type == PT_LOAD);
-
if (p->p_vaddr < (bfd_vma) off)
{
(*_bfd_error_handler)
if (m->count > 0)
{
- BFD_ASSERT (p->p_type == PT_LOAD);
p->p_vaddr -= off - p->p_offset;
if (!m->p_paddr_valid)
p->p_paddr -= off - p->p_offset;
Elf_Internal_Phdr *phdrs;
Elf_Internal_Phdr *p;
struct elf_segment_map *m;
+ struct elf_segment_map *hdrs_segment;
bfd_vma filehdr_vaddr, filehdr_paddr;
bfd_vma phdrs_vaddr, phdrs_paddr;
file_ptr off;
filehdr_paddr = 0;
phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
phdrs_paddr = 0;
+ hdrs_segment = NULL;
phdrs = elf_tdata (abfd)->phdr;
for (m = elf_tdata (abfd)->segment_map, p = phdrs;
m != NULL;
phdrs_paddr = p->p_paddr;
if (m->includes_filehdr)
{
+ hdrs_segment = m;
phdrs_vaddr += bed->s->sizeof_ehdr;
phdrs_paddr += bed->s->sizeof_ehdr;
}
}
}
+ if (hdrs_segment != NULL && link_info != NULL)
+ {
+ /* There is a segment that contains both the file headers and the
+ program headers, so provide a symbol __ehdr_start pointing there.
+ A program can use this to examine itself robustly. */
+
+ struct elf_link_hash_entry *hash
+ = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+ FALSE, FALSE, TRUE);
+ /* If the symbol was referenced and not defined, define it. */
+ if (hash != NULL
+ && (hash->root.type == bfd_link_hash_new
+ || hash->root.type == bfd_link_hash_undefined
+ || hash->root.type == bfd_link_hash_undefweak
+ || hash->root.type == bfd_link_hash_common))
+ {
+ asection *s = NULL;
+ if (hdrs_segment->count != 0)
+ /* The segment contains sections, so use the first one. */
+ s = hdrs_segment->sections[0];
+ else
+ /* Use the first (i.e. lowest-addressed) section in any segment. */
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ if (m->count != 0)
+ {
+ s = m->sections[0];
+ break;
+ }
+
+ if (s != NULL)
+ {
+ hash->root.u.def.value = filehdr_vaddr - s->vma;
+ hash->root.u.def.section = s;
+ }
+ else
+ {
+ hash->root.u.def.value = filehdr_vaddr;
+ hash->root.u.def.section = bfd_abs_section_ptr;
+ }
+
+ hash->root.type = bfd_link_hash_defined;
+ hash->def_regular = 1;
+ hash->non_elf = 0;
+ }
+ }
+
for (m = elf_tdata (abfd)->segment_map, p = phdrs;
m != NULL;
m = m->next, p++)
if (p->p_type == PT_GNU_RELRO)
{
const Elf_Internal_Phdr *lp;
-
- BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+ struct elf_segment_map *lm;
if (link_info != NULL)
{
/* During linking the range of the RELRO segment is passed
in link_info. */
- for (lp = phdrs; lp < phdrs + count; ++lp)
+ for (lm = elf_tdata (abfd)->segment_map, lp = phdrs;
+ lm != NULL;
+ lm = lm->next, lp++)
{
if (lp->p_type == PT_LOAD
- && lp->p_vaddr >= link_info->relro_start
&& lp->p_vaddr < link_info->relro_end
- && lp->p_vaddr + lp->p_filesz >= link_info->relro_end)
+ && lp->p_vaddr + lp->p_filesz >= link_info->relro_end
+ && lm->count != 0
+ && lm->sections[0]->vma >= link_info->relro_start)
break;
}
+
+ /* PR ld/14207. If the RELRO segment doesn't fit in the
+ LOAD segment, it should be removed. */
+ BFD_ASSERT (lm != NULL);
}
else
{
else
abort ();
p->p_memsz = p->p_filesz;
- /* Preserve the alignment and flags if they are valid. The gold
- linker generates RW/4 for the PT_GNU_RELRO section. It is better
- for objcopy/strip to honor these attributes otherwise gdb will
- choke when using separate debug files. */
- if (!m->p_align_valid)
- p->p_align = 1;
- if (!m->p_flags_valid)
- p->p_flags = (lp->p_flags & ~PF_W);
+ /* Preserve the alignment and flags if they are valid. The
+ gold linker generates RW/4 for the PT_GNU_RELRO section.
+ It is better for objcopy/strip to honor these attributes
+ otherwise gdb will choke when using separate debug files.
+ */
+ if (!m->p_align_valid)
+ p->p_align = 1;
+ if (!m->p_flags_valid)
+ p->p_flags = (lp->p_flags & ~PF_W);
}
else
{
const char **filename_ptr,
const char **functionname_ptr)
{
- const char *filename;
- asymbol *func, *file;
- bfd_vma low_func;
- asymbol **p;
- /* ??? Given multiple file symbols, it is impossible to reliably
- choose the right file name for global symbols. File symbols are
- local symbols, and thus all file symbols must sort before any
- global symbols. The ELF spec may be interpreted to say that a
- file symbol must sort before other local symbols, but currently
- ld -r doesn't do this. So, for ld -r output, it is possible to
- make a better choice of file name for local symbols by ignoring
- file symbols appearing after a given local symbol. */
- enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ static asection *last_section;
+ static asymbol *func;
+ static const char *filename;
+ static bfd_size_type func_size;
if (symbols == NULL)
return FALSE;
- filename = NULL;
- func = NULL;
- file = NULL;
- low_func = 0;
- state = nothing_seen;
-
- for (p = symbols; *p != NULL; p++)
- {
- asymbol *sym = *p;
- asection *code_sec;
- bfd_vma code_off;
-
- if ((sym->flags & BSF_FILE) != 0)
- {
- file = sym;
- if (state == symbol_seen)
- state = file_after_symbol_seen;
- continue;
- }
+ if (last_section != section
+ || func == NULL
+ || offset < func->value
+ || offset >= func->value + func_size)
+ {
+ asymbol *file;
+ bfd_vma low_func;
+ asymbol **p;
+ /* ??? Given multiple file symbols, it is impossible to reliably
+ choose the right file name for global symbols. File symbols are
+ local symbols, and thus all file symbols must sort before any
+ global symbols. The ELF spec may be interpreted to say that a
+ file symbol must sort before other local symbols, but currently
+ ld -r doesn't do this. So, for ld -r output, it is possible to
+ make a better choice of file name for local symbols by ignoring
+ file symbols appearing after a given local symbol. */
+ enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ filename = NULL;
+ func = NULL;
+ file = NULL;
+ low_func = 0;
+ state = nothing_seen;
+ func_size = 0;
+ last_section = section;
+
+ for (p = symbols; *p != NULL; p++)
+ {
+ asymbol *sym = *p;
+ bfd_vma code_off;
+ bfd_size_type size;
+
+ if ((sym->flags & BSF_FILE) != 0)
+ {
+ file = sym;
+ if (state == symbol_seen)
+ state = file_after_symbol_seen;
+ continue;
+ }
- if (bed->maybe_function_sym (sym, &code_sec, &code_off)
- && code_sec == section
- && code_off >= low_func
- && code_off <= offset)
- {
- func = sym;
- low_func = code_off;
- filename = NULL;
- if (file != NULL
- && ((sym->flags & BSF_LOCAL) != 0
- || state != file_after_symbol_seen))
- filename = bfd_asymbol_name (file);
+ size = bed->maybe_function_sym (sym, section, &code_off);
+ if (size != 0
+ && code_off <= offset
+ && (code_off > low_func
+ || (code_off == low_func
+ && size > func_size)))
+ {
+ func = sym;
+ func_size = size;
+ low_func = code_off;
+ filename = NULL;
+ if (file != NULL
+ && ((sym->flags & BSF_LOCAL) != 0
+ || state != file_after_symbol_seen))
+ filename = bfd_asymbol_name (file);
+ }
+ if (state == nothing_seen)
+ state = symbol_seen;
}
- if (state == nothing_seen)
- state = symbol_seen;
}
if (func == NULL)
const char **filename_ptr,
const char **functionname_ptr,
unsigned int *line_ptr)
+{
+ return _bfd_elf_find_nearest_line_discriminator (abfd, section, symbols,
+ offset, filename_ptr,
+ functionname_ptr,
+ line_ptr,
+ NULL);
+}
+
+bfd_boolean
+_bfd_elf_find_nearest_line_discriminator (bfd *abfd,
+ asection *section,
+ asymbol **symbols,
+ bfd_vma offset,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *line_ptr,
+ unsigned int *discriminator_ptr)
{
bfd_boolean found;
if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
section, symbols, offset,
filename_ptr, functionname_ptr,
- line_ptr, 0,
+ line_ptr, discriminator_ptr, 0,
&elf_tdata (abfd)->dwarf2_find_line_info))
{
if (!*functionname_ptr)
bfd_boolean
_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
const char **filename_ptr, unsigned int *line_ptr)
+{
+ return _bfd_elf_find_line_discriminator (abfd, symbols, symbol,
+ filename_ptr, line_ptr,
+ NULL);
+}
+
+bfd_boolean
+_bfd_elf_find_line_discriminator (bfd *abfd, asymbol **symbols, asymbol *symbol,
+ const char **filename_ptr,
+ unsigned int *line_ptr,
+ unsigned int *discriminator_ptr)
{
return _bfd_dwarf2_find_line (abfd, symbols, symbol,
- filename_ptr, line_ptr, 0,
+ filename_ptr, line_ptr, discriminator_ptr, 0,
&elf_tdata (abfd)->dwarf2_find_line_info);
}
(bfd *templ,
bfd_vma ehdr_vma,
bfd_vma *loadbasep,
- int (*target_read_memory) (bfd_vma, bfd_byte *, int))
+ int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type))
{
return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
(templ, ehdr_vma, loadbasep, target_read_memory);
|| type == STT_GNU_IFUNC);
}
-/* Return TRUE iff the ELF symbol SYM might be a function. Set *CODE_SEC
- and *CODE_OFF to the function's entry point. */
+/* If the ELF symbol SYM might be a function in SEC, return the
+ function size and set *CODE_OFF to the function's entry point,
+ otherwise return zero. */
-bfd_boolean
-_bfd_elf_maybe_function_sym (const asymbol *sym,
- asection **code_sec, bfd_vma *code_off)
+bfd_size_type
+_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+ bfd_vma *code_off)
{
+ bfd_size_type size;
+
if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
- | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
- return FALSE;
+ | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+ || sym->section != sec)
+ return 0;
- *code_sec = sym->section;
*code_off = sym->value;
- return TRUE;
+ size = 0;
+ if (!(sym->flags & BSF_SYNTHETIC))
+ size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+ if (size == 0)
+ size = 1;
+ return size;
}