From 6bf4a34047452f882c5cc66bd85812ee1bb5a41c Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 13 Oct 2020 05:18:13 -0700 Subject: gold: Properly align the NT_GNU_PROPERTY_TYPE_0 note The NT_GNU_PROPERTY_TYPE_0 note should be aligned to 8 bytes for 64-bit ELF as specified by gABI. A note section can be only placed in a PT_NOTE segment with the same alignment. PR gold/22914 PR gold/23535 * layout.cc (Layout::attach_allocated_section_to_segment): Place a note section in a PT_NOTE segment with the same alignment. Set the alignment of the PT_NOTE segment from the alignment of the note section. (Layout::create_note): Align the NT_GNU_PROPERTY_TYPE_0 note to 8 bytes for 64-bit ELF. (Layout::segment_precedes): Place segments with larger alignments first. * output.cc (Output_segment::Output_segment): Initialize align_. * output.h (Output_segment): Add align, set_align and align_. * testsuite/Makefile.am (gnu_property_test.stdout): Pass -lhSWn to $(TEST_READELF). (gnu_property_test): Pass --build-id to ld. * testsuite/Makefile.in: Regenerated. * testsuite/gnu_property_test.sh (check_alignment): New. Use check_alignment to check the NT_GNU_PROPERTY_TYPE_0 note alignment. Verify that there are 2 PT_NOTE segments. --- gold/ChangeLog | 22 ++++++++++++++++++++++ gold/layout.cc | 15 ++++++++++++++- gold/output.cc | 1 + gold/output.h | 12 ++++++++++++ gold/testsuite/Makefile.am | 4 ++-- gold/testsuite/Makefile.in | 4 ++-- gold/testsuite/gnu_property_test.sh | 20 ++++++++++++++++++++ 7 files changed, 73 insertions(+), 5 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 5defad4..2ebe2c1 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,27 @@ 2020-10-13 H.J. Lu + PR gold/22914 + PR gold/23535 + * layout.cc (Layout::attach_allocated_section_to_segment): Place + a note section in a PT_NOTE segment with the same alignment. Set + the alignment of the PT_NOTE segment from the alignment of the + note section. + (Layout::create_note): Align the NT_GNU_PROPERTY_TYPE_0 note to 8 + bytes for 64-bit ELF. + (Layout::segment_precedes): Place segments with larger alignments + first. + * output.cc (Output_segment::Output_segment): Initialize align_. + * output.h (Output_segment): Add align, set_align and align_. + * testsuite/Makefile.am (gnu_property_test.stdout): Pass -lhSWn + to $(TEST_READELF). + (gnu_property_test): Pass --build-id to ld. + * testsuite/Makefile.in: Regenerated. + * testsuite/gnu_property_test.sh (check_alignment): New. + Use check_alignment to check the NT_GNU_PROPERTY_TYPE_0 note + alignment. Verify that there are 2 PT_NOTE segments. + +2020-10-13 H.J. Lu + PR gold/21452 * x86_64.cc (Scan::local_reloc_may_be_function_pointer): Remove check for shared library. diff --git a/gold/layout.cc b/gold/layout.cc index 13e533a..8563f11 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -2062,12 +2062,15 @@ Layout::attach_allocated_section_to_segment(const Target* target, // segment. if (os->type() == elfcpp::SHT_NOTE) { + uint64_t os_align = os->addralign(); + // See if we already have an equivalent PT_NOTE segment. for (p = this->segment_list_.begin(); p != segment_list_.end(); ++p) { if ((*p)->type() == elfcpp::PT_NOTE + && (*p)->align() == os_align && (((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))) { @@ -2081,6 +2084,7 @@ Layout::attach_allocated_section_to_segment(const Target* target, Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE, seg_flags); oseg->add_output_section_to_nonload(os, seg_flags); + oseg->set_align(os_align); } } @@ -3184,6 +3188,10 @@ Layout::create_note(const char* name, int note_type, #else const int size = 32; #endif + // The NT_GNU_PROPERTY_TYPE_0 note is aligned to the pointer size. + const int addralign = ((note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0 + ? parameters->target().get_size() + : size) / 8); // The contents of the .note section. size_t namesz = strlen(name) + 1; @@ -3247,7 +3255,7 @@ Layout::create_note(const char* name, int note_type, return NULL; Output_section_data* posd = new Output_data_const_buffer(buffer, notehdrsz, - size / 8, + addralign, "** note header"); os->add_output_section_data(posd); @@ -3705,6 +3713,11 @@ Layout::segment_precedes(const Output_segment* seg1, { if (type1 != type2) return type1 < type2; + uint64_t align1 = seg1->align(); + uint64_t align2 = seg2->align(); + // Place segments with larger alignments first. + if (align1 != align2) + return align1 > align2; gold_assert(flags1 != flags2 || this->script_options_->saw_phdrs_clause()); return flags1 < flags2; diff --git a/gold/output.cc b/gold/output.cc index 75d2fc3..ed021c9 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -4113,6 +4113,7 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) : vaddr_(0), paddr_(0), memsz_(0), + align_(0), max_align_(0), min_p_align_(0), offset_(0), diff --git a/gold/output.h b/gold/output.h index 77b6697..35170c3 100644 --- a/gold/output.h +++ b/gold/output.h @@ -4688,6 +4688,16 @@ class Output_segment offset() const { return this->offset_; } + // Return the segment alignment. + uint64_t + align() const + { return this->align_; } + + // Set the segment alignment. + void + set_align(uint64_t align) + { this->align_ = align; } + // Whether this is a segment created to hold large data sections. bool is_large_data_segment() const @@ -4910,6 +4920,8 @@ class Output_segment uint64_t paddr_; // The size of the segment in memory. uint64_t memsz_; + // The segment alignment. + uint64_t align_; // The maximum section alignment. The is_max_align_known_ field // indicates whether this has been finalized. uint64_t max_align_; diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 0644e23..026d101 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -3306,9 +3306,9 @@ check_SCRIPTS += gnu_property_test.sh check_DATA += gnu_property_test.stdout MOSTLYCLEANFILES += gnu_property_test gnu_property_test.stdout: gnu_property_test - $(TEST_READELF) -n $< >$@ + $(TEST_READELF) -lhSWn $< >$@ gnu_property_test: gcctestdir/ld gnu_property_a.o gnu_property_b.o gnu_property_c.o - gcctestdir/ld -o $@ gnu_property_a.o gnu_property_b.o gnu_property_c.o + gcctestdir/ld --build-id -o $@ gnu_property_a.o gnu_property_b.o gnu_property_c.o gnu_property_main.o: gnu_property_main.c $(COMPILE) -c -o $@ $< gnu_property_a.o: gnu_property_a.S diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index dfcafcd..35c442e 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -9525,9 +9525,9 @@ uninstall-am: @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_x86_64_bnd_2.o: exception_test_2.cc gcctestdir/as @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -Wa,-madd-bnd-prefix -o $@ $< @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_test.stdout: gnu_property_test -@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -n $< >$@ +@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lhSWn $< >$@ @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_test: gcctestdir/ld gnu_property_a.o gnu_property_b.o gnu_property_c.o -@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ gnu_property_a.o gnu_property_b.o gnu_property_c.o +@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld --build-id -o $@ gnu_property_a.o gnu_property_b.o gnu_property_c.o @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_main.o: gnu_property_main.c @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -o $@ $< @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_a.o: gnu_property_a.S diff --git a/gold/testsuite/gnu_property_test.sh b/gold/testsuite/gnu_property_test.sh index 4a2d217..1806d34 100755 --- a/gold/testsuite/gnu_property_test.sh +++ b/gold/testsuite/gnu_property_test.sh @@ -53,8 +53,28 @@ check_count() fi } +check_alignment () +{ + if egrep -q "Class:[ \t]+ELF64" "$1" + then + align=8 + else + align=4 + fi + if ! egrep -q ".note.gnu.property[ \t]+NOTE.*$align$" "$1" + then + echo "Wrong .note.gnu.property alignment in $1:" + egrep ".note.gnu.property[ \t]+NOTE.*$align" "$1" + exit 1 + fi +} + +check_alignment gnu_property_test.stdout + check_count gnu_property_test.stdout "GNU\s*0x[0-9a-f]*\s*NT_GNU_PROPERTY_TYPE_0" 1 +check_count gnu_property_test.stdout "^ NOTE" 2 + check gnu_property_test.stdout "stack size: 0x111100" check gnu_property_test.stdout "no copy on protected" check gnu_property_test.stdout "x86 ISA used: i486, SSE2, SSE4_2, AVX512CD" -- cgit v1.1