Skip to content

Commit 4f6d70b

Browse files
Use indirect call in pre-checker function to avoid relocation in XIP mode (#3142)
The stack profiler `aot_func#xxx` calls the wrapped function of `aot_func_internal#xxx` by using symbol reference, but in some platform like xtensa, it’s translated into a native long call, which needs to resolve the indirect address by relocation and breaks the XIP feature which requires the eliminating of relocation. The solution is to change the symbol reference into an indirect call through the lookup table, the code will be like this: ```llvm call_wrapped_func: ; preds = %stack_bound_check_block %func_addr1 = getelementptr inbounds ptr, ptr %func_ptrs_ptr, i32 75 %func_tmp2 = load ptr, ptr %func_addr1, align 4 tail call void %func_tmp2(ptr %exec_env) ret void ```
1 parent 2349df1 commit 4f6d70b

File tree

4 files changed

+132
-17
lines changed

4 files changed

+132
-17
lines changed

core/iwasm/aot/aot_loader.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,15 +2500,26 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
25002500
const uint8 *p = buf, *p_end = buf_end;
25012501
uint32 i;
25022502
uint64 size, text_offset;
2503+
uint32 func_count = module->func_count;
25032504

2504-
size = sizeof(void *) * (uint64)module->func_count;
2505+
#if defined(BUILD_TARGET_XTENSA)
2506+
/*
2507+
* For Xtensa XIP, real func_count is doubled, including aot_func and
2508+
* aot_func_internal, so need to multipy func_count by 2 here.
2509+
*/
2510+
if (module->is_indirect_mode) {
2511+
func_count *= 2;
2512+
}
2513+
#endif
2514+
2515+
size = sizeof(void *) * (uint64)func_count;
25052516
if (size > 0
25062517
&& !(module->func_ptrs =
25072518
loader_malloc(size, error_buf, error_buf_size))) {
25082519
return false;
25092520
}
25102521

2511-
for (i = 0; i < module->func_count; i++) {
2522+
for (i = 0; i < func_count; i++) {
25122523
if (sizeof(void *) == 8) {
25132524
read_uint64(p, p_end, text_offset);
25142525
}
@@ -2543,14 +2554,14 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
25432554
module->start_function = NULL;
25442555
}
25452556

2546-
size = sizeof(uint32) * (uint64)module->func_count;
2557+
size = sizeof(uint32) * (uint64)func_count;
25472558
if (size > 0
25482559
&& !(module->func_type_indexes =
25492560
loader_malloc(size, error_buf, error_buf_size))) {
25502561
return false;
25512562
}
25522563

2553-
for (i = 0; i < module->func_count; i++) {
2564+
for (i = 0; i < func_count; i++) {
25542565
read_uint32(p, p_end, module->func_type_indexes[i]);
25552566
if (module->func_type_indexes[i] >= module->type_count) {
25562567
set_error_buf(error_buf, error_buf_size, "unknown type");

core/iwasm/aot/aot_runtime.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,10 +1108,21 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module,
11081108
{
11091109
uint32 i;
11101110
void **func_ptrs;
1111-
uint64 total_size = ((uint64)module->import_func_count + module->func_count)
1112-
* sizeof(void *);
1111+
uint32 func_count = module->func_count;
1112+
#if defined(BUILD_TARGET_XTENSA)
1113+
/*
1114+
* For Xtensa XIP, real func_count is doubled, including aot_func and
1115+
* aot_func_internal, so need to multipy func_count by 2 here.
1116+
*/
1117+
if (module->is_indirect_mode) {
1118+
func_count *= 2;
1119+
}
1120+
#endif
1121+
1122+
uint64 total_size =
1123+
((uint64)module->import_func_count + func_count) * sizeof(void *);
11131124

1114-
if (module->import_func_count + module->func_count == 0)
1125+
if (module->import_func_count + func_count == 0)
11151126
return true;
11161127

11171128
/* Allocate memory */
@@ -1133,8 +1144,8 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module,
11331144
}
11341145

11351146
/* Set defined function pointers */
1136-
bh_memcpy_s(func_ptrs, sizeof(void *) * module->func_count,
1137-
module->func_ptrs, sizeof(void *) * module->func_count);
1147+
bh_memcpy_s(func_ptrs, sizeof(void *) * func_count, module->func_ptrs,
1148+
sizeof(void *) * func_count);
11381149
return true;
11391150
}
11401151

@@ -1144,10 +1155,21 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module,
11441155
{
11451156
uint32 i;
11461157
uint32 *func_type_index;
1147-
uint64 total_size = ((uint64)module->import_func_count + module->func_count)
1148-
* sizeof(uint32);
1158+
uint32 func_count = module->func_count;
1159+
#if defined(BUILD_TARGET_XTENSA)
1160+
/*
1161+
* For Xtensa XIP, real func_count is doubled, including aot_func and
1162+
* aot_func_internal, so need to multipy func_count by 2 here.
1163+
*/
1164+
if (module->is_indirect_mode) {
1165+
func_count *= 2;
1166+
}
1167+
#endif
1168+
1169+
uint64 total_size =
1170+
((uint64)module->import_func_count + func_count) * sizeof(uint32);
11491171

1150-
if (module->import_func_count + module->func_count == 0)
1172+
if (module->import_func_count + func_count == 0)
11511173
return true;
11521174

11531175
/* Allocate memory */
@@ -1161,8 +1183,8 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module,
11611183
for (i = 0; i < module->import_func_count; i++, func_type_index++)
11621184
*func_type_index = module->import_funcs[i].func_type_index;
11631185

1164-
bh_memcpy_s(func_type_index, sizeof(uint32) * module->func_count,
1165-
module->func_type_indexes, sizeof(uint32) * module->func_count);
1186+
bh_memcpy_s(func_type_index, sizeof(uint32) * func_count,
1187+
module->func_type_indexes, sizeof(uint32) * func_count);
11661188
return true;
11671189
}
11681190

core/iwasm/compilation/aot_emit_aot_file.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ is_little_endian_binary(const AOTObjectData *obj_data)
179179
return obj_data->target_info.bin_type & 1 ? false : true;
180180
}
181181

182+
static bool
183+
need_call_wrapped_indirect(const AOTObjectData *obj_data)
184+
{
185+
const bool need_precheck = obj_data->comp_ctx->enable_stack_bound_check
186+
|| obj_data->comp_ctx->enable_stack_estimation;
187+
188+
return obj_data->comp_ctx->is_indirect_mode && need_precheck
189+
&& !strncmp(obj_data->comp_ctx->target_arch, "xtensa", 6);
190+
}
191+
182192
static bool
183193
str_starts_with(const char *str, const char *prefix)
184194
{
@@ -870,6 +880,10 @@ get_func_section_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
870880
/* function type indexes */
871881
size += (uint32)sizeof(uint32) * comp_data->func_count;
872882

883+
/* aot_func#xxx + aot_func_internal#xxx in XIP mode for xtensa */
884+
if (need_call_wrapped_indirect(obj_data))
885+
size *= 2;
886+
873887
/* max_local_cell_nums */
874888
size += (uint32)sizeof(uint32) * comp_data->func_count;
875889

@@ -2595,9 +2609,30 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
25952609
EMIT_U64(func->text_offset);
25962610
}
25972611

2612+
if (need_call_wrapped_indirect(obj_data)) {
2613+
/*
2614+
* Explicitly emit aot_func_internal#xxx for Xtensa XIP, therefore,
2615+
* for aot_func#xxx, func_indexes ranged from 0 ~ func_count,
2616+
* for aot_func_internal#xxxx, from func_count + 1 ~ 2 * func_count.
2617+
*/
2618+
for (i = 0, func = obj_data->funcs; i < obj_data->func_count;
2619+
i++, func++) {
2620+
if (is_32bit_binary(obj_data))
2621+
EMIT_U32(func->text_offset_of_aot_func_internal);
2622+
else
2623+
EMIT_U64(func->text_offset_of_aot_func_internal);
2624+
}
2625+
}
2626+
25982627
for (i = 0; i < comp_data->func_count; i++)
25992628
EMIT_U32(funcs[i]->func_type_index);
26002629

2630+
if (need_call_wrapped_indirect(obj_data)) {
2631+
/* func_type_index for aot_func_internal#xxxx */
2632+
for (i = 0; i < comp_data->func_count; i++)
2633+
EMIT_U32(funcs[i]->func_type_index);
2634+
}
2635+
26012636
for (i = 0; i < comp_data->func_count; i++) {
26022637
uint32 max_local_cell_num =
26032638
funcs[i]->param_cell_num + funcs[i]->local_cell_num;

core/iwasm/compilation/aot_llvm.c

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ create_native_stack_bound(const AOTCompContext *comp_ctx,
2424
static bool
2525
create_native_stack_top_min(const AOTCompContext *comp_ctx,
2626
AOTFuncContext *func_ctx);
27+
static bool
28+
create_func_ptrs(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
2729

2830
LLVMTypeRef
2931
wasm_type_to_llvm_type(const AOTCompContext *comp_ctx,
@@ -537,8 +539,51 @@ aot_build_precheck_function(AOTCompContext *comp_ctx, LLVMModuleRef module,
537539
if (ret_type == VOID_TYPE) {
538540
name = "";
539541
}
540-
LLVMValueRef retval =
541-
LLVMBuildCall2(b, func_type, wrapped_func, params, param_count, name);
542+
543+
LLVMValueRef retval;
544+
if (comp_ctx->is_indirect_mode
545+
&& !strncmp(comp_ctx->target_arch, "xtensa", 6)) {
546+
/* call wrapped_func indirectly */
547+
if (!create_func_ptrs(comp_ctx, func_ctx)) {
548+
goto fail;
549+
}
550+
551+
LLVMTypeRef func_ptr_type;
552+
LLVMValueRef wrapped_func_indirect;
553+
uint32 import_func_count = comp_ctx->comp_data->import_func_count;
554+
uint32 func_count = comp_ctx->func_ctx_count;
555+
556+
/* Check function index */
557+
if (func_index >= import_func_count + func_count) {
558+
aot_set_last_error("Function index out of range.");
559+
goto fail;
560+
}
561+
562+
/* Get function type */
563+
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) {
564+
aot_set_last_error("create LLVM function type failed.");
565+
goto fail;
566+
}
567+
568+
/*
569+
* func_index layout :
570+
* aot_func#xxx, range from 0 ~ func_conut - 1;
571+
* aot_func#internal#xxx, range from func_conut ~ 2 * func_conut - 1;
572+
*/
573+
if (!(wrapped_func_indirect = aot_get_func_from_table(
574+
comp_ctx, func_ctx->func_ptrs, func_ptr_type,
575+
func_index + func_count + import_func_count))) {
576+
goto fail;
577+
}
578+
579+
/* Call the function indirectly */
580+
retval = LLVMBuildCall2(b, func_type, wrapped_func_indirect, params,
581+
param_count, name);
582+
}
583+
else
584+
retval = LLVMBuildCall2(b, func_type, wrapped_func, params, param_count,
585+
name);
586+
542587
if (!retval) {
543588
goto fail;
544589
}
@@ -734,7 +779,9 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
734779
}
735780

736781
if (need_precheck) {
737-
if (!comp_ctx->is_jit_mode)
782+
if (!comp_ctx->is_jit_mode
783+
&& !(comp_ctx->is_indirect_mode
784+
&& !strncmp(comp_ctx->target_arch, "xtensa", 6)))
738785
LLVMSetLinkage(func, LLVMInternalLinkage);
739786
unsigned int kind =
740787
LLVMGetEnumAttributeKindForName("noinline", strlen("noinline"));

0 commit comments

Comments
 (0)