--- binutils.orig/bfd/elf.c 2018-05-01 11:42:03.151425659 +0100 +++ binutils-2.30/bfd/elf.c 2018-05-01 12:30:42.129206856 +0100 @@ -5713,6 +5713,9 @@ assign_file_positions_for_load_sections return TRUE; } +#define IS_TBSS(s) \ + ((s->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) == SEC_THREAD_LOCAL) + /* Assign file positions for the other sections. */ static bfd_boolean @@ -5862,65 +5865,100 @@ assign_file_positions_for_non_load_secti { if (p->p_type == PT_GNU_RELRO) { - const Elf_Internal_Phdr *lp; - struct elf_segment_map *lm; + bfd_vma start, end; + bfd_boolean ok; if (link_info != NULL) { /* During linking the range of the RELRO segment is passed - in link_info. */ + in link_info. Note that there may be padding between + relro_start and the first RELRO section. */ + start = link_info->relro_start; + end = link_info->relro_end; + } + else if (m->count != 0) + { + if (!m->p_size_valid) + abort (); + start = m->sections[0]->vma; + end = start + m->p_size; + } + else + { + start = 0; + end = 0; + } + + ok = FALSE; + if (start < end) + { + struct elf_segment_map *lm; + const Elf_Internal_Phdr *lp; + unsigned int i; + + /* Find a LOAD segment containing a section in the RELRO + segment. */ for (lm = elf_seg_map (abfd), lp = phdrs; lm != NULL; lm = lm->next, lp++) { if (lp->p_type == PT_LOAD - && lp->p_vaddr < link_info->relro_end && lm->count != 0 - && lm->sections[0]->vma >= link_info->relro_start) + && (lm->sections[lm->count - 1]->vma + + (!IS_TBSS (lm->sections[lm->count - 1]) + ? lm->sections[lm->count - 1]->size + : 0)) > start + && lm->sections[0]->vma < end) break; } - BFD_ASSERT (lm != NULL); - } - else - { - /* Otherwise we are copying an executable or shared - library, but we need to use the same linker logic. */ - for (lp = phdrs; lp < phdrs + count; ++lp) + if (lm != NULL) { - if (lp->p_type == PT_LOAD - && lp->p_paddr == p->p_paddr) - break; + /* Find the section starting the RELRO segment. */ + for (i = 0; i < lm->count; i++) + { + asection *s = lm->sections[i]; + if (s->vma >= start + && s->vma < end + && s->size != 0) + break; + } + + if (i < lm->count) + { + p->p_vaddr = lm->sections[i]->vma; + p->p_paddr = lm->sections[i]->lma; + p->p_offset = lm->sections[i]->filepos; + p->p_memsz = end - p->p_vaddr; + p->p_filesz = p->p_memsz; + + /* The RELRO segment typically ends a few bytes + into .got.plt but other layouts are possible. + In cases where the end does not match any + loaded section (for instance is in file + padding), trim p_filesz back to correspond to + the end of loaded section contents. */ + if (p->p_filesz > lp->p_vaddr + lp->p_filesz - p->p_vaddr) + p->p_filesz = lp->p_vaddr + lp->p_filesz - p->p_vaddr; + + /* 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 = PF_R; + ok = TRUE; + } } } - - if (lp < phdrs + count) - { - p->p_vaddr = lp->p_vaddr; - p->p_paddr = lp->p_paddr; - p->p_offset = lp->p_offset; - if (link_info != NULL) - p->p_filesz = link_info->relro_end - lp->p_vaddr; - else if (m->p_size_valid) - p->p_filesz = m->p_size; - 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 = PF_R; - } - else - { - memset (p, 0, sizeof *p); - p->p_type = PT_NULL; - } + if (link_info != NULL) + BFD_ASSERT (ok); + if (!ok) + memset (p, 0, sizeof *p); } else if (p->p_type == PT_GNU_STACK) {