ld: Rewrite lang_size_relro_segment_1

1. Compute the desired PT_GNU_RELRO segment base and find the maximum
section alignment of sections starting from the PT_GNU_RELRO segment.
2. Find the first preceding load section.
3. Don't add the 1-page gap between the first preceding load section and
the relro segment if the maximum page size >= the maximum section
alignment.  Align the PT_GNU_RELRO segment first.  Subtract the maximum
page size if therer is still a 1-page gap.

	PR ld/28743
	PR ld/28819
	* 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.
This commit is contained in:
H.J. Lu 2022-01-14 13:48:36 -08:00
parent 8357282156
commit c804c6f98d
4 changed files with 118 additions and 44 deletions

View file

@ -6370,94 +6370,101 @@ lang_size_segment (seg_align_type *seg)
static bfd_vma static bfd_vma
lang_size_relro_segment_1 (seg_align_type *seg) lang_size_relro_segment_1 (seg_align_type *seg)
{ {
bfd_vma relro_end, desired_end; bfd_vma relro_end, desired_relro_base;
asection *sec, *prev_sec = NULL; asection *sec, *relro_sec = NULL;
bool remove_page_gap = false;
unsigned int max_alignment_power = 0; unsigned int max_alignment_power = 0;
bool seen_reloc_section = false;
bool desired_relro_base_reduced = false;
/* Compute the expected PT_GNU_RELRO/PT_LOAD segment end. */ /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end. */
relro_end = ((seg->relro_end + seg->pagesize - 1) relro_end = ((seg->relro_end + seg->pagesize - 1)
& ~(seg->pagesize - 1)); & ~(seg->pagesize - 1));
/* Adjust by the offset arg of XXX_SEGMENT_RELRO_END. */ /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END. */
desired_end = relro_end - seg->relro_offset; desired_relro_base = relro_end - seg->relro_offset;
/* For sections in the relro segment.. */ /* For sections in the relro segment. */
for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev) for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
if ((sec->flags & SEC_ALLOC) != 0) if ((sec->flags & SEC_ALLOC) != 0)
{ {
/* Record the maximum alignment for all sections starting from
the relro segment. */
if (sec->alignment_power > max_alignment_power) if (sec->alignment_power > max_alignment_power)
max_alignment_power = sec->alignment_power; max_alignment_power = sec->alignment_power;
if (sec->vma >= seg->base if (sec->vma >= seg->base
&& sec->vma < seg->relro_end - seg->relro_offset) && sec->vma < seg->relro_end - seg->relro_offset)
{ {
/* Where do we want to put this section so that it ends as /* Where do we want to put the relro section so that the
desired? */ relro segment ends on the page bounary? */
bfd_vma start, end, bump; bfd_vma start, end, bump;
end = start = sec->vma; end = start = sec->vma;
if (!IS_TBSS (sec)) if (!IS_TBSS (sec))
end += TO_ADDR (sec->size); end += TO_ADDR (sec->size);
bump = desired_end - end; bump = desired_relro_base - end;
/* We'd like to increase START by BUMP, but we must heed /* We'd like to increase START by BUMP, but we must heed
alignment so the increase might be less than optimum. */ alignment so the increase might be less than optimum. */
start += bump; start += bump;
start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1); start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
/* This is now the desired end for the previous section. */ /* This is now the desired end for the previous section. */
desired_end = start; desired_relro_base = start;
prev_sec = sec->prev; relro_sec = sec;
seen_reloc_section = true;
} }
} else if (seen_reloc_section)
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. */ /* Stop searching if we see a non-relro section after seeing
remove_page_gap = ((prev_sec->vma + prev_sec->size relro sections. */
+ seg->maxpagesize) < desired_end);
break; break;
} }
} }
if (remove_page_gap) if (relro_sec != NULL
&& seg->maxpagesize >= (1U << max_alignment_power))
{ {
/* Find the maximum section alignment. */ asection *prev_sec;
for (sec = prev_sec; sec; sec = sec->prev) bfd_vma prev_sec_end_plus_1_page;
if ((sec->flags & SEC_ALLOC) != 0
&& sec->alignment_power > max_alignment_power)
max_alignment_power = sec->alignment_power;
/* Remove the 1-page gap before the RELRO segment only if the /* Find the first preceding load section. */
maximum page size >= the maximum section alignment. */ for (prev_sec = relro_sec->prev;
if (seg->maxpagesize >= (1U << max_alignment_power)) prev_sec != NULL;
prev_sec = prev_sec->prev)
if ((prev_sec->flags & SEC_ALLOC) != 0)
break;
prev_sec_end_plus_1_page = (prev_sec->vma + prev_sec->size
+ seg->maxpagesize);
if (prev_sec_end_plus_1_page < desired_relro_base)
{ {
/* If the preceding section size is greater than the maximum bfd_vma aligned_relro_base;
page size, subtract the maximum page size. Otherwise,
align the RELRO segment to the maximum page size. */ desired_relro_base_reduced = true;
if (prev_sec->size > seg->maxpagesize)
/* Don't add the 1-page gap before the relro segment. Align
the relro segment first. */
aligned_relro_base = (desired_relro_base
& ~(seg->maxpagesize - 1));
if (prev_sec_end_plus_1_page < aligned_relro_base)
{ {
desired_end -= seg->maxpagesize; /* Subtract the maximum page size if therer is still a
1-page gap. */
desired_relro_base -= seg->maxpagesize;
relro_end -= seg->maxpagesize; relro_end -= seg->maxpagesize;
} }
else else
{ {
desired_end &= ~(seg->maxpagesize - 1); /* Align the relro segment. */
desired_relro_base = aligned_relro_base;
relro_end &= ~(seg->maxpagesize - 1); relro_end &= ~(seg->maxpagesize - 1);
} }
} }
} }
seg->base = desired_end; seg->phase = exp_seg_relro_adjust;
ASSERT (desired_relro_base_reduced
|| desired_relro_base >= seg->base);
seg->base = desired_relro_base;
return relro_end; return relro_end;
} }

