Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstream fixes #195

Merged
merged 2 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions arch/risc-v/include/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,25 @@
#define R_RISCV_SET32 56
#define R_RISCV_32_PCREL 57

#define ARCH_ELFDATA 1
#define ARCH_ELF_RELCNT 8

/****************************************************************************
* Public Types
****************************************************************************/

#ifndef __ASSEMBLY__

struct arch_elfdata_s
{
struct hi20_rels_s
{
uintptr_t hi20_rel;
uintptr_t hi20_offset;
}
hi20_rels[ARCH_ELF_RELCNT];
};
typedef struct arch_elfdata_s arch_elfdata_t;

#endif /* __ASSEMBLY__ */
#endif /* __ARCH_RISCV_INCLUDE_ELF_H */
29 changes: 27 additions & 2 deletions arch/risc-v/src/common/riscv_pmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include <nuttx/compiler.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/lib/math32.h>

#include "riscv_internal.h"

Expand Down Expand Up @@ -89,6 +88,32 @@ typedef struct pmp_entry_s pmp_entry_t;
* Private Functions
****************************************************************************/

/****************************************************************************
* Name: log2ceil
*
* Description:
* Calculate the up-rounded power-of-two for input.
*
* Input Parameters:
* x - Argument to calculate the power-of-two from.
*
* Returned Value:
* Power-of-two for argument, rounded up.
*
****************************************************************************/

static uintptr_t log2ceil(uintptr_t x)
{
uintptr_t pot = 0;

for (x = x - 1; x; x >>= 1)
{
pot++;
}

return pot;
}

/****************************************************************************
* Name: pmp_check_region_attrs
*
Expand Down Expand Up @@ -143,7 +168,7 @@ static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size,

/* Get the power-of-two for size, rounded up */

