воскресенье, 10 февраля 2013 г.

No ARM code on Windows on ARM

He-he. No ARM code on Windows on ARM. Period.
Though MS called their new OS "Windows on ARM" (sometimes Windows on Snapdragon, Windows on Tegra and now Windows RT) - you can't see ARM code in it. Everything is THUMB2.
I don't know the reason of such a limitation - but that caused me several days of debugging while I was working on a DosBox dynamic core WinRT port last year. The dynamic code generated by DosBox is ARM, even the original THUMB generator was using small ARM thunks. Original DosBox works fine on ARM Linux, but on Windows RT it behaves differently. The generated code executes once, twice, but on the 100500 time - it crashes.
The reason was simple. If you read the ARM developer's manual, you'll see that OS should determine the previous mode (ARM or THUMB) on kernel mode entrance (via SWI, interrupt, ...). Seems that MS decided to simplify the handler's code - and assume that the user's code is always THUMB. And they always set the T bit on return to the user land.
So if you are running generated ARM code in your program - you may be forced to the THUMB mode any moment by an interrupt or a task switch.

Another ARM-code error I've came across.
In my project I need to emulate dialog procedures of the x86 program. Windows calls my own DlgProc, where I pass its parameters to the original x86 function through the emulation layer. But where to store the x86 dialog function address to call it from my code? You can't use SetProp() as the window is not created yet. CreateDialogXxxParam can't be used too - parameter is sent in WM_INITDIALOG message, while it is not the first message you receive (WM_SETFONT and other messages precede it).
So I've decided to generate a small thunk that calls my DlgProc prepending the x86 address before a first parameter. Generated THUMB2 code is simple, tested it in a separate project - idea works fine. But in main project it works once, twice, but on 10th time - the program crashes. And in the exception you see that the lowest bit of LR register points to your code, but is zero. This means that the previous code was executed as ARM, not THUMB2 as I've expected! It took me 2 days to debug. The reason was simple - I've forgot to set the bit 0 of the generated thunk address to one while passing it as DlgProc to the Windows API to indicate that it points to THUMB code. For normal functions Visual Studio does this automatically - but for generated code you should do that yourself.
Windows kernel was "kind enough" to fix that for me 9 times, but on 10th - something went different and my thunk was executed as ARM code. Setting the lowest bit of an address to one - fixed the problem immediately.

During debugging I've found a good article on the internals of Windows kernel to user mode callbacks here. Though it is about a desktop - it is worth reading anyway.

Комментариев нет: