This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: PATCH: Preserve ELF program header
On Thu, May 25, 2006 at 09:32:39PM -0700, H. J. Lu wrote:
> On Fri, May 26, 2006 at 01:19:21PM +0930, Alan Modra wrote:
> > Sure. Obviously you need to subtract off space for the headers then
> > align. I'm thinking that you can do this by modifying the assignments
> > to "align" in the function, particularly places that set "align" from
> > "bed->maxpagesize" to instead use your m->p_align. After all, the
> > problem you are trying to solve is one where alignment due to
> > bed->maxpagesize changes.
>
> Here is the updated patch.
This still isn't correct. You ignored bed->maxpagesize used when
aligning PT_TLS segments. Applying the following.
bfd/
* elf.c (assign_file_positions_for_load_sections): Retrieve
maxpagesize from m->p_align if it is valid. Set p_vaddr,
p_paddr and p_align earlier. Revert 2006-05-19 change to p_align.
(copy_elf_program_header): Copy p_align. Set p_align_valid.
include/elf/
* internal.h (struct elf_segment_map): Add p_align and p_align_valid.
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.339
diff -u -p -r1.339 elf.c
--- bfd/elf.c 25 May 2006 15:08:28 -0000 1.339
+++ bfd/elf.c 27 May 2006 00:23:13 -0000
@@ -4111,6 +4111,7 @@ assign_file_positions_for_load_sections
Elf_Internal_Phdr *phdrs;
Elf_Internal_Phdr *p;
file_ptr off, voff;
+ bfd_size_type maxpagesize;
unsigned int count;
unsigned int alloc;
unsigned int i;
@@ -4196,6 +4197,10 @@ assign_file_positions_for_load_sections
if (phdrs == NULL)
return FALSE;
+ maxpagesize = 1;
+ if ((abfd->flags & D_PAGED) != 0)
+ maxpagesize = bed->maxpagesize;
+
off = bed->s->sizeof_ehdr;
off += alloc * bed->s->sizeof_phdr;
@@ -4227,6 +4232,39 @@ assign_file_positions_for_load_sections
p->p_type = m->p_type;
p->p_flags = m->p_flags;
+ if (m->count == 0)
+ p->p_vaddr = 0;
+ else
+ p->p_vaddr = m->sections[0]->vma;
+
+ if (m->p_paddr_valid)
+ p->p_paddr = m->p_paddr;
+ else if (m->count == 0)
+ p->p_paddr = 0;
+ else
+ p->p_paddr = m->sections[0]->lma;
+
+ if (p->p_type == PT_LOAD
+ && (abfd->flags & D_PAGED) != 0)
+ {
+ /* p_align in demand paged PT_LOAD segments effectively stores
+ the maximum page size. When copying an executable with
+ objcopy, we set m->p_align from the input file. Use this
+ value for maxpagesize rather than bed->maxpagesize, which
+ may be different. Note that we use maxpagesize for PT_TLS
+ segment alignment later in this function, so we are relying
+ on at least one PT_LOAD segment appearing before a PT_TLS
+ segment. */
+ if (m->p_align_valid)
+ maxpagesize = m->p_align;
+
+ p->p_align = maxpagesize;
+ }
+ else if (m->count == 0)
+ p->p_align = 1 << bed->s->log_file_align;
+ else
+ p->p_align = 0;
+
if (p->p_type == PT_LOAD
&& m->count > 0)
{
@@ -4244,8 +4282,8 @@ assign_file_positions_for_load_sections
}
align = (bfd_size_type) 1 << align_power;
- if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > align)
- align = bed->maxpagesize;
+ if (align < maxpagesize)
+ align = maxpagesize;
adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
off += adjust;
@@ -4286,26 +4324,6 @@ assign_file_positions_for_load_sections
return FALSE;
}
- if (m->count == 0)
- p->p_vaddr = 0;
- else
- p->p_vaddr = m->sections[0]->vma;
-
- if (m->p_paddr_valid)
- p->p_paddr = m->p_paddr;
- else if (m->count == 0)
- p->p_paddr = 0;
- else
- p->p_paddr = m->sections[0]->lma;
-
- if (p->p_type == PT_LOAD
- && (abfd->flags & D_PAGED) != 0)
- p->p_align = bed->maxpagesize;
- else if (m->count == 0)
- p->p_align = 1 << bed->s->log_file_align;
- else
- p->p_align = 0;
-
p->p_offset = 0;
p->p_filesz = 0;
p->p_memsz = 0;
@@ -4386,7 +4404,7 @@ assign_file_positions_for_load_sections
sec = *secpp;
flags = sec->flags;
- align = 1 << bfd_get_section_alignment (abfd, sec);
+ align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
if (p->p_type == PT_LOAD
|| p->p_type == PT_TLS)
@@ -4416,8 +4434,8 @@ assign_file_positions_for_load_sections
/* The section VMA must equal the file position
modulo the page size. */
bfd_size_type page = align;
- if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > page)
- page = bed->maxpagesize;
+ if (page < maxpagesize)
+ page = maxpagesize;
adjust = vma_page_aligned_bias (sec->vma,
p->p_vaddr + p->p_memsz,
page);
@@ -4494,8 +4512,7 @@ assign_file_positions_for_load_sections
if (align > p->p_align
&& (p->p_type != PT_LOAD
- || (abfd->flags & D_PAGED) == 0
- || ((p->p_vaddr - p->p_offset) & (align - 1)) == 0))
+ || (abfd->flags & D_PAGED) == 0))
p->p_align = align;
}
@@ -5800,6 +5817,8 @@ copy_elf_program_header (bfd *ibfd, bfd
map->p_flags_valid = 1;
map->p_paddr = segment->p_paddr;
map->p_paddr_valid = 1;
+ map->p_align = segment->p_align;
+ map->p_align_valid = 1;
/* Determine if this segment contains the ELF file header
and if it contains the program headers themselves. */
Index: include/elf/internal.h
===================================================================
RCS file: /cvs/src/src/include/elf/internal.h,v
retrieving revision 1.13
diff -u -p -r1.13 internal.h
--- include/elf/internal.h 10 Feb 2006 15:04:19 -0000 1.13
+++ include/elf/internal.h 27 May 2006 00:23:13 -0000
@@ -235,12 +235,17 @@ struct elf_segment_map
unsigned long p_flags;
/* Program segment physical address. */
bfd_vma p_paddr;
+ /* Program segment alignment. */
+ bfd_vma p_align;
/* Whether the p_flags field is valid; if not, the flags are based
on the section flags. */
unsigned int p_flags_valid : 1;
/* Whether the p_paddr field is valid; if not, the physical address
is based on the section lma values. */
unsigned int p_paddr_valid : 1;
+ /* Whether the p_align field is valid; if not, PT_LOAD segment
+ alignment is based on the default maximum page size. */
+ unsigned int p_align_valid : 1;
/* Whether this segment includes the file header. */
unsigned int includes_filehdr : 1;
/* Whether this segment includes the program headers. */
--
Alan Modra
IBM OzLabs - Linux Technology Centre