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-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org