Thread overview
Problem using small inout parameters with inline asm
Dec 20, 2005
Sean Kelly
Dec 21, 2005
Tiago Gasiba
Dec 21, 2005
Sean Kelly
Dec 21, 2005
Tiago Gasiba
Dec 21, 2005
Tiago Gasiba
Dec 27, 2005
Chris Lajoie
Dec 27, 2005
Tiago Gasiba
December 20, 2005
I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary.


C:\code\d>type test.d
void fn( inout byte b )
{
    asm
    {
        mov EAX, b;
    }
}


int main()
{
    byte b;
    fn( b );
}
C:\code\d>dmd test
test.d(5): bad type/size of operands 'mov'
December 21, 2005
Sean Kelly schrieb:

> I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary.
> 
> 
> C:\code\d>type test.d
> void fn( inout byte b )
> {
>      asm
>      {
>          mov EAX, b;
>      }
> }
> 
> 
> int main()
> {
>      byte b;
>      fn( b );
> }
> C:\code\d>dmd test
> test.d(5): bad type/size of operands 'mov'

How about doing this:
mov EAX,0;
mov AL, b;

The input parameter is a single byte and should not be loaded directly into EAX.
Note that there is no sign extension!
The following is a dissasembled version of the program.

<snip>
Disassembly of section .gnu.linkonce.t_D5test12fnFKgZv:

0804bbe4 <_D5test12fnFKgZv>:
 804bbe4:       55                      push   ebp
 804bbe5:       8b ec                   mov    ebp,esp
 804bbe7:       83 ec 04                sub    esp,0x4
 804bbea:       89 45 fc                mov    DWORD PTR [ebp-4],eax
 804bbed:       b8 00 00 00 00          mov    eax,0x0
 804bbf2:       8a 45 fc                mov    al,BYTE PTR [ebp-4]
 804bbf5:       c9                      leave
 804bbf6:       c3                      ret
 804bbf7:       90                      nop
Disassembly of section .gnu.linkonce.t_Dmain:

0804bbf8 <_Dmain>:
 804bbf8:       55                      push   ebp
 804bbf9:       8b ec                   mov    ebp,esp
 804bbfb:       83 ec 04                sub    esp,0x4
 804bbfe:       c6 45 fc 00             mov    BYTE PTR [ebp-4],0x0
 804bc02:       8d 45 fc                lea    eax,[ebp-4]
 804bc05:       e8 da ff ff ff          call   804bbe4 <_D5test12fnFKgZv>
 804bc0a:       b8 0d 00 00 00          mov    eax,0xd
 804bc0f:       e8 04 00 00 00          call   804bc18 <_assert_5test1>
 804bc14:       c9                      leave
 804bc15:       c3                      ret
 804bc16:       90                      nop
 804bc17:       90                      nop
<snip>

At address 804bbfe only one byte is pushed into the stack - the other values are "trash".
If you really want to do it, try this:
mov EAX, int ptr b;

Compiles well:
<snip>
0804bbe4 <_D5test12fnFKgZv>:
 804bbe4:       55                      push   ebp
 804bbe5:       8b ec                   mov    ebp,esp
 804bbe7:       83 ec 04                sub    esp,0x4
 804bbea:       89 45 fc                mov    DWORD PTR [ebp-4],eax
 804bbed:       8b 45 fc                mov    eax,DWORD PTR [ebp-4]
 804bbf0:       c9                      leave
 804bbf1:       c3                      ret
 804bbf2:       90                      nop
 804bbf3:       90                      nop
Disassembly of section .gnu.linkonce.t_Dmain:

0804bbf4 <_Dmain>:
 804bbf4:       55                      push   ebp
 804bbf5:       8b ec                   mov    ebp,esp
 804bbf7:       83 ec 04                sub    esp,0x4
 804bbfa:       c6 45 fc 00             mov    BYTE PTR [ebp-4],0x0
 804bbfe:       8d 45 fc                lea    eax,[ebp-4]
 804bc01:       e8 de ff ff ff          call   804bbe4 <_D5test12fnFKgZv>
 804bc06:       b8 0d 00 00 00          mov    eax,0xd
 804bc0b:       e8 04 00 00 00          call   804bc14 <_assert_5test1>
 804bc10:       c9                      leave
 804bc11:       c3                      ret
 804bc12:       90                      nop
 804bc13:       90                      nop
<snip>

Best,
Tiago

-- 
Tiago Gasiba (M.Sc.) - http://www.gasiba.de
Everything should be made as simple as possible, but not simpler.
December 21, 2005
Tiago Gasiba wrote:
> Sean Kelly schrieb:
> 
>> I can workaround this by using a temporary pointer variable, but it
>> doesn't seem like this should be necessary.
>>
>>
>> C:\code\d>type test.d
>> void fn( inout byte b )
>> {
>>      asm
>>      {
>>          mov EAX, b;
>>      }
>> }
>>
>>
>> int main()
>> {
>>      byte b;
>>      fn( b );
>> }
>> C:\code\d>dmd test
>> test.d(5): bad type/size of operands 'mov'
> 
> How about doing this:
> mov EAX,0;
> mov AL, b;
> 
> The input parameter is a single byte and should not be loaded directly into EAX.

