mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 19:47:27 +00:00
ntdll: Switch to the kernel stack for syscalls on ARM.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
08c4419a49
commit
7954b86f6b
|
@ -172,20 +172,31 @@ enum arm_trap_code
|
|||
|
||||
struct syscall_frame
|
||||
{
|
||||
DWORD pad;
|
||||
DWORD cpsr;
|
||||
DWORD r4;
|
||||
DWORD r5;
|
||||
DWORD r6;
|
||||
DWORD r7;
|
||||
DWORD r8;
|
||||
DWORD r9;
|
||||
DWORD r10;
|
||||
DWORD r11;
|
||||
DWORD ret_addr;
|
||||
DWORD thunk_addr;
|
||||
DWORD r0; /* 000 */
|
||||
DWORD r1; /* 004 */
|
||||
DWORD r2; /* 008 */
|
||||
DWORD r3; /* 00c */
|
||||
DWORD r4; /* 010 */
|
||||
DWORD r5; /* 014 */
|
||||
DWORD r6; /* 018 */
|
||||
DWORD r7; /* 01c */
|
||||
DWORD r8; /* 020 */
|
||||
DWORD r9; /* 024 */
|
||||
DWORD r10; /* 028 */
|
||||
DWORD r11; /* 02c */
|
||||
DWORD r12; /* 030 */
|
||||
DWORD pc; /* 034 */
|
||||
DWORD sp; /* 038 */
|
||||
DWORD lr; /* 03c */
|
||||
DWORD cpsr; /* 040 */
|
||||
DWORD restore_flags; /* 044 */
|
||||
DWORD fpscr; /* 048 */
|
||||
DWORD align; /* 04c */
|
||||
ULONGLONG d[32]; /* 050 */
|
||||
};
|
||||
|
||||
C_ASSERT( sizeof( struct syscall_frame ) == 0x150);
|
||||
|
||||
struct arm_thread_data
|
||||
{
|
||||
void *exit_frame; /* 1d4 exit frame pointer */
|
||||
|
@ -201,6 +212,12 @@ static inline struct arm_thread_data *arm_thread_data(void)
|
|||
return (struct arm_thread_data *)ntdll_get_thread_data()->cpu_data;
|
||||
}
|
||||
|
||||
static BOOL is_inside_syscall( ucontext_t *sigcontext )
|
||||
{
|
||||
return ((char *)SP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack &&
|
||||
(char *)SP_sig(sigcontext) <= (char *)arm_thread_data()->syscall_frame);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* unwind_builtin_dll
|
||||
|
@ -301,28 +318,6 @@ static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* set_cpu_context
|
||||
*
|
||||
* Set the new CPU context.
|
||||
*/
|
||||
void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context );
|
||||
__ASM_GLOBAL_FUNC( set_cpu_context,
|
||||
"ldr r2, [r0, #0x44]\n\t" /* context->Cpsr */
|
||||
"tst r2, #0x20\n\t" /* thumb? */
|
||||
"ldr r1, [r0, #0x40]\n\t" /* context->Pc */
|
||||
"ite ne\n\t"
|
||||
"orrne r1, r1, #1\n\t" /* Adjust PC according to thumb */
|
||||
"biceq r1, r1, #1\n\t" /* Adjust PC according to arm */
|
||||
"msr CPSR_f, r2\n\t"
|
||||
"ldr lr, [r0, #0x3c]\n\t" /* context->Lr */
|
||||
"ldr sp, [r0, #0x38]\n\t" /* context->Sp */
|
||||
"push {r1}\n\t"
|
||||
"add r0, #0x4\n\t"
|
||||
"ldm r0, {r0-r12}\n\t" /* context->R0..R12 */
|
||||
"pop {pc}" )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* signal_restore_full_cpu_context
|
||||
*
|
||||
|
@ -330,6 +325,7 @@ __ASM_GLOBAL_FUNC( set_cpu_context,
|
|||
*/
|
||||
void signal_restore_full_cpu_context(void)
|
||||
{
|
||||
arm_thread_data()->syscall_frame->restore_flags |= CONTEXT_INTEGER;
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,15 +336,46 @@ void signal_restore_full_cpu_context(void)
|
|||
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
BOOL self;
|
||||
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
|
||||
DWORD flags = context->ContextFlags & ~CONTEXT_ARM;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_ARMNT );
|
||||
if (self && ret == STATUS_SUCCESS)
|
||||
if (!self)
|
||||
{
|
||||
arm_thread_data()->syscall_frame = NULL;
|
||||
set_cpu_context( context );
|
||||
ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_ARMNT );
|
||||
if (ret || !self) return ret;
|
||||
}
|
||||
return ret;
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
frame->r0 = context->R0;
|
||||
frame->r1 = context->R1;
|
||||
frame->r2 = context->R2;
|
||||
frame->r3 = context->R3;
|
||||
frame->r4 = context->R4;
|
||||
frame->r5 = context->R5;
|
||||
frame->r6 = context->R6;
|
||||
frame->r7 = context->R7;
|
||||
frame->r8 = context->R8;
|
||||
frame->r9 = context->R9;
|
||||
frame->r10 = context->R10;
|
||||
frame->r11 = context->R11;
|
||||
frame->r12 = context->R12;
|
||||
}
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
frame->sp = context->Sp;
|
||||
frame->lr = context->Lr;
|
||||
frame->pc = context->Pc & ~1;
|
||||
frame->cpsr = context->Cpsr;
|
||||
if (context->Cpsr & 0x20) frame->pc |= 1; /* thumb */
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
frame->fpscr = context->Fpscr;
|
||||
memcpy( frame->d, context->u.D, sizeof(context->u.D) );
|
||||
}
|
||||
frame->restore_flags |= flags & ~CONTEXT_INTEGER;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -373,10 +400,10 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|||
{
|
||||
if (needed_flags & CONTEXT_INTEGER)
|
||||
{
|
||||
context->R0 = 0;
|
||||
context->R1 = 0;
|
||||
context->R2 = 0;
|
||||
context->R3 = 0;
|
||||
context->R0 = frame->r0;
|
||||
context->R1 = frame->r1;
|
||||
context->R2 = frame->r2;
|
||||
context->R3 = frame->r3;
|
||||
context->R4 = frame->r4;
|
||||
context->R5 = frame->r5;
|
||||
context->R6 = frame->r6;
|
||||
|
@ -385,18 +412,23 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|||
context->R9 = frame->r9;
|
||||
context->R10 = frame->r10;
|
||||
context->R11 = frame->r11;
|
||||
context->R12 = 0;
|
||||
context->R12 = frame->r12;
|
||||
context->ContextFlags |= CONTEXT_INTEGER;
|
||||
}
|
||||
if (needed_flags & CONTEXT_CONTROL)
|
||||
{
|
||||
context->Sp = (DWORD)(frame + 1);
|
||||
context->Lr = frame->thunk_addr;
|
||||
context->Pc = frame->thunk_addr;
|
||||
context->Sp = frame->sp;
|
||||
context->Lr = frame->lr;
|
||||
context->Pc = frame->pc;
|
||||
context->Cpsr = frame->cpsr;
|
||||
context->ContextFlags |= CONTEXT_CONTROL;
|
||||
}
|
||||
if (needed_flags & CONTEXT_FLOATING_POINT) FIXME( "floating point not implemented\n" );
|
||||
if (needed_flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
context->Fpscr = frame->fpscr;
|
||||
memcpy( context->u.D, frame->d, sizeof(frame->d) );
|
||||
context->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -464,66 +496,70 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
|
|||
/***********************************************************************
|
||||
* call_user_apc_dispatcher
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
|
||||
"mov r5, r1\n\t" /* arg1 */
|
||||
"mov r6, r2\n\t" /* arg2 */
|
||||
"mov r7, r3\n\t" /* arg3 */
|
||||
"ldr r8, [sp]\n\t" /* func */
|
||||
"ldr r9, [sp, #4]\n\t" /* dispatcher */
|
||||
"ldr r10, [sp, #8]\n\t" /* status */
|
||||
"mrc p15, 0, r11, c13, c0, 2\n\t" /* NtCurrentTeb() */
|
||||
"cmp r0, #0\n\t" /* context_ptr */
|
||||
"beq 1f\n\t"
|
||||
"ldr r0, [r0, #0x38]\n\t" /* context_ptr->Sp */
|
||||
"sub r0, r0, #0x1c8\n\t" /* sizeof(CONTEXT) + offsetof(frame,r4) */
|
||||
"mov ip, #0\n\t"
|
||||
"str ip, [r11, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
|
||||
"mov sp, r0\n\t"
|
||||
"b 2f\n"
|
||||
"1:\tldr r0, [r11, #0x1d8]\n\t"
|
||||
"sub r0, #0x1a0\n\t"
|
||||
"mov sp, r0\n\t"
|
||||
"mov r0, #3\n\t"
|
||||
"movt r0, #32\n\t"
|
||||
"str r0, [sp]\n\t" /* context.ContextFlags = CONTEXT_FULL */
|
||||
"mov r1, sp\n\t"
|
||||
"mov r0, #~1\n\t"
|
||||
"bl " __ASM_NAME("NtGetContextThread") "\n\t"
|
||||
"str r10, [sp, #4]\n\t" /* context.R0 = status */
|
||||
"mov r0, sp\n\t"
|
||||
"mov ip, #0\n\t"
|
||||
"str ip, [r11, #0x1d8]\n\t"
|
||||
"2:\tmov r1, r5\n\t" /* arg1 */
|
||||
"mov r2, r6\n\t" /* arg2 */
|
||||
"mov r3, r7\n\t" /* arg3 */
|
||||
"push {r8, r9}\n\t" /* func */
|
||||
"ldr lr, [r0, #0x3c]\n\t" /* context.Lr */
|
||||
"bx r9" )
|
||||
NTSTATUS WINAPI call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3,
|
||||
PNTAPCFUNC func,
|
||||
void (WINAPI *dispatcher)(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR,PNTAPCFUNC),
|
||||
NTSTATUS status )
|
||||
{
|
||||
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
|
||||
ULONG sp = context ? context->Sp : frame->sp;
|
||||
struct apc_stack_layout
|
||||
{
|
||||
void *func;
|
||||
void *align;
|
||||
CONTEXT context;
|
||||
} *stack;
|
||||
|
||||
sp &= ~15;
|
||||
stack = (struct apc_stack_layout *)sp - 1;
|
||||
if (context)
|
||||
{
|
||||
memmove( &stack->context, context, sizeof(stack->context) );
|
||||
NtSetContextThread( GetCurrentThread(), &stack->context );
|
||||
}
|
||||
else
|
||||
{
|
||||
stack->context.ContextFlags = CONTEXT_FULL;
|
||||
NtGetContextThread( GetCurrentThread(), &stack->context );
|
||||
stack->context.R0 = status;
|
||||
}
|
||||
frame->sp = (DWORD)stack;
|
||||
frame->pc = (DWORD)dispatcher;
|
||||
frame->r0 = (DWORD)&stack->context;
|
||||
frame->r1 = arg1;
|
||||
frame->r2 = arg2;
|
||||
frame->r3 = arg3;
|
||||
stack->func = func;
|
||||
frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* call_raise_user_exception_dispatcher
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( call_raise_user_exception_dispatcher,
|
||||
"mov r2, r0\n\t" /* dispatcher */
|
||||
"b " __ASM_NAME("call_user_exception_dispatcher") )
|
||||
void WINAPI call_raise_user_exception_dispatcher( NTSTATUS (WINAPI *dispatcher)(void) )
|
||||
{
|
||||
arm_thread_data()->syscall_frame->pc = (DWORD)dispatcher;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* call_user_exception_dispatcher
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
||||
"mrc p15, 0, r7, c13, c0, 2\n\t" /* NtCurrentTeb() */
|
||||
"ldr r3, [r7, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
|
||||
"mov ip, #0\n\t"
|
||||
"str ip, [r7, #0x1d8]\n\t"
|
||||
"add r3, r3, #8\n\t"
|
||||
"ldm r3, {r5-r11}\n\t"
|
||||
"ldr r4, [r3, #32]\n\t"
|
||||
"ldr lr, [r3, #36]\n\t"
|
||||
"add r3, #40\n\t"
|
||||
"mov sp, r3\n\t"
|
||||
"bx r2" )
|
||||
NTSTATUS WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) )
|
||||
{
|
||||
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
|
||||
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
|
||||
|
||||
if (status) return status;
|
||||
frame->r0 = (DWORD)rec;
|
||||
frame->r1 = (DWORD)context;
|
||||
frame->pc = (DWORD)dispatcher;
|
||||
frame->restore_flags |= CONTEXT_INTEGER | CONTEXT_CONTROL;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -536,7 +572,7 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
|
|||
struct syscall_frame *frame = arm_thread_data()->syscall_frame;
|
||||
DWORD i;
|
||||
|
||||
if (!frame) return FALSE;
|
||||
if (!is_inside_syscall( context )) return FALSE;
|
||||
|
||||
TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
||||
|
@ -564,7 +600,7 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
|
|||
}
|
||||
else
|
||||
{
|
||||
TRACE( "returning to user mode ip=%08x ret=%08x\n", frame->ret_addr, rec->ExceptionCode );
|
||||
TRACE( "returning to user mode ip=%08x ret=%08x\n", frame->pc, rec->ExceptionCode );
|
||||
REGn_sig(0, context) = rec->ExceptionCode;
|
||||
REGn_sig(4, context) = frame->r4;
|
||||
REGn_sig(5, context) = frame->r5;
|
||||
|
@ -574,11 +610,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
|
|||
REGn_sig(9, context) = frame->r9;
|
||||
REGn_sig(10, context) = frame->r10;
|
||||
FP_sig(context) = frame->r11;
|
||||
LR_sig(context) = frame->thunk_addr;
|
||||
SP_sig(context) = (DWORD)&frame->r4;
|
||||
PC_sig(context) = frame->thunk_addr;
|
||||
LR_sig(context) = frame->lr;
|
||||
SP_sig(context) = frame->sp;
|
||||
PC_sig(context) = frame->pc;
|
||||
CPSR_sig(context) = frame->cpsr;
|
||||
arm_thread_data()->syscall_frame = NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -762,9 +797,19 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
|||
{
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, sigcontext );
|
||||
wait_suspend( &context );
|
||||
restore_context( &context, sigcontext );
|
||||
if (is_inside_syscall( sigcontext ))
|
||||
{
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
NtGetContextThread( GetCurrentThread(), &context );
|
||||
wait_suspend( &context );
|
||||
NtSetContextThread( GetCurrentThread(), &context );
|
||||
}
|
||||
else
|
||||
{
|
||||
save_context( &context, sigcontext );
|
||||
wait_suspend( &context );
|
||||
restore_context( &context, sigcontext );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -828,6 +873,9 @@ void signal_init_thread( TEB *teb )
|
|||
void signal_init_process(void)
|
||||
{
|
||||
struct sigaction sig_act;
|
||||
void *kernel_stack = (char *)ntdll_get_thread_data()->kernel_stack + kernel_stack_size;
|
||||
|
||||
arm_thread_data()->syscall_frame = (struct syscall_frame *)kernel_stack - 1;
|
||||
|
||||
sig_act.sa_mask = server_block_set;
|
||||
sig_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
|
||||
|
@ -911,8 +959,13 @@ __ASM_GLOBAL_FUNC( signal_start_thread,
|
|||
/* store exit frame */
|
||||
"ldr r3, [sp, #40]\n\t" /* teb */
|
||||
"str sp, [r3, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */
|
||||
/* set syscall frame */
|
||||
"ldr r6, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
|
||||
"cbnz r6, 1f\n\t"
|
||||
"sub r6, sp, #0x150\n\t" /* sizeof(struct syscall_frame) */
|
||||
"str r6, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
|
||||
/* switch to thread stack */
|
||||
"ldr r4, [r3, #4]\n\t" /* teb->Tib.StackBase */
|
||||
"1:\tldr r4, [r3, #4]\n\t" /* teb->Tib.StackBase */
|
||||
"sub r4, #0x1000\n\t"
|
||||
"mov sp, r4\n\t"
|
||||
/* attach dlls */
|
||||
|
|
|
@ -1665,15 +1665,27 @@ static void output_syscall_dispatcher(void)
|
|||
output( "\tjmp 2b\n" );
|
||||
break;
|
||||
case CPU_ARM:
|
||||
output( "\tpush {r4-r11}\n" );
|
||||
output( "\tadd r6, sp, #40\n" ); /* stack parameters */
|
||||
output( "\tsub sp, sp, #8\n" );
|
||||
output( "\tmrc p15, 0, r7, c13, c0, 2\n" ); /* NtCurrentTeb() */
|
||||
output( "\tadd r7, #0x1d8\n" ); /* arm_thread_data()->syscall_frame */
|
||||
output( "\tmrc p15, 0, r1, c13, c0, 2\n" ); /* NtCurrentTeb() */
|
||||
output( "\tldr r1, [r1, #0x1d8]\n" ); /* arm_thread_data()->syscall_frame */
|
||||
output( "\tadd r0, r1, #0x10\n" );
|
||||
output( "\tstm r0, {r4-r12,lr}\n" );
|
||||
output( "\tstr sp, [r1, #0x38]\n" );
|
||||
output( "\tstr r3, [r1, #0x3c]\n" );
|
||||
output( "\tmrs r0, CPSR\n" );
|
||||
output( "\tbfi r0, lr, #5, #1\n" ); /* set thumb bit */
|
||||
output( "\tstr r0, [sp, #4]\n" );
|
||||
output( "\tstr sp, [r7]\n" ); /* syscall frame */
|
||||
output( "\tstr r0, [r1, #0x40]\n" );
|
||||
output( "\tmov r0, #0\n" );
|
||||
output( "\tstr r0, [r1, #0x44]\n" ); /* frame->restore_flags */
|
||||
if (strcmp( float_abi_option, "soft" ))
|
||||
{
|
||||
output( "\tvmrs r0, fpscr\n" );
|
||||
output( "\tstr r0, [r1, #0x48]\n" );
|
||||
output( "\tadd r0, r1, #0x50\n" );
|
||||
output( "\tvstm r0, {d0-d15}\n" );
|
||||
}
|
||||
output( "\tmov r6, sp\n" );
|
||||
output( "\tmov sp, r1\n" );
|
||||
output( "\tmov r8, r1\n" );
|
||||
output( "\tldr r5, 6f\n");
|
||||
if (UsePIC) output( "1:\tadd r5, pc\n");
|
||||
output( "\tubfx r4, ip, #12, #2\n" ); /* syscall table number */
|
||||
|
@ -1698,11 +1710,24 @@ static void output_syscall_dispatcher(void)
|
|||
output( "\tldr r5, [r4]\n"); /* table->ServiceTable */
|
||||
output( "\tldr ip, [r5, ip, lsl #2]\n");
|
||||
output( "\tblx ip\n");
|
||||
output( "4:\tmov ip, #0\n" );
|
||||
output( "\tstr ip, [r7]\n" );
|
||||
output( "\tsub ip, r6, #40\n" );
|
||||
output( "\tmov sp, ip\n" );
|
||||
output( "\tpop {r4-r12,pc}\n" );
|
||||
output( "\tldr ip, [r8, #0x44]\n" ); /* frame->restore_flags */
|
||||
if (strcmp( float_abi_option, "soft" ))
|
||||
{
|
||||
output( "\ttst ip, #4\n" ); /* CONTEXT_FLOATING_POINT */
|
||||
output( "\tbeq 3f\n" );
|
||||
output( "\tldr r4, [r8, #0x48]\n" );
|
||||
output( "\tvmsr fpscr, r4\n" );
|
||||
output( "\tadd r4, r8, #0x50\n" );
|
||||
output( "\tvldm r4, {d0-d15}\n" );
|
||||
output( "3:\n" );
|
||||
}
|
||||
output( "\ttst ip, #2\n" ); /* CONTEXT_INTEGER */
|
||||
output( "\tit ne\n" );
|
||||
output( "\tldmne r8, {r0-r3}\n" );
|
||||
output( "4:\tldr lr, [r8, #0x3c]\n" );
|
||||
output( "\tldr sp, [r8, #0x38]\n" );
|
||||
output( "\tadd r8, r8, #0x10\n" );
|
||||
output( "\tldm r8, {r4-r12,pc}\n" );
|
||||
output( "5:\tmovw r0, #0x%x\n", invalid_param & 0xffff );
|
||||
output( "\tmovt r0, #0x%x\n", invalid_param >> 16 );
|
||||
output( "\tb 4b\n" );
|
||||
|
@ -1940,7 +1965,7 @@ void output_syscalls( DLLSPEC *spec )
|
|||
output( "\tmov r3, lr\n" );
|
||||
output( "\tbl %s\n", asm_name("__wine_syscall") );
|
||||
output( "\tadd sp, #16\n" );
|
||||
output( "\tbx ip\n" );
|
||||
output( "\tbx lr\n" );
|
||||
break;
|
||||
case CPU_ARM64:
|
||||
output( "\tmov x8, #%u\n", i );
|
||||
|
@ -1969,7 +1994,6 @@ void output_syscalls( DLLSPEC *spec )
|
|||
output( "\t.align %d\n", get_alignment(16) );
|
||||
output( "\t%s\n", func_declaration("__wine_syscall") );
|
||||
output( "%s:\n", asm_name("__wine_syscall") );
|
||||
output( "\tpush {r3,lr}\n" );
|
||||
if (UsePIC)
|
||||
{
|
||||
output( "\tldr r0, 2f\n");
|
||||
|
|
Loading…
Reference in a new issue