arch:risc-v:bl602:add support for elf file apps.
Signed-off-by: hotislandn <hotislandn@hotmail.com>
This commit is contained in:
parent
702bc95cac
commit
256b83ef8a
83
boards/risc-v/bl602/bl602evb/configs/elf/defconfig
Normal file
83
boards/risc-v/bl602/bl602evb/configs/elf/defconfig
Normal file
@ -0,0 +1,83 @@
|
||||
#
|
||||
# This file is autogenerated: PLEASE DO NOT EDIT IT.
|
||||
#
|
||||
# You can use "make menuconfig" to make any modifications to the installed .config file.
|
||||
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
|
||||
# modifications.
|
||||
#
|
||||
# CONFIG_NSH_DISABLEBG is not set
|
||||
# CONFIG_NSH_DISABLE_LOSMART is not set
|
||||
# CONFIG_NSH_DISABLE_UNAME is not set
|
||||
CONFIG_ARCH="risc-v"
|
||||
CONFIG_ARCH_BOARD="bl602evb"
|
||||
CONFIG_ARCH_BOARD_BL602EVB=y
|
||||
CONFIG_ARCH_CHIP="bl602"
|
||||
CONFIG_ARCH_CHIP_BL602=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=8192
|
||||
CONFIG_ARCH_RISCV=y
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_BL602_HAVE_UART0=y
|
||||
CONFIG_BL602_TIMER0=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=10000
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEBUG_FEATURES=y
|
||||
CONFIG_DEBUG_FULLOPT=y
|
||||
CONFIG_DEBUG_SYMBOLS=y
|
||||
CONFIG_DEFAULT_SMALL=y
|
||||
CONFIG_DEV_ZERO=y
|
||||
CONFIG_DISABLE_MQUEUE=y
|
||||
CONFIG_ELF=y
|
||||
CONFIG_EXAMPLES_ELF=y
|
||||
CONFIG_EXAMPLES_HELLO=y
|
||||
CONFIG_EXAMPLES_HELLO_STACKSIZE=8192
|
||||
CONFIG_EXAMPLES_TIMER=y
|
||||
CONFIG_EXECFUNCS_HAVE_SYMTAB=y
|
||||
CONFIG_EXECFUNCS_SYSTEM_SYMTAB=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_FS_ROMFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=8192
|
||||
CONFIG_INTELHEX_BINARY=y
|
||||
CONFIG_LIBC_PERROR_STDOUT=y
|
||||
CONFIG_LIBC_STRERROR=y
|
||||
CONFIG_MAX_TASKS=8
|
||||
CONFIG_NFILE_DESCRIPTORS=6
|
||||
CONFIG_NSH_ARCHINIT=y
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_DISABLE_CD=y
|
||||
CONFIG_NSH_DISABLE_CP=y
|
||||
CONFIG_NSH_DISABLE_IFUPDOWN=y
|
||||
CONFIG_NSH_DISABLE_MKDIR=y
|
||||
CONFIG_NSH_DISABLE_RM=y
|
||||
CONFIG_NSH_DISABLE_RMDIR=y
|
||||
CONFIG_NSH_DISABLE_UMOUNT=y
|
||||
CONFIG_NSH_FILEIOSIZE=64
|
||||
CONFIG_NSH_FILE_APPS=y
|
||||
CONFIG_NSH_STRERROR=y
|
||||
CONFIG_PREALLOC_TIMERS=0
|
||||
CONFIG_PTHREAD_STACK_DEFAULT=8192
|
||||
CONFIG_RAM_SIZE=134217728
|
||||
CONFIG_RAM_START=0xc0800000
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_RR_INTERVAL=200
|
||||
CONFIG_RV32IM_CUSTOM_IRQ_SUPPORT=y
|
||||
CONFIG_SCHED_WAITPID=y
|
||||
CONFIG_STACK_COLORATION=y
|
||||
CONFIG_START_DAY=20
|
||||
CONFIG_START_MONTH=3
|
||||
CONFIG_START_YEAR=2020
|
||||
CONFIG_STDIO_DISABLE_BUFFERING=y
|
||||
CONFIG_SYMTAB_ORDEREDBYNAME=y
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_TASK_NAME_SIZE=12
|
||||
CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=8192
|
||||
CONFIG_TESTING_GETPRIME=y
|
||||
CONFIG_TESTING_OSTEST=y
|
||||
CONFIG_TESTING_OSTEST_FPUSIZE=132
|
||||
CONFIG_TIMER=y
|
||||
CONFIG_TIMER_ARCH=y
|
||||
CONFIG_UART0_BAUD=2000000
|
||||
CONFIG_UART0_RXBUFSIZE=128
|
||||
CONFIG_UART0_SERIAL_CONSOLE=y
|
||||
CONFIG_UART0_TXBUFSIZE=128
|
||||
CONFIG_USERMAIN_STACKSIZE=8192
|
||||
CONFIG_USER_ENTRYPOINT="nsh_main"
|
@ -64,5 +64,17 @@ NXFLATLDFLAGS1 = -r -d -warn-common
|
||||
NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections
|
||||
LDNXFLATFLAGS = -e main -s 2048
|
||||
|
||||
# ELF module definitions
|
||||
|
||||
CELFFLAGS = $(CFLAGS) -fno-common
|
||||
CXXELFFLAGS = $(CXXFLAGS) -fno-common
|
||||
|
||||
LDELFFLAGS = -melf32lriscv -r -e main
|
||||
ifeq ($(CONFIG_CYGWIN_WINTOOL),y)
|
||||
LDELFFLAGS += -T "${shell cygpath -w $(BOARD_DIR)$(DELIM)scripts$(DELIM)gnu-elf.ld}"
|
||||
else
|
||||
LDELFFLAGS += -T $(BOARD_DIR)$(DELIM)scripts$(DELIM)gnu-elf.ld
|
||||
endif
|
||||
|
||||
LDFLAGS += --gc-sections -melf32lriscv
|
||||
|
||||
|
115
boards/risc-v/bl602/bl602evb/scripts/gnu-elf.ld
Normal file
115
boards/risc-v/bl602/bl602evb/scripts/gnu-elf.ld
Normal file
@ -0,0 +1,115 @@
|
||||
/****************************************************************************
|
||||
* boards/risc-v/k210/maix-bit/scripts/gnu-elf.ld
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text 0x00000000 :
|
||||
{
|
||||
_stext = . ;
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.warning)
|
||||
*(.stub)
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
*(.jcr)
|
||||
|
||||
/* C++ support: The .init and .fini sections contain specific logic
|
||||
* to manage static constructors and destructors.
|
||||
*/
|
||||
|
||||
*(.gnu.linkonce.t.*)
|
||||
*(.init) /* Old ABI */
|
||||
*(.fini) /* Old ABI */
|
||||
_etext = . ;
|
||||
}
|
||||
|
||||
.rodata :
|
||||
{
|
||||
_srodata = . ;
|
||||
*(.rodata)
|
||||
*(.rodata1)
|
||||
*(.rodata.*)
|
||||
*(.gnu.linkonce.r*)
|
||||
_erodata = . ;
|
||||
}
|
||||
|
||||
.data :
|
||||
{
|
||||
_sdata = . ;
|
||||
*(.data)
|
||||
*(.data1)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d*)
|
||||
. = ALIGN(4);
|
||||
_edata = . ;
|
||||
}
|
||||
|
||||
/* C++ support. For each global and static local C++ object,
|
||||
* GCC creates a small subroutine to construct the object. Pointers
|
||||
* to these routines (not the routines themselves) are stored as
|
||||
* simple, linear arrays in the .ctors section of the object file.
|
||||
* Similarly, pointers to global/static destructor routines are
|
||||
* stored in .dtors.
|
||||
*/
|
||||
|
||||
.ctors :
|
||||
{
|
||||
_sctors = . ;
|
||||
*(.ctors) /* Old ABI: Unallocated */
|
||||
*(.init_array) /* New ABI: Allocated */
|
||||
_edtors = . ;
|
||||
}
|
||||
|
||||
.dtors :
|
||||
{
|
||||
_sdtors = . ;
|
||||
*(.dtors) /* Old ABI: Unallocated */
|
||||
*(.fini_array) /* New ABI: Allocated */
|
||||
_edtors = . ;
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
_sbss = . ;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.b*)
|
||||
*(COMMON)
|
||||
_ebss = . ;
|
||||
}
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
}
|
@ -45,6 +45,17 @@
|
||||
#include <bl602_spiflash.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FS_ROMFS
|
||||
#include <nuttx/drivers/ramdisk.h>
|
||||
|
||||
#define BL602_XIP_START_ADDR (0x23000000)
|
||||
#define BL602_XIP_OFFSET (*(volatile uint32_t *)0x4000B434)
|
||||
#define BL602_ROMFS_FLASH_ADDR (0x1C0000)
|
||||
#define BL602_ROMFS_XIP_ADDR (BL602_XIP_START_ADDR \
|
||||
+ BL602_ROMFS_FLASH_ADDR \
|
||||
- BL602_XIP_OFFSET)
|
||||
#endif /* CONFIG_FS_ROMFS */
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
@ -201,5 +212,31 @@ int bl602_bringup(void)
|
||||
#endif /* CONFIG_FS_LITTLEFS */
|
||||
#endif /* CONFIG_BL602_SPIFLASH */
|
||||
|
||||
#ifdef CONFIG_FS_ROMFS
|
||||
/* Create a ROM disk for the /sbin filesystem */
|
||||
|
||||
ret = romdisk_register(0, BL602_ROMFS_XIP_ADDR,
|
||||
512,
|
||||
512);
|
||||
if (ret < 0)
|
||||
{
|
||||
_err("ERROR: romdisk_register failed: %d\n", -ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Mount the file system */
|
||||
|
||||
ret = mount("/dev/ram0",
|
||||
"/sbin",
|
||||
"romfs", MS_RDONLY, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
_err("ERROR: mount(%s,%s,romfs) failed: %d\n",
|
||||
"dev/ram0",
|
||||
"/sbin", errno);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FS_ROMFS */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -19,11 +19,13 @@
|
||||
############################################################################
|
||||
|
||||
ifeq ($(CONFIG_RISCV_MEMCPY),y)
|
||||
|
||||
ASRCS += arch_memcpy.S
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LIBC_ARCH_ELF),y)
|
||||
CSRCS += arch_elf.c
|
||||
endif
|
||||
|
||||
DEPPATH += --dep-path machine/risc-v/rv32
|
||||
VPATH += :machine/risc-v/rv32
|
||||
|
||||
endif
|
||||
|
||||
|
510
libs/libc/machine/risc-v/rv32/arch_elf.c
Normal file
510
libs/libc/machine/risc-v/rv32/arch_elf.c
Normal file
@ -0,0 +1,510 @@
|
||||
/****************************************************************************
|
||||
* libs/libc/machine/risc-v/rv32/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 <assert.h>
|
||||
|
||||
#include <arch/elf.h>
|
||||
#include <nuttx/elf.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define OPCODE_SW 0x23
|
||||
#define OPCODE_LUI 0x37
|
||||
|
||||
#define RVI_OPCODE_MASK 0x7F
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data Types
|
||||
****************************************************************************/
|
||||
|
||||
struct rname_code_s
|
||||
{
|
||||
const char *name;
|
||||
int type;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct rname_code_s _rname_table[] =
|
||||
{
|
||||
{"RELAX", R_RISCV_RELAX},
|
||||
{"RISCV_32", R_RISCV_32},
|
||||
{"PCREL_LO12_I", R_RISCV_PCREL_LO12_I},
|
||||
{"PCREL_LO12_S", R_RISCV_PCREL_LO12_S},
|
||||
{"PCREL_HI20", R_RISCV_PCREL_HI20},
|
||||
{"HI20", R_RISCV_HI20},
|
||||
{"LO12_I", R_RISCV_LO12_I},
|
||||
{"LO12_S", R_RISCV_LO12_S},
|
||||
{"CALL", R_RISCV_CALL},
|
||||
{"CALL_PLT", R_RISCV_CALL_PLT},
|
||||
{"BRANCH", R_RISCV_BRANCH},
|
||||
{"RVC_JUMP", R_RISCV_RVC_JUMP},
|
||||
{"RVC_BRANCH", R_RISCV_RVC_BRANCH},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static const char *_get_rname(int type)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < sizeof(_rname_table) / sizeof(struct rname_code_s); i++)
|
||||
{
|
||||
if (_rname_table[i].type == type)
|
||||
{
|
||||
return _rname_table[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found in the table */
|
||||
|
||||
return "?????";
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: _get_val, set_val, _add_val
|
||||
*
|
||||
* Description:
|
||||
* These functions are used when relocating an instruction because we can
|
||||
* not assume the instruction is word-aligned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t _get_val(uint16_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
ret = *addr | (*(addr + 1)) << 16;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _set_val(uint16_t *addr, uint32_t val)
|
||||
{
|
||||
*addr = (val & 0xffff);
|
||||
*(addr + 1) = (val >> 16);
|
||||
|
||||
/* NOTE: Ensure relocation before execution */
|
||||
|
||||
asm volatile ("fence.i");
|
||||
}
|
||||
|
||||
static void _add_val(uint16_t *addr, uint32_t val)
|
||||
{
|
||||
uint32_t cur = _get_val(addr);
|
||||
_set_val(addr, cur + val);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: _calc_imm
|
||||
*
|
||||
* Description:
|
||||
* Given offset and obtain imm_hi (20bit) and imm_lo (12bit)
|
||||
*
|
||||
* Input Parameters:
|
||||
* offset - signed 32bit
|
||||
* imm_hi - signed 20bit
|
||||
* imm_lo - signed 12bit
|
||||
*
|
||||
* Returned Value:
|
||||
* none
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void _calc_imm(long offset, long *imm_hi, long *imm_lo)
|
||||
{
|
||||
long lo;
|
||||
long hi = offset / 4096;
|
||||
long r = offset % 4096;
|
||||
|
||||
if (2047 < r)
|
||||
{
|
||||
hi++;
|
||||
}
|
||||
else if (r < -2048)
|
||||
{
|
||||
hi--;
|
||||
}
|
||||
|
||||
lo = offset - (hi * 4096);
|
||||
|
||||
binfo("offset=%ld: hi=%ld lo=%ld \n",
|
||||
offset, hi, lo);
|
||||
|
||||
ASSERT(-2048 <= lo && lo <= 2047);
|
||||
|
||||
*imm_lo = lo;
|
||||
*imm_hi = hi;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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(FAR const Elf_Ehdr *ehdr)
|
||||
{
|
||||
/* Make sure it's an RISCV executable */
|
||||
|
||||
if (ehdr->e_machine != EM_RISCV)
|
||||
{
|
||||
berr("ERROR: Not for RISCV: e_machine=%04x\n", ehdr->e_machine);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Make sure that 32-bit objects are supported */
|
||||
|
||||
if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
|
||||
{
|
||||
berr("ERROR: Need 32-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;
|
||||
}
|
||||
|
||||
/* Make sure the entry point address is properly aligned */
|
||||
|
||||
if ((ehdr->e_entry & 1) != 0)
|
||||
{
|
||||
berr("ERROR: Entry point is not properly aligned: %08" PRIx32 "\n",
|
||||
ehdr->e_entry);
|
||||
}
|
||||
|
||||
/* TODO: Check ABI here. */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_relocate and up_relocateadd
|
||||
*
|
||||
* Description:
|
||||
* Perform on 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(FAR const Elf_Rel *rel, FAR const Elf_Sym *sym,
|
||||
uintptr_t addr)
|
||||
{
|
||||
berr("Not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int up_relocateadd(FAR const Elf_Rela *rel, FAR const Elf_Sym *sym,
|
||||
uintptr_t addr)
|
||||
{
|
||||
long offset;
|
||||
unsigned int relotype;
|
||||
|
||||
/* All relocations depend upon having valid symbol information */
|
||||
|
||||
relotype = ELF32_R_TYPE(rel->r_info);
|
||||
|
||||
if (relotype == R_RISCV_RELAX)
|
||||
{
|
||||
/* NOTE: RELAX has no symbol, so just return */
|
||||
|
||||
binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] \n",
|
||||
_get_rname(relotype),
|
||||
addr, _get_val((uint16_t *)addr));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (sym == NULL && relotype != R_RISCV_NONE)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do relocation based on relocation type */
|
||||
|
||||
switch (relotype)
|
||||
{
|
||||
case R_RISCV_32:
|
||||
{
|
||||
binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
|
||||
"to sym=%p st_value=%08" PRIx32 "\n",
|
||||
_get_rname(relotype),
|
||||
addr, _get_val((uint16_t *)addr),
|
||||
sym, sym->st_value);
|
||||
|
||||
_set_val((uint16_t *)addr,
|
||||
(uint32_t)(sym->st_value + rel->r_addend));
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
{
|
||||
binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
|
||||
"to sym=%p st_value=%08" PRIx32 "\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 */
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_PCREL_HI20:
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_CALL_PLT:
|
||||
{
|
||||
binfo("%s at %08" PRIxPTR " [%08" PRIx32 "] "
|
||||
"to sym=%p st_value=%08" PRIx32 "\n",
|
||||
_get_rname(relotype),
|
||||
addr, _get_val((uint16_t *)addr),
|
||||
sym, sym->st_value);
|
||||
|
||||
offset = (long)sym->st_value - (long)addr;
|
||||
|
||||
long imm_hi;
|
||||
long imm_lo;
|
||||
|
||||
_calc_imm(offset, &imm_hi, &imm_lo);
|
||||
|
||||
/* Adjust auipc (add upper immediate to pc) : 20bit */
|
||||
|
||||
_add_val((uint16_t *)addr, (imm_hi << 12));
|
||||
|
||||
if ((_get_val((uint16_t *)(addr + 4)) & 0x7f) == OPCODE_SW)
|
||||
{
|
||||
/* Adjust imm for SW : S-type */
|
||||
|
||||
uint32_t val =
|
||||
(((int32_t)imm_lo >> 5) << 25) +
|
||||
(((int32_t)imm_lo & 0x1f) << 7);
|
||||
|
||||
binfo("imm_lo=%ld (%lx), val=%lx \n", imm_lo, imm_lo, val);
|
||||
|
||||
_add_val((uint16_t *)(addr + 4), val);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Adjust imm for MV(ADDI)/JALR : I-type */
|
||||
|
||||
_add_val((uint16_t *)(addr + 4), ((int32_t)imm_lo << 20));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
{
|
||||
binfo("%s at %08lx [%08lx] to sym=%p st_value=%08lx\n",
|
||||
_get_rname(relotype),
|
||||
(long)addr, _get_val((uint16_t *)addr),
|
||||
sym, (long)sym->st_value);
|
||||
|
||||
/* P.23 Conditinal Branches : B type (imm=12bit) */
|
||||
|
||||
offset = (long)sym->st_value - (long)addr;
|
||||
uint32_t val = _get_val((uint16_t *)addr) & 0xfe000f80;
|
||||
|
||||
/* NOTE: we assume that a compiler adds an immediate value */
|
||||
|
||||
ASSERT(offset && val);
|
||||
|
||||
binfo("offset for Bx=%ld (0x%lx) (val=0x%08lx) already set! \n",
|
||||
offset, offset, val);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_HI20:
|
||||
{
|
||||
binfo("%s at %08lx [%08lx] to sym=%p st_value=%08lx\n",
|
||||
_get_rname(relotype),
|
||||
(long)addr, _get_val((uint16_t *)addr),
|
||||
sym, (long)sym->st_value);
|
||||
|
||||
/* P.19 LUI */
|
||||
|
||||
offset = (long)sym->st_value;
|
||||
uint32_t insn = _get_val((uint16_t *)addr);
|
||||
|
||||
ASSERT(OPCODE_LUI == (insn & RVI_OPCODE_MASK));
|
||||
|
||||
long imm_hi;
|
||||
long imm_lo;
|
||||
_calc_imm(offset, &imm_hi, &imm_lo);
|
||||
insn = (insn & 0x00000fff) | (imm_hi << 12);
|
||||
|
||||
_set_val((uint16_t *)addr, insn);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_LO12_I:
|
||||
{
|
||||
binfo("%s at %08lx [%08lx] to sym=%p st_value=%08lx\n",
|
||||
_get_rname(relotype),
|
||||
(long)addr, _get_val((uint16_t *)addr),
|
||||
sym, (long)sym->st_value);
|
||||
|
||||
/* ADDI, FLW, LD, ... : I-type */
|
||||
|
||||
offset = (long)sym->st_value;
|
||||
uint32_t insn = _get_val((uint16_t *)addr);
|
||||
|
||||
long imm_hi;
|
||||
long imm_lo;
|
||||
_calc_imm(offset, &imm_hi, &imm_lo);
|
||||
insn = (insn & 0x000fffff) | (imm_lo << 20);
|
||||
|
||||
_set_val((uint16_t *)addr, insn);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_LO12_S:
|
||||
{
|
||||
binfo("%s at %08lx [%08lx] to sym=%p st_value=%08lx\n",
|
||||
_get_rname(relotype),
|
||||
(long)addr, _get_val((uint16_t *)addr),
|
||||
sym, (long)sym->st_value);
|
||||
|
||||
/* SW : S-type.
|
||||
* not merge with R_RISCV_HI20 since the compiler
|
||||
* may not generates these two instructions continuously.
|
||||
*/
|
||||
|
||||
offset = (long)sym->st_value;
|
||||
|
||||
long imm_hi;
|
||||
long imm_lo;
|
||||
_calc_imm(offset, &imm_hi, &imm_lo);
|
||||
|
||||
uint32_t val =
|
||||
(((int32_t)imm_lo >> 5) << 25) +
|
||||
(((int32_t)imm_lo & 0x1f) << 7);
|
||||
|
||||
binfo("imm_lo=%ld (%lx), val=%lx \n", imm_lo, imm_lo, val);
|
||||
|
||||
_add_val((uint16_t *)addr, val);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_RVC_JUMP:
|
||||
{
|
||||
binfo("%s at %08lx [%04lx] to sym=%p st_value=%08lx\n",
|
||||
_get_rname(relotype),
|
||||
(long)addr, _get_val((uint16_t *)addr),
|
||||
sym, (long)sym->st_value);
|
||||
|
||||
/* P.111 Table 16.6 : Instruction listings for RVC */
|
||||
|
||||
offset = ((long)sym->st_value - (long)addr);
|
||||
ASSERT(-2048 <= offset && offset <= 2047);
|
||||
|
||||
uint16_t val = (*(uint16_t *)addr) & 0x1ffc;
|
||||
|
||||
/* NOTE: we assume that a compiler adds an immediate value */
|
||||
|
||||
ASSERT(offset && val);
|
||||
|
||||
binfo("offset for C.J=%ld (0x%lx) (val=0x%04x) already set! \n",
|
||||
offset, offset, val);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_RISCV_RVC_BRANCH:
|
||||
{
|
||||
binfo("%s at %08lx [%04lx] to sym=%p st_value=%08lx\n",
|
||||
_get_rname(relotype),
|
||||
(long)addr, _get_val((uint16_t *)addr),
|
||||
sym, (long)sym->st_value);
|
||||
|
||||
/* P.111 Table 16.6 : Instruction listings for RVC */
|
||||
|
||||
offset = ((long)sym->st_value - (long)addr);
|
||||
ASSERT(-256 <= offset && offset <= 255);
|
||||
|
||||
uint16_t val = (*(uint16_t *)addr) & 0x1c7c;
|
||||
|
||||
/* NOTE: we assume that a compiler adds an immediate value */
|
||||
|
||||
ASSERT(offset && val);
|
||||
|
||||
binfo("offset for C.Bx=%ld (0x%lx) (val=0x%04x) already set!\n",
|
||||
offset, offset, val);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
berr("ERROR: Unsupported relocation: %" PRId32 "\n",
|
||||
ELF32_R_TYPE(rel->r_info));
|
||||
ASSERT(false);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user