Merge "bionic: tests: Remove PAGE_SIZE usage" into main
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 1591785..8068fc2 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -179,26 +179,10 @@
 }
 
 #ifdef __aarch64__
-static bool __read_memtag_note(const ElfW(Nhdr)* note, const char* name, const char* desc,
-                               unsigned* result) {
-  if (note->n_type != NT_ANDROID_TYPE_MEMTAG) {
-    return false;
-  }
-  if (note->n_namesz != 8 || strncmp(name, "Android", 8) != 0) {
-    return false;
-  }
-  // Previously (in Android 12), if the note was != 4 bytes, we check-failed
-  // here. Let's be more permissive to allow future expansion.
-  if (note->n_descsz < 4) {
-    async_safe_fatal("unrecognized android.memtag note: n_descsz = %d, expected >= 4",
-                     note->n_descsz);
-  }
-  *result = *reinterpret_cast<const ElfW(Word)*>(desc);
-  return true;
-}
-
-static unsigned __get_memtag_note(const ElfW(Phdr)* phdr_start, size_t phdr_ct,
-                                  const ElfW(Addr) load_bias) {
+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) {
@@ -216,13 +200,68 @@
       if (p > note_end) {
         break;
       }
-      unsigned ret;
-      if (__read_memtag_note(note, name, desc, &ret)) {
-        return ret;
+      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 0;
+  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)) {
+    return M_HEAP_TAGGING_LEVEL_TBI;
+  }
+
+  // Previously (in Android 12), if the note was != 4 bytes, we check-failed
+  // here. Let's be more permissive to allow future expansion.
+  if (note->n_descsz < 4) {
+    async_safe_fatal("unrecognized android.memtag note: n_descsz = %d, expected >= 4",
+                     note->n_descsz);
+  }
+
+  // `desc` is always aligned due to ELF requirements, enforced in __get_elf_note().
+  ElfW(Word) note_val = *reinterpret_cast<const ElfW(Word)*>(desc);
+  *stack = (note_val & NT_MEMTAG_STACK) != 0;
+
+  // Warning: In Android 12, any value outside of bits [0..3] resulted in a check-fail.
+  if (!(note_val & (NT_MEMTAG_HEAP | NT_MEMTAG_STACK))) {
+    async_safe_format_log(ANDROID_LOG_INFO, "libc",
+                          "unrecognised memtag note_val did not specificy heap or stack: %u",
+                          note_val);
+    return M_HEAP_TAGGING_LEVEL_TBI;
+  }
+
+  unsigned mode = note_val & NT_MEMTAG_LEVEL_MASK;
+  switch (mode) {
+    case NT_MEMTAG_LEVEL_NONE:
+      // Note, previously (in Android 12), NT_MEMTAG_LEVEL_NONE was
+      // NT_MEMTAG_LEVEL_DEFAULT, which implied SYNC mode. This was never used
+      // by anyone, but we note it (heh) here for posterity, in case the zero
+      // level becomes meaningful, and binaries with this note can be executed
+      // on Android 12 devices.
+      return M_HEAP_TAGGING_LEVEL_TBI;
+    case NT_MEMTAG_LEVEL_ASYNC:
+      return M_HEAP_TAGGING_LEVEL_ASYNC;
+    case NT_MEMTAG_LEVEL_SYNC:
+    default:
+      // We allow future extensions to specify mode 3 (currently unused), with
+      // the idea that it might be used for ASYMM mode or something else. On
+      // this version of Android, it falls back to SYNC mode.
+      return M_HEAP_TAGGING_LEVEL_SYNC;
+  }
 }
 
 // Returns true if there's an environment setting (either sysprop or env var)
@@ -273,48 +312,57 @@
 // Returns the initial heap tagging level. Note: This function will never return
 // M_HEAP_TAGGING_LEVEL_NONE, if MTE isn't enabled for this process we enable
 // M_HEAP_TAGGING_LEVEL_TBI.
