Merge changes Ie770320e,I32c05cce,Ia7cb2f40 into main

* changes:
  bionic: linker_phdr: Introduce kPageSize
  bionic: Introduce ElfReader::ReadPadSegmentNote()
  bionic: Refactor __get_elf_note()
diff --git a/libc/Android.bp b/libc/Android.bp
index 244cbfb..807073a 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -222,6 +222,11 @@
     name: "libc_bootstrap",
 }
 
+filegroup {
+    name: "elf_note_sources",
+    srcs: ["bionic/elf_note.cpp"],
+}
+
 // libc_init_static.cpp and libc_init_dynamic.cpp need to be built without stack protector.
 // libc_init_static.cpp sets up TLS for static executables, and libc_init_dynamic.cpp initializes
 // the stack protector global variable.
@@ -229,7 +234,10 @@
 cc_library_static {
     name: "libc_init_static",
     defaults: ["libc_defaults"],
-    srcs: ["bionic/libc_init_static.cpp"],
+    srcs: [
+        "bionic/libc_init_static.cpp",
+        ":elf_note_sources",
+    ],
     cflags: [
         "-fno-stack-protector",
 
diff --git a/libc/bionic/elf_note.cpp b/libc/bionic/elf_note.cpp
new file mode 100644
index 0000000..d5cd5de
--- /dev/null
+++ b/libc/bionic/elf_note.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "platform/bionic/macros.h"
+#include "private/elf_note.h"
+
+#include <string.h>
+
+bool __get_elf_note(unsigned note_type, const char* note_name, const ElfW(Addr) note_addr,
+                    const ElfW(Phdr)* phdr_note, const ElfW(Nhdr)** note_hdr,
+                    const char** note_desc) {
+  if (phdr_note->p_type != PT_NOTE || !note_name || !note_addr) {
+    return false;
+  }
+
+  ElfW(Addr) p = note_addr;
+  ElfW(Addr) note_end = p + phdr_note->p_memsz;
+
+  while (p + sizeof(ElfW(Nhdr)) <= note_end) {
+    const ElfW(Nhdr)* note = reinterpret_cast<const ElfW(Nhdr)*>(p);
+    p += sizeof(ElfW(Nhdr));
+    const char* name = reinterpret_cast<const char*>(p);
+    p += align_up(note->n_namesz, 4);
+    const char* desc = reinterpret_cast<const char*>(p);
+    p += align_up(note->n_descsz, 4);
+    if (p > note_end) {
+      break;
+    }
+    if (note->n_type != note_type) {
+      continue;
+    }
+    size_t note_name_len = strlen(note_name) + 1;
+    if (note->n_namesz != note_name_len || strncmp(note_name, name, note_name_len) != 0) {
+      break;
+    }
+
+    *note_hdr = note;
+    *note_desc = desc;
+
+    return true;
+  }
+  return false;
+}
+
+bool __find_elf_note(unsigned int note_type, const char* note_name, const ElfW(Phdr)* phdr_start,
+                     size_t phdr_ct, const ElfW(Nhdr)** note_hdr, const char** note_desc,
+                     const ElfW(Addr) load_bias) {
+  for (size_t i = 0; i < phdr_ct; ++i) {
+    const ElfW(Phdr)* phdr = &phdr_start[i];
+
+    ElfW(Addr) note_addr = load_bias + phdr->p_vaddr;
+    if (__get_elf_note(note_type, note_name, note_addr, phdr, note_hdr, note_desc)) {
+      return true;
+    }
+  }
+
+  return false;
+}
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index f46d702..00faa5b 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -51,6 +51,7 @@
 #include "private/bionic_elf_tls.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
+#include "private/elf_note.h"
 #include "pthread_internal.h"
 #include "sys/system_properties.h"
 #include "sysprop_helpers.h"
@@ -157,49 +158,12 @@
 }
 
 #ifdef __aarch64__
-static bool __get_elf_note(const ElfW(Phdr) * phdr_start, size_t phdr_ct,
-                           const ElfW(Addr) load_bias, unsigned desired_type,
-                           const char* desired_name, const ElfW(Nhdr) * *note_out,
-                           const char** desc_out) {
-  for (size_t i = 0; i < phdr_ct; ++i) {
-    const ElfW(Phdr)* phdr = &phdr_start[i];
-    if (phdr->p_type != PT_NOTE) {
-      continue;
-    }
-    ElfW(Addr) p = load_bias + phdr->p_vaddr;
-    ElfW(Addr) note_end = load_bias + phdr->p_vaddr + phdr->p_memsz;
-    while (p + sizeof(ElfW(Nhdr)) <= note_end) {
-      const ElfW(Nhdr)* note = reinterpret_cast<const ElfW(Nhdr)*>(p);
-      p += sizeof(ElfW(Nhdr));
-      const char* name = reinterpret_cast<const char*>(p);
-      p += align_up(note->n_namesz, 4);
-      const char* desc = reinterpret_cast<const char*>(p);
-      p += align_up(note->n_descsz, 4);
-      if (p > note_end) {
-        break;
-      }
-      if (note->n_type != desired_type) {
-        continue;
-      }
-      size_t desired_name_len = strlen(desired_name);
-      if (note->n_namesz != desired_name_len + 1 ||
-          strncmp(desired_name, name, desired_name_len) != 0) {
-        break;
-      }
-      *note_out = note;
-      *desc_out = desc;
-      return true;
-    }
-  }
-  return false;
-}
-
 static HeapTaggingLevel __get_memtag_level_from_note(const ElfW(Phdr) * phdr_start, size_t phdr_ct,
                                                      const ElfW(Addr) load_bias, bool* stack) {
   const ElfW(Nhdr) * note;
   const char* desc;
-  if (!__get_elf_note(phdr_start, phdr_ct, load_bias, NT_ANDROID_TYPE_MEMTAG, "Android", &note,
-                      &desc)) {
+  if (!__find_elf_note(NT_ANDROID_TYPE_MEMTAG, "Android", phdr_start, phdr_ct, &note, &desc,
+                       load_bias)) {
     return M_HEAP_TAGGING_LEVEL_TBI;
   }
 
@@ -210,7 +174,7 @@
                      note->n_descsz);
   }
 
-  // `desc` is always aligned due to ELF requirements, enforced in __get_elf_note().
+  // `desc` is always aligned due to ELF requirements, enforced in __find_elf_note().
   ElfW(Word) note_val = *reinterpret_cast<const ElfW(Word)*>(desc);
   *stack = (note_val & NT_MEMTAG_STACK) != 0;
 
diff --git a/libc/private/elf_note.h b/libc/private/elf_note.h
new file mode 100644
index 0000000..6a9399b
--- /dev/null
+++ b/libc/private/elf_note.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <elf.h>
+#include <link.h>
+
+// Get desired ELF note (Nhdr/desc) from mmapped PT_NOTE
+bool __get_elf_note(unsigned note_type, const char* note_name, const ElfW(Addr) note_addr,
+                    const ElfW(Phdr)* phdr_note, const ElfW(Nhdr)** note_hdr,
+                    const char** note_desc);
+
+// Search all mapped PT_NOTE's for the desired ELF note (Nhdr/desc)
+bool __find_elf_note(unsigned int note_type, const char* note_name, const ElfW(Phdr)* phdr_start,
+                     size_t phdr_ct, const ElfW(Nhdr)** note_hdr, const char** note_desc,
+                     const ElfW(Addr) load_bias);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index ffbf136..724f821 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -639,6 +639,7 @@
     si_->phdr = elf_reader.loaded_phdr();
     si_->set_gap_start(elf_reader.gap_start());
     si_->set_gap_size(elf_reader.gap_size());
+    si_->set_should_pad_segments(elf_reader.should_pad_segments());
 
     return true;
   }
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 0ad0fd5..85cd949 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -42,7 +42,9 @@
 #include "linker_debug.h"
 #include "linker_utils.h"
 
