This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: loadbase alignment - ld.so/prelink/kernel or bfd_elf_bfd_from_remote_memory() bug?
On Wed, Aug 15, 2007 at 03:56:10PM +0200, Jan Kratochvil wrote:
> Hi,
>
> bfd_elf_bfd_from_remote_memory() would almost work for general ELF files but it
> fails (I have no simple testcase) now due to the ELF `Base address' alignment.
> BFD uses `& -i_phdrs[i].p_align' for the VMA addresses but the real mapping
> is only PAGE_SIZE aligned (illustrated in the `BEFORE' dumps below).
>
> For x86_64:
>
> * bfd_elf_bfd_from_remote_memory() expects `loadbase' is P_ALIGN aligned.
>
> * GCC on x86_64 produces P_ALIGN 0x200000 == 2MB.
>
> * ld.so loads ELF to `l_map_start' being only PAGE_SIZE aligned.
> (The same problem applies to prelink and Linux kernel elf loading.)
>
> * gELF standard in its `Base Address' computation expects the `base address' to
> be `maximum page size' aligned, according to the last sentence:
> http://x86.ddj.com/ftp/manuals/tools/elf.pdf
> This address is truncated to the nearest multiple of the maximum page
> size. The corresponding p_vaddr value itself is also truncated to the
> nearest multiple of the maximum page size. The base address is the
> difference between the truncated memory address and the truncated
> p_vaddr value.
>
> * x86_64 ELF standard in its `3.3.3 Page Size' talks about maximum page size
> 64KB (I would expect it should scale up to 2MB for the 2MB PSE pages).
> http://www.x86-64.org/documentation/abi.pdf
> Systems are permitted to use any power-of-two page size between 4KB and
> 64KB, inclusive.
>
> According to the Roland's mail below (p_align is supposed to match "maxpage")
> IMO ld.so + prelink + kernel violate the gELF standard.
>
> Proper ld.so P_ALIGN-compliant mapping would also make possible a kernel 2MB
> PSE pages optimized mapping for very large .so libraries.
>
> Removing P_ALIGN masking from bfd_elf_bfd_from_remote_memory() workarounds it
> well but I expect this problem should move to glibc + prelink + kernel, right?
>
>
> Proposing ld.so patch which fixes the bfd_elf_bfd_from_remote_memory() problem.
>
> Program Headers:
> Type Offset VirtAddr PhysAddr
> FileSiz MemSiz Flags Align
> LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
> 0x00000000000004bc 0x00000000000004bc R E 200000
> LOAD 0x00000000000004c0 0x00000000002004c0 0x00000000002004c0
> 0x00000000000001e8 0x00000000000001f8 RW 200000
>
> BEFORE:
> 00400000-00401000 r-xp 00000000 08:01 4717502 /tmp/alignmain
> 00600000-00601000 rw-p 00000000 08:01 4717502 /tmp/alignmain
> ...
> 2aaaaaaad000-2aaaaaaae000 r-xp 00000000 08:01 4717503 /tmp/alignlib.so
> 2aaaaaaae000-2aaaaacad000 ---p 00001000 08:01 4717503 /tmp/alignlib.so
> 2aaaaacad000-2aaaaacae000 rw-p 00000000 08:01 4717503 /tmp/alignlib.so
>
> open("./alignlib.so", O_RDONLY) = 3
> ...
> mmap(NULL, 2098872, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x2aaaaaaad000
> mprotect(0x2aaaaaaae000, 2093056, PROT_NONE) = 0
> mmap(0x2aaaaacad000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x2aaaaacad000
> close(3) = 0
>
>
> AFTER:
> 00400000-00401000 r-xp 00000000 08:01 4717502 /tmp/alignmain
> 00600000-00601000 rw-p 00000000 08:01 4717502 /tmp/alignmain
> ...
> 2aaaaac00000-2aaaaac01000 r-xp 00000000 08:01 4717503 /tmp/alignlib.so
> 2aaaaac01000-2aaaaae00000 ---p 2aaaaac01000 00:00 0
> 2aaaaae00000-2aaaaae01000 rw-p 00000000 08:01 4717503 /tmp/alignlib.so
>
> open("./alignlib.so", O_RDONLY) = 3
> ...
> mmap(NULL, 4194304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0x2aaaaaaad000
> munmap(0x2aaaaaaad000, 1388544) = 0
> munmap(0x2aaaaae01000, 704512) = 0
> mprotect(0x2aaaaac01000, 2093056, PROT_NONE) = 0
> mmap(0x2aaaaac00000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x2aaaaac00000
> mmap(0x2aaaaae00000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x2aaaaae00000
> close(3) = 0
>
>
>
> Regards,
> Jan
>
>
> http://sourceware.org/ml/binutils/2007-08/msg00184.html
>
> On Mon, 13 Aug 2007 03:15:44 +0200, Roland McGrath wrote:
> ...
> > The file itself doesn't tell you what "maxpage" is, but p_align is
> > supposed to match it.
>
> > You can't presume the actual memory addresses
> > used will be so aligned (it's the maximum page size, not the minimum).
>
> This sentence contradicts my deduction above.
>
>
> > However, in a correct ELF object's phdrs, each p_vaddr and p_offset
> > must be congruent to that alignment.
> ...
> > you need to know the actual page size. bfd_elf_bfd_from_remote_memory
> > doesn't know this. (The debugger might know it by some external means.
> 2007-08-15 Jan Kratochvil <jan.kratochvil@redhat.com>
>
> * elf/dl-load.c (_dl_map_object_from_fd): New variable ALIGNMAX.
> New sanity check if P_ALIGN is a power of two.
> New variables ALIGNEDSTART, ALIGNEDMAPPEDEND and ALIGNEDMAPLENGTH.
> Map ET_DYN ELFs with the P_ALIGN compliant ELF Base address.
>
> --- glibc-20070810T2152-orig/elf/dl-load.c 2007-08-03 17:50:24.000000000 +0200
> +++ glibc-20070810T2152/elf/dl-load.c 2007-08-15 00:41:03.000000000 +0200
> @@ -1012,6 +1012,7 @@ _dl_map_object_from_fd (const char *name
> int prot;
> } loadcmds[l->l_phnum], *c;
> size_t nloadcmds = 0;
> + ElfW(Addr) alignmax = GLRO(dl_pagesize);
Why not replace all GLRO(dl_pagesize) with alignmax?
H.J.