View file

@ -0,0 +1,50 @@
#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 0000000000000120 000120 000018 04 A 2 0 8
\[ 2\] .dynsym DYNSYM 0000000000000138 000138 000048 18 A 3 1 8
\[ 3\] .dynstr STRTAB 0000000000000180 000180 00000a 00 A 0 0 1
\[ 4\] .rela.dyn RELA 0000000000000190 000190 000018 18 A 2 0 8
\[ 5\] .plt PROGBITS 00000000000001b0 0001b0 000010 10 AX 0 0 16
\[ 6\] .plt.got PROGBITS 00000000000001c0 0001c0 000008 08 AX 0 0 8
\[ 7\] .text PROGBITS 00000000000001c8 0001c8 00000c 00 AX 0 0 1
\[ 8\] .eh_frame PROGBITS 00000000000001d8 0001d8 00006c 00 A 0 0 8
\[ 9\] .init_array INIT_ARRAY 00000000000ffff8 0ffff8 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 4 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000244 0x000244 R E 0x1000
LOAD 0x0ffff8 0x00000000000ffff8 0x00000000000ffff8 0x001108 0x001108 RW 0x100000
DYNAMIC 0x100100 0x0000000000100100 0x0000000000100100 0x000150 0x000150 RW 0x8
GNU_RELRO 0x0ffff8 0x00000000000ffff8 0x00000000000ffff8 0x001008 0x001008 R 0x1
Section to Segment mapping:
Segment Sections...
00 .hash .dynsym .dynstr .rela.dyn .plt .plt.got .text .eh_frame
01 .init_array .fini_array .dynamic .got .data
02 .dynamic
03 .init_array .fini_array .dynamic .got
#pass

View file

@ -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

View file

@ -511,6 +511,7 @@ run_dump_test "dt-relr-1a"
run_dump_test "dt-relr-1a-x32" run_dump_test "dt-relr-1a-x32"
run_dump_test "dt-relr-1b" run_dump_test "dt-relr-1b"
run_dump_test "dt-relr-1b-x32" run_dump_test "dt-relr-1b-x32"
run_dump_test "pr28743-1"
if ![istarget "x86_64-*-linux*"] { if ![istarget "x86_64-*-linux*"] {
return return