mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2026-01-17 06:46:39 +00:00
Merge 7c7ecf0795 into f71165f0ed
This commit is contained in:
commit
a91dcab69f
|
|
@ -3203,6 +3203,14 @@ do_text_relocation(AOTModule *module, AOTRelocationGroup *group,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(BUILD_TARGET_RISCV32_ILP32) \
|
||||
|| defined(BUILD_TARGET_RISCV32_ILP32F) \
|
||||
|| defined(BUILD_TARGET_RISCV32_ILP32D) \
|
||||
|| defined(BUILD_TARGET_RISCV64_LP64) \
|
||||
|| defined(BUILD_TARGET_RISCV64_LP64D)
|
||||
aot_reloc_reset_cache();
|
||||
#endif
|
||||
|
||||
for (i = 0; i < group->relocation_count; i++, relocation++) {
|
||||
int32 symbol_index = -1;
|
||||
symbol_len = (uint32)strlen(relocation->symbol_name);
|
||||
|
|
|
|||
|
|
@ -252,6 +252,17 @@ apply_relocation(AOTModule *module,
|
|||
uint64 reloc_offset, int64 reloc_addend,
|
||||
uint32 reloc_type, void *symbol_addr, int32 symbol_index,
|
||||
char *error_buf, uint32 error_buf_size);
|
||||
|
||||
/**
|
||||
* Reset any target-specific relocation state.
|
||||
*
|
||||
* Some targets (e.g. RISC-V) need to cache information across multiple
|
||||
* relocation entries (such as PC-relative HI20/LO12 pairs). This function must
|
||||
* be called by the relocation loader before applying a relocation group/section
|
||||
* to avoid stale state leaking between groups.
|
||||
*/
|
||||
void
|
||||
aot_reloc_reset_cache(void);
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -192,6 +192,79 @@ static SymbolMap target_sym_map[] = {
|
|||
/* clang-format on */
|
||||
};
|
||||
|
||||
/*
|
||||
* Cache entries for matching R_RISCV_PCREL_HI20 with its corresponding
|
||||
* R_RISCV_PCREL_LO12_{I,S}. The relocation table is typically ordered by
|
||||
* increasing offset, so only a small number of "in-flight" HI20 entries are
|
||||
* expected at any moment; 8 is a conservative fixed bound.
|
||||
*/
|
||||
#define PCREL_CACHE_SIZE 8
|
||||
|
||||
typedef struct {
|
||||
uintptr_t hi20_addr;
|
||||
uintptr_t cached_offset;
|
||||
} pcrel_cache_entry_t;
|
||||
|
||||
static pcrel_cache_entry_t pcrel_cache[PCREL_CACHE_SIZE];
|
||||
static int pcrel_cache_count = 0;
|
||||
|
||||
void
|
||||
aot_reloc_reset_cache(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PCREL_CACHE_SIZE; i++) {
|
||||
pcrel_cache[i].hi20_addr = 0;
|
||||
pcrel_cache[i].cached_offset = 0;
|
||||
}
|
||||
pcrel_cache_count = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
add_hi20_to_cache(uintptr_t hi20_reloc_addr, uintptr_t hi20_offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PCREL_CACHE_SIZE; i++) {
|
||||
if (pcrel_cache[i].hi20_addr == 0) {
|
||||
pcrel_cache[i].hi20_addr = hi20_reloc_addr;
|
||||
pcrel_cache[i].cached_offset = hi20_offset;
|
||||
pcrel_cache_count++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
find_hi20_in_cache(uintptr_t hi20_reloc_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PCREL_CACHE_SIZE; i++) {
|
||||
if (pcrel_cache[i].hi20_addr == hi20_reloc_addr) {
|
||||
pcrel_cache[i].hi20_addr = 0;
|
||||
pcrel_cache[i].cached_offset = 0;
|
||||
pcrel_cache_count--;
|
||||
return pcrel_cache[i].cached_offset;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
valid_hi20_imm(long imm_hi)
|
||||
{
|
||||
#if __riscv_xlen == 64
|
||||
long hi = imm_hi & ((1 << 20) - 1);
|
||||
long sign = -((imm_hi >> 19) & 1);
|
||||
hi = ((hi << 12) | sign << 32) >> 12;
|
||||
return imm_hi == hi;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
|
||||
{
|
||||
|
|
@ -257,17 +330,17 @@ rv_add_val(uint16 *addr, uint32 val)
|
|||
/**
|
||||
* Get imm_hi and imm_lo from given integer
|
||||
*
|
||||
* @param imm given integer, signed 32bit
|
||||
* @param imm given integer (intptr_t, 32-bit on RV32, 64-bit on RV64)
|
||||
* @param imm_hi signed 20bit
|
||||
* @param imm_lo signed 12bit
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rv_calc_imm(int32 imm, int32 *imm_hi, int32 *imm_lo)
|
||||
rv_calc_imm(intptr_t imm, int32 *imm_hi, int32 *imm_lo)
|
||||
{
|
||||
int32 lo;
|
||||
int32 hi = imm / 4096;
|
||||
int32 r = imm % 4096;
|
||||
intptr_t lo;
|
||||
intptr_t hi = imm / 4096;
|
||||
intptr_t r = imm % 4096;
|
||||
|
||||
if (2047 < r) {
|
||||
hi++;
|
||||
|
|
@ -278,8 +351,8 @@ rv_calc_imm(int32 imm, int32 *imm_hi, int32 *imm_lo)
|
|||
|
||||
lo = imm - (hi * 4096);
|
||||
|
||||
*imm_lo = lo;
|
||||
*imm_hi = hi;
|
||||
*imm_lo = (int32)lo;
|
||||
*imm_hi = (int32)hi;
|
||||
}
|
||||
|
||||
uint32
|
||||
|
|
@ -325,10 +398,7 @@ typedef struct RelocTypeStrMap {
|
|||
char *reloc_str;
|
||||
} RelocTypeStrMap;
|
||||
|
||||
#define RELOC_TYPE_MAP(reloc_type) \
|
||||
{ \
|
||||
reloc_type, #reloc_type \
|
||||
}
|
||||
#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_64),
|
||||
|
|
@ -436,6 +506,21 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
|
||||
rv_calc_imm(val, &imm_hi, &imm_lo);
|
||||
|
||||
if (reloc_type == R_RISCV_PCREL_HI20) {
|
||||
if (!valid_hi20_imm(imm_hi)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: invalid HI20 "
|
||||
"immediate for RV64");
|
||||
return false;
|
||||
}
|
||||
if (!add_hi20_to_cache((uintptr_t)addr, (uintptr_t)val)) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"AOT module load failed: PCREL relocation "
|
||||
"cache overflow.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
@ -453,15 +538,20 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
|
||||
case R_RISCV_HI20: /* S + A */
|
||||
{
|
||||
val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(uint32));
|
||||
if (val != ((intptr_t)symbol_addr + (intptr_t)reloc_addend)) {
|
||||
goto fail_addr_out_of_range;
|
||||
|
||||
intptr_t val = (intptr_t)symbol_addr + (intptr_t)reloc_addend;
|
||||
int32_t imm_hi, imm_lo;
|
||||
rv_calc_imm(val, &imm_hi, &imm_lo);
|
||||
|
||||
if (!valid_hi20_imm(imm_hi)) {
|
||||
set_error_buf(
|
||||
error_buf, error_buf_size,
|
||||
"AOT module load failed: invalid HI20 immediate for RV64");
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -470,46 +560,44 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
case R_RISCV_PCREL_LO12_I: /* S - P */
|
||||
case R_RISCV_PCREL_LO12_S: /* S - P */
|
||||
{
|
||||
/* Already handled in R_RISCV_PCREL_HI20, it should be skipped for
|
||||
* most cases. But it is still needed for some special cases, e.g.
|
||||
* ```
|
||||
* label:
|
||||
* auipc t0, %pcrel_hi(symbol) # R_RISCV_PCREL_HI20 (symbol)
|
||||
* lui t1, 1
|
||||
* lw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_I (label)
|
||||
* add t2, t2, t1
|
||||
* sw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_S (label)
|
||||
* ```
|
||||
* In this case, the R_RISCV_PCREL_LO12_I/S relocation should be
|
||||
* handled after R_RISCV_PCREL_HI20 relocation.
|
||||
*
|
||||
* So, if the R_RISCV_PCREL_LO12_I/S relocation is not followed by
|
||||
* R_RISCV_PCREL_HI20 relocation, it should be handled here but
|
||||
* not implemented yet.
|
||||
*/
|
||||
uintptr_t cached_offset;
|
||||
|
||||
if ((uintptr_t)addr - (uintptr_t)symbol_addr
|
||||
- (uintptr_t)reloc_addend
|
||||
!= 4) {
|
||||
goto fail_addr_out_of_range;
|
||||
cached_offset = find_hi20_in_cache((uintptr_t)addr - 4);
|
||||
|
||||
if (cached_offset != 0) {
|
||||
val = (int32)cached_offset;
|
||||
}
|
||||
else {
|
||||
val = (int32)(intptr_t)((uint8 *)symbol_addr + reloc_addend
|
||||
- addr - 4);
|
||||
}
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(uint32));
|
||||
|
||||
rv_calc_imm(val, &imm_hi, &imm_lo);
|
||||
|
||||
if (reloc_type == R_RISCV_PCREL_LO12_I) {
|
||||
rv_add_val((uint16 *)addr, ((int32)imm_lo << 20));
|
||||
}
|
||||
else {
|
||||
val = (((int32)imm_lo >> 5) << 25)
|
||||
+ (((int32)imm_lo & 0x1f) << 7);
|
||||
rv_add_val((uint16 *)addr, val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case R_RISCV_LO12_I: /* S + A */
|
||||
{
|
||||
|
||||
val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(uint32));
|
||||
|
||||
if (val != (intptr_t)symbol_addr + (intptr_t)reloc_addend) {
|
||||
goto fail_addr_out_of_range;
|
||||
}
|
||||
|
||||
addr = target_section_addr + reloc_offset;
|
||||
insn = rv_get_val((uint16 *)addr);
|
||||
|
||||
intptr_t val = (intptr_t)symbol_addr + (intptr_t)reloc_addend;
|
||||
int32_t imm_hi, imm_lo;
|
||||
rv_calc_imm(val, &imm_hi, &imm_lo);
|
||||
|
||||
insn = (insn & 0x000fffff) | (imm_lo << 20);
|
||||
rv_set_val((uint16 *)addr, insn);
|
||||
break;
|
||||
|
|
@ -517,15 +605,14 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
|
|||
|
||||
case R_RISCV_LO12_S:
|
||||
{
|
||||
val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
|
||||
|
||||
CHECK_RELOC_OFFSET(sizeof(uint32));
|
||||
if (val != ((intptr_t)symbol_addr + (intptr_t)reloc_addend)) {
|
||||
goto fail_addr_out_of_range;
|
||||
}
|
||||
|
||||
addr = target_section_addr + reloc_offset;
|
||||
|
||||
intptr_t val = (intptr_t)symbol_addr + (intptr_t)reloc_addend;
|
||||
int32_t imm_hi, imm_lo;
|
||||
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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user