You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by "Donny9 (via GitHub)" <gi...@apache.org> on 2023/10/25 13:05:04 UTC

[PR] arch/arm64: support relocate for aarch64 [nuttx]

Donny9 opened a new pull request, #11037:
URL: https://github.com/apache/nuttx/pull/11037

   ## Summary
   arch/arm64: support relocate for aarch64
   ## Impact
   support relocate for aarch64
   ## Testing
   qemu-armv8a:sotest 
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "Donny9 (via GitHub)" <gi...@apache.org>.
Donny9 commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1373193862


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G1_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G2_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 48,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 48,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      /* Immediate instruction relocations. */
+
+      case R_AARCH64_LD_PREL_LO19:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 19,
+                               INSN_IMM_19);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_LO21:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 0, 21,
+                               INSN_IMM_ADR);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_PG_HI21_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_ADR_PREL_PG_HI21:
+        {
+          if (((uint64_t)addr & 0xfff) < 0xff8)
+            {
+              ret = reloc_insn_imm(RELOC_OP_PAGE, addr, val, 12, 21,
+                                   INSN_IMM_ADR);
+            }
+          else
+            {
+              uint32_t insn;
+
+              /* patch ADRP to ADR if it is in range */
+
+              ret = reloc_insn_imm(RELOC_OP_PREL, addr, val & ~0xfff, 0, 21,
+                                   INSN_IMM_ADR);
+              if (ret == 0)
+                {
+                  insn = le32toh(*(uint32_t *)addr);
+                  insn &= ~BIT(31);
+                  *(uint32_t *)addr = htole32(insn);
+                }
+              else
+                {
+                  berr("Out of range for ADR\n");
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case R_AARCH64_ADD_ABS_LO12_NC:
+      case R_AARCH64_LDST8_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 0, 12,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST16_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 1, 11,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST32_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 2, 10,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST64_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 3, 9,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST128_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 4, 8,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_TSTBR14:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 14,
+                               INSN_IMM_14);
+        }
+        break;
+
+      case R_AARCH64_CONDBR19:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 19,
+                               INSN_IMM_19);
+        }
+        break;
+
+      case R_AARCH64_JUMP26:
+      case R_AARCH64_CALL26:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 26,
+                               INSN_IMM_26);
+        }
+        break;
+
+      default:
+        berr("ERROR: Unsupported relocation: %d\n",
+             (int)ELF64_R_TYPE(rel->r_info));

Review Comment:
   Done~



##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G1_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G2_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 48,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 48,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      /* Immediate instruction relocations. */
+
+      case R_AARCH64_LD_PREL_LO19:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 19,
+                               INSN_IMM_19);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_LO21:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 0, 21,
+                               INSN_IMM_ADR);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_PG_HI21_NC:
+        {
+          overflow_check = false;
+        }

Review Comment:
   Done~



##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));

Review Comment:
   Done~



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "xiaoxiang781216 (via GitHub)" <gi...@apache.org>.
xiaoxiang781216 merged PR #11037:
URL: https://github.com/apache/nuttx/pull/11037


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "pkarashchenko (via GitHub)" <gi...@apache.org>.
pkarashchenko commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1373011878


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;

Review Comment:
   Just to confirm that usage of a signed type (sing bit propagation) is used intentionally here?



##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));

Review Comment:
   ```suggestion
             mask = (ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
                    (ADR_IMM_HIMASK << ADR_IMM_HISHIFT);
   ```



##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;

Review Comment:
   ditto



