diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5ceb5a0e661..fa82d466412 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2018-01-11 H.J. Lu + + PR ld/22393 + * elf.c (_bfd_elf_map_sections_to_segments): When generating + separate code and read-only data LOAD segments, create a new + LOAD segment if the previous section contains text and the + current section doesn't or vice versa. Don't put a writable + section in a read-only segment if there is a RELRO segment. + 2018-01-11 H.J. Lu PR ld/22649 diff --git a/bfd/elf.c b/bfd/elf.c index 9f44ff978ad..1d0eefd0536 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -4566,6 +4566,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) asection **hdrpp; bfd_boolean phdr_in_segment = TRUE; bfd_boolean writable; + bfd_boolean executable; int tls_count = 0; asection *first_tls = NULL; asection *first_mbind = NULL; @@ -4654,6 +4655,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) if (maxpagesize == 0) maxpagesize = 1; writable = FALSE; + executable = FALSE; dynsec = bfd_get_section_by_name (abfd, ".dynamic"); if (dynsec != NULL && (dynsec->flags & SEC_LOAD) == 0) @@ -4756,18 +4758,27 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) file, then there is no other reason for a new segment. */ new_segment = FALSE; } + else if (info != NULL + && info->separate_code + && executable != ((hdr->flags & SEC_CODE) != 0)) + { + new_segment = TRUE; + } else if (! writable && (hdr->flags & SEC_READONLY) == 0 - && (((last_hdr->lma + last_size - 1) & -maxpagesize) - != (hdr->lma & -maxpagesize))) + && ((info != NULL + && info->relro_end > info->relro_start) + || (((last_hdr->lma + last_size - 1) & -maxpagesize) + != (hdr->lma & -maxpagesize)))) { /* We don't want to put a writable section in a read only segment, unless they are on the same page in memory - anyhow. We already know that the last section does not - bring us past the current section on the page, so the - only case in which the new section is not on the same - page as the previous section is when the previous section - ends precisely on a page boundary. */ + anyhow and there is no RELRO segment. We already + know that the last section does not bring us past the + current section on the page, so the only case in which + the new section is not on the same page as the previous + section is when the previous section ends precisely on + a page boundary. */ new_segment = TRUE; } else @@ -4789,6 +4800,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) { if ((hdr->flags & SEC_READONLY) == 0) writable = TRUE; + if ((hdr->flags & SEC_CODE) != 0) + executable = TRUE; last_hdr = hdr; /* .tbss sections effectively have zero size. */ if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) @@ -4814,6 +4827,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) else writable = FALSE; + if ((hdr->flags & SEC_CODE) == 0) + executable = FALSE; + else + executable = TRUE; + last_hdr = hdr; /* .tbss sections effectively have zero size. */ if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)