[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Bug ld/25354] On RISCV64 LD, with EXACTLY 72 headers/sections, PhysAddr
wilson at gcc dot gnu.org
[Bug ld/25354] On RISCV64 LD, with EXACTLY 72 headers/sections, PhysAddr for first Program Header is wrong
Fri, 23 Oct 2020 01:15:44 +0000
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->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
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
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
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.
Author: Alan Modra <email@example.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
* 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
You are receiving this mail because:
You are on the CC list for the bug.
- [Bug ld/25354] On RISCV64 LD, with EXACTLY 72 headers/sections, PhysAddr for first Program Header is wrong,
wilson at gcc dot gnu.org <=