| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * Copyright (C) 2019 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include "aot_reloc.h"
- #define R_XTENSA_32 1 /* Direct 32 bit */
- #define R_XTENSA_SLOT0_OP 20 /* PC relative */
- /* clang-format off */
- /* for soft-float */
- void __floatsidf(void);
- void __divdf3(void);
- void __ltdf2(void);
- /* for mul32 */
- void __mulsi3(void);
- void __muldi3(void);
- void __modsi3(void);
- void __divdi3(void);
- void __udivdi3(void);
- void __unorddf2(void);
- void __adddf3(void);
- void __eqdf2(void);
- void __muldf3(void);
- void __gedf2(void);
- void __ledf2(void);
- void __fixunsdfsi(void);
- void __floatunsidf(void);
- void __subdf3(void);
- void __nedf2(void);
- void __fixdfsi(void);
- void __moddi3(void);
- void __extendsfdf2(void);
- void __truncdfsf2(void);
- void __gtdf2(void);
- void __umoddi3(void);
- void __floatdidf(void);
- void __divsf3(void);
- void __fixdfdi(void);
- void __floatundidf(void);
- void __fixsfdi(void);
- void __fixunssfdi(void);
- void __fixunsdfdi(void);
- void __floatdisf(void);
- void __floatundisf(void);
- static SymbolMap target_sym_map[] = {
- REG_COMMON_SYMBOLS
- /* API's for soft-float */
- /* TODO: only register these symbols when Floating-Point Coprocessor
- * Option is not enabled */
- REG_SYM(__floatsidf),
- REG_SYM(__divdf3),
- REG_SYM(__ltdf2),
- /* API's for 32-bit integer multiply */
- /* TODO: only register these symbols when 32-bit Integer Multiply Option
- * is not enabled */
- REG_SYM(__mulsi3),
- REG_SYM(__muldi3),
- REG_SYM(__modsi3),
- REG_SYM(__divdi3),
- REG_SYM(__udivdi3),
- REG_SYM(__unorddf2),
- REG_SYM(__adddf3),
- REG_SYM(__eqdf2),
- REG_SYM(__muldf3),
- REG_SYM(__gedf2),
- REG_SYM(__ledf2),
- REG_SYM(__fixunsdfsi),
- REG_SYM(__floatunsidf),
- REG_SYM(__subdf3),
- REG_SYM(__nedf2),
- REG_SYM(__fixdfsi),
- REG_SYM(__moddi3),
- REG_SYM(__extendsfdf2),
- REG_SYM(__truncdfsf2),
- REG_SYM(__gtdf2),
- REG_SYM(__umoddi3),
- REG_SYM(__floatdidf),
- REG_SYM(__divsf3),
- REG_SYM(__fixdfdi),
- REG_SYM(__floatundidf),
- REG_SYM(__fixsfdi),
- REG_SYM(__fixunssfdi),
- REG_SYM(__fixunsdfdi),
- REG_SYM(__floatdisf),
- REG_SYM(__floatundisf),
- };
- /* clang-format on */
- 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);
- }
- SymbolMap *
- get_target_symbol_map(uint32 *sym_num)
- {
- *sym_num = sizeof(target_sym_map) / sizeof(SymbolMap);
- return target_sym_map;
- }
- void
- get_current_target(char *target_buf, uint32 target_buf_size)
- {
- snprintf(target_buf, target_buf_size, "xtensa");
- }
- static uint32
- get_plt_item_size(void)
- {
- return 0;
- }
- void
- init_plt_table(uint8 *plt)
- {
- (void)plt;
- }
- uint32
- get_plt_table_size()
- {
- return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
- }
- 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;
- }
- /*
- * CPU like esp32 can read and write data through the instruction bus, but only
- * in a word aligned manner; non-word-aligned access will cause a CPU exception.
- * This function uses a world aligned manner to write 16bit value to instruction
- * address.
- */
- static void
- put_imm16_to_addr(int16 imm16, int16 *addr)
- {
- int8 bytes[8];
- int32 *addr_aligned1, *addr_aligned2;
- addr_aligned1 = (int32 *)((intptr_t)addr & ~3);
- if ((intptr_t)addr % 4 != 3) {
- *(int32 *)bytes = *addr_aligned1;
- *(int16 *)(bytes + ((intptr_t)addr % 4)) = imm16;
- *addr_aligned1 = *(int32 *)bytes;
- }
- else {
- addr_aligned2 = (int32 *)(((intptr_t)addr + 3) & ~3);
- *(int32 *)bytes = *addr_aligned1;
- *(int32 *)(bytes + 4) = *addr_aligned2;
- *(int16 *)(bytes + 3) = imm16;
- memcpy(addr_aligned1, bytes, 8);
- }
- }
- static union {
- int a;
- char b;
- } __ue = { .a = 1 };
- #define is_little_endian() (__ue.b == 1)
- #if !defined(__packed)
- /*
- * Note: This version check is a bit relaxed.
- * The __packed__ attribute has been there since gcc 2 era.
- */
- #if __GNUC__ >= 3
- #define __packed __attribute__((__packed__))
- #endif
- #endif
- typedef union {
- struct l32r_le {
- int8 other;
- int16 imm16;
- } __packed l;
- struct l32r_be {
- int16 imm16;
- int8 other;
- } __packed b;
- } l32r_insn_t;
- bool
- apply_relocation(AOTModule *module, uint8 *target_section_addr,
- uint32 target_section_size, uint64 reloc_offset,
- int64 reloc_addend, uint32 reloc_type, void *symbol_addr,
- int32 symbol_index, char *error_buf, uint32 error_buf_size)
- {
- switch (reloc_type) {
- case R_XTENSA_32:
- {
- uint8 *insn_addr = target_section_addr + reloc_offset;
- #if (WASM_MEM_DUAL_BUS_MIRROR != 0)
- insn_addr = os_get_dbus_mirror((void *)insn_addr);
- bh_assert(insn_addr != NULL);
- #endif
- int32 initial_addend;
- /* (S + A) */
- if ((intptr_t)insn_addr & 3) {
- set_error_buf(error_buf, error_buf_size,
- "AOT module load failed: "
- "instruction address unaligned.");
- return false;
- }
- CHECK_RELOC_OFFSET(4);
- initial_addend = *(int32 *)insn_addr;
- *(uintptr_t *)insn_addr = (uintptr_t)symbol_addr + initial_addend
- + (intptr_t)reloc_addend;
- break;
- }
- case R_XTENSA_SLOT0_OP:
- {
- uint8 *insn_addr = target_section_addr + reloc_offset;
- /* Currently only l32r instruction generates R_XTENSA_SLOT0_OP
- * relocation */
- l32r_insn_t *l32r_insn = (l32r_insn_t *)insn_addr;
- uint8 *reloc_addr;
- int32 relative_offset /*, initial_addend */;
- int16 imm16;
- CHECK_RELOC_OFFSET(3); /* size of l32r instruction */
- /*
- imm16 = is_little_endian() ?
- l32r_insn->l.imm16 : l32r_insn->b.imm16;
- initial_addend = (int32)imm16 << 2;
- */
- reloc_addr =
- (uint8 *)((uintptr_t)symbol_addr + (intptr_t)reloc_addend);
- if ((intptr_t)reloc_addr & 3) {
- set_error_buf(error_buf, error_buf_size,
- "AOT module load failed: "
- "relocation address unaligned.");
- return false;
- }
- relative_offset =
- (int32)((intptr_t)reloc_addr
- - (((intptr_t)insn_addr + 3) & ~(intptr_t)3));
- /* relative_offset += initial_addend; */
- /* check relative offset boundary */
- if (relative_offset < -256 * BH_KB || relative_offset > -4) {
- set_error_buf(error_buf, error_buf_size,
- "AOT module load failed: "
- "target address out of range.\n"
- "Try using `wamrc --size-level=0` to generate "
- ".literal island.");
- return false;
- }
- #if (WASM_MEM_DUAL_BUS_MIRROR != 0)
- insn_addr = os_get_dbus_mirror((void *)insn_addr);
- bh_assert(insn_addr != NULL);
- l32r_insn = (l32r_insn_t *)insn_addr;
- #endif
- imm16 = (int16)(relative_offset >> 2);
- /* write back the imm16 to the l32r instruction */
- /* GCC >= 9 complains if we have a pointer that could be
- * unaligned. This can happen because the struct is packed.
- * These pragma are to suppress the warnings because the
- * function put_imm16_to_addr already handles unaligned
- * pointers correctly. */
- #if __GNUC__ >= 9
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
- #endif
- if (is_little_endian())
- put_imm16_to_addr(imm16, &l32r_insn->l.imm16);
- else
- put_imm16_to_addr(imm16, &l32r_insn->b.imm16);
- #if __GNUC__ >= 9
- #pragma GCC diagnostic pop
- #endif
- break;
- }
- default:
- if (error_buf != NULL)
- snprintf(error_buf, error_buf_size,
- "Load relocation section failed: "
- "invalid relocation type %d.",
- (int)reloc_type);
- return false;
- }
- return true;
- }
|