-static HeapTaggingLevel __get_heap_tagging_level(const void* phdr_start, size_t phdr_ct,
-                                                 uintptr_t load_bias, bool* stack) {
-  unsigned note_val =
-      __get_memtag_note(reinterpret_cast<const ElfW(Phdr)*>(phdr_start), phdr_ct, load_bias);
-  *stack = note_val & NT_MEMTAG_STACK;
+static HeapTaggingLevel __get_tagging_level(const memtag_dynamic_entries_t* memtag_dynamic_entries,
+                                            const void* phdr_start, size_t phdr_ct,
+                                            uintptr_t load_bias, bool* stack) {
+  HeapTaggingLevel level = M_HEAP_TAGGING_LEVEL_TBI;
 
-  HeapTaggingLevel level;
-  if (get_environment_memtag_setting(&level)) return level;
-
-  // Note, previously (in Android 12), any value outside of bits [0..3] resulted
-  // in a check-fail. In order to be permissive of further extensions, we
-  // relaxed this restriction.
-  if (!(note_val & (NT_MEMTAG_HEAP | NT_MEMTAG_STACK))) return M_HEAP_TAGGING_LEVEL_TBI;
-
-  unsigned mode = note_val & NT_MEMTAG_LEVEL_MASK;
-  switch (mode) {
-    case NT_MEMTAG_LEVEL_NONE:
-      // Note, previously (in Android 12), NT_MEMTAG_LEVEL_NONE was
-      // NT_MEMTAG_LEVEL_DEFAULT, which implied SYNC mode. This was never used
-      // by anyone, but we note it (heh) here for posterity, in case the zero
-      // level becomes meaningful, and binaries with this note can be executed
-      // on Android 12 devices.
-      return M_HEAP_TAGGING_LEVEL_TBI;
-    case NT_MEMTAG_LEVEL_ASYNC:
-      return M_HEAP_TAGGING_LEVEL_ASYNC;
-    case NT_MEMTAG_LEVEL_SYNC:
-    default:
-      // We allow future extensions to specify mode 3 (currently unused), with
-      // the idea that it might be used for ASYMM mode or something else. On
-      // this version of Android, it falls back to SYNC mode.
-      return M_HEAP_TAGGING_LEVEL_SYNC;
+  // If the dynamic entries exist, use those. Otherwise, fall back to the old
+  // Android note, which is still used for fully static executables. When
+  // -fsanitize=memtag* is used in newer toolchains, currently both the dynamic
+  // entries and the old note are created, but we'd expect to move to just the
+  // dynamic entries for dynamically linked executables in the future. In
+  // addition, there's still some cleanup of the build system (that uses a
+  // manually-constructed note) needed. For more information about the dynamic
+  // entries, see:
+  // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#dynamic-section
+  if (memtag_dynamic_entries && memtag_dynamic_entries->has_memtag_mode) {
+    switch (memtag_dynamic_entries->memtag_mode) {
+      case 0:
+        level = M_HEAP_TAGGING_LEVEL_SYNC;
+        break;
+      case 1:
+        level = M_HEAP_TAGGING_LEVEL_ASYNC;
+        break;
+      default:
+        async_safe_format_log(ANDROID_LOG_INFO, "libc",
+                              "unrecognised DT_AARCH64_MEMTAG_MODE value: %u",
+                              memtag_dynamic_entries->memtag_mode);
+    }
+    *stack = memtag_dynamic_entries->memtag_stack;
+  } else {
+    level = __get_memtag_level_from_note(reinterpret_cast<const ElfW(Phdr)*>(phdr_start), phdr_ct,
+                                         load_bias, stack);
   }
+
+  // We can't short-circuit the environment override, as `stack` is still inherited from the
+  // binary's settings.
+  if (get_environment_memtag_setting(&level)) {
+    if (level == M_HEAP_TAGGING_LEVEL_NONE || level == M_HEAP_TAGGING_LEVEL_TBI) {
+      *stack = false;
+    }
+  }
+  return level;
 }
 
 // Figure out the desired memory tagging mode (sync/async, heap/globals/stack) for this executable.
 // This function is called from the linker before the main executable is relocated.
-__attribute__((no_sanitize("hwaddress", "memtag"))) void __libc_init_mte(const void* phdr_start,
-                                                                         size_t phdr_ct,
-                                                                         uintptr_t load_bias,
-                                                                         void* stack_top) {
-  bool memtag_stack;
-  HeapTaggingLevel level = __get_heap_tagging_level(phdr_start, phdr_ct, load_bias, &memtag_stack);
+__attribute__((no_sanitize("hwaddress", "memtag"))) void __libc_init_mte(
+    const memtag_dynamic_entries_t* memtag_dynamic_entries, const void* phdr_start, size_t phdr_ct,
+    uintptr_t load_bias, void* stack_top) {
+  bool memtag_stack = false;
+  HeapTaggingLevel level =
+      __get_tagging_level(memtag_dynamic_entries, phdr_start, phdr_ct, load_bias, &memtag_stack);
   char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS");
   static const char kAppProcessName[] = "app_process64";
   const char* progname = __libc_shared_globals()->init_progname;
@@ -385,7 +433,7 @@
   __libc_shared_globals()->heap_tagging_upgrade_timer_sec = 0;
 }
 #else   // __aarch64__
-void __libc_init_mte(const void*, size_t, uintptr_t, void*) {}
+void __libc_init_mte(const memtag_dynamic_entries_t*, const void*, size_t, uintptr_t, void*) {}
 #endif  // __aarch64__
 
 void __libc_init_profiling_handlers() {
@@ -412,7 +460,8 @@
   layout_static_tls(args);
   __libc_init_main_thread_final();
   __libc_init_common();
-  __libc_init_mte(reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR)), getauxval(AT_PHNUM),
+  __libc_init_mte(/*memtag_dynamic_entries=*/nullptr,
+                  reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR)), getauxval(AT_PHNUM),
                   /*load_bias = */ 0, /*stack_top = */ raw_args);
   __libc_init_scudo();
   __libc_init_profiling_handlers();
diff --git a/libc/include/elf.h b/libc/include/elf.h
index 1dfc008..04a73f7 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -266,4 +266,6 @@
 /* TODO: upstream these to FreeBSD? */
 #define R_ARM_TLS_DESC 13
 #define R_ARM_IRELATIVE 160
-#define R_X86_64_JUMP_SLOT 7
+
+/* BSD spells this slightly differently to Linux. */
+#define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 40e1f26..c0b379b 100755
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1471,9 +1471,18 @@
                             made_change = True
                     i += 1
 
-                if b.isDefine() and b.define_id in replacements:
-                    b.define_id = replacements[b.define_id]
-                    made_change = True
+                if b.isDefine():
+                    tokens = CppStringTokenizer(b.define_id).tokens
+                    id_change = False
+                    for tok in tokens:
+                        if tok.kind == TokenKind.IDENTIFIER:
+                            if tok.id in replacements:
+                                tok.id = replacements[tok.id]
+                                id_change = True
+                    if id_change:
+                        b.define_id = ''.join([tok.id for tok in tokens])
+                        made_change = True
+
 
             if made_change and b.isIf():
                 # Keep 'expr' in sync with 'tokens'.
@@ -2578,10 +2587,12 @@
         text = """\
 #define SIGRTMIN 32
 #define SIGRTMAX _NSIG
+#define SIGRTMAX(a,class) some_func(a, class)
 """
         expected = """\
 #define __SIGRTMIN 32
 #define __SIGRTMAX _KERNEL__NSIG
+#define __SIGRTMAX(a,__linux_class) some_func(a, __linux_class)
 """
         self.assertEqual(self.parse(text), expected)
 
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index 91d26ce..65e0117 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -63,6 +63,7 @@
     # The kernel usage of __unused for unused struct fields conflicts with the macro defined in <sys/cdefs.h>.
     "__unused": "__linux_unused",
     # The kernel usage of C++ keywords causes problems for C++ code so rename.
+    "class": "__linux_class",
     "private": "__linux_private",
     "virtual": "__linux_virtual",
     # The non-64 stuff is legacy; msqid64_ds/ipc64_perm is what userspace wants.
@@ -125,6 +126,8 @@
           # These are required to support the above functions.
           "__fswahw32",
           "__fswahb32",
+          # This is used by various macros in <linux/ioprio.h>.
+          "ioprio_value",
         ]
     )
 
