News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

OUT & inline assembler Visual Studio C++

Started by nonosto, January 31, 2018, 02:59:43 PM

Previous topic - Next topic

nonosto

Hello World

I continue to translate some of code from GCC inline assembler to Visual C++ inline assembler.

I have this C++ function:


void IoOutputDword(unsigned short address, unsigned int value)
{
__asm__ __volatile__ ("outl %0,%w1": :"a" (value), "Nd" (address));
}


and I try it in Visual C++:


void IoOutputDword(unsigned short address, unsigned int value)
{
__asm
{
out address, eax;
}
}


But I have this log:


error C2415: improper operand type


Could you help me please?

THX

Mikl__

#1
hi, nonosto!
instructions in, ins, out, outs, cli, sti, int, into, iret are the privileged instructions in windows that can only be executed in kernel space (ring 0), so you can't use them in normal Windows programs

aw27

It is a syntax error. Acceptable variations are: https://c9x.me/x86/html/file_module_x86_id_222.html
This will compile:
__asm
   {
      mov dx, address
      out dx, eax;
   }

Of course, it does not execute in user mode, but that is not the compilation issue.

Mikl__

hi, aw27!
if "address" is constant then "OUT imm8, EAX" is correct instruction, although I will not argue, since I do not write on C/ะก++

aw27

hi Mikl__!

Cdecl, parameters passed on the stack, caller cleans the stack. The function can be translated to:

IoOutputDword proc
   push ebp
   mov ebp, esp
   mov eax, dword ptr [ebp+12]
   mov dx, word ptr[ebp+8]
   out dx, eax
   pop ebp
   ret
IoOutputDword endp

So, there is still something missing to make it work (in kernel mode):  mov eax, dword ptr [ebp+12]

Mikl__


nonosto

THX all. One question why add mov instruction? In original code dont used.

aw27

#7
It is gcc inline __asm__ specifics.
This part '"a" (value)' means place the value in eax.

You can check that with gdb or even better build in Windows under Cygwin and debug with Windbg or Olly, both are more friendly than gdb.
Insert __asm ("int $3"); before the other instruction to make it stop.

For 32-bit is better the 32-bit distribution of Cygwin, although it is possible as well to cross compile under 64-bit Cygwin, but is a bit tricky (like everything in the Unix World).



nonosto

It's so hard...for example I have other function:


void disableInterrupts(void) {
  __asm__ __volatile__("cli");
  return;
}

void enableInterrupts(void) {
  __asm__ __volatile__("sti");
  return;
}

void flushCache(void) {
  __asm__ __volatile__("wbinvd");
  return;
}



And I translate like this:


void disableInterrupts(void)
{
  __asm
{
cli
}
  return;
}

void enableInterrupts(void)
{
__asm
{
sti
}
  return;
}

void flushCache(void)
{
__asm
{
wbinvd
}
  return;
}


I have no error but with what you said I have a doubt return same result. What do you think?

aw27

Look good, but all will crash in user mode, as you know.

nonosto

THX very much. I work ina very special and very old hardware. The code/exe is by default in kernel mode.
I am sorry to abuse but I have this function I dont succes to translate..... :icon_redface:
the first:

void wrmsr(uint32_t msr, uint32_t high, uint32_t low)
{
  __asm__ __volatile__ ("wrmsr"
                        :
                        :"a"(low), "c"(msr), "d"(high));
  return;
}


and I try this from a web source (It's seems crazy...):
void wrmsr(uint32_t msr, uint32_t high, uint32_t low)
{
  __asm
{ push ecx
push edx
push eax
mov ecx,msr
mov low,eax
mov high,edx
mov ecx, msr
wrmsr
pop eax
pop edx
pop ecx
}
  return;
}


For the next my big problem are last line:


void disableCache(void) {
  uint32_t mask = (1 << 30) | (1 << 29); // CD | NW
  __asm__ __volatile__ ("movl %%cr0,%%eax\n"
                        "orl %%ecx,%%eax\n"
                        "movl %%eax,%%cr0"
                        :
                        :"c"(mask)
                        :"eax","memory");
  return;
}



and I try this:


void disableCache(void)
{
  uint32_t mask = (1 << 30) | (1 << 29); // CD | NW
__asm
{
mov eax, cr0
or eax, ecx
        mov cr0, eax
        mov ecx, mask
        eax,memory
}
  return;
}


exactly this line is a problem for me:


:"c"(mask)
:"eax","memory");


Could help me ?

aw27

The first one is wrong and you don't need to push volatile registers, they are fair play.

void wrmsr(uint32_t msr, uint32_t high, uint32_t low)
{
  __asm
   {   
      mov eax, low
      mov ecx, msr
      mov edx, high
      wrmsr
   }
  return;
}

The second one is wrong too. Don't bother with "memory", it is a clobber argument - a special instruction to the gcc compiler to let it know there is data coming from memory (mask in this case) - Visual Studio can figure that out.

void disableCache(void)
{
   uint32_t mask = (1 << 30) | (1 << 29);
   __asm
   {
      mov ecx,mask
      mov eax,cr0
      or eax,ecx
            mov cr0,eax
   }
  return;
}

This can be simplified to:

void disableCache(void)
{
   __asm
   {
      mov eax, cr0
      or eax, (1 << 30) | (1 << 29)
      mov cr0, eax
   }
   return;
}

nonosto

Thank you very much.

for:


void wrmsr(uint32_t msr, uint32_t high, uint32_t low)
{
  __asm
   {
   mov eax, low
   mov ecx, msr
   mov edx, high
   wrmsr
   }
  return;
}


I have this compiler error:

error C2400: inline assembler syntax error in 'second operand'; found 'newline'
error C2400: inline assembler syntax error in 'second operand'; found 'newline'


I dont know how to fix it.

Thanks to you I translate this code witout compil error:

from:


void enableCache(void) {
  uint32_t mask = ~((1 << 30) | (1 << 29)); // CD | NW
  __asm__ __volatile__ ("movl %%cr0,%%eax\n"
                        "andl %%ecx,%%eax\n"
                        "movl %%eax,%%cr0"
                        :
                        :"c"(mask)
                        :"eax","memory");
  return;
}


to


void enableCache(void)
{
uint32_t mask = ~((1 << 30) | (1 << 29)); // CD | NW
  __asm
   {
      mov ecx,mask
      mov eax,cr0
      and eax,ecx
      mov cr0,eax
   }
  return;
}


and from:


void flushTlb(void) {
  __asm__ __volatile__("movl %%cr3, %%eax\n"
                       "movl %%eax, %%cr3"
                       :
                       :
                       :"eax","memory");
  return;
}


to

void flushTlb(void)
{
  __asm
{
       mov eax, cr3
   mov cr3, eax
}
  return;
}


Please could you confirm me no error please?

aw27

low and high are reserved words, not names for variables, change them.

And I think you got enough info to walk on your own.  :t

nonosto