+#include "private/bionic_asm_note.h"
 #include "private/CFIShadow.h" // For kLibraryAlignment
+#include "private/elf_note.h"
 
 static int GetTargetElfMachine() {
 #if defined(__arm__)
@@ -140,8 +142,18 @@
                                       MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
                                       MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
 
-// Default PMD size for x86_64 and aarch64 (2MB).
-static constexpr size_t kPmdSize = (1UL << 21);
+static const size_t kPageSize = page_size();
+
+/*
+ * Generic PMD size calculation:
+ *    - Each page table (PT) is of size 1 page.
+ *    - Each page table entry (PTE) is of size 64 bits.
+ *    - Each PTE locates one physical page frame (PFN) of size 1 page.
+ *    - A PMD entry locates 1 page table (PT)
+ *
+ *   PMD size = Num entries in a PT * page_size
+ */
+static const size_t kPmdSize = (kPageSize / sizeof(uint64_t)) * kPageSize;
 
 ElfReader::ElfReader()
     : did_read_(false), did_load_(false), fd_(-1), file_offset_(0), file_size_(0), phdr_num_(0),
@@ -163,7 +175,8 @@
       VerifyElfHeader() &&
       ReadProgramHeaders() &&
       ReadSectionHeaders() &&
-      ReadDynamicSection()) {
+      ReadDynamicSection() &&
+      ReadPadSegmentNote()) {
     did_read_ = true;
   }
 
