Skip to content

Commit b490a22

Browse files
authored
Enhance XIP and add XIP document (#863)
Auto detect whether file is XIP file before loading module in posix like and linux-sgx platforms, and if yes, mmap executable memory automatically to run the XIP file. Add document about XIP feature. Enable test spec cases with XIP feature.
1 parent 3f808d4 commit b490a22

File tree

11 files changed

+184
-24
lines changed

11 files changed

+184
-24
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ iwasm VM core
2929
- [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread)
3030
- [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md)
3131
- [Source debugging](./doc/source_debugging.md)
32+
- [XIP (Execution In Place) support](./doc/xip.md)
3233

3334
### post-MVP features
3435
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)

core/iwasm/aot/aot_loader.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,13 +2190,16 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end,
21902190
|| !strcmp(group->section_name, ".text")
21912191
#endif
21922192
) {
2193+
#if !defined(BH_PLATFORM_LINUX) && !defined(BH_PLATFORM_LINUX_SGX) \
2194+
&& !defined(BH_PLATFORM_DARWIN)
21932195
if (module->native_symbol_count > 0) {
21942196
set_error_buf(error_buf, error_buf_size,
21952197
"cannot apply relocation to text section "
21962198
"for aot file generated with "
21972199
"\"--enable-indirect-mode\" flag");
21982200
goto fail;
21992201
}
2202+
#endif
22002203
if (!do_text_relocation(module, group, error_buf, error_buf_size))
22012204
goto fail;
22022205
}

core/iwasm/common/wasm_runtime_common.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,64 @@ get_package_type(const uint8 *buf, uint32 size)
294294
return Package_Type_Unknown;
295295
}
296296

297+
#if WASM_ENABLE_AOT != 0
298+
static uint8 *
299+
align_ptr(const uint8 *p, uint32 b)
300+
{
301+
uintptr_t v = (uintptr_t)p;
302+
uintptr_t m = b - 1;
303+
return (uint8 *)((v + m) & ~m);
304+
}
305+
306+
#define CHECK_BUF(buf, buf_end, length) \
307+
do { \
308+
if (buf + length < buf || buf + length > buf_end) \
309+
return false; \
310+
} while (0)
311+
312+
#define read_uint32(p, p_end, res) \
313+
do { \
314+
p = (uint8 *)align_ptr(p, sizeof(uint32)); \
315+
CHECK_BUF(p, p_end, sizeof(uint32)); \
316+
res = *(uint32 *)p; \
317+
p += sizeof(uint32); \
318+
} while (0)
319+
320+
bool
321+
wasm_runtime_is_xip_file(const uint8 *buf, uint32 size)
322+
{
323+
const uint8 *p = buf, *p_end = buf + size;
324+
uint32 section_type, sub_section_type, section_size;
325+
326+
if (get_package_type(buf, size) != Wasm_Module_AoT)
327+
return false;
328+
329+
CHECK_BUF(p, p_end, 8);
330+
p += 8;
331+
while (p < p_end) {
332+
read_uint32(p, p_end, section_type);
333+
read_uint32(p, p_end, section_size);
334+
CHECK_BUF(p, p_end, section_size);
335+
336+
if (section_type == AOT_SECTION_TYPE_CUSTOM) {
337+
read_uint32(p, p_end, sub_section_type);
338+
if (sub_section_type == AOT_CUSTOM_SECTION_NATIVE_SYMBOL) {
339+
return true;
340+
}
341+
else {
342+
p -= sizeof(uint32);
343+
}
344+
}
345+
else if (section_type >= AOT_SECTION_TYPE_SIGANATURE) {
346+
return false;
347+
}
348+
p += section_size;
349+
}
350+
351+
return false;
352+
}
353+
#endif /* end of WASM_ENABLE_AOT */
354+
297355
#if (WASM_ENABLE_THREAD_MGR != 0) && (WASM_ENABLE_DEBUG_INTERP != 0)
298356
uint32
299357
wasm_runtime_start_debug_instance(WASMExecEnv *exec_env)

core/iwasm/common/wasm_runtime_common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ wasm_runtime_destroy(void);
406406
WASM_RUNTIME_API_EXTERN PackageType
407407
get_package_type(const uint8 *buf, uint32 size);
408408