I disagree :-)  inout parameters are pointers and so will always be 32 bits on x86.

> Note that there is no sign extension!
> The following is a dissasembled version of the program.
> 
> <snip>
> Disassembly of section .gnu.linkonce.t_D5test12fnFKgZv:
> 
> 0804bbe4 <_D5test12fnFKgZv>:
>  804bbe4:       55                      push   ebp
>  804bbe5:       8b ec                   mov    ebp,esp
>  804bbe7:       83 ec 04                sub    esp,0x4
>  804bbea:       89 45 fc                mov    DWORD PTR [ebp-4],eax
>  804bbed:       b8 00 00 00 00          mov    eax,0x0
>  804bbf2:       8a 45 fc                mov    al,BYTE PTR [ebp-4]
>  804bbf5:       c9                      leave
>  804bbf6:       c3                      ret
>  804bbf7:       90                      nop
> Disassembly of section .gnu.linkonce.t_Dmain:
> 
> 0804bbf8 <_Dmain>:
>  804bbf8:       55                      push   ebp
>  804bbf9:       8b ec                   mov    ebp,esp
>  804bbfb:       83 ec 04                sub    esp,0x4
>  804bbfe:       c6 45 fc 00             mov    BYTE PTR [ebp-4],0x0
>  804bc02:       8d 45 fc                lea    eax,[ebp-4]
>  804bc05:       e8 da ff ff ff          call   804bbe4 <_D5test12fnFKgZv>
>  804bc0a:       b8 0d 00 00 00          mov    eax,0xd
>  804bc0f:       e8 04 00 00 00          call   804bc18 <_assert_5test1>
>  804bc14:       c9                      leave
>  804bc15:       c3                      ret
>  804bc16:       90                      nop
>  804bc17:       90                      nop
> <snip>
> 
> At address 804bbfe only one byte is pushed into the stack - the other values are "trash".

Really?  I thought "byte ptr" meant that 'b' is a pointer to a byte. Shouldn't it be 32 bits then?


Sean
December 21, 2005
Sean Kelly schrieb:

> Tiago Gasiba wrote:
>> Sean Kelly schrieb:
>> 
>>> I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary.
>>>
>>>
>>> C:\code\d>type test.d
>>> void fn( inout byte b )
>>> {
>>>      asm
>>>      {
>>>          mov EAX, b;
>>>      }
>>> }
>>>
>>>
>>> int main()
>>> {
>>>      byte b;
>>>      fn( b );
>>> }
>>> C:\code\d>dmd test
>>> test.d(5): bad type/size of operands 'mov'
>> 
>> How about doing this:
>> mov EAX,0;
>> mov AL, b;
>> 
>> The input parameter is a single byte and should not be loaded directly into EAX.
> 
> I disagree :-)  inout parameters are pointers and so will always be 32 bits on x86.
> 
>> Note that there is no sign extension!
>> The following is a dissasembled version of the program.
>> 
>> <snip>
>> Disassembly of section .gnu.linkonce.t_D5test12fnFKgZv:
>> 
>> 0804bbe4 <_D5test12fnFKgZv>:
>>  804bbe4:       55                      push   ebp
>>  804bbe5:       8b ec                   mov    ebp,esp
>>  804bbe7:       83 ec 04                sub    esp,0x4
>>  804bbea:       89 45 fc                mov    DWORD PTR [ebp-4],eax
>>  804bbed:       b8 00 00 00 00          mov    eax,0x0
>>  804bbf2:       8a 45 fc                mov    al,BYTE PTR [ebp-4]
>>  804bbf5:       c9                      leave
>>  804bbf6:       c3                      ret
>>  804bbf7:       90                      nop
>> Disassembly of section .gnu.linkonce.t_Dmain:
>> 
>> 0804bbf8 <_Dmain>:
>>  804bbf8:       55                      push   ebp
>>  804bbf9:       8b ec                   mov    ebp,esp
>>  804bbfb:       83 ec 04                sub    esp,0x4
>>  804bbfe:       c6 45 fc 00             mov    BYTE PTR [ebp-4],0x0
>>  804bc02:       8d 45 fc                lea    eax,[ebp-4]
>>  804bc05:       e8 da ff ff ff          call   804bbe4 <_D5test12fnFKgZv>
>>  804bc0a:       b8 0d 00 00 00          mov    eax,0xd
>>  804bc0f:       e8 04 00 00 00          call   804bc18 <_assert_5test1>
>>  804bc14:       c9                      leave
>>  804bc15:       c3                      ret
>>  804bc16:       90                      nop
>>  804bc17:       90                      nop
>> <snip>
>> 
>> At address 804bbfe only one byte is pushed into the stack - the other values are "trash".
> 
> Really?  I thought "byte ptr" meant that 'b' is a pointer to a byte. Shouldn't it be 32 bits then?
> 
> 
> Sean