@@ -694,6 +707,46 @@
   return true;
 }
 
+// Find the ELF note of type NT_ANDROID_TYPE_PAD_SEGMENT and check that the desc value is 1.
+bool ElfReader::ReadPadSegmentNote() {
+  // The ELF can have multiple PT_NOTE's, check them all
+  for (size_t i = 0; i < phdr_num_; ++i) {
+    const ElfW(Phdr)* phdr = &phdr_table_[i];
+
+    if (phdr->p_type != PT_NOTE) {
+      continue;
+    }
+
+    // note_fragment is scoped to within the loop so that there is
+    // at most 1 PT_NOTE mapped at anytime during this search.
+    MappedFileFragment note_fragment;
+    if (!note_fragment.Map(fd_, file_offset_, phdr->p_offset, phdr->p_memsz)) {
+      DL_ERR("\"%s\" note mmap failed: %s", name_.c_str(), strerror(errno));
+      return false;
+    }
+
+    const ElfW(Nhdr)* note_hdr = nullptr;
+    const char* note_desc = nullptr;
+    if (!__get_elf_note(NT_ANDROID_TYPE_PAD_SEGMENT, "Android",
+                        reinterpret_cast<ElfW(Addr)>(note_fragment.data()),
+                        phdr, &note_hdr, &note_desc)) {
+      continue;
+    }
+
+    if (note_hdr->n_descsz != sizeof(ElfW(Word))) {
+      DL_ERR("\"%s\" NT_ANDROID_TYPE_PAD_SEGMENT note has unexpected n_descsz: %u",
+             name_.c_str(), reinterpret_cast<unsigned int>(note_hdr->n_descsz));
+      return false;
+    }
+
+    // 1 == enabled, 0 == disabled
+    should_pad_segments_ = *reinterpret_cast<const ElfW(Word)*>(note_desc) == 1;
+    return true;
+  }
+
+  return true;
+}
+
 bool ElfReader::LoadSegments() {
   for (size_t i = 0; i < phdr_num_; ++i) {
     const ElfW(Phdr)* phdr = &phdr_table_[i];
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 98bf020..e5b87bb 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -58,6 +58,7 @@
   const char* get_string(ElfW(Word) index) const;
   bool is_mapped_by_caller() const { return mapped_by_caller_; }
   ElfW(Addr) entry_point() const { return header_.e_entry + load_bias_; }
+  bool should_pad_segments() const { return should_pad_segments_; }
 
  private:
   bool ReadElfHeader();
@@ -65,6 +66,7 @@
   bool ReadProgramHeaders();
   bool ReadSectionHeaders();
   bool ReadDynamicSection();
+  bool ReadPadSegmentNote();
   bool ReserveAddressSpace(address_space_params* address_space);
   bool LoadSegments();
   bool FindPhdr();
@@ -113,6 +115,9 @@
   // Is map owned by the caller
   bool mapped_by_caller_;
 
+  // Pad gaps between segments when memory mapping?
+  bool should_pad_segments_ = false;
+
   // Only used by AArch64 at the moment.
   GnuPropertySection note_gnu_property_ __unused;
 };
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 622719d..a5d31d5 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -364,6 +364,11 @@
   bool memtag_heap() const { return memtag_dynamic_entries()->memtag_heap; }
   bool memtag_stack() const { return memtag_dynamic_entries()->memtag_stack; }
 
+  void set_should_pad_segments(bool should_pad_segments) {
+   should_pad_segments_ = should_pad_segments;
+  }
+  bool should_pad_segments() const { return should_pad_segments_; }
+
  private:
   bool is_image_linked() const;
   void set_image_linked();
@@ -449,6 +454,9 @@
 
   // version >= 7
   memtag_dynamic_entries_t memtag_dynamic_entries_;
+
+  // Pad gaps between segments when memory mapping?
+  bool should_pad_segments_ = false;
 };
 
 // This function is used by dlvsym() to calculate hash of sym_ver