Uploaded image for project: 'RHEL'
  1. RHEL
  2. RHEL-60807

binutils: Way to avoid gaps between LOAD segments on mixed page size architectures

    • Icon: Story Story
    • Resolution: Unresolved
    • Icon: Minor Minor
    • None
    • rhel-9.6
    • binutils
    • rhel-sst-pt-gcc
    • ssg_platform_tools
    • 24
    • 13
    • False
    • Hide

      None

      Show
      None
    • No
    • Red Hat Enterprise Linux
    • None
    • None
    • None
    • Unspecified Release Note Type - Unknown
    • aarch64, ppc64le
    • None

      RHEL-45873 fixed unintended gaps due to a bug in RELRO handling. I believe this addresses the gap issue for single page size targets such as s390x and x86-64. However, on aarch64 and pp64le, the minimum page size is 4096 bytes, but we build the binaries for compatibility with 65,536 byte pages (as required by the respective ABIs). This may or may not be a problem on ppc64le, where the page size is more or less fixed to 65,536 bytes in practice (I assume) because not even Fedora ships a 4096 byte page kernel.

      However, on aarch64, I think we have a real issue because the page size is expected to vary in practice, and 4096 byte pages are supported even in RHEL. This results in gaps because the way ld lays out the binaries, there are no gaps only if the page size is 65,546 bytes:

      # eu-readelf -l /lib/ld-linux-aarch64.so.1 
      Program Headers:
        Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
        LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x028620 0x028620 R E 0x10000
        LOAD           0x02e818 0x000000000003e818 0x000000000003e818 0x002908 0x002a98 RW  0x10000
        DYNAMIC        0x02fdf0 0x000000000003fdf0 0x000000000003fdf0 0x0001b0 0x0001b0 RW  0x8
        NOTE           0x0001c8 0x00000000000001c8 0x00000000000001c8 0x000024 0x000024 R   0x4
        GNU_EH_FRAME   0x0247b8 0x00000000000247b8 0x00000000000247b8 0x0008d4 0x0008d4 R   0x4
        GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
        GNU_RELRO      0x02e818 0x000000000003e818 0x000000000003e818 0x0017e8 0x0017e8 R   0x1
      
       Section to Segment mapping:
        Segment Sections...
         00      [RO: .note.gnu.build-id .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .rela.dyn .rela.plt .plt .text .rodata .stapsdt.base .eh_frame_hdr .eh_frame]
         01      [RELRO: .init_array .data.rel.ro .dynamic .got] .data .bss
         02      [RELRO: .dynamic]
         03      [RO: .note.gnu.build-id]
         04      [RO: .eh_frame_hdr]
         05     
         06      [RELRO: .init_array .data.rel.ro .dynamic .got]
      

      And:

      info: LOAD segment 0: address 0x0, size 164244, range [0x0,0x29000)
      info: LOAD segment 1: address 0x3e8e0, size 10704, range [0x3e000,0x42000)
      error: gap between load segments: 86016 bytes
      

      This is from glibc-2.34-132.el9.aarch64, built with binutils-2.35.2-54.el9.aarch64.

      I think we only need a way to link ld.so so that there no gaps, possibly using custom linker options. (But it would be preferable if we had a solution for the main program, too.) I tried using -z common-page-size=65536 with binutils-2.41-48.el10.aarch64, but it did not have any effect. And -z separate-code does not fill the gaps, either, it just produces more of them.

      The issue is also present in ld version 2.43.1.20240927 (upstream) across multiple architectures. There is a related glibc dynamic linker bug that requests a glibc change in the other direction (create more gaps):

              nickc@redhat.com Nick Clifton
              fweimer@redhat.com Florian Weimer
              Nick Clifton Nick Clifton
              Milos Prchlik Milos Prchlik
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated: