This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker


On Tue, Nov 14, 2017 at 4:55 AM, Michael Matz <matz@suse.de> wrote:
> Hi,
>
> On Mon, 13 Nov 2017, H.J. Lu wrote:
>
>> Text-only LOAD segment has the same requirement for segment alignment
>> and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
>> segment may not end at the same address of the end of data segment.
>> But for text-only LOAD segment, it is exactly the same as text LOAD
>> segment.
>>
>> The new "-z textonly" option will turn on both text-only LOAD segment
>> and GNU_RELRO segment.  The new "-z notextonly" option will turn off
>> only text-only LOAD segment.  "-z relro" is updated not to turn off
>> text-only LOAD segment.  "-z norelro" is updated to turn off both
>> GNU_RELRO segment and text-only LOAD segment.
>>
>> 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
>
> This seems strange.  The (file)offset of the fourth segment is much larger
> than than the added sizes of the individual segments, which isn't
> necessary.
>
>> 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
>
> This is the result of the above problem, but it's not necessary.  Like in
> a traditional two-LOAD-segment file, which also isn't larger than 2MB,
> just because the page size is 2MB.  It achieves this by mapping the same
> file bytes multiple times, and you could do the same.  E.g. for the file
> above the better layout would be:
>
>   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           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
>
> But even then something is wrong: The RE and the second R page are both
> mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
> protections.  (You'd need 4k pages again, which defeats the whole purpose
> of having 2MB pages in the file to start with).

You have found out yourself that it is impossible.   In elf.c, there are

static file_ptr
vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize)
{
  /* PR binutils/16199: Handle an alignment of zero.  */
  if (maxpagesize == 0)
    maxpagesize = 1;
  return ((vma - off) % maxpagesize);
}

It is used to adjust file offset to align to the maximum page size.   It can
be quite large, up to the maximum page size.

>>
>> "-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
>
> Also this shows strangeness.  The second R and the RW page are both mapped
> to 0x2xxx, the same 4k page, which can't have different protections.  Also
> the offsets are somehow wrong.  The second R page starts at 0x1000 (in
> file), and is 0x58 bytes long (memsize is 0x58 as well).  So the next
> thing in file should start at 0x1060, not 0x1f80 (and should be mapped to
> 0x3060, not 0x2f80).
>

You need to look at the whole picture:

      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

Part of the 4th segment is in GNU_RELRO segment which becomes read-only after
relocation and is merged with the 3rd R page:

  [ 8] .rodata           PROGBITS        00002000 001000 000006 01 AMS  0   0  1
  [ 9] .eh_frame         PROGBITS        00002008 001008 000050 00   A  0   0  4
  [10] .dynamic          DYNAMIC         00002f80 001f80 000080 08  WA  4   0  4
  [11] .got.plt          PROGBITS        00003000 002000 000020 08  WA  0   0  8

After relocation, the 3rd page has .rodata, .eh_frame and .dynamic.


-- 
H.J.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]