diff --git a/libc/kernel/uapi/linux/ioprio.h b/libc/kernel/uapi/linux/ioprio.h
index c6dc42a..9ae9dae 100644
--- a/libc/kernel/uapi/linux/ioprio.h
+++ b/libc/kernel/uapi/linux/ioprio.h
@@ -61,6 +61,10 @@
   IOPRIO_HINT_DEV_DURATION_LIMIT_7 = 7,
 };
 #define IOPRIO_BAD_VALUE(val,max) ((val) < 0 || (val) >= (max))
-#define IOPRIO_PRIO_VALUE(class,level) ioprio_value(class, level, IOPRIO_HINT_NONE)
-#define IOPRIO_PRIO_VALUE_HINT(class,level,hint) ioprio_value(class, level, hint)
+static __always_inline __u16 ioprio_value(int __linux_class, int level, int hint) {
+  if(IOPRIO_BAD_VALUE(__linux_class, IOPRIO_NR_CLASSES) || IOPRIO_BAD_VALUE(level, IOPRIO_NR_LEVELS) || IOPRIO_BAD_VALUE(hint, IOPRIO_NR_HINTS)) return IOPRIO_CLASS_INVALID << IOPRIO_CLASS_SHIFT;
+  return(__linux_class << IOPRIO_CLASS_SHIFT) | (hint << IOPRIO_HINT_SHIFT) | level;
+}
+#define IOPRIO_PRIO_VALUE(__linux_class,level) ioprio_value(__linux_class, level, IOPRIO_HINT_NONE)
+#define IOPRIO_PRIO_VALUE_HINT(__linux_class,level,hint) ioprio_value(__linux_class, level, hint)
 #endif
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 510d556..d9c4234 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -66,6 +66,15 @@
   MallocDispatch malloc_dispatch_table;
 };
 
