This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 3/6] ld: Create a new LOAD segment for text-only LOAD segment
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: binutils at sourceware dot org
- Date: Mon, 13 Nov 2017 15:08:27 -0800
- Subject: [PATCH 3/6] ld: Create a new LOAD segment for text-only LOAD segment
- Authentication-results: sourceware.org; auth=none
- References: <20171113230830.3334-1-hjl.tools@gmail.com>
When there is a text-only 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 0x200ff0
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 0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
LOAD 0x001000 0x00201000 0x00201000 0x00058 0x00058 R 0x200000
LOAD 0x200f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW 0x200000
DYNAMIC 0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x200f80 0x00400f80 0x00400f80 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
This is to prevent executing data in read-only sections as instructions.
Also don't put a writable section in a read-only segment if there is a
RELRO segment.
Since there are more than 2 LOAD segments, the minimum file size is
bigger than the maximum page size which is 2MB (0x200000):
-rwxr-xr-x 1 hjl hjl 2104892 Nov 12 11:53 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 11836 Nov 12 13:22 libfoo.so
Elf file type is DYN (Shared object file)
Entry point 0x1ff0
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 0x1000
LOAD 0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
LOAD 0x001000 0x00002000 0x00002000 0x00058 0x00058 R 0x1000
LOAD 0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW 0x1000
DYNAMIC 0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 RW 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x001f80 0x00002f80 0x00002f80 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
PR ld/22393
* elf.c (_bfd_elf_map_sections_to_segments): When there is a
text-only LOAD segment, 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.
---
bfd/elf.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/bfd/elf.c b/bfd/elf.c
index 694e43540f..9c5de9675c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4555,6 +4555,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;
@@ -4643,6 +4644,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)
@@ -4745,18 +4747,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->text_end > info->text_start
+ && 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
@@ -4778,6 +4789,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))
@@ -4803,6 +4816,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)
--
2.13.6