summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-01-11 19:04:55 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-01-11 19:05:06 -0800
commit2888249fc9eb38b6d6e4bd969ce63c26e3753d5e (patch)
tree83cb93b8dbae33130cc655bee72ef8c2ef982d04
parent47acac12c83f173481debc64618626b50ecf7498 (diff)
downloadbinutils-gdb-2888249fc9eb38b6d6e4bd969ce63c26e3753d5e.tar.gz
ld: Create a new LOAD segment for separate code segment
When generating separate code LOAD segment, create a new LOAD segment if the previous section contains text and the current section doesn't or vice versa: Elf file type is DYN (Shared object file) Entry point 0x200020 There are 7 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x00000000 0x00000000 0x00200 0x00200 R 0x200000 LOAD 0x200000 0x00200000 0x00200000 0x00036 0x00036 R E 0x200000 LOAD 0x400000 0x00400000 0x00400000 0x00064 0x00064 R 0x200000 LOAD 0x400f80 0x00600f80 0x00600f80 0x000a0 0x000a0 RW 0x200000 DYNAMIC 0x400f80 0x00600f80 0x00600f80 0x00080 0x00080 RW 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10 GNU_RELRO 0x400f80 0x00600f80 0x00600f80 0x00080 0x00080 R 0x1 Section to Segment mapping: Segment Sections... 00 .hash .gnu.hash .dynsym .dynstr .rela.plt 01 .plt .text 02 .rodata .eh_frame 03 .dynamic .got.plt 04 .dynamic 05 06 .dynamic to prevent fetching or executing data in code pages as instructions. Also don't put a writable section in a read-only segment if there is a RELRO segment. Since code segment is aligned and padded to the maximum page size on disk, the minimum file size is bigger than the maximum page size which is 2MB (0x200000): -rwxr-xr-x 1 hjl hjl 4201932 Jan 10 10:41 libfoo.so "-z max-page-size=0x1000" can be used to reduce the maximum page size to 4KB (0x1000): -rwxr-xr-x 1 hjl hjl 15820 Jan 10 10:44 libfoo.so 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.
-rw-r--r--bfd/ChangeLog9
-rw-r--r--bfd/elf.c32
2 files changed, 34 insertions, 7 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 5ceb5a0e661..fa82d466412 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,14 @@
2018-01-11 H.J. Lu <hongjiu.lu@intel.com>
+ 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 <hongjiu.lu@intel.com>
+
PR ld/22649
* elflink.c (bfd_elf_gc_mark_dynamic_ref_symbol): Ignore dynamic
references on forced local symbols.
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)