diff options
-rw-r--r-- | bfd/elf-bfd.h | 4 | ||||
-rw-r--r-- | bfd/elf.c | 71 | ||||
-rw-r--r-- | bfd/elfxx-target.h | 5 | ||||
-rw-r--r-- | bfd/elfxx-x86.h | 2 | ||||
-rw-r--r-- | include/bfdlink.h | 3 | ||||
-rw-r--r-- | ld/emultempl/elf.em | 1 | ||||
-rw-r--r-- | ld/ldelf.c | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/elf.exp | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/header.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/linux-x86.exp | 36 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/p_align-1.c | 25 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/page-size-1.d | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26936.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/seg.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-pru/pru_irq_map-1.d | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-pru/pru_irq_map-2.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/pr23571.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/rgn-at5.d | 2 |
18 files changed, 162 insertions, 12 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 19abd59..896aa08 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -945,6 +945,10 @@ struct elf_backend_data /* The value of commonpagesize to use when -z relro for this backend. */ bfd_vma relropagesize; + /* The p_align value for this backend. If it is set, p_align of + PT_LOAD alignment will be to p_align by default. */ + bfd_vma p_align; + /* The BFD flags applied to sections created for dynamic linking. */ flagword dynamic_sec_flags; @@ -5407,6 +5407,8 @@ assign_file_positions_for_load_sections (bfd *abfd, Elf_Internal_Phdr *p; file_ptr off; /* Octets. */ bfd_size_type maxpagesize; + bfd_size_type p_align; + bool p_align_p = false; unsigned int alloc, actual; unsigned int i, j; struct elf_segment_map **sorted_seg_map; @@ -5491,6 +5493,7 @@ assign_file_positions_for_load_sections (bfd *abfd, qsort (sorted_seg_map, alloc, sizeof (*sorted_seg_map), elf_sort_segments); + p_align = bed->p_align; maxpagesize = 1; if ((abfd->flags & D_PAGED) != 0) { @@ -5561,6 +5564,15 @@ assign_file_positions_for_load_sections (bfd *abfd, segment. */ if (m->p_align_valid) maxpagesize = m->p_align; + else if (p_align != 0 + && (link_info == NULL + || !link_info->maxpagesize_is_set)) + /* Set p_align to the default p_align value while laying + out segments aligning to the maximum page size or the + largest section alignment. The run-time loader can + align segments to the default p_align value or the + maximum page size, depending on system page size. */ + p_align_p = true; p->p_align = maxpagesize; } @@ -5598,7 +5610,22 @@ assign_file_positions_for_load_sections (bfd *abfd, } align = (bfd_size_type) 1 << align_power; if (align < maxpagesize) - align = maxpagesize; + { + /* If a section requires alignment higher than the + default p_align value, don't set p_align to the + default p_align value. */ + if (align > p_align) + p_align_p = false; + align = maxpagesize; + } + else + { + /* If a section requires alignment higher than the + maximum page size, set p_align to the section + alignment. */ + p_align_p = true; + p_align = align; + } } for (i = 0; i < m->count; i++) @@ -5977,6 +6004,9 @@ assign_file_positions_for_load_sections (bfd *abfd, print_segment_map (m); } } + + if (p_align_p) + p->p_align = p_align; } } @@ -7484,6 +7514,40 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize) return true; } +/* Return true if p_align in the ELF program header in ABFD is valid. */ + +static bool +elf_is_p_align_valid (bfd *abfd) +{ + unsigned int i; + Elf_Internal_Phdr *segment; + unsigned int num_segments; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_size_type maxpagesize = bed->maxpagesize; + bfd_size_type p_align = bed->p_align; + + /* Return true if the default p_align value isn't set or the maximum + page size is the same as the minimum page size. */ + if (p_align == 0 || maxpagesize == bed->minpagesize) + return true; + + /* When the default p_align value is set, p_align may be set to the + default p_align value while segments are aligned to the maximum + page size. In this case, the input p_align will be ignored and + the maximum page size will be used to align the output segments. */ + segment = elf_tdata (abfd)->phdr; + num_segments = elf_elfheader (abfd)->e_phnum; + for (i = 0; i < num_segments; i++, segment++) + if (segment->p_type == PT_LOAD + && (segment->p_align != p_align + || vma_page_aligned_bias (segment->p_vaddr, + segment->p_offset, + maxpagesize) != 0)) + return true; + + return false; +} + /* Copy ELF program header information. */ static bool @@ -7498,6 +7562,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) unsigned int num_segments; bool phdr_included = false; bool p_paddr_valid; + bool p_palign_valid; unsigned int opb = bfd_octets_per_byte (ibfd, NULL); iehdr = elf_elfheader (ibfd); @@ -7518,6 +7583,8 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) break; } + p_palign_valid = elf_is_p_align_valid (ibfd); + for (i = 0, segment = elf_tdata (ibfd)->phdr; i < num_segments; i++, segment++) @@ -7560,7 +7627,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) map->p_paddr = segment->p_paddr; map->p_paddr_valid = p_paddr_valid; map->p_align = segment->p_align; - map->p_align_valid = 1; + map->p_align_valid = p_palign_valid; map->p_vaddr_offset = 0; if (map->p_type == PT_GNU_RELRO diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index b9af578..360b056 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -400,6 +400,10 @@ # error ELF_MINPAGESIZE > ELF_RELROPAGESIZE #endif +#ifndef ELF_P_ALIGN +#define ELF_P_ALIGN 0 +#endif + #ifndef ELF_DYNAMIC_SEC_FLAGS /* Note that we set the SEC_IN_MEMORY flag for these sections. */ #define ELF_DYNAMIC_SEC_FLAGS \ @@ -813,6 +817,7 @@ static const struct elf_backend_data elfNN_bed = ELF_MINPAGESIZE, /* minpagesize */ ELF_COMMONPAGESIZE, /* commonpagesize */ ELF_RELROPAGESIZE, /* commonpagesize to use with -z relro */ + ELF_P_ALIGN, /* p_align */ ELF_DYNAMIC_SEC_FLAGS, /* dynamic_sec_flags */ elf_backend_arch_data, elf_info_to_howto, diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index eedb162..25791af 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -755,6 +755,8 @@ extern void _bfd_x86_elf_link_report_relative_reloc #define elf_backend_fixup_gnu_properties \ _bfd_x86_elf_link_fixup_gnu_properties +#define ELF_P_ALIGN ELF_MINPAGESIZE + /* Return true if H is a __start_SECNAME/__stop_SECNAME symbol for the SECNAME section which has been garbage collected by --gc-sections -z start-stop-gc. */ diff --git a/include/bfdlink.h b/include/bfdlink.h index 6a61d7e..01f57c2 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -525,6 +525,9 @@ struct bfd_link_info /* TRUE if all symbol names should be unique. */ unsigned int unique_symbol : 1; + /* TRUE if maxpagesize is set on command-line. */ + unsigned int maxpagesize_is_set : 1; + /* Char that may appear as the first char of a symbol, but should be skipped (like symbol_leading_char) when looking up symbols in wrap_hash. Used by PowerPC Linux for 'dot' symbols. */ diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em index 9c8e792..5977526 100644 --- a/ld/emultempl/elf.em +++ b/ld/emultempl/elf.em @@ -721,6 +721,7 @@ fragment <<EOF || (link_info.maxpagesize & (link_info.maxpagesize - 1)) != 0) einfo (_("%F%P: invalid maximum page size \`%s'\n"), optarg + 14); + link_info.maxpagesize_is_set = true; } else if (startswith (optarg, "common-page-size=")) { @@ -72,6 +72,9 @@ ldelf_after_parse (void) link_info.dynamic_undefined_weak = 0; } after_parse_default (); + if (link_info.commonpagesize > link_info.maxpagesize) + einfo (_("%F%P: common page size (0x%v) > maximum page size (0x%v)\n"), + link_info.commonpagesize, link_info.maxpagesize); } /* Handle the generation of DT_NEEDED tags. */ diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp index 119908c..16128c2 100644 --- a/ld/testsuite/ld-elf/elf.exp +++ b/ld/testsuite/ld-elf/elf.exp @@ -365,7 +365,7 @@ if { [istarget *-*-linux*] run_ld_link_exec_tests [list \ [list \ "Run mbind2a" \ - "$NOPIE_LDFLAGS -Wl,-z,common-page-size=0x4000" \ + "$NOPIE_LDFLAGS -Wl,-z,common-page-size=0x4000,-z,max-page-size=0x4000" \ "" \ { mbind2a.s mbind2b.c } \ "mbind2a" \ @@ -374,7 +374,7 @@ if { [istarget *-*-linux*] ] \ [list \ "Run mbind2b" \ - "-static -Wl,-z,common-page-size=0x4000" \ + "-static -Wl,-z,common-page-size=0x4000,-z,max-page-size=0x4000" \ "" \ { mbind2a.s mbind2b.c } \ "mbind2b" \ diff --git a/ld/testsuite/ld-elf/header.d b/ld/testsuite/ld-elf/header.d index c4d174a..67f0c98 100644 --- a/ld/testsuite/ld-elf/header.d +++ b/ld/testsuite/ld-elf/header.d @@ -1,5 +1,5 @@ # target: *-*-linux* *-*-gnu* *-*-vxworks arm*-*-uclinuxfdpiceabi -# ld: -T header.t -z max-page-size=0x100 +# ld: -T header.t -z max-page-size=0x100 -z common-page-size=0x100 # objdump: -hpw #... diff --git a/ld/testsuite/ld-elf/linux-x86.exp b/ld/testsuite/ld-elf/linux-x86.exp index f48c196..2e0cbd3 100644 --- a/ld/testsuite/ld-elf/linux-x86.exp +++ b/ld/testsuite/ld-elf/linux-x86.exp @@ -185,6 +185,42 @@ run_ld_link_exec_tests [list \ "" \ "tmpdir/indirect-extern-access-2.so" \ ] \ + [list \ + "Run p_align-1a without PIE" \ + "$NOPIE_LDFLAGS" \ + "" \ + { p_align-1.c } \ + "p_align-1a" \ + "pass.out" \ + "$NOPIE_CFLAGS" \ + ] \ + [list \ + "Run p_align-1b with PIE" \ + "-pie" \ + "" \ + { p_align-1.c } \ + "p_align-1b" \ + "pass.out" \ + "-fpie" \ + ] \ + [list \ + "Run p_align-1c with -Wl,-z,max-page-size=0x1000 without PIE" \ + "$NOPIE_LDFLAGS -Wl,-z,max-page-size=0x1000" \ + "" \ + { p_align-1.c } \ + "p_align-1c" \ + "pass.out" \ + "$NOPIE_CFLAGS" \ + ] \ + [list \ + "Run p_align-1d with -Wl,-z,max-page-size=0x1000 with PIE" \ + "-pie -Wl,-z,max-page-size=0x1000" \ + "" \ + { p_align-1.c } \ + "p_align-1d" \ + "pass.out" \ + "-fpie" \ + ] \ ] proc elfedit_test { options test output } { diff --git a/ld/testsuite/ld-elf/p_align-1.c b/ld/testsuite/ld-elf/p_align-1.c new file mode 100644 index 0000000..6579cd7 --- /dev/null +++ b/ld/testsuite/ld-elf/p_align-1.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#ifndef ALIGN +# define ALIGN 0x800000 +#endif + +int +__attribute__ ((weak)) +is_aligned (void *p, int align) +{ + return (((uintptr_t) p) & (align - 1)) == 0; +} + +int foo __attribute__ ((aligned (ALIGN))) = 1; + +int +main (void) +{ + if (!is_aligned (&foo, ALIGN)) + abort (); + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-elf/page-size-1.d b/ld/testsuite/ld-elf/page-size-1.d new file mode 100644 index 0000000..04d2153 --- /dev/null +++ b/ld/testsuite/ld-elf/page-size-1.d @@ -0,0 +1,4 @@ +#source: dummy.s +#ld: -z common-page-size=0x4000 -z max-page-size=0x1000 +#error: common page size \(0x4000\) > maximum page size \(0x1000\) +#target: *-*-linux-gnu *-*-gnu* arm*-*-uclinuxfdpiceabi diff --git a/ld/testsuite/ld-elf/pr26936.d b/ld/testsuite/ld-elf/pr26936.d index 0a2831d..c479f47 100644 --- a/ld/testsuite/ld-elf/pr26936.d +++ b/ld/testsuite/ld-elf/pr26936.d @@ -2,7 +2,7 @@ #source: pr26936b.s #source: pr26936c.s #as: --gen-debug -#ld: -z noseparate-code -Ttext-segment 0x10000 -z max-page-size=0x1000 +#ld: -z noseparate-code -Ttext-segment 0x10000 -z max-page-size=0x1000 -z common-page-size=0x1000 #readelf: -wL -W #target: [check_shared_lib_support] # Assembly source file for the HPPA assembler is renamed and modifed by diff --git a/ld/testsuite/ld-elf/seg.d b/ld/testsuite/ld-elf/seg.d index 3ff7aba..9dce11e 100644 --- a/ld/testsuite/ld-elf/seg.d +++ b/ld/testsuite/ld-elf/seg.d @@ -1,6 +1,6 @@ #target: *-*-linux* *-*-gnu* *-*-vxworks arm*-*-uclinuxfdpiceabi #source: seg.s -#ld: -T seg.t -z max-page-size=0x1000 +#ld: -T seg.t -z max-page-size=0x1000 -z common-page-size=0x1000 #readelf: -l --wide #... diff --git a/ld/testsuite/ld-pru/pru_irq_map-1.d b/ld/testsuite/ld-pru/pru_irq_map-1.d index bbdf5b6..2538f4c 100644 --- a/ld/testsuite/ld-pru/pru_irq_map-1.d +++ b/ld/testsuite/ld-pru/pru_irq_map-1.d @@ -1,4 +1,4 @@ -#name: pru_irq_map special section for host +#name: pru_irq_map special section for host 1 #source: pru_irq_map.s #ld: --defsym=__HEAP_SIZE=0 --defsym=__STACK_SIZE=0 #readelf: -l --wide @@ -9,7 +9,7 @@ Program Headers: +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg +Align +LOAD +0x[0-9a-f]+ 0x0+ 0x0+ 0x0+8 0x0+8 RW 0x1 - +LOAD +0x[0-9a-f]+ 0x20+ 0x20+ 0x0+4 0x0+4 R E 0x1 + +LOAD +0x[0-9a-f]+ 0x20+ 0x20+ 0x0+4 0x0+4 R E 0x4 Section to Segment mapping: +Segment Sections... diff --git a/ld/testsuite/ld-pru/pru_irq_map-2.d b/ld/testsuite/ld-pru/pru_irq_map-2.d index 3166595..d6c583f 100644 --- a/ld/testsuite/ld-pru/pru_irq_map-2.d +++ b/ld/testsuite/ld-pru/pru_irq_map-2.d @@ -1,4 +1,4 @@ -#name: pru_irq_map special section for host +#name: pru_irq_map special section for host 2 #source: pru_irq_map.s #ld: --defsym=__HEAP_SIZE=0 --defsym=__STACK_SIZE=0 #readelf: -S --wide diff --git a/ld/testsuite/ld-scripts/pr23571.d b/ld/testsuite/ld-scripts/pr23571.d index adf4796..45b4059 100644 --- a/ld/testsuite/ld-scripts/pr23571.d +++ b/ld/testsuite/ld-scripts/pr23571.d @@ -1,5 +1,5 @@ #source: align2a.s -#ld: -T pr23571.t -z common-page-size=0x1000 +#ld: -T pr23571.t -z common-page-size=0x1000 -z max-page-size=0x1000 #objdump: -h -w .*: +file format .* diff --git a/ld/testsuite/ld-scripts/rgn-at5.d b/ld/testsuite/ld-scripts/rgn-at5.d index 767285c..e9ab081 100644 --- a/ld/testsuite/ld-scripts/rgn-at5.d +++ b/ld/testsuite/ld-scripts/rgn-at5.d @@ -1,6 +1,6 @@ # name: rgn-at5 # source: rgn-at5.s -# ld: -T rgn-at5.t -z max-page-size=0x1000 +# ld: -T rgn-at5.t -z max-page-size=0x1000 -z common-page-size=0x1000 # objdump: -w -h # target: *-*-linux* *-*-gnu* arm*-*-uclinuxfdpiceabi # xfail: rx-*-* |