[PATCH 14/18] ntdll: Don't use NtSetContextThread in NtContinue.

Jacek Caban jacek at codeweavers.com
Fri Feb 5 09:18:35 CST 2021


On 05.02.2021 03:43, Zebediah Figura (she/her) wrote:
> On 1/22/21 9:51 AM, Jacek Caban wrote:
>>
>> NtSetContextThread, unlike NtContinue, should not set nonvolatile 
>> registers.
>>
>> Signed-off-by: Jacek Caban <jacek at codeweavers.com>
>> ---
>>    dlls/ntdll/unix/server.c        |  2 +-
>>    dlls/ntdll/unix/signal_arm.c    | 18 +++++++++++++-----
>>    dlls/ntdll/unix/signal_arm64.c  | 20 ++++++++++++++------
>>    dlls/ntdll/unix/signal_i386.c   | 14 +++++++++++++-
>>    dlls/ntdll/unix/signal_x86_64.c | 15 ++++++++++++++-
>>    dlls/ntdll/unix/unix_private.h  |  1 +
>>    6 files changed, 56 insertions(+), 14 deletions(-)
>>
>>
>
> Just to clarify—our NtSetContextThread does set nonvolatile registers, 
> and continues to do so after this series. Is that incorrect behaviour?


No, it does not continue to do so after this series. This is covered by 
the test at the end of the series. NtSetContextThread does set 
nonvolatile registers in syscall frame so that if you set them and then 
query them before syscall returns, you will get modified values. 
However, syscall dispatcher does not restore them from syscall frame. It 
means that if you call NtSetContectThread on current thread, it will not 
set nonvolatile registers to passed values.


> Also:
>
>> diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
>> index db09d7759da..fe581cca7b2 100644
>> --- a/dlls/ntdll/unix/server.c
>> +++ b/dlls/ntdll/unix/server.c
>> @@ -726,7 +726,7 @@ NTSTATUS WINAPI NtContinue( CONTEXT *context, 
>> BOOLEAN alertable )
>>          status = server_select( NULL, 0, SELECT_INTERRUPTIBLE | 
>> SELECT_ALERTABLE, 0, NULL, NULL, &apc );
>>          if (status == STATUS_USER_APC) invoke_apc( context, &apc );
>>      }
>> -    return NtSetContextThread( GetCurrentThread(), context );
>> +    signal_set_cpu_context( context );
>>  }
>>
>>
>
> Would it be simpler just to move NtContinue() to signal_*.c instead?


We'd then need to expose invoke_apc somehow, so I'm not sure if that 
would be better.


> One further question regarding this patch series / patch 0017: I 
> assume you're also planning to also change NtContinue() to use the 
> syscall exit code instead of set_full_cpu_context()?


I considered it. My very first prototype worked like that because it 
always restored all registers, except for rax/eax which becomes a bit 
tricky for that use case. I was thinking about providing an alternative 
syscall leave implementation (NtContinue could replace its own return 
address to opt-in to this), which would do full restore. I didn't try 
implementing that variant yet to see if it's worth it.


For potential future plans, there are also call_user_apc_dispatcher and 
call_user_exception_dispatcher. They could potentially use the same 
mechanism as well instead of manually implementing crossing syscall 
barrier. They are more tricky to change, because we'd need to allow 
using stack is a more similar way to actual syscalls first. A simple 
solution would be to preserve enough unused stack on syscall entry, but 
a more complete solution like separated stacks could be even better.


BTW, as far as this series is considered, I think we will want a few 
specialized implementations for different CPU generations, so I plan to 
look at moving syscall dispatcher code from winebuild to ntdll first. 
ntdll.so would then set proper dispatcher depending on CPU capabilities. 
That requires changes to the way we access syscall table. I didn't do 
the actual implementation yet.


Jacek




More information about the wine-devel mailing list