Refine interpreter call native process and memory boundary check (#124)

This commit is contained in:
wenyongh 2019-09-19 04:05:15 -05:00 committed by GitHub
parent 6e99a37bf2
commit 42dc2d65a1
4 changed files with 127 additions and 143 deletions

View File

@ -1,72 +1,70 @@
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Ivan Volosyuk
//
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.text
.align 2
.globl invokeNative
.type invokeNative, @function
invokeNative:
/* rdi - memory */
/* rsi - n fp args */
/* rdx - n mem args */
/* rcx - function ptr */
/* rdi - function ptr */
/* rsi - argv */
/* rdx - n_stacks */
push %rbp
mov %rsp, %rbp
/* cycle to fill all fp args */
movq 8(%rdi), %xmm0
movq 16(%rdi), %xmm1
movq 24(%rdi), %xmm2
movq 32(%rdi), %xmm3
movq 40(%rdi), %xmm4
movq 48(%rdi), %xmm5
movq 56(%rdi), %xmm6
movq 64(%rdi), %xmm7
mov %rsp, %r10 /* Check that stack is aligned on */
and $8, %r10 /* 16 bytes. This code may be removed */
jz no_abort /* when we are sure that compiler always */
int3 /* calls us with aligned stack */
no_abort:
mov %rdx, %r10 /* Align stack on 16 bytes before pushing */
and $1, %r10 /* stack arguments in case we have an odd */
shl $3, %r10 /* number of stack arguments */
sub %r10, %rsp
mov %rdx, %r10
mov %rsp, %r11 /* Check that stack is aligned on */
and $8, %r11 /* 16 bytes. This code may be removed */
je check_stack_succ /* when we are sure that compiler always */
int3 /* calls us with aligned stack */
check_stack_succ:
mov %r10, %r11 /* Align stack on 16 bytes before pushing */
and $1, %r11 /* stack arguments in case we have an odd */
shl $3, %r11 /* number of stack arguments */
sub %r11, %rsp
/* store memory args */
movq %rcx, %r10 /* func ptr */
movq %rdx, %rcx /* counter */
lea 8+64+48-8(%rdi,%rcx,8), %rdx
sub %rsp, %rdx
movq %rdi, %r11 /* func ptr */
movq %r10, %rcx /* counter */
lea 64+48-8(%rsi,%rcx,8), %r10
sub %rsp, %r10
cmpq $0, %rcx
jz cycle_end
cycle:
push 0(%rsp,%rdx)
loop cycle
cycle_end:
movq 80(%rdi), %rsi
movq 88(%rdi), %rdx
movq 96(%rdi), %rcx
movq 104(%rdi), %r8
movq 112(%rdi), %r9
je push_args_end
push_args:
push 0(%rsp,%r10)
loop push_args
push_args_end:
/* fill all fp args */
movq 0x00(%rsi), %xmm0
movq 0x08(%rsi), %xmm1
movq 0x10(%rsi), %xmm2
movq 0x18(%rsi), %xmm3
movq 0x20(%rsi), %xmm4
movq 0x28(%rsi), %xmm5
movq 0x30(%rsi), %xmm6
movq 0x38(%rsi), %xmm7
movq 72(%rdi), %rdi
/* fill all int args */
movq 0x40(%rsi), %rdi
movq 0x50(%rsi), %rdx
movq 0x58(%rsi), %rcx
movq 0x60(%rsi), %r8
movq 0x68(%rsi), %r9
movq 0x48(%rsi), %rsi
call *%r10
call *%r11
leave
ret

View File

@ -1,56 +1,38 @@
// Copyright (C) 2019 Intel Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Ivan Volosyuk
//
.text
.align 2
.globl invokeNative
.type invokeNative, @function
invokeNative:
push %ebp
movl %esp, %ebp
push %ecx
movl 8(%ebp), %eax /* eax = argv */
movl 12(%ebp), %ecx /* ecx = argc */
movl 16(%ebp), %ecx /* ecx = argc */
movl 12(%ebp), %edx /* edx = argv */
test %ecx, %ecx
je restore_ecx /* if ecx == 0, skip pushing arguments */
leal -4(%eax,%ecx,4), %eax /* eax = eax + ecx * 4 - 4 */
subl %esp, %eax /* eax = eax - esp */
jz skip_push_args /* if ecx == 0, skip pushing arguments */
leal -4(%edx,%ecx,4), %edx /* edx = edx + ecx * 4 - 4 */
subl %esp, %edx /* edx = edx - esp */
1:
push 0(%esp,%eax)
push 0(%esp,%edx)
loop 1b /* loop ecx counts */
restore_ecx:
movl -4(%ebp), %ecx /* restore ecx */
movl 16(%ebp), %eax /* eax = func_ptr */
call *%eax
skip_push_args:
movl 8(%ebp), %edx /* edx = func_ptr */
call *%edx
leave
ret

View File

@ -75,17 +75,17 @@ GET_F64_FROM_ADDR (uint32 *addr)
#endif /* WASM_CPU_SUPPORTS_UNALIGNED_64BIT_ACCESS != 0 */
#if WASM_ENABLE_EXT_MEMORY_SPACE != 0
#define CHECK_EXT_MEMORY_SPACE() \
#define CHECK_EXT_MEMORY_SPACE() \
else if (module->ext_mem_data \
&& module->ext_mem_base_offset <= offset1 \
&& offset1 < module->ext_mem_base_offset \
+ module->ext_mem_size) { \
/* If offset1 is in valid range, maddr must also be in valid range, \
no need to check it again. */ \
maddr = module->ext_mem_data \
+ (offset1 - module->ext_mem_base_offset); \
if (maddr < module->ext_mem_data) \
goto out_of_bounds; \
maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \
if (maddr1 > module->ext_mem_data_end) \
if (maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD] > \
module->ext_mem_data_end) \
goto out_of_bounds; \
}
#else
@ -94,26 +94,25 @@ GET_F64_FROM_ADDR (uint32 *addr)
#define CHECK_MEMORY_OVERFLOW() do { \
uint32 offset1 = offset + addr; \
uint8 *maddr1; \
if (flags != 2) \
LOG_VERBOSE("unaligned load/store in wasm interp, flag is: %d.\n", flags);\
if (offset1 < offset) \
goto out_of_bounds; \
if (offset1 < heap_base_offset) { \
/* if (flags != 2) \
LOG_VERBOSE("unaligned load/store in wasm interp, flag: %d.\n", flags); */\
/* The WASM spec doesn't require that the dynamic address operand must be \
unsigned, so we don't check whether integer overflow or not here. */ \
/* if (offset1 < offset) \
goto out_of_bounds; */ \
if (offset1 < memory_data_size) { \
/* If offset1 is in valid range, maddr must also be in valid range, \
no need to check it again. */ \
maddr = memory->memory_data + offset1; \
if (maddr < memory->base_addr) \
goto out_of_bounds; \
maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \
if (maddr1 > memory->end_addr) \
if (maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD] > memory->end_addr) \
goto out_of_bounds; \
} \
else if (offset1 < memory->heap_base_offset \
+ (memory->heap_data_end - memory->heap_data)) { \
else if (offset1 > heap_base_offset \
&& offset1 < heap_base_offset + heap_data_size) { \
/* If offset1 is in valid range, maddr must also be in valid range, \
no need to check it again. */ \
maddr = memory->heap_data + offset1 - memory->heap_base_offset; \
if (maddr < memory->heap_data) \
goto out_of_bounds; \
maddr1 = maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD]; \
if (maddr1 > memory->heap_data_end) \
if (maddr + LOAD_SIZE[opcode - WASM_OP_I32_LOAD] > memory->heap_data_end) \
goto out_of_bounds; \
} \
CHECK_EXT_MEMORY_SPACE() \
@ -684,7 +683,11 @@ wasm_interp_call_func_bytecode(WASMThread *self,
{
WASMModuleInstance *module = self->module_inst;
WASMMemoryInstance *memory = module->default_memory;
int32 heap_base_offset = memory ? memory->heap_base_offset : 0;
uint32 memory_data_size = memory
? NumBytesPerPage * memory->cur_page_count : 0;
uint32 heap_base_offset = memory ? memory->heap_base_offset : 0;
uint32 heap_data_size = memory
? memory->heap_data_end - memory->heap_data : 0;
WASMTableInstance *table = module->default_table;
uint8 opcode_IMPDEP2 = WASM_OP_IMPDEP2;
WASMInterpFrame *frame = NULL;
@ -1302,6 +1305,7 @@ wasm_interp_call_func_bytecode(WASMThread *self,
PUSH_I32(prev_page_count);
/* update the memory instance ptr */
memory = module->default_memory;
memory_data_size = NumBytesPerPage * memory->cur_page_count;
}
(void)reserved;

View File

@ -1459,13 +1459,13 @@ word_copy(uint32 *dest, uint32 *src, unsigned num)
#if !defined(__x86_64__) && !defined(__amd_64__)
typedef void (*GenericFunctionPointer)();
int64 invokeNative(uint32 *args, uint32 sz, GenericFunctionPointer f);
int64 invokeNative(GenericFunctionPointer f, uint32 *args, uint32 sz);
typedef float64 (*Float64FuncPtr)(uint32*, uint32, GenericFunctionPointer);
typedef float32 (*Float32FuncPtr)(uint32*, uint32, GenericFunctionPointer);
typedef int64 (*Int64FuncPtr)(uint32*, uint32, GenericFunctionPointer);
typedef int32 (*Int32FuncPtr)(uint32*, uint32, GenericFunctionPointer);
typedef void (*VoidFuncPtr)(uint32*, uint32, GenericFunctionPointer);
typedef float64 (*Float64FuncPtr)(GenericFunctionPointer f, uint32*, uint32);
typedef float32 (*Float32FuncPtr)(GenericFunctionPointer f, uint32*, uint32);
typedef int64 (*Int64FuncPtr)(GenericFunctionPointer f, uint32*, uint32);
typedef int32 (*Int32FuncPtr)(GenericFunctionPointer f, uint32*, uint32);
typedef void (*VoidFuncPtr)(GenericFunctionPointer f, uint32*, uint32);
static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)invokeNative;
static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)invokeNative;
@ -1528,21 +1528,21 @@ wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type,
argc1 = j;
if (func_type->result_count == 0) {
invokeNative_Void(argv1, argc1, func_ptr);
invokeNative_Void(func_ptr, argv1, argc1);
}
else {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
ret[0] = invokeNative_Int32(argv1, argc1, func_ptr);
ret[0] = invokeNative_Int32(func_ptr, argv1, argc1);
break;
case VALUE_TYPE_I64:
PUT_I64_TO_ADDR(ret, invokeNative_Int64(argv1, argc1, func_ptr));
PUT_I64_TO_ADDR(ret, invokeNative_Int64(func_ptr, argv1, argc1));
break;
case VALUE_TYPE_F32:
*(float32*)ret = invokeNative_Float32(argv1, argc1, func_ptr);
*(float32*)ret = invokeNative_Float32(func_ptr, argv1, argc1);
break;
case VALUE_TYPE_F64:
PUT_F64_TO_ADDR(ret, invokeNative_Float64(argv1, argc1, func_ptr));
PUT_F64_TO_ADDR(ret, invokeNative_Float64(func_ptr, argv1, argc1));
break;
default:
wasm_assert(0);
@ -1558,13 +1558,13 @@ wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type,
#else /* else of !defined(__x86_64__) && !defined(__amd_64__) */
typedef void (*GenericFunctionPointer)();
int64 invokeNative(uint64 *args, uint64 n_fps, uint64 n_stacks, GenericFunctionPointer f);
int64 invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks);
typedef float64 (*Float64FuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer);
typedef float32 (*Float32FuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer);
typedef int64 (*Int64FuncPtr)(uint64*,uint64, uint64, GenericFunctionPointer);
typedef int32 (*Int32FuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer);
typedef void (*VoidFuncPtr)(uint64*, uint64, uint64, GenericFunctionPointer);
typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint64*, uint64);
typedef float32 (*Float32FuncPtr)(GenericFunctionPointer, uint64*, uint64);
typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint64*,uint64);
typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint64*, uint64);
typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint64*, uint64);
static Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)invokeNative;
static Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)invokeNative;
@ -1604,7 +1604,7 @@ wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type,
}
}
fps = argv1 + 1;
fps = argv1;
ints = fps + MAX_REG_FLOATS;
stacks = ints + MAX_REG_INTS;
@ -1645,21 +1645,21 @@ wasm_runtime_invoke_native(void *func_ptr, WASMType *func_type,
}
if (func_type->result_count == 0) {
invokeNative_Void(argv1, n_fps, n_stacks, func_ptr);
invokeNative_Void(func_ptr, argv1, n_stacks);
}
else {
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
ret[0] = invokeNative_Int32(argv1, n_fps, n_stacks, func_ptr);
ret[0] = invokeNative_Int32(func_ptr, argv1, n_stacks);
break;
case VALUE_TYPE_I64:
PUT_I64_TO_ADDR(ret, invokeNative_Int64(argv1, n_fps, n_stacks, func_ptr));
PUT_I64_TO_ADDR(ret, invokeNative_Int64(func_ptr, argv1, n_stacks));
break;
case VALUE_TYPE_F32:
*(float32*)ret = invokeNative_Float32(argv1, n_fps, n_stacks, func_ptr);
*(float32*)ret = invokeNative_Float32(func_ptr, argv1, n_stacks);
break;
case VALUE_TYPE_F64:
PUT_F64_TO_ADDR(ret, invokeNative_Float64(argv1, n_fps, n_stacks, func_ptr));
PUT_F64_TO_ADDR(ret, invokeNative_Float64(func_ptr, argv1, n_stacks));
break;
default:
wasm_assert(0);