Change the program to the following:

<snip>
void fn( inout byte b ){
  static byte x;

  x = b;
  b = 0x12;
}

int main() {
  byte b;

  fn( b );
}
<snip>

compile and examine the assembly generated code. The function "fn" looks like this:

<snip>
0804bbe4 <_D5test12fnFKgZv>:
 804bbe4:       55                      push   ebp
 804bbe5:       8b ec                   mov    ebp,esp
 804bbe7:       8a 08                   mov    cl,BYTE PTR [eax]
 804bbe9:       88 0d 00 d8 05 08       mov    ds:0x805d800,cl
 804bbef:       c6 00 12                mov    BYTE PTR [eax],0x12
 804bbf2:       5d                      pop    ebp
 804bbf3:       c3                      ret
<snip>


EAX contains the memory pointer and, as you can clearly see, CL is loaded with "b", i.e. a single byte.
The output to "b" is also a single byte, namely 0x12.
Therefore, I think that accessing it with "int ptr" is a bad idea.

Proof of concept:

<snip>
void fn( inout byte x ){
  int  y;
  asm {
    mov EAX, int ptr[x];
    inc byte ptr [EAX];

    mov ECX, int ptr [EAX];
    mov y, ECX;
  }
  printf("y=%x\n",y);

}


int main() {
  byte  x = 0x12;

  fn( x );
  printf("X=%x  \n",x);

  return 0;
}
<snip>

Output:
y=400dad13
X=13

Clearly variable "y" is not being properly used!
However, "x" is correctly incremented and 0x13 is displayed in the output.

Best,
Tiago
-- 
Tiago Gasiba (M.Sc.) - http://www.gasiba.de
Everything should be made as simple as possible, but not simpler.
December 21, 2005
Sean Kelly schrieb:

> Tiago Gasiba wrote:
>> Sean Kelly schrieb:
>> 
>>> I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary.
>>>
>>>
>>> C:\code\d>type test.d
>>> void fn( inout byte b )
>>> {
>>>      asm
>>>      {
>>>          mov EAX, b;
>>>      }
>>> }
>>>
>>>
>>> int main()
>>> {
>>>      byte b;
>>>      fn( b );
>>> }
>>> C:\code\d>dmd test
>>> test.d(5): bad type/size of operands 'mov'
>> 
>> How about doing this:
>> mov EAX,0;
>> mov AL, b;
>> 
>> The input parameter is a single byte and should not be loaded directly into EAX.
> 
> I disagree :-)  inout parameters are pointers and so will always be 32 bits on x86.

Oh! I have just realized that I have messed up a bit... shame on me. That's what happens when I reply too fast. You're totally right - pointers are 32bit.

> 
> Really?  I thought "byte ptr" meant that 'b' is a pointer to a byte. Shouldn't it be 32 bits then?
True!
Although I have messed it up a little, I did manage to give the correct
solution on my last message:

mov EAX, int ptr[x];   // 32 bit pointer
inc byte ptr [EAX];    // address a single byte

Best,
Tiago

-- 
Tiago Gasiba (M.Sc.) - http://www.gasiba.de
Everything should be made as simple as possible, but not simpler.
December 27, 2005
> I disagree :-)  inout parameters are pointers and so will always be 32 bits on x86.

I don't know assembly, but I am really trying to understand this thread. inout parameters are dereferenced implicitly.. so in the asm it is probably being dereferenced the same way it would in normal code (so it wouldn't be a 32 bit ptr, but a byte instead). Are you saying that is incorrect, and it should not be getting dereferenced if it is in
asm { ... } context?

Chris
December 27, 2005
Chris Lajoie schrieb:

> 
>> I disagree :-)  inout parameters are pointers and so will always be 32 bits on x86.
> 
> I don't know assembly, but I am really trying to understand this thread.
> inout parameters are dereferenced implicitly.. so in the asm it is
> probably being dereferenced the same way it would in normal code (so it
> wouldn't be a 32 bit ptr, but a byte instead). Are you saying that is
> incorrect, and it should not be getting dereferenced if it is in
> asm { ... } context?
> 
> Chris
What Sean meant was that the argument that gets passed with an inout parameter
is a pointer, like in the following declaration:  void fn( byte *ptn ){}
The pointer itself (the container for the memory address) is 32bit long, while
the pointer's memory address points to a byte (byte *). Therefore, the true
argument that is passed is a 32bit value, which is why it must be loaded like:

mov EAX, int ptr[x];   // 32 bit pointer
inc byte ptr [EAX];    // address a single byte

The first intruction takes a 32bit value into EAX (the memory address) and the second increments the byte that is pointed by it.

Tiago

-- 
Tiago Gasiba (M.Sc.) - http://www.gasiba.de
Everything should be made as simple as possible, but not simpler.