if ((base & ((UINT64_C(1) << LOG2_CEIL(size)) - 1)) != 0)
if ((base & ((UINT64_C(1) << log2ceil(size)) - 1)) != 0)
{
/* The start address is not properly aligned with size */

Expand Down
21 changes: 19 additions & 2 deletions binfmt/libelf/libelf_bind.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@
# define elf_dumpbuffer(m,b,n)
#endif

#ifdef ARCH_ELFDATA
# define ARCH_ELFDATA_DEF arch_elfdata_t arch_data; \
memset(&arch_data, 0, sizeof(arch_elfdata_t))
# define ARCH_ELFDATA_PARM &arch_data
#else
# define ARCH_ELFDATA_DEF
# define ARCH_ELFDATA_PARM NULL
#endif

/****************************************************************************
* Private Types
****************************************************************************/
Expand Down Expand Up @@ -185,6 +194,10 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx,
int i;
int j;

/* Define potential architecture specific elf data container */

ARCH_ELFDATA_DEF;

rels = kmm_malloc(CONFIG_ELF_RELOCATION_BUFFERCOUNT * sizeof(Elf_Rel));
if (rels == NULL)
{
Expand Down Expand Up @@ -334,7 +347,7 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx,

/* Now perform the architecture-specific relocation */

ret = up_relocate(rel, sym, addr);
ret = up_relocate(rel, sym, addr, ARCH_ELFDATA_PARM);
if (ret < 0)
{
berr("ERROR: Section %d reloc %d: Relocation failed: %d\n",
Expand Down Expand Up @@ -370,6 +383,10 @@ static int elf_relocateadd(FAR struct elf_loadinfo_s *loadinfo, int relidx,
int i;
int j;

/* Define potential architecture specific elf data container */

ARCH_ELFDATA_DEF;

relas = kmm_malloc(CONFIG_ELF_RELOCATION_BUFFERCOUNT * sizeof(Elf_Rela));
if (relas == NULL)
{
Expand Down Expand Up @@ -519,7 +536,7 @@ static int elf_relocateadd(FAR struct elf_loadinfo_s *loadinfo, int relidx,

/* Now perform the architecture-specific relocation */

ret = up_relocateadd(rela, sym, addr);
ret = up_relocateadd(rela, sym, addr, ARCH_ELFDATA_PARM);
if (ret < 0)
{
berr("ERROR: Section %d reloc %d: Relocation failed: %d\n",
Expand Down
6 changes: 3 additions & 3 deletions include/nuttx/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ bool up_checkarch(FAR const Elf_Ehdr *hdr);

#ifdef CONFIG_LIBC_ARCH_ELF
int up_relocate(FAR const Elf_Rel *rel, FAR const Elf_Sym *sym,
uintptr_t addr);
int up_relocateadd(FAR const Elf_Rela *rel,
FAR const Elf_Sym *sym, uintptr_t addr);
uintptr_t addr, FAR void *arch_data);
int up_relocateadd(FAR const Elf_Rela *rel, FAR const Elf_Sym *sym,
uintptr_t addr, FAR void *arch_data);
#endif

/****************************************************************************
Expand Down
170 changes: 146 additions & 24 deletions libs/libc/machine/risc-v/arch_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,84 @@ static void _calc_imm(long offset, long *imm_hi, long *imm_lo)
*imm_hi = hi;
}

/****************************************************************************
* Name: _add_hi20
*
* Description:
* Add PCREL_HI20 relocation offset to the LUT. When a PCREL_LO12_I/_S is
* encountered, the corresponding PCREL_HI20 value can be found from it.
*
* Input Parameters:
* arch_data - Where the PCREL_HI20 relocations are listed.
* hi20_rel - The PCREL_HI20 relocation entry.
* hi20_offset - The corresponding offset value.
*
* Returned Value:
* None.
*
****************************************************************************/

static void _add_hi20(void *arch_data, uintptr_t hi20_rel,
uintptr_t hi20_offset)
{
arch_elfdata_t *data = (arch_elfdata_t *)arch_data;
int i;

/* Try to find a free slot from the list */

for (i = 0; i < ARCH_ELF_RELCNT; i++)
{
struct hi20_rels_s *hi20 = &data->hi20_rels[i];

if (hi20->hi20_rel == 0)
{
hi20->hi20_rel = hi20_rel;
hi20->hi20_offset = hi20_offset;
break;
}
}
}

/****************************************************************************
* Name: _find_hi20
*
* Description:
* Find PCREL_HI20 relocation offset from the LUT. When a PCREL_LO12_I/_S
* is encountered, the corresponding PCREL_HI20 value is needed to do the
* relocation.
*
* Input Parameters:
* arch_data - Where the PCREL_HI20 relocations are listed.
* hi20_rel - The PCREL_HI20 relocation entry.
*
* Returned Value:
* The corresponding hi20_offset value.
*
****************************************************************************/

static uintptr_t _find_hi20(void *arch_data, uintptr_t hi20_rel)
{
arch_elfdata_t *data = (arch_elfdata_t *)arch_data;
int i;

/* Try to find the hi20 value from the list */

for (i = 0; i < ARCH_ELF_RELCNT; i++)
{
struct hi20_rels_s *hi20 = &data->hi20_rels[i];

if (hi20->hi20_rel == hi20_rel)
{
/* Found it, we can clear the entry now */

hi20->hi20_rel = 0;
return hi20->hi20_offset;
}
}

return 0;
}

/****************************************************************************
* Public Functions
****************************************************************************/
Expand Down Expand Up @@ -266,14 +344,15 @@ bool up_checkarch(const Elf_Ehdr *ehdr)
*
****************************************************************************/

int up_relocate(const Elf_Rel *rel, const Elf_Sym *sym, uintptr_t addr)
int up_relocate(const Elf_Rel *rel, const Elf_Sym *sym, uintptr_t addr,
void *arch_data)
{
berr("Not implemented\n");
return -ENOSYS;
}

int up_relocateadd(const Elf_Rela *rel, const Elf_Sym *sym,
uintptr_t addr)
uintptr_t addr, void *arch_data)
{
long offset;
unsigned int relotype;
Expand Down Expand Up @@ -317,58 +396,101 @@ int up_relocateadd(const Elf_Rela *rel, const Elf_Sym *sym,
break;

case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S:
{
long imm_hi;
long imm_lo;

binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
"to sym=%p st_value=%08lx\n",
_get_rname(relotype),
addr, _get_val((uint16_t *)addr),
sym, sym->st_value);

/* NOTE: imm value for mv has been adjusted in previous HI20 */
offset = _find_hi20(arch_data, sym->st_value);

/* Adjust imm for MV(ADDI) / JR (JALR) : I-type */

_calc_imm(offset, &imm_hi, &imm_lo);

_add_val((uint16_t *)addr, (int32_t)imm_lo << 20);
}
break;

case R_RISCV_PCREL_HI20:
case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
case R_RISCV_PCREL_LO12_S:
{
uint32_t val;
long imm_hi;
long imm_lo;

binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
"to sym=%p st_value=%08lx\n",
_get_rname(relotype),
addr, _get_val((uint16_t *)addr),
sym, sym->st_value);

offset = (long)sym->st_value + (long)rel->r_addend - (long)addr;
offset = _find_hi20(arch_data, sym->st_value);

/* Adjust imm for SW : S-type */

_calc_imm(offset, &imm_hi, &imm_lo);

val = (((int32_t)imm_lo >> 5) << 25) +
(((int32_t)imm_lo & 0x1f) << 7);

binfo("imm_lo=%ld (%lx), val=%" PRIx32 "\n", imm_lo, imm_lo, val);

_add_val((uint16_t *)addr, val);
}
break;

case R_RISCV_PCREL_HI20:
{
long imm_hi;
long imm_lo;

binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
"to sym=%p st_value=%08lx\n",
_get_rname(relotype),
addr, _get_val((uint16_t *)addr),
sym, sym->st_value);

offset = (long)sym->st_value + (long)rel->r_addend - (long)addr;

_calc_imm(offset, &imm_hi, &imm_lo);

/* Adjust auipc (add upper immediate to pc) : 20bit */

_add_val((uint16_t *)addr, (imm_hi << 12));
_add_val((uint16_t *)addr, imm_hi << 12);

if ((_get_val((uint16_t *)(addr + 4)) & 0x7f) == OPCODE_SW)
{
/* Adjust imm for SW : S-type */
/* Add the hi20 value to the cache */

uint32_t val =
(((int32_t)imm_lo >> 5) << 25) +
(((int32_t)imm_lo & 0x1f) << 7);
_add_hi20(arch_data, addr, offset);
}
break;

case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
{
long imm_hi;
long imm_lo;

binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
"to sym=%p st_value=%08lx\n",
_get_rname(relotype),
addr, _get_val((uint16_t *)addr),
sym, sym->st_value);

offset = (long)sym->st_value + (long)rel->r_addend - (long)addr;

_calc_imm(offset, &imm_hi, &imm_lo);

/* Adjust auipc (add upper immediate to pc) : 20bit */

binfo("imm_lo=%ld (%lx), val=%" PRIx32 "\n",
imm_lo, imm_lo, val);
_add_val((uint16_t *)addr, imm_hi << 12);

_add_val((uint16_t *)(addr + 4), val);
}
else
{
/* Adjust imm for MV(ADDI)/JALR : I-type */
/* Adjust imm for CALL (JALR) : I-type */

_add_val((uint16_t *)(addr + 4), ((int32_t)imm_lo << 20));
}
_add_val((uint16_t *)(addr + 4), (int32_t)imm_lo << 20);
}
break;

Expand Down
Loading