409+
/* See wasm_export.h for description */
410+
WASM_RUNTIME_API_EXTERN bool
411+
wasm_runtime_is_xip_file(const uint8 *buf, uint32 size);
412+
409413
/* See wasm_export.h for description */
410414
WASM_RUNTIME_API_EXTERN WASMModuleCommon *
411415
wasm_runtime_load(const uint8 *buf, uint32 size, char *error_buf,

core/iwasm/include/wasm_export.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,17 @@ wasm_runtime_free(void *ptr);
235235
WASM_RUNTIME_API_EXTERN package_type_t
236236
get_package_type(const uint8_t *buf, uint32_t size);
237237

238+
/**
239+
* Check whether a file is an AOT XIP (Execution In Place) file
240+
*
241+
* @param buf the package buffer
242+
* @param size the package buffer size
243+
*
244+
* @return true if success, false otherwise
245+
*/
246+
WASM_RUNTIME_API_EXTERN bool
247+
wasm_runtime_is_xip_file(const uint8_t *buf, uint32_t size);
248+
238249
/**
239250
* It is a callback for WAMR providing by embedding to load a module file
240251
* into a buffer

doc/xip.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# WAMR XIP (Execution In Place) feature introduction
2+
3+
Some IoT devices may require to run the AOT file from flash or ROM which is read-only, so as to reduce the memory consumption, or resolve the issue that there is no executable memory available to run AOT code. In such case, the AOT code inside the AOT file shouldn't be duplicated into memory and shouldn't be modified (or patched) by the AOT relocations. To address this, WAMR implements the XIP (Execution In Place) feature, which generates the AOT relocations as few as possible:
4+
- In the AOT code, an AOT function calls other functions with indirect mode: it doesn't call other functions directly, but looks up their pointers from the function pointer table passed by its first argument exec_env, and then calls the function pointer found. By this way the relocations to other functions are eliminated.
5+
- Eliminate the calls to the LLVM intrinsic functions, or, replace calling them with calling runtime self implemented functions instead, e.g. the calling to `llvm.experimental.constrained.fadd.f32` is replaced by the calling to `aot_intrinsic_fadd_f32`.
6+
7+
The XIP file is an AOT file without (or with few) relocations to patch the AOT code (or text section). Developer can use the option `--enable-indirect-mode --disable-llvm-intrinsics` for wamrc to generate the AOT file, e.g.:
8+
```bash
9+
wamrc --enable-indirect-mode --disable-llvm-intrinsics -o <aot_file> <wasm_file>
10+
```
11+
12+
## Known issues
13+
14+
There may be some relocations to the ".rodata" like sections which require to patch the AOT code. More work will be done to resolve it in the future.

product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ typedef struct EnclaveModule {
5252
uint32 wasi_env_list_size;
5353
char **wasi_argv;
5454
uint32 wasi_argc;
55+
bool is_xip_file;
56+
uint32 total_size_mapped;
5557
} EnclaveModule;
5658

5759
#if WASM_ENABLE_SPEC_TEST == 0
@@ -127,28 +129,57 @@ handle_cmd_load_module(uint64 *args, uint32 argc)
127129
uint32 error_buf_size = *(uint32 *)args++;
128130
uint64 total_size = sizeof(EnclaveModule) + (uint64)wasm_file_size;
129131
EnclaveModule *enclave_module;
132+
bool is_xip_file = false;
130133

131134
bh_assert(argc == 4);
132135

133-
if (total_size >= UINT32_MAX
134-
|| !(enclave_module =
135-
(EnclaveModule *)wasm_runtime_malloc((uint32)total_size))) {
136-
set_error_buf(error_buf, error_buf_size,
137-
"WASM module load failed: "
138-
"allocate memory failed.");
139-
*(void **)args_org = NULL;
140-
return;
136+
#if WASM_ENABLE_AOT != 0
137+
is_xip_file = wasm_runtime_is_xip_file((uint8 *)wasm_file, wasm_file_size);
138+
#endif
139+
140+
if (!is_xip_file) {
141+
if (total_size >= UINT32_MAX
142+
|| !(enclave_module = (EnclaveModule *)wasm_runtime_malloc(
143+
(uint32)total_size))) {
144+
set_error_buf(error_buf, error_buf_size,
145+
"WASM module load failed: "
146+
"allocate memory failed.");
147+
*(void **)args_org = NULL;
148+
return;
149+
}
150+
memset(enclave_module, 0, (uint32)total_size);
151+
}
152+
else {
153+
int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
154+
int map_flags = MMAP_MAP_NONE;
155+
156+
if (total_size >= UINT32_MAX
157+
|| !(enclave_module = (EnclaveModule *)os_mmap(
158+
NULL, (uint32)total_size, map_prot, map_flags))) {
159+
set_error_buf(error_buf, error_buf_size,
160+
"WASM module load failed: mmap memory failed.");
161+
*(void **)args_org = NULL;
162+
return;
163+
}
164+
memset(enclave_module, 0, (uint32)total_size);
165+
enclave_module->is_xip_file = true;
166+
enclave_module->total_size_mapped = (uint32)total_size;
141167
}
142168

143-
memset(enclave_module, 0, (uint32)total_size);
144169
enclave_module->wasm_file = (uint8 *)enclave_module + sizeof(EnclaveModule);
145170
bh_memcpy_s(enclave_module->wasm_file, wasm_file_size, wasm_file,
146171
wasm_file_size);
172+
if (is_xip_file) {
173+
enclave_module->is_xip_file = true;
174+
}
147175

148176
if (!(enclave_module->module =
149177
wasm_runtime_load(enclave_module->wasm_file, wasm_file_size,
150178
error_buf, error_buf_size))) {
151-
wasm_runtime_free(enclave_module);
179+
if (!is_xip_file)
180+
wasm_runtime_free(enclave_module);
181+
else
182+
os_munmap(enclave_module, (uint32)total_size);
152183
*(void **)args_org = NULL;
153184
return;
154185
}
@@ -170,7 +201,10 @@ handle_cmd_unload_module(uint64 *args, uint32 argc)
170201
wasm_runtime_free(enclave_module->wasi_arg_buf);
171202

172203
wasm_runtime_unload(enclave_module->module);
173-
wasm_runtime_free(enclave_module);
204+
if (!enclave_module->is_xip_file)
205+
wasm_runtime_free(enclave_module);
206+
else
207+
os_munmap(enclave_module, enclave_module->total_size_mapped);
174208

175209
LOG_VERBOSE("Unload module success.\n");
176210
}

product-mini/platforms/posix/main.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ print_help()
3434
printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n");
3535
printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n"
3636
" that runs commands in the form of \"FUNC ARG...\"\n");
37-
printf(" --xip Enable XIP (Execution In Place) mode to run AOT file\n"
38-
" generated with \"--enable-indirect-mode\" flag\n");
3937
#if WASM_ENABLE_LIBC_WASI != 0
4038
printf(" --env=<env> Pass wasi environment variables with \"key=value\"\n");
4139
printf(" to the program, for example:\n");
@@ -240,7 +238,7 @@ main(int argc, char *argv[])
240238
int log_verbose_level = 2;
241239
#endif
242240
bool is_repl_mode = false;
243-
bool is_xip_mode = false;
241+
bool is_xip_file = false;
244242
#if WASM_ENABLE_LIBC_WASI != 0
245243
const char *dir_list[8] = { NULL };
246244
uint32 dir_list_size = 0;
@@ -273,9 +271,6 @@ main(int argc, char *argv[])
273271
else if (!strcmp(argv[0], "--repl")) {
274272
is_repl_mode = true;
275273
}
276-
else if (!strcmp(argv[0], "--xip")) {
277-
is_xip_mode = true;
278-
}
279274
else if (!strncmp(argv[0], "--stack-size=", 13)) {
280275
if (argv[0][13] == '\0')
281276
return print_help();
@@ -392,10 +387,11 @@ main(int argc, char *argv[])
392387
(uint8 *)bh_read_file_to_buffer(wasm_file, &wasm_file_size)))
393388
goto fail1;
394389

395-
if (is_xip_mode) {
390+
#if WASM_ENABLE_AOT != 0
391+
if (wasm_runtime_is_xip_file(wasm_file_buf, wasm_file_size)) {
396392
uint8 *wasm_file_mapped;
397393
int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC;
398-
int map_flags = MMAP_MAP_NONE;
394+
int map_flags = MMAP_MAP_32BIT;
399395

400396
if (!(wasm_file_mapped =
401397
os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) {
@@ -408,7 +404,9 @@ main(int argc, char *argv[])
408404
wasm_file_size);
409405
wasm_runtime_free(wasm_file_buf);
410406
wasm_file_buf = wasm_file_mapped;
407+
is_xip_file = true;
411408
}
409+
#endif
412410

413411
#if WASM_ENABLE_MULTI_MODULE != 0
414412
wasm_runtime_set_module_reader(module_reader_callback, moudle_destroyer);
@@ -450,7 +448,7 @@ main(int argc, char *argv[])
450448

451449
fail2:
452450
/* free the file buffer */
453-
if (!is_xip_mode)
451+
if (!is_xip_file)
454452
wasm_runtime_free(wasm_file_buf);
455453
else
456454
os_munmap(wasm_file_buf, wasm_file_size);

tests/wamr-test-suites/spec-test-script/all.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def ignore_the_case(
5151
multi_module_flag=False,
5252
multi_thread_flag=False,
5353
simd_flag=False,
54+
xip_flag=False,
5455
):
5556
if case_name in ["comments", "inline-module", "names"]:
5657
return True
@@ -100,6 +101,7 @@ def test_case(
100101
multi_module_flag=False,
101102
multi_thread_flag=False,
102103
simd_flag=False,
104+
xip_flag=False,
103105
clean_up_flag=True,
104106
verbose_flag=True,
105107
):
@@ -114,6 +116,7 @@ def test_case(
114116
multi_module_flag,
115117
multi_thread_flag,
116118
simd_flag,
119+
xip_flag,
117120
):
118121
return True
119122

@@ -139,6 +142,9 @@ def test_case(
139142
if simd_flag:
140143
CMD.append("--simd")
141144

145+
if xip_flag:
146+
CMD.append("--xip")
147+
142148
if not clean_up_flag:
143149
CMD.append("--no_cleanup")
144150

@@ -195,6 +201,7 @@ def test_suite(
195201
multi_module_flag=False,
196202
multi_thread_flag=False,
197203
simd_flag=False,
204+
xip_flag=False,
198205
clean_up_flag=True,
199206
verbose_flag=True,
200207
):
@@ -217,6 +224,7 @@ def test_suite(
217224
multi_module_flag,
218225
multi_thread_flag,
219226
simd_flag,
227+
xip_flag,
220228
clean_up_flag,
221229
verbose_flag,
222230
)
@@ -239,6 +247,7 @@ def test_suite_parallelly(
239247
multi_module_flag=False,
240248
multi_thread_flag=False,
241249
simd_flag=False,
250+
xip_flag=False,
242251
clean_up_flag=False,
243252
verbose_flag=False,
244253
):
@@ -266,6 +275,7 @@ def test_suite_parallelly(
266275
multi_module_flag,
267276
multi_thread_flag,
268277
simd_flag,
278+
xip_flag,
269279
clean_up_flag,
270280
verbose_flag,
271281
],
@@ -323,6 +333,13 @@ def main():
323333
dest="simd_flag",
324334
help="Running with the SIMD feature",
325335
)
336+
parser.add_argument(
337+
"-X",
338+
action="store_true",
339+
default=False,
340+
dest="xip_flag",
341+
help="Running with the XIP feature",
342+
)
326343
parser.add_argument(
327344
"-t",
328345
action="store_true",
@@ -387,6 +404,7 @@ def main():
387404
options.multi_module_flag,
388405
options.multi_thread_flag,
389406
options.simd_flag,
407+
options.xip_flag,
390408
options.clean_up_flag,
391409
options.verbose_flag,
392410
)
@@ -403,6 +421,7 @@ def main():
403421
options.multi_module_flag,
404422
options.multi_thread_flag,
405423
options.simd_flag,
424+
options.xip_flag,
406425
options.clean_up_flag,
407426
options.verbose_flag,
408427
)
@@ -419,6 +438,7 @@ def main():
419438
options.multi_module_flag,
420439
options.multi_thread_flag,
421440
options.simd_flag,
441+
options.xip_flag,
422442
options.clean_up_flag,
423443
options.verbose_flag,
424444
)

0 commit comments

Comments
 (0)