0

I have coded in VS2019 using VC++ and compiled using the Intel C++ compiler, a 64 bit command line music file player to play WAV files using WASAPI. The OS is Win 7-SP1.

This is the part of code on which I have questions and need help on. Declaration of variables are left out for conciseness.

// activate an IAudioClient
IAudioClient* pAudioClient;

...
...

// create an event
HANDLE hNeedDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

// set the event handle
hr = pAudioClient->SetEventHandle(hNeedDataEvent);

...
...

//works fine
do
{
    WaitForSingleObject(hNeedDataEvent, INFINITE);

    hr = pAudioRenderClient->ReleaseBuffer(nFramesInBuffer, 0);
    hr = pAudioRenderClient->GetBuffer(nFramesInBuffer, &pData);

    memcpy(pData, sound_buffer + nBytesToSkip, nBytesThisPass);

    nBytesToSkip += nBytesThisPass;
} while (--nBuffersPlayed);

I want to replace the line of code: WaitForSingleObject(hNeedDataEvent, INFINITE); with inline Assembly code using a syscall. Portability is unimportant since this is just for experimentation/learning because have no knowledge of Assembler.

I found a syscall table for Win7-SP1 on Github and here's what it says for NtWaitForSingleObject:

; ULONG64 __stdcall NtWaitForSingleObject( ULONG64 arg_01 , ULONG64 arg_02 , ULONG64 arg_03 );
NtWaitForSingleObject PROC STDCALL 

    mov r10 , rcx
    mov eax , 1

    ;syscall
    db 0Fh , 05h

    ret
NtWaitForSingleObject ENDP

I think the inline Assembly code to replace the call to WaitForSingleObject should be:

__asm
{
    mov r10, ?????? ; pHandle
    xor edx, edx    ; FALSE: The alert cannot be delivered
    xor r8d, r8d    ; Time-out interval, in microseconds. NULL means infinite
    mov eax, 1      ; code number for WaitForSingleObject
    syscall
}

My questions are:

  1. What exactly do I need to move to r10 so that it will contain the "handle" of the event?
  2. Is the rest of the inline Assembly code correct?

As an aside, when I disassembled my compiled code I see this:

    mov     rcx, [rbp+220h+hHandle] ; hHandle
    mov     edx, 0FFFFFFFFh ; dwMilliseconds
    call    cs:WaitForSingleObject
halfer
  • 19,824
  • 17
  • 99
  • 186
ThraxAn
  • 19
  • 4
  • MSVC doesn't support inline assembly for x86-64, only 32-bit x86. MSVC's internals were apparently such a mess that they couldn't safely support inline asm, or something like that, so they removed it. Unless there's an intrinsic for the `syscall` instruction, you're going to have to use a better compiler. Clang supports `-fasm-blocks` to allow basically the same inefficient MSVC inline asm syntax, as well as GNU C inline asm (with output/input constraints, a clobber list, and a template to substitute operands into. See https://gcc.gnu.org/wiki/DontUseInlineAsm for more about it) – Peter Cordes Apr 01 '20 at 16:34
  • Or do you just mean hypothetically, if you did have a compiler that could compile this for x86-64? (And BTW, your English is fine, and welcome to Stack Overflow.) – Peter Cordes Apr 01 '20 at 16:35
  • 1
    I know. I'm using the Intel C++ compiler and edited my question to specify that just before your comment. Thanks! :) – ThraxAn Apr 01 '20 at 16:37
  • Given that the syscalls change between Windows versions, this seems like a [bad idea](https://stackoverflow.com/a/2489975/2189500). You say this is for learning, but learning to call ntdll code might be a more useful thing to learn. That said, [intel](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-inline-assembly) supports gcc's inline asm format. The value for r10 should be the return value from CreateEvent. – David Wohlferd Apr 01 '20 at 22:11
  • @DavidWohlferd - Thank you for your response. I was aware of the caveats/potential issues if I use syscalls as mentioned in the page you linked to. I was aware of the support for inline asm by the Intel compiler. I also knew that the handle of the CreateEvent needed to be passed to r10 but since I have no knowledge of assembly, was not aware of what EXACTLY to pass there. In the end, your response got me thinking some more and I coded this which worked: – ThraxAn Apr 02 '20 at 13:28
  • `__asm { mov r10, hNeedDataEvent ; pHandle xor edx, edx ; FALSE: The alert cannot be delivered xor r8d, r8d ; Time-out interval, in microseconds. NULL means infinite mov eax, 1 ; code number for WaitForSingleObject syscall }` – ThraxAn Apr 02 '20 at 13:29
  • I had no clue that a C++ variable [**hNeedDataEvent** in this case] could be used in asm code directly. – ThraxAn Apr 02 '20 at 13:43

1 Answers1

1
__asm
{
   mov r10, hNeedDataEvent ; pHandle
   xor edx, edx ; FALSE: The alert cannot be delivered
   xor r8d, r8d ; Time-out interval, in microseconds. NULL means infinite
   mov eax, 1 ; code number for WaitForSingleObject syscall
}

I just assigned the value of hNeedDataEvent to r10 and it worked.

ThraxAn
  • 19
  • 4
  • Hi, thanks for sharing the solution. And please feel free to mark yourself to help people with the same issue. – Drake Wu Apr 14 '20 at 05:22