From 6cef5bac1669defc772927d0dd93a66b0a32d027 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 14 Jan 2022 13:48:36 -0800 Subject: [PATCH v2] ld: Rewrite lang_size_relro_segment_1 Rewrite lang_size_relro_segment_1: 1. Find the first section in the relro segment. 2. Find the first non-empty preceding section. 3. Find the maximum section alignment in sections starting from the PT_GNU_RELRO segment. 4. Don't add the 1-page gap before the relro segment if the maximum page size >= the maximum section alignment. When the maximum page size >= the maximum section alignment, align the PT_GNU_RELRO segment to the maximum page size won't impact the maximum section alignment in sections starting from the PT_GNU_RELRO segment. 5. Align the relro segment if there is a 1-page gap before the relro segment. PR ld/28743 * ldlang.c (lang_size_relro_segment_1): Rewrite. * testsuite/ld-x86-64/pr28743-1.d: New file. * testsuite/ld-x86-64/pr28743-1.s: Likewise. * testsuite/ld-x86-64/x86-64.exp: Run pr28743-1. --- ld/ldlang.c | 115 +++++++++++++++-------------- ld/testsuite/ld-x86-64/pr28743-1.d | 52 +++++++++++++ ld/testsuite/ld-x86-64/pr28743-1.s | 16 ++++ ld/testsuite/ld-x86-64/x86-64.exp | 1 + 4 files changed, 128 insertions(+), 56 deletions(-) create mode 100644 ld/testsuite/ld-x86-64/pr28743-1.d create mode 100644 ld/testsuite/ld-x86-64/pr28743-1.s diff --git a/ld/ldlang.c b/ld/ldlang.c index 93fcfc4cbc7..5403bfe237f 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -6370,10 +6370,15 @@ lang_size_segment (seg_align_type *seg) static bfd_vma lang_size_relro_segment_1 (seg_align_type *seg) { - bfd_vma relro_end, desired_end; - asection *sec, *prev_sec = NULL; - bool remove_page_gap = false; + bfd_vma relro_end, desired_end, aligned_start = 0; + asection *sec, *prev_sec = NULL, *relro_sec = NULL; unsigned int max_alignment_power = 0; + enum + { + relro_sec_after, /* After the relro segment. */ + relro_sec_in, /* In the relro segment. */ + relro_sec_before /* Before the relro segment. */ + } last_sec_status = relro_sec_after; /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end. */ relro_end = ((seg->relro_end + seg->pagesize - 1) @@ -6382,81 +6387,79 @@ lang_size_relro_segment_1 (seg_align_type *seg) /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END. */ desired_end = relro_end - seg->relro_offset; - /* For sections in the relro segment.. */ + /* Find the first section in the relro segment. */ for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev) if ((sec->flags & SEC_ALLOC) != 0) { - if (sec->alignment_power > max_alignment_power) + if (last_sec_status != relro_sec_before + && sec->alignment_power > max_alignment_power) max_alignment_power = sec->alignment_power; if (sec->vma >= seg->base && sec->vma < seg->relro_end - seg->relro_offset) { - /* Where do we want to put this section so that it ends as - desired? */ - bfd_vma start, end, bump; - - end = start = sec->vma; - if (!IS_TBSS (sec)) - end += TO_ADDR (sec->size); - bump = desired_end - end; - /* We'd like to increase START by BUMP, but we must heed - alignment so the increase might be less than optimum. */ - start += bump; - start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1); - /* This is now the desired end for the previous section. */ - desired_end = start; + relro_sec = sec; prev_sec = sec->prev; + last_sec_status = relro_sec_in; } + else + last_sec_status = relro_sec_before; } - seg->phase = exp_seg_relro_adjust; - ASSERT (desired_end >= seg->base); - - for (; prev_sec; prev_sec = prev_sec->prev) - if ((prev_sec->flags & SEC_ALLOC) != 0) - { - if (prev_sec->alignment_power > max_alignment_power) - max_alignment_power = prev_sec->alignment_power; - - if (prev_sec->size != 0) - { - /* The 1-page gap before the RELRO segment may be removed. */ - remove_page_gap = ((prev_sec->vma + prev_sec->size - + seg->maxpagesize) < desired_end); - - break; - } - } - - if (remove_page_gap) + if (relro_sec) { - /* Find the maximum section alignment. */ - for (sec = prev_sec; sec; sec = sec->prev) - if ((sec->flags & SEC_ALLOC) != 0 - && sec->alignment_power > max_alignment_power) - max_alignment_power = sec->alignment_power; + /* Where do we want to put this section so that it ends as + desired? */ + bfd_vma start, end, bump; + + /* Find the first non-empty preceding section. */ + for (; prev_sec; prev_sec = prev_sec->prev) + if (prev_sec->size != 0 && (prev_sec->flags & SEC_ALLOC) != 0) + break; - /* Remove the 1-page gap before the RELRO segment only if the - maximum page size >= the maximum section alignment. */ + end = start = relro_sec->vma; + if (!IS_TBSS (relro_sec)) + end += TO_ADDR (relro_sec->size); + bump = desired_end - end; if (seg->maxpagesize >= (1U << max_alignment_power)) { - /* If the preceding section size is greater than the maximum - page size, subtract the maximum page size. Otherwise, - align the RELRO segment to the maximum page size. */ - if (prev_sec->size > seg->maxpagesize) + /* Don't add the 1-page gap before the relro segment if the + maximum page size >= the maximum section alignment. */ + if (bump > seg->maxpagesize) { - desired_end -= seg->maxpagesize; + bump -= seg->maxpagesize; relro_end -= seg->maxpagesize; } - else + else if (prev_sec != NULL) { - desired_end &= ~(seg->maxpagesize - 1); - relro_end &= ~(seg->maxpagesize - 1); + /* Align the relro segment if there is a 1-page gap + before the relro segment. */ + aligned_start = start + bump; + aligned_start &= ~(((bfd_vma) 1 << relro_sec->alignment_power) + - 1); + if ((prev_sec->vma + prev_sec->size + seg->maxpagesize) + < aligned_start) + { + aligned_start &= ~(seg->maxpagesize - 1); + relro_end &= ~(seg->maxpagesize - 1); + } } - } - } + } + /* We'd like to increase START by BUMP, but we must heed + alignment so the increase might be less than optimum. */ + if (aligned_start != 0) + start = aligned_start; + else + { + start += bump; + start &= ~(((bfd_vma) 1 << relro_sec->alignment_power) - 1); + } + /* This is now the desired end for the previous section. */ + desired_end = start; + } + seg->phase = exp_seg_relro_adjust; + ASSERT (aligned_start != 0 || desired_end >= seg->base); seg->base = desired_end; return relro_end; } diff --git a/ld/testsuite/ld-x86-64/pr28743-1.d b/ld/testsuite/ld-x86-64/pr28743-1.d new file mode 100644 index 00000000000..36297d284e8 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr28743-1.d @@ -0,0 +1,52 @@ +#as: --64 +#ld: -melf_x86_64 -shared -z relro -z now --hash-style=sysv -z max-page-size=0x1000 -z noseparate-code $NO_DT_RELR_LDFLAGS +#readelf: -S -l --wide +#target: x86_64-*-linux* + +There are 17 section headers, starting at offset 0x101228: + +Section Headers: + \[Nr\] Name Type Address Off Size ES Flg Lk Inf Al + \[ 0\] NULL 0000000000000000 000000 000000 00 0 0 0 + \[ 1\] .hash HASH 0000000000000158 000158 000018 04 A 2 0 8 + \[ 2\] .dynsym DYNSYM 0000000000000170 000170 000048 18 A 3 1 8 + \[ 3\] .dynstr STRTAB 00000000000001b8 0001b8 00000a 00 A 0 0 1 + \[ 4\] .rela.dyn RELA 00000000000001c8 0001c8 000018 18 A 2 0 8 + \[ 5\] .plt PROGBITS 00000000000001e0 0001e0 000010 10 AX 0 0 16 + \[ 6\] .plt.got PROGBITS 00000000000001f0 0001f0 000008 08 AX 0 0 8 + \[ 7\] .text PROGBITS 00000000000001f8 0001f8 00000c 00 AX 0 0 1 + \[ 8\] .eh_frame PROGBITS 0000000000000208 000208 00006c 00 A 0 0 8 + \[ 9\] .init_array INIT_ARRAY 0000000000001278 000278 000004 08 WA 0 0 8 + \[10\] .fini_array FINI_ARRAY 0000000000100000 100000 000100 08 WA 0 0 1048576 + \[11\] .dynamic DYNAMIC 0000000000100100 100100 000150 10 WA 3 0 8 + \[12\] .got PROGBITS 0000000000100250 100250 000020 08 WA 0 0 8 + \[13\] .data PROGBITS 0000000000101000 101000 000100 00 WA 0 0 1 + \[14\] .symtab SYMTAB 0000000000000000 101100 000078 18 15 3 8 + \[15\] .strtab STRTAB 0000000000000000 101178 000029 00 0 0 1 + \[16\] .shstrtab STRTAB 0000000000000000 1011a1 000080 00 0 0 1 +Key to Flags: + W \(write\), A \(alloc\), X \(execute\), M \(merge\), S \(strings\), I \(info\), + L \(link order\), O \(extra OS processing required\), G \(group\), T \(TLS\), + C \(compressed\), x \(unknown\), o \(OS specific\), E \(exclude\), + D \(mbind\), l \(large\), p \(processor specific\) + +Elf file type is DYN \(Shared object file\) +Entry point 0x0 +There are 5 program headers, starting at offset 64 + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000274 0x000274 R E 0x1000 + LOAD 0x000278 0x0000000000001278 0x0000000000001278 0x000004 0x000004 RW 0x1000 + LOAD 0x100000 0x0000000000100000 0x0000000000100000 0x001100 0x001100 RW 0x100000 + DYNAMIC 0x100100 0x0000000000100100 0x0000000000100100 0x000150 0x000150 RW 0x8 + GNU_RELRO 0x000278 0x0000000000001278 0x0000000000001278 0x000004 0x0ffd88 R 0x1 + + Section to Segment mapping: + Segment Sections... + 00 .hash .dynsym .dynstr .rela.dyn .plt .plt.got .text .eh_frame + 01 .init_array + 02 .fini_array .dynamic .got .data + 03 .dynamic + 04 .init_array +#pass diff --git a/ld/testsuite/ld-x86-64/pr28743-1.s b/ld/testsuite/ld-x86-64/pr28743-1.s new file mode 100644 index 00000000000..2e9a1503741 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr28743-1.s @@ -0,0 +1,16 @@ + .text + .globl foo + .type foo, @function +foo: + .cfi_startproc + call func@plt + movq func@GOTPCREL(%rip), %rax + .cfi_endproc + .section .init_array,"aw",@init_array + .p2align 3 + .zero 0x4 + .section .fini_array,"aw",@fini_array + .p2align 20 + .zero 0x100 + .data + .zero 0x100 diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 3bfc5e6e467..5ef66a237ef 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -511,6 +511,7 @@ run_dump_test "dt-relr-1a" run_dump_test "dt-relr-1a-x32" run_dump_test "dt-relr-1b" run_dump_test "dt-relr-1b-x32" +run_dump_test "pr28743-1" if ![istarget "x86_64-*-linux*"] { return -- 2.34.1