ld/ 2009-10-07 Nathan Sidwell PR ld/10744 * ldlang.c (lang_new_phdr): Allow PHDRS and FILEHDR in PT_LOAD segment if previous segment contains either PHDRS or FILEHDR. * ld.texinfo (PHDRS): Updated. ld/testsuite/ 2009-10-07 H.J. Lu Nathan Sidwell * ld-scripts/phdrs3.d: Updated. * ld-scripts/phdrs3.exp: Run phdrs3a. * ld-scripts/phdrs3a.d: New. * ld-scripts/phdrs3a.t: Likewise. diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 978ae66..8ca0e14 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -4739,8 +4739,9 @@ You may use the @code{FILEHDR} and @code{PHDRS} keywords after the program header type to further describe the contents of the segment. The @code{FILEHDR} keyword means that the segment should include the ELF file header. The @code{PHDRS} keyword means that the segment should -include the ELF program headers themselves. If applied to a loadable -segment (@code{PT_LOAD}), it must be the first loadable segment. +include the ELF program headers themselves. These may only be applied +to the first segment, or to a segment that appears immediately after +another segment containing either @code{PHDRS} or @code{FILEHDR}. The @var{type} may be one of the following. The numbers indicate the value of the keyword. diff --git a/ld/ldlang.c b/ld/ldlang.c index a46438e..92dccbb 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -6765,7 +6765,6 @@ lang_new_phdr (const char *name, etree_type *flags) { struct lang_phdr *n, **pp; - bfd_boolean hdrs; n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr)); n->next = NULL; @@ -6775,14 +6774,12 @@ lang_new_phdr (const char *name, n->phdrs = phdrs; n->at = at; n->flags = flags; - - hdrs = n->type == 1 && (phdrs || filehdr); for (pp = &lang_phdr_list; *pp != NULL; pp = &(*pp)->next) - if (hdrs && (*pp)->type == 1) + if ((filehdr || phdrs) && !((*pp)->filehdr || (*pp)->phdrs)) { - einfo (_("%X%P:%S: PHDRS and FILEHDR are only permitted for the first PT_LOAD segment\n")); - hdrs = FALSE; + einfo (_("%X%P:%S: PHDRS and FILEHDR are only permitted if all previous segments contain headers, `%s' does not\n"), (*pp)->name); + filehdr = phdrs = FALSE; } *pp = n; diff --git a/ld/testsuite/ld-scripts/phdrs3.d b/ld/testsuite/ld-scripts/phdrs3.d index 78fe4e4..ecbe84f 100644 --- a/ld/testsuite/ld-scripts/phdrs3.d +++ b/ld/testsuite/ld-scripts/phdrs3.d @@ -1,4 +1,4 @@ # name: PHDRS headers # source: phdrs.s # ld: -T phdrs3.t -# error: \A[^ \n:]*:[^:\n]*:5: PHDRS and FILEHDR are only permitted for the first PT_LOAD segment\Z +# error: \A[^ \n:]*:[^:\n]*:4: PHDRS and FILEHDR are only permitted if all previous segments contain headers, `data' does not\n[^ \n:]*:[^:\n]*:5: PHDRS and FILEHDR are only permitted if all previous segments contain headers, `data' does not\Z diff --git a/ld/testsuite/ld-scripts/phdrs3.exp b/ld/testsuite/ld-scripts/phdrs3.exp index 90651af..e7e0414 100644 --- a/ld/testsuite/ld-scripts/phdrs3.exp +++ b/ld/testsuite/ld-scripts/phdrs3.exp @@ -34,5 +34,6 @@ if { [istarget spu*-*-*] } { } run_dump_test "phdrs3" +run_dump_test "phdrs3a" set LDFLAGS $old_ldflags diff --git a/ld/testsuite/ld-scripts/phdrs3a.d b/ld/testsuite/ld-scripts/phdrs3a.d new file mode 100644 index 0000000..cd151a9 --- /dev/null +++ b/ld/testsuite/ld-scripts/phdrs3a.d @@ -0,0 +1,9 @@ +#name: PHDRS headers 3a +#source: phdrs.s +#ld: -T phdrs3a.t +#readelf: -l --wide + +#... +[ \t]+LOAD.* +[ \t]+LOAD.* +#pass diff --git a/ld/testsuite/ld-scripts/phdrs3a.t b/ld/testsuite/ld-scripts/phdrs3a.t new file mode 100644 index 0000000..c07ff34 --- /dev/null +++ b/ld/testsuite/ld-scripts/phdrs3a.t @@ -0,0 +1,15 @@ +PHDRS +{ + data PT_LOAD FILEHDR PHDRS FLAGS(4); + text PT_LOAD FILEHDR PHDRS FLAGS(1); +} + +SECTIONS +{ + /* This test will fail on architectures where the startaddress below + is less than the constant MAXPAGESIZE. */ + . = 0x800000 + SIZEOF_HEADERS; + .text : { *(.text) } :text + .data : { *(.data) } :data + /DISCARD/ : { *(.*) } +}