##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G1_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G2_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 48,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 48,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      /* Immediate instruction relocations. */
+
+      case R_AARCH64_LD_PREL_LO19:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 19,
+                               INSN_IMM_19);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_LO21:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 0, 21,
+                               INSN_IMM_ADR);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_PG_HI21_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_ADR_PREL_PG_HI21:
+        {
+          if (((uint64_t)addr & 0xfff) < 0xff8)
+            {
+              ret = reloc_insn_imm(RELOC_OP_PAGE, addr, val, 12, 21,
+                                   INSN_IMM_ADR);
+            }
+          else
+            {
+              uint32_t insn;
+
+              /* patch ADRP to ADR if it is in range */
+
+              ret = reloc_insn_imm(RELOC_OP_PREL, addr, val & ~0xfff, 0, 21,
+                                   INSN_IMM_ADR);
+              if (ret == 0)
+                {
+                  insn = le32toh(*(uint32_t *)addr);
+                  insn &= ~BIT(31);
+                  *(uint32_t *)addr = htole32(insn);
+                }
+              else
+                {
+                  berr("Out of range for ADR\n");
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case R_AARCH64_ADD_ABS_LO12_NC:
+      case R_AARCH64_LDST8_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 0, 12,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST16_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 1, 11,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST32_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 2, 10,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST64_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 3, 9,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_LDST128_ABS_LO12_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_imm(RELOC_OP_ABS, addr, val, 4, 8,
+                               INSN_IMM_12);
+        }
+        break;
+
+      case R_AARCH64_TSTBR14:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 14,
+                               INSN_IMM_14);
+        }
+        break;
+
+      case R_AARCH64_CONDBR19:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 19,
+                               INSN_IMM_19);
+        }
+        break;
+
+      case R_AARCH64_JUMP26:
+      case R_AARCH64_CALL26:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 26,
+                               INSN_IMM_26);
+        }
+        break;
+
+      default:
+        berr("ERROR: Unsupported relocation: %d\n",
+             (int)ELF64_R_TYPE(rel->r_info));

Review Comment:
   Why not to use `PRIu64` here the same as at line 786?



