Implement AOT support for RISCV (#649)

Enable RISCV AOT support, the supported ABIs are LP64 and LP64D for riscv64, ILP32 and ILP32D for riscv32.
For wamrc:
    use --target=riscv64/riscv32 to specify the target arch of output AOT file,
    use --target-abi=lp64d/lp64/ilp32d/ilp32 to specify the target ABI,
    if --target-abi isn't specified, by default lp64d is used for riscv64, and ilp32d is used for riscv32.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
Co-authored-by: wenyongh <wenyong.huang@intel.com>
This commit is contained in:
Huang Qi
2021-07-22 11:16:47 +08:00
committed by GitHub
parent ea06c19a9d
commit e4023c8e02
29 changed files with 667 additions and 459 deletions

View File

@ -182,6 +182,7 @@ GET_U64_FROM_ADDR(uint32 *addr)
#define E_MACHINE_MIPS_X 51 /* Stanford MIPS-X */
#define E_MACHINE_X86_64 62 /* AMD x86-64 architecture */
#define E_MACHINE_XTENSA 94 /* Tensilica Xtensa Architecture */
#define E_MACHINE_RISCV 243 /* RISC-V 32/64 */
#define E_MACHINE_WIN_X86_64 0x8664 /* Windowx x86-64 architecture */
/* Legal values for e_version */
@ -257,6 +258,9 @@ get_aot_file_target(AOTTargetInfo *target_info,
case E_MACHINE_XTENSA:
machine_type = "xtensa";
break;
case E_MACHINE_RISCV:
machine_type = "riscv";
break;
default:
set_error_buf_v(error_buf, error_buf_size,
"unknown machine type %d",
@ -1030,7 +1034,8 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end,
/* Create each data section */
for (i = 0; i < module->data_section_count; i++) {
int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_RISCV64_LP64D) || defined(BUILD_TARGET_RISCV64_LP64)
/* aot code and data in x86_64 must be in range 0 to 2G due to
relocation for R_X86_64_32/32S/PC32 */
int map_flags = MMAP_MAP_32BIT;
@ -1501,6 +1506,7 @@ do_text_relocation(AOTModule *module,
symbol_addr = module->code;
}
else if (!strcmp(symbol, ".data")
|| !strcmp(symbol, ".sdata")
|| !strcmp(symbol, ".rdata")
|| !strcmp(symbol, ".rodata")
/* ".rodata.cst4/8/16/.." */
@ -2235,7 +2241,8 @@ create_sections(const uint8 *buf, uint32 size,
if (section_size > 0) {
int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE
| MMAP_PROT_EXEC;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \
|| defined(BUILD_TARGET_RISCV64_LP64D) || defined(BUILD_TARGET_RISCV64_LP64)
/* aot code and data in x86_64 must be in range 0 to 2G due to
relocation for R_X86_64_32/32S/PC32 */
int map_flags = MMAP_MAP_32BIT;

View File

@ -2776,12 +2776,12 @@ aot_table_copy(AOTModuleInstance *module_inst,
/* if src_offset >= dst_offset, copy from front to back */
/* if src_offset < dst_offset, copy from back to front */
/* merge all together */
bh_memcpy_s((uint8 *)(dst_tbl_inst) + offsetof(AOTTableInstance, data)
+ dst_offset * sizeof(uint32),
(dst_tbl_inst->cur_size - dst_offset) * sizeof(uint32),
(uint8 *)(src_tbl_inst) + offsetof(AOTTableInstance, data)
+ src_offset * sizeof(uint32),
length * sizeof(uint32));
bh_memmove_s((uint8 *)(dst_tbl_inst) + offsetof(AOTTableInstance, data)
+ dst_offset * sizeof(uint32),
(dst_tbl_inst->cur_size - dst_offset) * sizeof(uint32),
(uint8 *)(src_tbl_inst) + offsetof(AOTTableInstance, data)
+ src_offset * sizeof(uint32),
length * sizeof(uint32));
}
void

View File

@ -0,0 +1,337 @@
/*
* Copyright (C) 2021 XiaoMi Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_reloc.h"
#define R_RISCV_32 1
#define R_RISCV_64 2
#define R_RISCV_CALL 18
#define R_RISCV_CALL_PLT 19
#define R_RISCV_HI20 26
#define R_RISCV_LO12_I 27
#define R_RISCV_LO12_S 28
#define RV_OPCODE_SW 0x23
void __divdi3();
void __moddi3();
void __muldi3();
void __udivdi3();
void __umoddi3();
static SymbolMap target_sym_map[] = {
REG_COMMON_SYMBOLS
REG_SYM(__divdi3),
REG_SYM(__moddi3),
REG_SYM(__muldi3),
REG_SYM(__udivdi3),
REG_SYM(__umoddi3),
};
static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
{
if (error_buf != NULL)
snprintf(error_buf, error_buf_size, "%s", string);
}
void
get_current_target(char *target_buf, uint32 target_buf_size)
{
snprintf(target_buf, target_buf_size, "riscv");
}
uint32
get_plt_item_size()
{
#if __riscv_xlen == 64
/* auipc + ld + jalr + nop + addr */
return 20;
#else
return 0;
#endif
}
SymbolMap *
get_target_symbol_map(uint32 *sym_num)
{
*sym_num = sizeof(target_sym_map) / sizeof(SymbolMap);
return target_sym_map;
}
/* Get a val from given address */
static uint32
rv_get_val(uint16 *addr)
{
uint32 ret;
ret = *addr | (*(addr + 1)) << 16;
return ret;
}
/* Set a val to given address */
static void
rv_set_val(uint16 *addr, uint32 val)
{
*addr = (val & 0xffff);
*(addr + 1) = (val >> 16);
asm volatile("fence.i");
}
/* Add a val to given address */
static void
rv_add_val(uint16 *addr, uint32 val)
{
uint32 cur = rv_get_val(addr);
rv_set_val(addr, cur + val);
}
/**
* Get imm_hi and imm_lo from given integer
*
* @param imm given integer, signed 32bit
* @param imm_hi signed 20bit
* @param imm_lo signed 12bit
*
*/
static void
rv_calc_imm(int32 imm, int32 *imm_hi, int32 *imm_lo)
{
int32 lo;
int32 hi = imm / 4096;
int32 r = imm % 4096;
if (2047 < r) {
hi++;
}
else if (r < -2048) {
hi--;
}
lo = imm - (hi * 4096);
*imm_lo = lo;
*imm_hi = hi;
}
uint32
get_plt_table_size()
{
return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
}
void
init_plt_table(uint8 *plt)
{
#if __riscv_xlen == 64
uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap);
uint8 *p;
for (i = 0; i < num; i++) {
p = plt;
/* auipc t1, 0 */
*(uint16*)p = 0x0317;
p += 2;
*(uint16*)p = 0x0000;
p += 2;
/* ld t1, 8(t1) */
*(uint16*)p = 0x3303;
p += 2;
*(uint16*)p = 0x00C3;
p += 2;
/* jr t1 */
*(uint16*)p = 0x8302;
p += 2;
/* nop */
*(uint16*)p = 0x0001;
p += 2;
bh_memcpy_s(p, 8, &target_sym_map[i].symbol_addr, 8);
p += 8;
plt += get_plt_item_size();
}
#endif
}
typedef struct RelocTypeStrMap {
uint32 reloc_type;
char *reloc_str;
} RelocTypeStrMap;
#define RELOC_TYPE_MAP(reloc_type) { reloc_type, #reloc_type }
static RelocTypeStrMap reloc_type_str_maps[] = {
RELOC_TYPE_MAP(R_RISCV_32),
RELOC_TYPE_MAP(R_RISCV_CALL),
RELOC_TYPE_MAP(R_RISCV_CALL_PLT),
RELOC_TYPE_MAP(R_RISCV_HI20),
RELOC_TYPE_MAP(R_RISCV_LO12_I),
RELOC_TYPE_MAP(R_RISCV_LO12_S),
};
static const char *
reloc_type_to_str(uint32 reloc_type)
{
uint32 i;
for (i = 0; i < sizeof(reloc_type_str_maps) / sizeof(RelocTypeStrMap); i++) {
if (reloc_type_str_maps[i].reloc_type == reloc_type)
return reloc_type_str_maps[i].reloc_str;
}
return "Unknown_Reloc_Type";
}
static bool
check_reloc_offset(uint32 target_section_size,
uint64 reloc_offset, uint32 reloc_data_size,
char *error_buf, uint32 error_buf_size)
{
if (!(reloc_offset < (uint64)target_section_size
&& reloc_offset + reloc_data_size <= (uint64)target_section_size)) {
set_error_buf(error_buf, error_buf_size,
"AOT module load failed: invalid relocation offset.");
return false;
}
return true;
}
bool
apply_relocation(AOTModule *module,
uint8 *target_section_addr, uint32 target_section_size,
uint64 reloc_offset, uint64 reloc_addend, uint32 reloc_type,
void *symbol_addr, int32 symbol_index,
char *error_buf, uint32 error_buf_size)
{
int32 val, imm_hi, imm_lo, insn;
uint8 *addr = target_section_addr + reloc_offset;
char buf[128];
switch (reloc_type) {
case R_RISCV_32:
{
uint32 val_32 = (uint32)(uintptr_t)((uint8 *)symbol_addr + reloc_addend);
CHECK_RELOC_OFFSET(sizeof(uint32));
if (val_32 != (uintptr_t)((uint8 *)symbol_addr + reloc_addend)) {
goto fail_addr_out_of_range;
}
rv_set_val((uint16 *)addr, val_32);
break;
}
case R_RISCV_64:
{
uint64 val_64 = (uint64)(uintptr_t)((uint8 *)symbol_addr + reloc_addend);
CHECK_RELOC_OFFSET(sizeof(uint64));
bh_memcpy_s(addr, 8, &val_64, 8);
break;
}
case R_RISCV_CALL:
case R_RISCV_CALL_PLT:
{
val = (int32)(intptr_t)((uint8 *)symbol_addr - addr);
CHECK_RELOC_OFFSET(sizeof(uint32));
if (val != (intptr_t)((uint8 *)symbol_addr - addr)) {
if (symbol_index >= 0) {
/* Call runtime function by plt code */
symbol_addr = (uint8*)module->code + module->code_size
- get_plt_table_size()
+ get_plt_item_size() * symbol_index;
val = (int32)(intptr_t)((uint8*)symbol_addr - addr);
}
}
if (val != (intptr_t)((uint8 *)symbol_addr - addr)) {
goto fail_addr_out_of_range;
}
rv_calc_imm(val, &imm_hi, &imm_lo);
rv_add_val((uint16 *)addr, (imm_hi << 12));
if ((rv_get_val((uint16 *)(addr + 4)) & 0x7f) == RV_OPCODE_SW) {
/* Adjust imm for SW : S-type */
val =
(((int32)imm_lo >> 5) << 25) + (((int32)imm_lo & 0x1f) << 7);
rv_add_val((uint16 *)(addr + 4), val);
}
else {
/* Adjust imm for MV(ADDI)/JALR : I-type */
rv_add_val((uint16 *)(addr + 4), ((int32)imm_lo << 20));
}
break;
}
case R_RISCV_HI20:
{
val = (int32)(intptr_t)(symbol_addr + reloc_addend);
CHECK_RELOC_OFFSET(sizeof(uint32));
if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend)) {
goto fail_addr_out_of_range;
}
addr = target_section_addr + reloc_offset;
insn = rv_get_val((uint16 *)addr);
rv_calc_imm(val, &imm_hi, &imm_lo);
insn = (insn & 0x00000fff) | (imm_hi << 12);
rv_set_val((uint16 *)addr, insn);
break;
}
case R_RISCV_LO12_I:
{
val = (int32)(intptr_t)(symbol_addr + reloc_addend);
CHECK_RELOC_OFFSET(sizeof(uint32));
if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend)) {
goto fail_addr_out_of_range;
}
addr = target_section_addr + reloc_offset;
insn = rv_get_val((uint16 *)addr);
rv_calc_imm(val, &imm_hi, &imm_lo);
insn = (insn & 0x000fffff) | (imm_lo << 20);
rv_set_val((uint16 *)addr, insn);
break;
}
case R_RISCV_LO12_S:
{
val = (int32)(intptr_t)(symbol_addr + reloc_addend);
CHECK_RELOC_OFFSET(sizeof(uint32));
if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend)) {
goto fail_addr_out_of_range;
}
addr = target_section_addr + reloc_offset;
rv_calc_imm(val, &imm_hi, &imm_lo);
val =
(((int32)imm_lo >> 5) << 25) + (((int32)imm_lo & 0x1f) << 7);
rv_add_val((uint16 *)addr, val);
break;
}
default:
if (error_buf != NULL)
snprintf(error_buf, error_buf_size,
"Load relocation section failed: "
"invalid relocation type %d.",
reloc_type);
return false;
}
return true;
fail_addr_out_of_range:
snprintf(buf, sizeof(buf),
"AOT module load failed: "
"relocation truncated to fit %s failed.",
reloc_type_to_str(reloc_type));
set_error_buf(error_buf, error_buf_size, buf);
return false;
}

View File

@ -23,6 +23,8 @@ elseif (WAMR_BUILD_TARGET STREQUAL "MIPS")
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_mips.c)
elseif (WAMR_BUILD_TARGET STREQUAL "XTENSA")
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_xtensa.c)
elseif (WAMR_BUILD_TARGET MATCHES "RISCV*")
set (arch_source ${IWASM_AOT_DIR}/arch/aot_reloc_riscv.c)
else ()
message (FATAL_ERROR "Build target isn't set")
endif ()