+struct memtag_dynamic_entries_t {
+  void* memtag_globals;
+  size_t memtag_globalssz;
+  bool has_memtag_mode;
+  unsigned memtag_mode;
+  bool memtag_heap;
+  bool memtag_stack;
+};
+
 #ifdef __aarch64__
 static_assert(OFFSETOF_libc_globals_memtag_stack == offsetof(libc_globals, memtag_stack));
 #endif
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 1553ba9..135eaa3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -71,11 +71,12 @@
 #include "linker_translate_path.h"
 #include "linker_utils.h"
 
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
+#include "private/bionic_asm_note.h"
 #include "private/bionic_call_ifunc_resolver.h"
 #include "private/bionic_globals.h"
-#include "android-base/macros.h"
-#include "android-base/strings.h"
-#include "android-base/stringprintf.h"
 #include "ziparchive/zip_archive.h"
 
 static std::unordered_map<void*, size_t> g_dso_handle_counters;
@@ -3194,13 +3195,32 @@
       case DT_AARCH64_VARIANT_PCS:
         // Ignored: AArch64 processor-specific dynamic array tags.
         break;
-      // TODO(mitchp): Add support to libc_init_mte to use these dynamic array entries instead of
-      // the Android-specific ELF note.
       case DT_AARCH64_MEMTAG_MODE:
+        memtag_dynamic_entries_.has_memtag_mode = true;
+        memtag_dynamic_entries_.memtag_mode = d->d_un.d_val;
+        break;
       case DT_AARCH64_MEMTAG_HEAP:
+        memtag_dynamic_entries_.memtag_heap = d->d_un.d_val;
+        break;
+      // The AArch64 MemtagABI originally erroneously defined
+      // DT_AARCH64_MEMTAG_STACK as `d_ptr`, which is why the dynamic tag value
+      // is odd (`0x7000000c`). `d_val` is clearly the correct semantics, and so
+      // this was fixed in the ABI, but the value (0x7000000c) didn't change
+      // because we already had Android binaries floating around with dynamic
+      // entries, and didn't want to create a whole new dynamic entry and
+      // reserve a value just to fix that tiny mistake. P.S. lld was always
+      // outputting DT_AARCH64_MEMTAG_STACK as `d_val` anyway.
       case DT_AARCH64_MEMTAG_STACK:
