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 <amo...@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.