bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/25354] On RISCV64 LD, with EXACTLY 72 headers/sections, PhysAddr


From: wilson at gcc dot gnu.org
Subject: [Bug ld/25354] On RISCV64 LD, with EXACTLY 72 headers/sections, PhysAddr for first Program Header is wrong
Date: Fri, 23 Oct 2020 01:15:44 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=25354

Jim Wilson <wilson at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |wilson at gcc dot gnu.org

--- Comment #1 from Jim Wilson <wilson at gcc dot gnu.org> ---
Reproducing this and debugging it, I find the problem is with code in elf.c in
_bfd_elf_map_sections_to_segments that does this

      if (count != 0
          && (((sections[0]->lma & addr_mask) & (maxpagesize - 1))
              >= (phdr_size & (maxpagesize - 1))))
        /* For compatibility with old scripts that may not be using             
           SIZEOF_HEADERS, add headers when it looks like space has             
           been left for them.  */
        phdr_in_segment = TRUE;

For riscv64-*, if there are 72 segments, then phdr_size is 4096, which is
exactly the page size, so the calculation (phdr_size & (maxpagesize - 1)) is 0,
the test always succeeds regardless of how the first section is defined, and
the linker decides that we must put the phdr in the first segment.  That causes
the first segment to be

    LOAD off    0x0000000000000000 vaddr 0x00000000000ff000 paddr
0x000000000000
f000 align 2**12
         filesz 0x0000000000001110 memsz 0x0000000000001110 flags r-x

when what the user wants is a load offset of 0x1000, a vaddr of 0x100000, a
filesz of 0x110, and a memsize of 0x110.

I see some obvious workarounds.

1) Don't have 72 segments.  This is impractical, since in general you can't
know the number of segments until after linking.

2) Turn off demand paging by adding the --nmagic option.  This will disable
placement of phdr into a segment.  It also disables some other stuff like page
alignment of sections/segments.  It does appear to give the right result for
this testcase.

3) Use the "-z separate-code" option.  This forces the phdrs into its own
segment which may not be what the user wants.  This requires that the first
segment contain code.  And requires that the port has shared library support
enaboled, which is true for riscv64-linux but not riscv64-elf (missing newlib
support) so this doesn't actually work in this case.  I had to use a
riscv64-linux toolchain to see that it does work.

4) Increase the page size to avoid the conflict.  Adding "-z
max-page-size=0x2000" avoids the problem.  This has the side effect of adding
an extra 4KB to the executable file, but it doesn't change any of the segment
addresses or sizes.  Just the offset that they are found in the executable
file.

5) Include ". += SIZEOF_HEADERS" in the linker script, right before the first
section.  The load address for the first segment is now correct, but its size
is 4KB larger than desired because it contains the phdrs.  This means your
program will use 4KB more memory than desired.

The problematic code was added by Alan Modra in 2018.

commit 5d695627883b32cf33adb529c8fc7271b46dcf55                                 
Author: Alan Modra <amodra@gmail.com>                                           
Date:   Sat Oct 6 12:24:28 2018 +0930                                           

    Use p_vaddr_offset to set p_vaddr on segments without sections              

    p_vaddr is currently set from the first section vma if a segment has        
    sections, and to zero if a segment has no sections.  This means we          
    lose p_vaddr when objcopy'ing executables if a segment without              
    sections has a non-zero p_vaddr.                                            

    This patch saves p_vaddr to p_vaddr_offset, and to make the use of          
    p_vaddr_offset consistent, inverts the sign.  (It's now added to            
    section vma to get segment vaddr, and added to zero when there are no       
    sections.)                                                                  

            * elf.c (assign_file_positions_for_load_sections): Set p_vaddr      
            from m->p_vaddr_offset for segments without sections.  Invert       
            sign of p_vaddr_offset.                                             
            (rewrite_elf_program_header, copy_elf_program_header): Save         
            old segment p_vaddr to p_vaddr_offset.  Invert sign of              
            p_vaddr_offset.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]