gold: Properly align the NT_GNU_PROPERTY_TYPE_0 note
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 13 Oct 2020 12:18:13 +0000 (05:18 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 13 Oct 2020 12:18:24 +0000 (05:18 -0700)
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
gold/layout.cc
gold/output.cc
gold/output.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/gnu_property_test.sh

index 5defad4ceeac78cbad6e4d1980e952d2c2eed252..2ebe2c1c3c684c0d8190e3e5ee696e926d2981f1 100644 (file)
@@ -1,3 +1,25 @@
+2020-10-13  H.J. Lu  <hongjiu.lu@intel.com>
+
+       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  <hongjiu.lu@intel.com>
 
        PR gold/21452
index 13e533aaf21393ac1717beab1aaeb73dc18f666f..8563f110995bd1246d641f4d08db08ea453a36e9 100644 (file)
@@ -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;
index 75d2fc354a55fbec400ba6a654901cb6b9df7cf5..ed021c9178f4dae8115373c0968bc79150390644 100644 (file)
@@ -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),
index 77b6697e06724d34f0371b3530c0c894d2e64fb4..35170c3a4f8736e75975d4e01dedb5a7acbabf05 100644 (file)
@@ -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_;
index 0644e23a1bb3effbc729cd14161c6babbdb97b67..026d1010b0b4cc733dcac858e5cf7391fc77580a 100644 (file)
@@ -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
index dfcafcdc5703ef2b5d3c58152998dfe827fe0ff2..35c442ee8b7fd116e1940eba60d44ef14c4bddea 100644 (file)
@@ -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
index 4a2d217cbe9a77861f1caad62e7c311ed625966b..1806d3474cca687e00c79619528c8750d038f23a 100755 (executable)
@@ -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"