+        memtag_dynamic_entries_.memtag_stack = d->d_un.d_val;
+        break;
+      // Same as above, except DT_AARCH64_MEMTAG_GLOBALS was incorrectly defined
+      // as `d_val` (hence an even value of `0x7000000d`), when it should have
+      // been `d_ptr` all along. lld has always outputted this as `d_ptr`.
       case DT_AARCH64_MEMTAG_GLOBALS:
+        memtag_dynamic_entries_.memtag_globals = reinterpret_cast<void*>(load_bias + d->d_un.d_ptr);
+        break;
       case DT_AARCH64_MEMTAG_GLOBALSSZ:
+        memtag_dynamic_entries_.memtag_globalssz = d->d_un.d_val;
         break;
 #endif
 
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 5a33a63..5f5eba4 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -68,8 +68,8 @@
 
 static void set_bss_vma_name(soinfo* si);
 
-void __libc_init_mte(const void* phdr_start, size_t phdr_count, uintptr_t load_bias,
-                     void* stack_top);
+void __libc_init_mte(const memtag_dynamic_entries_t* memtag_dynamic_entries, const void* phdr_start,
+                     size_t phdr_count, uintptr_t load_bias, void* stack_top);
 
 // These should be preserved static to avoid emitting
 // RELATIVE relocations for the part of the code running
@@ -405,7 +405,8 @@
     }
   }
 
-  __libc_init_mte(somain->phdr, somain->phnum, somain->load_bias, args.argv);
+  __libc_init_mte(somain->memtag_dynamic_entries(), somain->phdr, somain->phnum, somain->load_bias,
+                  args.argv);
 #endif
 
   // Register the main executable and the linker upfront to have
diff --git a/linker/linker_relocs.h b/linker/linker_relocs.h
index 37a7880..54aad18 100644
--- a/linker/linker_relocs.h
+++ b/linker/linker_relocs.h
@@ -84,8 +84,7 @@
 #define R_GENERIC_TLS_DTPMOD    R_RISCV_TLS_DTPMOD64
 #define R_GENERIC_TLS_DTPREL    R_RISCV_TLS_DTPREL64
 #define R_GENERIC_TLS_TPREL     R_RISCV_TLS_TPREL64
-// TODO: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/94
-// #define R_GENERIC_TLSDESC       R_RISCV_TLS_DESC
+#define R_GENERIC_TLSDESC       R_RISCV_TLSDESC
 
 #elif defined (__x86_64__)
 
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 9c589d6..622719d 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -34,9 +34,11 @@
 #include <string>
 #include <vector>
 
-#include "private/bionic_elf_tls.h"
+#include "async_safe/CHECK.h"
 #include "linker_namespaces.h"
 #include "linker_tls.h"
+#include "private/bionic_elf_tls.h"
+#include "private/bionic_globals.h"
 
 #define FLAG_LINKED           0x00000001
 #define FLAG_EXE              0x00000004 // The main executable
@@ -351,6 +353,17 @@
   void set_gap_size(size_t gap_size);
   size_t get_gap_size() const;
 
+  const memtag_dynamic_entries_t* memtag_dynamic_entries() const {
+    CHECK(has_min_version(7));
+    return &memtag_dynamic_entries_;
+  }
+  void* memtag_globals() const { return memtag_dynamic_entries()->memtag_globals; }
+  size_t memtag_globalssz() const { return memtag_dynamic_entries()->memtag_globalssz; }
+  bool has_memtag_mode() const { return memtag_dynamic_entries()->has_memtag_mode; }
+  unsigned memtag_mode() const { return memtag_dynamic_entries()->memtag_mode; }
+  bool memtag_heap() const { return memtag_dynamic_entries()->memtag_heap; }
+  bool memtag_stack() const { return memtag_dynamic_entries()->memtag_stack; }
+
  private:
   bool is_image_linked() const;
   void set_image_linked();
@@ -433,6 +446,9 @@
   // version >= 6
   ElfW(Addr) gap_start_;
   size_t gap_size_;
+
+  // version >= 7
+  memtag_dynamic_entries_t memtag_dynamic_entries_;
 };
 
 // This function is used by dlvsym() to calculate hash of sym_ver