##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G1_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G2_NC:
+        {
+          overflow_check = false;
+        }
+
+      case R_AARCH64_MOVW_UABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 48,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_SABS_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_ABS, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G0:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 0,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G1:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 16,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2_NC:
+        {
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVKZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G2:
+        {
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 32,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      case R_AARCH64_MOVW_PREL_G3:
+        {
+          /* We're using the top bits so we can't overflow. */
+
+          overflow_check = false;
+          ret = reloc_insn_movw(RELOC_OP_PREL, addr, val, 48,
+                                INSN_IMM_MOVNZ);
+        }
+        break;
+
+      /* Immediate instruction relocations. */
+
+      case R_AARCH64_LD_PREL_LO19:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 2, 19,
+                               INSN_IMM_19);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_LO21:
+        {
+          ret = reloc_insn_imm(RELOC_OP_PREL, addr, val, 0, 21,
+                               INSN_IMM_ADR);
+        }
+        break;
+
+      case R_AARCH64_ADR_PREL_PG_HI21_NC:
+        {
+          overflow_check = false;
+        }

Review Comment:
   Please add 'fall-thru' or similar comment here. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "xiaoxiang781216 (via GitHub)" <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1375189101


##########
include/nuttx/compiler.h:
##########
@@ -999,6 +999,13 @@
 
 #endif
 
+/* fallthrough */
+
+#define fallthrough do \

Review Comment:
   fallthrough is very easy conflict with other code, why add this



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "Donny9 (via GitHub)" <gi...@apache.org>.
Donny9 commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1374132974


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,794 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = (ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                 (ADR_IMM_HIMASK << ADR_IMM_HISHIFT);
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+        fallthrough;

Review Comment:
   Why can't we just use fallthrougn's implementation directly? need replace it  with a comment?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "Donny9 (via GitHub)" <gi...@apache.org>.
Donny9 commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1373062707


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,789 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                  (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;

Review Comment:
   Yes, follow linux. ditto.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "Donny9 (via GitHub)" <gi...@apache.org>.
Donny9 commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1375700901


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,794 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = (ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                 (ADR_IMM_HIMASK << ADR_IMM_HISHIFT);
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+        fallthrough;

Review Comment:
   Done



##########
include/nuttx/compiler.h:
##########
@@ -999,6 +999,13 @@
 
 #endif
 
+/* fallthrough */
+
+#define fallthrough do \

Review Comment:
   remove



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "pkarashchenko (via GitHub)" <gi...@apache.org>.
pkarashchenko commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1375976567


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,794 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = (ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                 (ADR_IMM_HIMASK << ADR_IMM_HISHIFT);
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+        fallthrough;

Review Comment:
   I think that the comment is enough to understand for reviewer that it is not a missing `break;`, but an intentional decision.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "pkarashchenko (via GitHub)" <gi...@apache.org>.
pkarashchenko commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1373207935


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,794 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = (ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                 (ADR_IMM_HIMASK << ADR_IMM_HISHIFT);
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+        fallthrough;

Review Comment:
   I meant something like
   ```suggestion
           /* fallthrough */
   ```
   but in case if you want to use C23 then most probably should be
   ```
   [[fallthrough]];
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "xiaoxiang781216 (via GitHub)" <gi...@apache.org>.
xiaoxiang781216 commented on PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#issuecomment-1779776987

   @Donny9 please fix:
   ```
   modlib/modlib_init.c:53: error: "modlib_dumpbuffer" redefined [-Werror]
      53 | #  define modlib_dumpbuffer(m,b,n) binfodumpbuffer(m,b,n)
         | 
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "Donny9 (via GitHub)" <gi...@apache.org>.
Donny9 commented on PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#issuecomment-1780329890

   > @Donny9 please fix:
   > 
   > ```
   > modlib/modlib_init.c:53: error: "modlib_dumpbuffer" redefined [-Werror]
   >    53 | #  define modlib_dumpbuffer(m,b,n) binfodumpbuffer(m,b,n)
   >       | 
   > ```
   
   This  PR depends on https://github.com/apache/nuttx/pull/11043,  this erros has fix at https://github.com/apache/nuttx/pull/11043
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "Donny9 (via GitHub)" <gi...@apache.org>.
Donny9 commented on PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#issuecomment-1784874018

   > please add commit messages
   
   Done~


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] arch/arm64: support relocate for aarch64 [nuttx]

Posted by "xiaoxiang781216 (via GitHub)" <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #11037:
URL: https://github.com/apache/nuttx/pull/11037#discussion_r1375189321


##########
libs/libc/machine/arm64/arch_elf.c:
##########
@@ -0,0 +1,794 @@
+/****************************************************************************
+ * libs/libc/machine/arm64/arch_elf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <debug.h>
+#include <endian.h>
+
+#include <nuttx/compiler.h>
+#include <nuttx/bits.h>
+#include <nuttx/elf.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* For triggering a fault on purpose (reserved) */
+
+#define FAULT_BRK_IMM           0x100
+
+/* BRK instruction encoding
+ * The #imm16 value should be placed at bits[20:5] within BRK ins
+ */
+
+#define AARCH64_BREAK_MON       0xd4200000
+
+/* BRK instruction for provoking a fault on purpose
+ * Unlike kgdb, #imm16 value with unallocated handler is used for faulting.
+ */
+
+#define AARCH64_BREAK_FAULT     (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5))
+
+#define ADR_IMM_HILOSPLIT       2
+#define ADR_IMM_SIZE            (2 * 1024 * 1024)
+#define ADR_IMM_LOMASK          ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK          ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT         29
+#define ADR_IMM_HISHIFT         5
+
+#define INSN_SF_BIT             BIT(31)
+#define INSN_N_BIT              BIT(22)
+#define INSN_LSL_12             BIT(22)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum reloc_op_e
+{
+  RELOC_OP_NONE,
+  RELOC_OP_ABS,
+  RELOC_OP_PREL,
+  RELOC_OP_PAGE,
+};
+
+enum insn_movw_imm_type_e
+{
+  INSN_IMM_MOVNZ,
+  INSN_IMM_MOVKZ,
+};
+
+enum insn_imm_type_e
+{
+  INSN_IMM_ADR,
+  INSN_IMM_26,
+  INSN_IMM_19,
+  INSN_IMM_16,
+  INSN_IMM_14,
+  INSN_IMM_12,
+  INSN_IMM_N,
+  INSN_IMM_MAX
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static uint32_t
+aarch64_insn_encode_immediate(enum insn_imm_type_e type,
+                              uint32_t insn, uint64_t imm)
+{
+  uint32_t immlo;
+  uint32_t immhi;
+  uint32_t mask;
+  int shift;
+
+  if (insn == AARCH64_BREAK_FAULT)
+    {
+      return AARCH64_BREAK_FAULT;
+    }
+
+  switch (type)
+    {
+      case INSN_IMM_ADR:
+        {
+          shift = 0;
+          immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+          imm >>= ADR_IMM_HILOSPLIT;
+          immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+          imm = immlo | immhi;
+          mask = (ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                 (ADR_IMM_HIMASK << ADR_IMM_HISHIFT);
+        }
+        break;
+
+      case INSN_IMM_26:
+        {
+          mask = BIT(26) - 1;
+          shift = 0;
+        }
+        break;
+
+      case INSN_IMM_19:
+        {
+          mask = BIT(19) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_16:
+        {
+          mask = BIT(16) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_14:
+        {
+          mask = BIT(14) - 1;
+          shift = 5;
+        }
+        break;
+
+      case INSN_IMM_12:
+        {
+          mask = BIT(12) - 1;
+          shift = 10;
+        }
+        break;
+
+      default:
+        {
+          berr("unknown immediate encoding %d\n", type);
+
+          return AARCH64_BREAK_FAULT;
+        }
+    }
+
+  /* Update the immediate field. */
+
+  insn &= ~(mask << shift);
+  insn |= (imm & mask) << shift;
+
+  return insn;
+}
+
+static uint64_t do_reloc(enum reloc_op_e op,
+                         uintptr_t place, uint64_t val)
+{
+  switch (op)
+    {
+      case RELOC_OP_ABS:
+        return val;
+      case RELOC_OP_PREL:
+        return val - (uint64_t)place;
+      case RELOC_OP_PAGE:
+        return (val & ~0xfff) - ((uint64_t)place & ~0xfff);
+      case RELOC_OP_NONE:
+        return 0;
+    }
+
+  return 0;
+}
+
+static int reloc_data(enum reloc_op_e op, uintptr_t place,
+                      uint64_t val, int len)
+{
+  int64_t sval = do_reloc(op, place, val);
+
+  /* The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+   * relative and absolute relocations as having a range of [-2^15, 2^16)
+   * or [-2^31, 2^32), respectively. However, in order to be able to
+   * detect overflows reliably, we have to choose whether we interpret
+   * such quantities as signed or as unsigned, and stick with it.
+   * The way we organize our address space requires a signed
+   * interpretation of 32-bit relative references, so let's use that
+   * for all R_AARCH64_PRELxx relocations. This means our upper
+   * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+   */
+
+  switch (len)
+    {
+      case 16:
+        {
+          *(int16_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT16_MIN || sval > INT16_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 16-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 32:
+        {
+          *(int32_t *)place = sval;
+          switch (op)
+            {
+              case RELOC_OP_ABS:
+                {
+                  if (sval < 0 || sval > UINT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              case RELOC_OP_PREL:
+                {
+                  if (sval < INT32_MIN || sval > INT32_MAX)
+                    {
+                      return -ERANGE;
+                    }
+                }
+                break;
+
+              default:
+                {
+                  berr("Invalid 32-bit data relocation (%d)\n", op);
+                  return -EINVAL;
+                }
+            }
+        }
+        break;
+
+      case 64:
+        {
+          *(int64_t *)place = sval;
+        }
+        break;
+
+      default:
+        {
+          berr("Invalid length (%d) for data relocation\n", len);
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+static int reloc_insn_movw(enum reloc_op_e op, uintptr_t place,
+                           uint64_t val, int lsb,
+                           enum insn_movw_imm_type_e imm_type)
+{
+  uint32_t insn = htole32(*(uint32_t *)place);
+  uint64_t imm;
+  int64_t sval;
+
+  sval = do_reloc(op, place, val);
+  imm = sval >> lsb;
+
+  if (imm_type == INSN_IMM_MOVNZ)
+    {
+      /* For signed MOVW relocations, we have to manipulate the
+       * instruction encoding depending on whether or not the
+       * immediate is less than zero.
+       */
+
+      insn &= ~(3 << 29);
+      if (sval >= 0)
+        {
+          /* >=0: Set the instruction to MOVZ (opcode 10b). */
+
+          insn |= 2 << 29;
+        }
+      else
+        {
+          /* <0: Set the instruction to MOVN (opcode 00b).
+           *     Since we've masked the opcode already, we
+           *     don't need to do anything other than
+           *     inverting the new immediate field.
+           */
+
+          imm = ~imm;
+        }
+    }
+
+  /* Update the instruction with the new encoding. */
+
+  insn = aarch64_insn_encode_immediate(INSN_IMM_16, insn, imm);
+  *(uint32_t *)place = le32toh(insn);
+
+  if (imm > UINT16_MAX)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+static int reloc_insn_imm(enum reloc_op_e op, uintptr_t place,
+                          uint64_t val, int lsb, int len,
+                          enum insn_imm_type_e imm_type)
+{
+  int64_t sval;
+  uint64_t imm;
+  uint64_t imm_mask;
+  uint32_t insn = le32toh(*(uint32_t *)place);
+
+  /* Calculate the relocation value. */
+
+  sval = do_reloc(op, place, val);
+  sval >>= lsb;
+
+  /* Extract the value bits and shift them to bit 0. */
+
+  imm_mask = (BIT(lsb + len) - 1) >> lsb;
+  imm = sval & imm_mask;
+
+  /* Update the instruction's immediate field. */
+
+  insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+  *(uint32_t *)place = htole32(insn);
+
+  /* Extract the upper value bits (including the sign bit) and
+   * shift them to bit 0.
+   */
+
+  sval = (int64_t)(sval & ~(imm_mask >> 1)) >> (len - 1);
+
+  /* Overflow has occurred if the upper bits are not all equal to
+   * the sign bit of the value.
+   */
+
+  if ((uint64_t)(sval + 1) >= 2)
+    {
+      return -ERANGE;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_checkarch
+ *
+ * Description:
+ *   Given the ELF header in 'hdr', verify that the ELF file is appropriate
+ *   for the current, configured architecture.  Every architecture that uses
+ *   the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   hdr - The ELF header read from the ELF file.
+ *
+ * Returned Value:
+ *   True if the architecture supports this ELF file.
+ *
+ ****************************************************************************/
+
+bool up_checkarch(const Elf64_Ehdr *ehdr)
+{
+  /* Make sure it's an ARM executable */
+
+  if (ehdr->e_machine != EM_AARCH64)
+    {
+      berr("ERROR: Not for AARCH64: e_machine=%04x\n", ehdr->e_machine);
+      return false;
+    }
+
+  /* Make sure that 64-bit objects are supported */
+
+  if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+      berr("ERROR: Need 64-bit objects: e_ident[EI_CLASS]=%02x\n",
+           ehdr->e_ident[EI_CLASS]);
+      return false;
+    }
+
+  /* Verify endian-ness */
+
+#ifdef CONFIG_ENDIAN_BIG
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
+#else
+  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
+#endif
+    {
+      berr("ERROR: Wrong endian-ness: e_ident[EI_DATA]=%02x\n",
+           ehdr->e_ident[EI_DATA]);
+      return false;
+    }
+
+  /* TODO:  Check ABI here. */
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_relocate and up_relocateadd
+ *
+ * Description:
+ *   Perform an architecture-specific ELF relocation.  Every architecture
+ *   that uses the ELF loader must provide this function.
+ *
+ * Input Parameters:
+ *   rel - The relocation type
+ *   sym - The ELF symbol structure containing the fully resolved value.
+ *         There are a few relocation types for a few architectures that do
+ *         not require symbol information.  For those, this value will be
+ *         NULL.  Implementations of these functions must be able to handle
+ *         that case.
+ *   addr - The address that requires the relocation.
+ *
+ * Returned Value:
+ *   Zero (OK) if the relocation was successful.  Otherwise, a negated errno
+ *   value indicating the cause of the relocation failure.
+ *
+ ****************************************************************************/
+
+int up_relocate(const Elf64_Rel *rel, const Elf64_Sym *sym, uintptr_t addr)
+{
+  berr("ERROR: REL relocation not supported\n");
+  return -ENOSYS;
+}
+
+int up_relocateadd(const Elf64_Rela *rel, const Elf64_Sym *sym,
+                   uintptr_t addr)
+{
+  bool overflow_check = true;
+  uint64_t val;
+  int ret = 0;
+
+  /* addr corresponds to P in the AArch64 ELF document. */
+
+  /* val corresponds to (S + A) in the AArch64 ELF document. */
+
+  val = sym->st_value + rel->r_addend;
+
+  /* Handle the relocation by relocation type */
+
+  switch (ELF64_R_TYPE(rel->r_info))
+    {
+      case R_AARCH64_NONE:
+        {
+          /* No relocation */
+        }
+        break;
+
+      /* Data relocations */
+
+      case R_AARCH64_ABS64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_ABS32:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_ABS16:
+        {
+          ret = reloc_data(RELOC_OP_ABS, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_PREL64:
+        {
+          overflow_check = false;
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 64);
+        }
+        break;
+
+      case R_AARCH64_PREL32:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 32);
+        }
+        break;
+
+      case R_AARCH64_PREL16:
+        {
+          ret = reloc_data(RELOC_OP_PREL, addr, val, 16);
+        }
+        break;
+
+      case R_AARCH64_MOVW_UABS_G0_NC:
+        {
+          overflow_check = false;
+        }
+        fallthrough;

Review Comment:
   It's enough to add some comment here, other solution(e.g. fallthrough macro or [[fallthrough]]) just make a simple thing complex.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org